This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 4d7fc0a0fc Add tests to increase code coverage: `DatesJUnit5Test`,
`NumberValueJUnit5Test`, etc.
4d7fc0a0fc is described below
commit 4d7fc0a0fc5210440dddb79a8a132fe144893761
Author: Daniel Sun <[email protected]>
AuthorDate: Sun Feb 1 22:34:58 2026 +0900
Add tests to increase code coverage: `DatesJUnit5Test`,
`NumberValueJUnit5Test`, etc.
---
.../java/groovy/util/CharsetToolkitJUnit5Test.java | 425 ++++++++++++++
.../codehaus/groovy/syntax/TypesJUnit5Test.java | 637 +++++++++++++++++++++
.../tools/LoaderConfigurationJUnit5Test.java | 326 +++++++++++
.../groovy/json/StringEscapeUtilsJUnit5Test.java | 372 ++++++++++++
.../json/internal/CharSequenceValueJUnit5Test.java | 431 ++++++++++++++
.../groovy/json/internal/DatesJUnit5Test.java | 304 ++++++++++
.../json/internal/NumberValueJUnit5Test.java | 395 +++++++++++++
.../json/internal/ValueContainerJUnit5Test.java | 301 ++++++++++
8 files changed, 3191 insertions(+)
diff --git a/src/test/java/groovy/util/CharsetToolkitJUnit5Test.java
b/src/test/java/groovy/util/CharsetToolkitJUnit5Test.java
new file mode 100644
index 0000000000..64cdd4105a
--- /dev/null
+++ b/src/test/java/groovy/util/CharsetToolkitJUnit5Test.java
@@ -0,0 +1,425 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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 groovy.util;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for CharsetToolkit class.
+ */
+class CharsetToolkitJUnit5Test {
+
+ @TempDir
+ Path tempDir;
+
+ // Constructor tests
+ @Test
+ void testConstructorWithEmptyFile() throws IOException {
+ File file = tempDir.resolve("empty.txt").toFile();
+ file.createNewFile();
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertNotNull(toolkit.getCharset());
+ }
+
+ @Test
+ void testConstructorWithSmallFile() throws IOException {
+ File file = tempDir.resolve("small.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertNotNull(toolkit.getCharset());
+ }
+
+ @Test
+ void testConstructorWithLargeFile() throws IOException {
+ File file = tempDir.resolve("large.txt").toFile();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 5000; i++) {
+ sb.append("Hello World\n");
+ }
+ Files.writeString(file.toPath(), sb.toString());
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertNotNull(toolkit.getCharset());
+ }
+
+ // getDefaultSystemCharset tests
+ @Test
+ void testGetDefaultSystemCharset() {
+ Charset charset = CharsetToolkit.getDefaultSystemCharset();
+ assertNotNull(charset);
+ assertEquals(Charset.defaultCharset(), charset);
+ }
+
+ // setDefaultCharset tests
+ @Test
+ void testSetDefaultCharset() throws IOException {
+ File file = tempDir.resolve("test.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ toolkit.setDefaultCharset(StandardCharsets.ISO_8859_1);
+ assertEquals(StandardCharsets.ISO_8859_1, toolkit.getDefaultCharset());
+ }
+
+ @Test
+ void testSetDefaultCharsetNull() throws IOException {
+ File file = tempDir.resolve("test.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ toolkit.setDefaultCharset(null);
+ // Should fall back to system default
+ assertEquals(CharsetToolkit.getDefaultSystemCharset(),
toolkit.getDefaultCharset());
+ }
+
+ // getEnforce8Bit/setEnforce8Bit tests
+ @Test
+ void testEnforce8BitDefault() throws IOException {
+ File file = tempDir.resolve("test.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertTrue(toolkit.getEnforce8Bit());
+ }
+
+ @Test
+ void testSetEnforce8Bit() throws IOException {
+ File file = tempDir.resolve("test.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ toolkit.setEnforce8Bit(false);
+ assertFalse(toolkit.getEnforce8Bit());
+ }
+
+ // UTF-8 BOM tests
+ @Test
+ void testHasUTF8Bom() throws IOException {
+ File file = tempDir.resolve("utf8bom.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}); //
UTF-8 BOM
+ fos.write("Hello".getBytes(StandardCharsets.UTF_8));
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertTrue(toolkit.hasUTF8Bom());
+ assertEquals(StandardCharsets.UTF_8, toolkit.getCharset());
+ }
+
+ @Test
+ void testNoUTF8Bom() throws IOException {
+ File file = tempDir.resolve("nobom.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertFalse(toolkit.hasUTF8Bom());
+ }
+
+ // UTF-16 LE BOM tests
+ @Test
+ void testHasUTF16LEBom() throws IOException {
+ File file = tempDir.resolve("utf16le.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xFF, (byte) 0xFE}); // UTF-16 LE BOM
+ fos.write("Hello".getBytes(StandardCharsets.UTF_16LE));
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertTrue(toolkit.hasUTF16LEBom());
+ assertEquals(StandardCharsets.UTF_16LE, toolkit.getCharset());
+ }
+
+ @Test
+ void testNoUTF16LEBom() throws IOException {
+ File file = tempDir.resolve("nobom.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertFalse(toolkit.hasUTF16LEBom());
+ }
+
+ // UTF-16 BE BOM tests
+ @Test
+ void testHasUTF16BEBom() throws IOException {
+ File file = tempDir.resolve("utf16be.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xFE, (byte) 0xFF}); // UTF-16 BE BOM
+ fos.write("Hello".getBytes(StandardCharsets.UTF_16BE));
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertTrue(toolkit.hasUTF16BEBom());
+ assertEquals(StandardCharsets.UTF_16BE, toolkit.getCharset());
+ }
+
+ @Test
+ void testNoUTF16BEBom() throws IOException {
+ File file = tempDir.resolve("nobom.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertFalse(toolkit.hasUTF16BEBom());
+ }
+
+ // BOM with short buffer tests
+ @Test
+ void testBomCheckWithOneByte() throws IOException {
+ File file = tempDir.resolve("onebyte.txt").toFile();
+ Files.write(file.toPath(), new byte[]{0x48}); // Just 'H'
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertFalse(toolkit.hasUTF8Bom());
+ assertFalse(toolkit.hasUTF16LEBom());
+ assertFalse(toolkit.hasUTF16BEBom());
+ }
+
+ @Test
+ void testBomCheckWithTwoBytes() throws IOException {
+ File file = tempDir.resolve("twobytes.txt").toFile();
+ Files.write(file.toPath(), new byte[]{0x48, 0x69}); // "Hi"
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertFalse(toolkit.hasUTF8Bom());
+ assertFalse(toolkit.hasUTF16LEBom());
+ assertFalse(toolkit.hasUTF16BEBom());
+ }
+
+ // US-ASCII detection tests
+ @Test
+ void testUsAsciiDetectionWithEnforce8BitTrue() throws IOException {
+ File file = tempDir.resolve("ascii.txt").toFile();
+ Files.writeString(file.toPath(), "Hello World"); // Pure ASCII
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ toolkit.setEnforce8Bit(true);
+ // Should return default charset instead of US-ASCII
+ assertNotEquals(StandardCharsets.US_ASCII, toolkit.getCharset());
+ }
+
+ @Test
+ void testUsAsciiDetectionWithEnforce8BitFalse() throws IOException {
+ File file = tempDir.resolve("ascii.txt").toFile();
+ Files.writeString(file.toPath(), "Hello World"); // Pure ASCII
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ toolkit.setEnforce8Bit(false);
+ assertEquals(StandardCharsets.US_ASCII, toolkit.getCharset());
+ }
+
+ // UTF-8 detection (without BOM) tests
+ @Test
+ void testUtf8DetectionTwoByteSequence() throws IOException {
+ File file = tempDir.resolve("utf8-2byte.txt").toFile();
+ // Create enough content to trigger UTF-8 detection
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 100; i++) {
+ sb.append("Héllo Wörld "); // Contains two-byte UTF-8 sequences
+ }
+ Files.writeString(file.toPath(), sb.toString(),
StandardCharsets.UTF_8);
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertEquals(StandardCharsets.UTF_8, toolkit.getCharset());
+ }
+
+ @Test
+ void testUtf8DetectionThreeByteSequence() throws IOException {
+ File file = tempDir.resolve("utf8-3byte.txt").toFile();
+ // Create content with three-byte UTF-8 sequences (Chinese characters)
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 100; i++) {
+ sb.append("你好世界 "); // Chinese characters are 3-byte UTF-8
sequences
+ }
+ Files.writeString(file.toPath(), sb.toString(),
StandardCharsets.UTF_8);
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertEquals(StandardCharsets.UTF_8, toolkit.getCharset());
+ }
+
+ @Test
+ void testUtf8DetectionFourByteSequence() throws IOException {
+ File file = tempDir.resolve("utf8-4byte.txt").toFile();
+ // Create content with four-byte UTF-8 sequences (emoji)
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 100; i++) {
+ sb.append("\uD83D\uDE00 "); // Grinning face emoji is a 4-byte
UTF-8 sequence
+ }
+ Files.writeString(file.toPath(), sb.toString(),
StandardCharsets.UTF_8);
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertEquals(StandardCharsets.UTF_8, toolkit.getCharset());
+ }
+
+ // Invalid UTF-8 detection
+ @Test
+ void testInvalidUtf8FallsBackToDefault() throws IOException {
+ File file = tempDir.resolve("invalid-utf8.txt").toFile();
+ // Write bytes that look like start of UTF-8 multi-byte but aren't
valid
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ // Write some content with invalid UTF-8 sequence
+ byte[] content = new byte[100];
+ for (int i = 0; i < content.length - 1; i++) {
+ content[i] = (byte) 'A'; // ASCII
+ }
+ // Add an invalid high-order byte without proper continuation
+ content[50] = (byte) 0xC0; // Start of 2-byte sequence
+ content[51] = (byte) 0x20; // Space (not a valid continuation byte)
+ fos.write(content);
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ // Should fall back to default charset since it's not valid UTF-8
+ assertNotNull(toolkit.getCharset());
+ }
+
+ // getReader tests
+ @Test
+ void testGetReaderAscii() throws IOException {
+ File file = tempDir.resolve("test.txt").toFile();
+ Files.writeString(file.toPath(), "Hello World");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ BufferedReader reader = toolkit.getReader();
+
+ assertNotNull(reader);
+ assertEquals("Hello World", reader.readLine());
+ reader.close();
+ }
+
+ @Test
+ void testGetReaderUtf8WithBom() throws IOException {
+ File file = tempDir.resolve("utf8bom.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}); //
UTF-8 BOM
+ fos.write("Hello".getBytes(StandardCharsets.UTF_8));
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ BufferedReader reader = toolkit.getReader();
+
+ assertNotNull(reader);
+ // BOM should be skipped
+ String line = reader.readLine();
+ assertEquals("Hello", line);
+ reader.close();
+ }
+
+ @Test
+ void testGetReaderUtf16LEWithBom() throws IOException {
+ File file = tempDir.resolve("utf16le.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xFF, (byte) 0xFE}); // UTF-16 LE BOM
+ fos.write("Hello".getBytes(StandardCharsets.UTF_16LE));
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ BufferedReader reader = toolkit.getReader();
+
+ assertNotNull(reader);
+ reader.close();
+ }
+
+ @Test
+ void testGetReaderUtf16BEWithBom() throws IOException {
+ File file = tempDir.resolve("utf16be.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xFE, (byte) 0xFF}); // UTF-16 BE BOM
+ fos.write("Hello".getBytes(StandardCharsets.UTF_16BE));
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ BufferedReader reader = toolkit.getReader();
+
+ assertNotNull(reader);
+ reader.close();
+ }
+
+ // getAvailableCharsets tests
+ @Test
+ void testGetAvailableCharsets() {
+ Charset[] charsets = CharsetToolkit.getAvailableCharsets();
+
+ assertNotNull(charsets);
+ assertTrue(charsets.length > 0);
+
+ // Should contain common charsets
+ boolean hasUtf8 = false;
+ for (Charset charset : charsets) {
+ if (StandardCharsets.UTF_8.equals(charset)) {
+ hasUtf8 = true;
+ break;
+ }
+ }
+ assertTrue(hasUtf8);
+ }
+
+ // getCharset caching test
+ @Test
+ void testGetCharsetCaching() throws IOException {
+ File file = tempDir.resolve("test.txt").toFile();
+ Files.writeString(file.toPath(), "Hello");
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ Charset first = toolkit.getCharset();
+ Charset second = toolkit.getCharset();
+
+ assertSame(first, second); // Should return cached value
+ }
+
+ // Edge case: file with just BOM
+ @Test
+ void testFileWithOnlyUtf8Bom() throws IOException {
+ File file = tempDir.resolve("bom-only.txt").toFile();
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ fos.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}); //
UTF-8 BOM only
+ }
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ assertTrue(toolkit.hasUTF8Bom());
+ assertEquals(StandardCharsets.UTF_8, toolkit.getCharset());
+ }
+
+ // Edge case: file with mixed content
+ @Test
+ void testLongAsciiFileWithEnforce8BitFalse() throws IOException {
+ File file = tempDir.resolve("long-ascii.txt").toFile();
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < 1000; i++) {
+ sb.append("abcdefghij"); // Pure ASCII
+ }
+ Files.writeString(file.toPath(), sb.toString());
+
+ CharsetToolkit toolkit = new CharsetToolkit(file);
+ toolkit.setEnforce8Bit(false);
+ assertEquals(StandardCharsets.US_ASCII, toolkit.getCharset());
+ }
+}
diff --git a/src/test/java/org/codehaus/groovy/syntax/TypesJUnit5Test.java
b/src/test/java/org/codehaus/groovy/syntax/TypesJUnit5Test.java
new file mode 100644
index 0000000000..4f03414127
--- /dev/null
+++ b/src/test/java/org/codehaus/groovy/syntax/TypesJUnit5Test.java
@@ -0,0 +1,637 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.codehaus.groovy.syntax;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for Types class - token type classification and matching.
+ */
+class TypesJUnit5Test {
+
+ // ofType basic tests
+ @Test
+ void testOfTypeSameType() {
+ assertTrue(Types.ofType(Types.PLUS, Types.PLUS));
+ assertTrue(Types.ofType(Types.KEYWORD_IF, Types.KEYWORD_IF));
+ }
+
+ @Test
+ void testOfTypeAny() {
+ assertTrue(Types.ofType(Types.PLUS, Types.ANY));
+ assertTrue(Types.ofType(Types.KEYWORD_IF, Types.ANY));
+ assertTrue(Types.ofType(Types.STRING, Types.ANY));
+ }
+
+ @Test
+ void testOfTypeNotEof() {
+ assertTrue(Types.ofType(Types.UNKNOWN, Types.NOT_EOF));
+ assertTrue(Types.ofType(Types.PLUS, Types.NOT_EOF));
+ assertTrue(Types.ofType(Types.SYNTH_VARIABLE_DECLARATION,
Types.NOT_EOF));
+ assertFalse(Types.ofType(Types.EOF, Types.NOT_EOF));
+ }
+
+ // End of statement tests
+ @Test
+ void testOfTypeGeneralEndOfStatement() {
+ assertTrue(Types.ofType(Types.EOF, Types.GENERAL_END_OF_STATEMENT));
+ assertTrue(Types.ofType(Types.NEWLINE,
Types.GENERAL_END_OF_STATEMENT));
+ assertTrue(Types.ofType(Types.SEMICOLON,
Types.GENERAL_END_OF_STATEMENT));
+ assertFalse(Types.ofType(Types.PLUS, Types.GENERAL_END_OF_STATEMENT));
+ }
+
+ @Test
+ void testOfTypeAnyEndOfStatement() {
+ assertTrue(Types.ofType(Types.EOF, Types.ANY_END_OF_STATEMENT));
+ assertTrue(Types.ofType(Types.NEWLINE, Types.ANY_END_OF_STATEMENT));
+ assertTrue(Types.ofType(Types.SEMICOLON, Types.ANY_END_OF_STATEMENT));
+ assertTrue(Types.ofType(Types.RIGHT_CURLY_BRACE,
Types.ANY_END_OF_STATEMENT));
+ assertFalse(Types.ofType(Types.PLUS, Types.ANY_END_OF_STATEMENT));
+ }
+
+ // Assignment operator tests
+ @Test
+ void testIsAssignment() {
+ assertTrue(Types.isAssignment(Types.EQUAL));
+ assertTrue(Types.isAssignment(Types.PLUS_EQUAL));
+ assertTrue(Types.isAssignment(Types.MINUS_EQUAL));
+ assertTrue(Types.isAssignment(Types.MULTIPLY_EQUAL));
+ assertTrue(Types.isAssignment(Types.DIVIDE_EQUAL));
+ assertTrue(Types.isAssignment(Types.MOD_EQUAL));
+ assertTrue(Types.isAssignment(Types.POWER_EQUAL));
+ assertTrue(Types.isAssignment(Types.ELVIS_EQUAL));
+ assertTrue(Types.isAssignment(Types.LOGICAL_OR_EQUAL));
+ assertTrue(Types.isAssignment(Types.LOGICAL_AND_EQUAL));
+ assertTrue(Types.isAssignment(Types.LEFT_SHIFT_EQUAL));
+ assertTrue(Types.isAssignment(Types.RIGHT_SHIFT_EQUAL));
+ assertTrue(Types.isAssignment(Types.BITWISE_OR_EQUAL));
+ assertTrue(Types.isAssignment(Types.BITWISE_AND_EQUAL));
+ assertTrue(Types.isAssignment(Types.BITWISE_XOR_EQUAL));
+ assertFalse(Types.isAssignment(Types.PLUS));
+ assertFalse(Types.isAssignment(Types.COMPARE_EQUAL));
+ }
+
+ @Test
+ void testOfTypeAssignmentOperator() {
+ assertTrue(Types.ofType(Types.EQUAL, Types.ASSIGNMENT_OPERATOR));
+ assertTrue(Types.ofType(Types.PLUS_EQUAL, Types.ASSIGNMENT_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.ASSIGNMENT_OPERATOR));
+ }
+
+ // Comparison operator tests
+ @Test
+ void testOfTypeComparisonOperator() {
+ assertTrue(Types.ofType(Types.COMPARE_EQUAL,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_NOT_EQUAL,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_LESS_THAN,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_LESS_THAN_EQUAL,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_GREATER_THAN,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_GREATER_THAN_EQUAL,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_TO, Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_IDENTICAL,
Types.COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_NOT_IDENTICAL,
Types.COMPARISON_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.COMPARISON_OPERATOR));
+ }
+
+ // Instanceof operator tests
+ @Test
+ void testOfTypeInstanceofOperator() {
+ assertTrue(Types.ofType(Types.KEYWORD_INSTANCEOF,
Types.INSTANCEOF_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_NOT_INSTANCEOF,
Types.INSTANCEOF_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.INSTANCEOF_OPERATOR));
+ }
+
+ // Math operator tests
+ @Test
+ void testOfTypeMathOperator() {
+ assertTrue(Types.ofType(Types.PLUS, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.MINUS, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.MULTIPLY, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.DIVIDE, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.MOD, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.POWER, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.LOGICAL_OR, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.LOGICAL_AND, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.NOT, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.BITWISE_OR, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.BITWISE_AND, Types.MATH_OPERATOR));
+ assertTrue(Types.ofType(Types.BITWISE_XOR, Types.MATH_OPERATOR));
+ assertFalse(Types.ofType(Types.EQUAL, Types.MATH_OPERATOR));
+ }
+
+ // Logical operator tests
+ @Test
+ void testOfTypeLogicalOperator() {
+ assertTrue(Types.ofType(Types.NOT, Types.LOGICAL_OPERATOR));
+ assertTrue(Types.ofType(Types.LOGICAL_OR, Types.LOGICAL_OPERATOR));
+ assertTrue(Types.ofType(Types.LOGICAL_AND, Types.LOGICAL_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.LOGICAL_OPERATOR));
+ }
+
+ // Bitwise operator tests
+ @Test
+ void testOfTypeBitwiseOperator() {
+ assertTrue(Types.ofType(Types.BITWISE_OR, Types.BITWISE_OPERATOR));
+ assertTrue(Types.ofType(Types.BITWISE_AND, Types.BITWISE_OPERATOR));
+ assertTrue(Types.ofType(Types.BITWISE_XOR, Types.BITWISE_OPERATOR));
+ assertTrue(Types.ofType(Types.BITWISE_NEGATION,
Types.BITWISE_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.BITWISE_OPERATOR));
+ }
+
+ // Range operator tests
+ @Test
+ void testOfTypeRangeOperator() {
+ assertTrue(Types.ofType(Types.DOT_DOT, Types.RANGE_OPERATOR));
+ assertTrue(Types.ofType(Types.DOT_DOT_DOT, Types.RANGE_OPERATOR));
+ assertFalse(Types.ofType(Types.DOT, Types.RANGE_OPERATOR));
+ }
+
+ // Regex comparison operator tests
+ @Test
+ void testOfTypeRegexComparisonOperator() {
+ assertTrue(Types.ofType(Types.FIND_REGEX,
Types.REGEX_COMPARISON_OPERATOR));
+ assertTrue(Types.ofType(Types.MATCH_REGEX,
Types.REGEX_COMPARISON_OPERATOR));
+ assertFalse(Types.ofType(Types.EQUAL,
Types.REGEX_COMPARISON_OPERATOR));
+ }
+
+ // Dereference operator tests
+ @Test
+ void testOfTypeDereferenceOperator() {
+ assertTrue(Types.ofType(Types.DOT, Types.DEREFERENCE_OPERATOR));
+ assertTrue(Types.ofType(Types.NAVIGATE, Types.DEREFERENCE_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.DEREFERENCE_OPERATOR));
+ }
+
+ // Prefix operator tests
+ @Test
+ void testOfTypePrefixOperator() {
+ assertTrue(Types.ofType(Types.MINUS, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PLUS_PLUS, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.MINUS_MINUS, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.REGEX_PATTERN, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.NOT, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_PLUS, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_MINUS, Types.PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.SYNTH_CAST, Types.PREFIX_OPERATOR));
+ }
+
+ // Pure prefix operator tests
+ @Test
+ void testOfTypePurePrefixOperator() {
+ assertTrue(Types.ofType(Types.REGEX_PATTERN,
Types.PURE_PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.NOT, Types.PURE_PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_PLUS,
Types.PURE_PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_PLUS_PLUS,
Types.PURE_PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_MINUS,
Types.PURE_PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_MINUS_MINUS,
Types.PURE_PREFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.SYNTH_CAST, Types.PURE_PREFIX_OPERATOR));
+ assertFalse(Types.ofType(Types.PLUS, Types.PURE_PREFIX_OPERATOR));
+ }
+
+ // Postfix operator tests
+ @Test
+ void testOfTypePostfixOperator() {
+ assertTrue(Types.ofType(Types.PLUS_PLUS, Types.POSTFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.POSTFIX_PLUS_PLUS,
Types.POSTFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.MINUS_MINUS, Types.POSTFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.POSTFIX_MINUS_MINUS,
Types.POSTFIX_OPERATOR));
+ assertFalse(Types.ofType(Types.NOT, Types.POSTFIX_OPERATOR));
+ }
+
+ // Infix operator tests
+ @Test
+ void testOfTypeInfixOperator() {
+ assertTrue(Types.ofType(Types.DOT, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.NAVIGATE, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.LOGICAL_OR, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.LOGICAL_AND, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PLUS, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.MINUS, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.MULTIPLY, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.DIVIDE, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.EQUAL, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.COMPARE_EQUAL, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.DOT_DOT, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.FIND_REGEX, Types.INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.KEYWORD_INSTANCEOF,
Types.INFIX_OPERATOR));
+ }
+
+ // Prefix or infix operator tests
+ @Test
+ void testOfTypePrefixOrInfixOperator() {
+ assertTrue(Types.ofType(Types.POWER, Types.PREFIX_OR_INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PLUS, Types.PREFIX_OR_INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.MINUS, Types.PREFIX_OR_INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_PLUS,
Types.PREFIX_OR_INFIX_OPERATOR));
+ assertTrue(Types.ofType(Types.PREFIX_MINUS,
Types.PREFIX_OR_INFIX_OPERATOR));
+ assertFalse(Types.ofType(Types.NOT, Types.PREFIX_OR_INFIX_OPERATOR));
+ }
+
+ // Keyword tests
+ @Test
+ void testOfTypeKeyword() {
+ assertTrue(Types.ofType(Types.KEYWORD_PRIVATE, Types.KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_PUBLIC, Types.KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_CLASS, Types.KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_IF, Types.KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_WHILE, Types.KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_TRUE, Types.KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_GOTO, Types.KEYWORD));
+ assertFalse(Types.ofType(Types.PLUS, Types.KEYWORD));
+ }
+
+ // Symbol tests
+ @Test
+ void testOfTypeSymbol() {
+ assertTrue(Types.ofType(Types.NEWLINE, Types.SYMBOL));
+ assertTrue(Types.ofType(Types.DOT, Types.SYMBOL));
+ assertTrue(Types.ofType(Types.COMMA, Types.SYMBOL));
+ assertTrue(Types.ofType(Types.COLON, Types.SYMBOL));
+ assertTrue(Types.ofType(Types.PIPE, Types.SYMBOL));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.SYMBOL));
+ }
+
+ // Literal tests
+ @Test
+ void testOfTypeLiteral() {
+ assertTrue(Types.ofType(Types.STRING, Types.LITERAL));
+ assertTrue(Types.ofType(Types.IDENTIFIER, Types.LITERAL));
+ assertTrue(Types.ofType(Types.INTEGER_NUMBER, Types.LITERAL));
+ assertTrue(Types.ofType(Types.DECIMAL_NUMBER, Types.LITERAL));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.LITERAL));
+ }
+
+ // Number tests
+ @Test
+ void testOfTypeNumber() {
+ assertTrue(Types.ofType(Types.INTEGER_NUMBER, Types.NUMBER));
+ assertTrue(Types.ofType(Types.DECIMAL_NUMBER, Types.NUMBER));
+ assertFalse(Types.ofType(Types.STRING, Types.NUMBER));
+ }
+
+ // Sign tests
+ @Test
+ void testOfTypeSign() {
+ assertTrue(Types.ofType(Types.PLUS, Types.SIGN));
+ assertTrue(Types.ofType(Types.MINUS, Types.SIGN));
+ assertFalse(Types.ofType(Types.MULTIPLY, Types.SIGN));
+ }
+
+ // Named value tests
+ @Test
+ void testOfTypeNamedValue() {
+ assertTrue(Types.ofType(Types.KEYWORD_TRUE, Types.NAMED_VALUE));
+ assertTrue(Types.ofType(Types.KEYWORD_FALSE, Types.NAMED_VALUE));
+ assertTrue(Types.ofType(Types.KEYWORD_NULL, Types.NAMED_VALUE));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.NAMED_VALUE));
+ }
+
+ // Truth value tests
+ @Test
+ void testOfTypeTruthValue() {
+ assertTrue(Types.ofType(Types.KEYWORD_TRUE, Types.TRUTH_VALUE));
+ assertTrue(Types.ofType(Types.KEYWORD_FALSE, Types.TRUTH_VALUE));
+ assertFalse(Types.ofType(Types.KEYWORD_NULL, Types.TRUTH_VALUE));
+ }
+
+ // Primitive type tests
+ @Test
+ void testOfTypePrimitiveType() {
+ assertTrue(Types.ofType(Types.KEYWORD_VOID, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_BOOLEAN, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_BYTE, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_SHORT, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_INT, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_LONG, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_FLOAT, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_DOUBLE, Types.PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_CHAR, Types.PRIMITIVE_TYPE));
+ assertFalse(Types.ofType(Types.KEYWORD_CLASS, Types.PRIMITIVE_TYPE));
+ }
+
+ // Creatable primitive type tests
+ @Test
+ void testOfTypeCreatablePrimitiveType() {
+ assertTrue(Types.ofType(Types.KEYWORD_BOOLEAN,
Types.CREATABLE_PRIMITIVE_TYPE));
+ assertTrue(Types.ofType(Types.KEYWORD_INT,
Types.CREATABLE_PRIMITIVE_TYPE));
+ assertFalse(Types.ofType(Types.KEYWORD_VOID,
Types.CREATABLE_PRIMITIVE_TYPE));
+ }
+
+ // Loop tests
+ @Test
+ void testOfTypeLoop() {
+ assertTrue(Types.ofType(Types.KEYWORD_DO, Types.LOOP));
+ assertTrue(Types.ofType(Types.KEYWORD_WHILE, Types.LOOP));
+ assertTrue(Types.ofType(Types.KEYWORD_FOR, Types.LOOP));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.LOOP));
+ }
+
+ // Reserved keyword tests
+ @Test
+ void testOfTypeReservedKeyword() {
+ assertTrue(Types.ofType(Types.KEYWORD_CONST, Types.RESERVED_KEYWORD));
+ assertTrue(Types.ofType(Types.KEYWORD_GOTO, Types.RESERVED_KEYWORD));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.RESERVED_KEYWORD));
+ }
+
+ // Type declaration tests
+ @Test
+ void testOfTypeTypeDeclaration() {
+ assertTrue(Types.ofType(Types.KEYWORD_CLASS, Types.TYPE_DECLARATION));
+ assertTrue(Types.ofType(Types.KEYWORD_INTERFACE,
Types.TYPE_DECLARATION));
+ assertTrue(Types.ofType(Types.KEYWORD_MIXIN, Types.TYPE_DECLARATION));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.TYPE_DECLARATION));
+ }
+
+ // Declaration modifier tests
+ @Test
+ void testOfTypeDeclarationModifier() {
+ assertTrue(Types.ofType(Types.KEYWORD_PUBLIC,
Types.DECLARATION_MODIFIER));
+ assertTrue(Types.ofType(Types.KEYWORD_PRIVATE,
Types.DECLARATION_MODIFIER));
+ assertTrue(Types.ofType(Types.KEYWORD_PROTECTED,
Types.DECLARATION_MODIFIER));
+ assertTrue(Types.ofType(Types.KEYWORD_STATIC,
Types.DECLARATION_MODIFIER));
+ assertTrue(Types.ofType(Types.KEYWORD_FINAL,
Types.DECLARATION_MODIFIER));
+ assertTrue(Types.ofType(Types.KEYWORD_ABSTRACT,
Types.DECLARATION_MODIFIER));
+ assertFalse(Types.ofType(Types.KEYWORD_IF,
Types.DECLARATION_MODIFIER));
+ }
+
+ // Type name tests
+ @Test
+ void testOfTypeTypeName() {
+ assertTrue(Types.ofType(Types.IDENTIFIER, Types.TYPE_NAME));
+ assertTrue(Types.ofType(Types.KEYWORD_INT, Types.TYPE_NAME));
+ assertTrue(Types.ofType(Types.KEYWORD_VOID, Types.TYPE_NAME));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.TYPE_NAME));
+ }
+
+ // Creatable type name tests
+ @Test
+ void testOfTypeCreatableTypeName() {
+ assertTrue(Types.ofType(Types.IDENTIFIER, Types.CREATABLE_TYPE_NAME));
+ assertTrue(Types.ofType(Types.KEYWORD_INT, Types.CREATABLE_TYPE_NAME));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.CREATABLE_TYPE_NAME));
+ }
+
+ // Matched container tests
+ @Test
+ void testOfTypeMatchedContainer() {
+ assertTrue(Types.ofType(Types.LEFT_PARENTHESIS,
Types.MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.RIGHT_PARENTHESIS,
Types.MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.LEFT_SQUARE_BRACKET,
Types.MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.RIGHT_SQUARE_BRACKET,
Types.MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.LEFT_CURLY_BRACE,
Types.MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.RIGHT_CURLY_BRACE,
Types.MATCHED_CONTAINER));
+ assertFalse(Types.ofType(Types.DOT, Types.MATCHED_CONTAINER));
+ }
+
+ @Test
+ void testOfTypeLeftOfMatchedContainer() {
+ assertTrue(Types.ofType(Types.LEFT_PARENTHESIS,
Types.LEFT_OF_MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.LEFT_SQUARE_BRACKET,
Types.LEFT_OF_MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.LEFT_CURLY_BRACE,
Types.LEFT_OF_MATCHED_CONTAINER));
+ assertFalse(Types.ofType(Types.RIGHT_PARENTHESIS,
Types.LEFT_OF_MATCHED_CONTAINER));
+ }
+
+ @Test
+ void testOfTypeRightOfMatchedContainer() {
+ assertTrue(Types.ofType(Types.RIGHT_PARENTHESIS,
Types.RIGHT_OF_MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.RIGHT_SQUARE_BRACKET,
Types.RIGHT_OF_MATCHED_CONTAINER));
+ assertTrue(Types.ofType(Types.RIGHT_CURLY_BRACE,
Types.RIGHT_OF_MATCHED_CONTAINER));
+ assertFalse(Types.ofType(Types.LEFT_PARENTHESIS,
Types.RIGHT_OF_MATCHED_CONTAINER));
+ }
+
+ // Expression tests
+ @Test
+ void testOfTypeExpression() {
+ assertTrue(Types.ofType(Types.DOT, Types.EXPRESSION));
+ assertTrue(Types.ofType(Types.PLUS, Types.EXPRESSION));
+ assertTrue(Types.ofType(Types.SYNTH_CAST, Types.EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_NEW, Types.EXPRESSION));
+ assertTrue(Types.ofType(Types.STRING, Types.EXPRESSION));
+ assertTrue(Types.ofType(Types.LEFT_SQUARE_BRACKET, Types.EXPRESSION));
+ }
+
+ @Test
+ void testOfTypeOperatorExpression() {
+ assertTrue(Types.ofType(Types.DOT, Types.OPERATOR_EXPRESSION));
+ assertTrue(Types.ofType(Types.PLUS, Types.OPERATOR_EXPRESSION));
+ assertTrue(Types.ofType(Types.MINUS, Types.OPERATOR_EXPRESSION));
+ assertTrue(Types.ofType(Types.LEFT_SHIFT, Types.OPERATOR_EXPRESSION));
// within DOT to RIGHT_SHIFT_UNSIGNED range
+ assertTrue(Types.ofType(Types.RIGHT_SHIFT_UNSIGNED,
Types.OPERATOR_EXPRESSION));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.OPERATOR_EXPRESSION));
+ }
+
+ @Test
+ void testOfTypeSynthExpression() {
+ assertTrue(Types.ofType(Types.SYNTH_CAST, Types.SYNTH_EXPRESSION));
+ assertTrue(Types.ofType(Types.SYNTH_TERNARY, Types.SYNTH_EXPRESSION));
+ assertTrue(Types.ofType(Types.SYNTH_CLOSURE, Types.SYNTH_EXPRESSION));
+ assertFalse(Types.ofType(Types.STRING, Types.SYNTH_EXPRESSION));
+ }
+
+ @Test
+ void testOfTypeKeywordExpression() {
+ assertTrue(Types.ofType(Types.KEYWORD_NEW, Types.KEYWORD_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_THIS, Types.KEYWORD_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_SUPER,
Types.KEYWORD_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_TRUE, Types.KEYWORD_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_FALSE,
Types.KEYWORD_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_NULL, Types.KEYWORD_EXPRESSION));
+ assertFalse(Types.ofType(Types.KEYWORD_IF, Types.KEYWORD_EXPRESSION));
+ }
+
+ @Test
+ void testOfTypeArrayExpression() {
+ assertTrue(Types.ofType(Types.LEFT_SQUARE_BRACKET,
Types.ARRAY_EXPRESSION));
+ assertFalse(Types.ofType(Types.RIGHT_SQUARE_BRACKET,
Types.ARRAY_EXPRESSION));
+ }
+
+ @Test
+ void testOfTypeSimpleExpression() {
+ assertTrue(Types.ofType(Types.STRING, Types.SIMPLE_EXPRESSION));
+ assertTrue(Types.ofType(Types.INTEGER_NUMBER,
Types.SIMPLE_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_THIS, Types.SIMPLE_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_TRUE, Types.SIMPLE_EXPRESSION));
+ assertFalse(Types.ofType(Types.PLUS, Types.SIMPLE_EXPRESSION));
+ }
+
+ @Test
+ void testOfTypeComplexExpression() {
+ assertTrue(Types.ofType(Types.STRING, Types.COMPLEX_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_THIS, Types.COMPLEX_EXPRESSION));
+ assertTrue(Types.ofType(Types.SYNTH_METHOD_CALL,
Types.COMPLEX_EXPRESSION));
+ assertTrue(Types.ofType(Types.KEYWORD_NEW, Types.COMPLEX_EXPRESSION));
+ assertTrue(Types.ofType(Types.SYNTH_GSTRING,
Types.COMPLEX_EXPRESSION));
+ assertTrue(Types.ofType(Types.SYNTH_LIST, Types.COMPLEX_EXPRESSION));
+ assertTrue(Types.ofType(Types.IDENTIFIER, Types.COMPLEX_EXPRESSION));
// also includes SIMPLE_EXPRESSION
+ }
+
+ // Terminators tests
+ @Test
+ void testOfTypeParameterTerminators() {
+ assertTrue(Types.ofType(Types.RIGHT_PARENTHESIS,
Types.PARAMETER_TERMINATORS));
+ assertTrue(Types.ofType(Types.COMMA, Types.PARAMETER_TERMINATORS));
+ assertFalse(Types.ofType(Types.SEMICOLON,
Types.PARAMETER_TERMINATORS));
+ }
+
+ @Test
+ void testOfTypeArrayItemTerminators() {
+ assertTrue(Types.ofType(Types.RIGHT_SQUARE_BRACKET,
Types.ARRAY_ITEM_TERMINATORS));
+ assertTrue(Types.ofType(Types.COMMA, Types.ARRAY_ITEM_TERMINATORS));
+ assertFalse(Types.ofType(Types.SEMICOLON,
Types.ARRAY_ITEM_TERMINATORS));
+ }
+
+ @Test
+ void testOfTypeSwitchBlockTerminators() {
+ assertTrue(Types.ofType(Types.KEYWORD_CASE,
Types.SWITCH_BLOCK_TERMINATORS));
+ assertTrue(Types.ofType(Types.KEYWORD_DEFAULT,
Types.SWITCH_BLOCK_TERMINATORS));
+ assertTrue(Types.ofType(Types.RIGHT_CURLY_BRACE,
Types.SWITCH_BLOCK_TERMINATORS));
+ assertFalse(Types.ofType(Types.SEMICOLON,
Types.SWITCH_BLOCK_TERMINATORS));
+ }
+
+ @Test
+ void testOfTypeSwitchEntries() {
+ assertTrue(Types.ofType(Types.KEYWORD_CASE, Types.SWITCH_ENTRIES));
+ assertTrue(Types.ofType(Types.KEYWORD_DEFAULT, Types.SWITCH_ENTRIES));
+ assertFalse(Types.ofType(Types.RIGHT_CURLY_BRACE,
Types.SWITCH_ENTRIES));
+ }
+
+ // getText tests
+ @Test
+ void testGetTextForOperators() {
+ assertEquals("{", Types.getText(Types.LEFT_CURLY_BRACE));
+ assertEquals("}", Types.getText(Types.RIGHT_CURLY_BRACE));
+ assertEquals("[", Types.getText(Types.LEFT_SQUARE_BRACKET));
+ assertEquals("]", Types.getText(Types.RIGHT_SQUARE_BRACKET));
+ assertEquals("(", Types.getText(Types.LEFT_PARENTHESIS));
+ assertEquals(")", Types.getText(Types.RIGHT_PARENTHESIS));
+ assertEquals(".", Types.getText(Types.DOT));
+ assertEquals("..", Types.getText(Types.DOT_DOT));
+ assertEquals("...", Types.getText(Types.DOT_DOT_DOT));
+ assertEquals("->", Types.getText(Types.NAVIGATE));
+ assertEquals("=~", Types.getText(Types.FIND_REGEX));
+ assertEquals("==~", Types.getText(Types.MATCH_REGEX));
+ assertEquals("~", Types.getText(Types.REGEX_PATTERN));
+ assertEquals("=", Types.getText(Types.EQUAL));
+ assertEquals("+", Types.getText(Types.PLUS));
+ assertEquals("-", Types.getText(Types.MINUS));
+ assertEquals("*", Types.getText(Types.MULTIPLY));
+ assertEquals("/", Types.getText(Types.DIVIDE));
+ assertEquals("%", Types.getText(Types.REMAINDER)); // REMAINDER is
registered, not MOD
+ assertEquals("**", Types.getText(Types.POWER));
+ }
+
+ @Test
+ void testGetTextForComparisonOperators() {
+ assertEquals("!=", Types.getText(Types.COMPARE_NOT_EQUAL));
+ assertEquals("===", Types.getText(Types.COMPARE_IDENTICAL));
+ assertEquals("!==", Types.getText(Types.COMPARE_NOT_IDENTICAL));
+ assertEquals("==", Types.getText(Types.COMPARE_EQUAL));
+ assertEquals("<", Types.getText(Types.COMPARE_LESS_THAN));
+ assertEquals("<=", Types.getText(Types.COMPARE_LESS_THAN_EQUAL));
+ assertEquals(">", Types.getText(Types.COMPARE_GREATER_THAN));
+ assertEquals(">=", Types.getText(Types.COMPARE_GREATER_THAN_EQUAL));
+ assertEquals("<=>", Types.getText(Types.COMPARE_TO));
+ }
+
+ @Test
+ void testGetTextForKeywords() {
+ assertEquals("private", Types.getText(Types.KEYWORD_PRIVATE));
+ assertEquals("public", Types.getText(Types.KEYWORD_PUBLIC));
+ assertEquals("class", Types.getText(Types.KEYWORD_CLASS));
+ assertEquals("if", Types.getText(Types.KEYWORD_IF));
+ assertEquals("else", Types.getText(Types.KEYWORD_ELSE));
+ assertEquals("while", Types.getText(Types.KEYWORD_WHILE));
+ assertEquals("for", Types.getText(Types.KEYWORD_FOR));
+ assertEquals("true", Types.getText(Types.KEYWORD_TRUE));
+ assertEquals("false", Types.getText(Types.KEYWORD_FALSE));
+ assertEquals("null", Types.getText(Types.KEYWORD_NULL));
+ }
+
+ @Test
+ void testGetTextReturnsEmptyForUnknown() {
+ // getText returns "" for types not in TEXTS map
+ assertEquals("", Types.getText(Types.UNKNOWN));
+ assertEquals("", Types.getText(Types.STRING));
+ assertEquals("", Types.getText(Types.IDENTIFIER));
+ }
+
+ // getDescription tests
+ @Test
+ void testGetDescription() {
+ assertNotNull(Types.getDescription(Types.EOF));
+ assertNotNull(Types.getDescription(Types.UNKNOWN));
+ assertNotNull(Types.getDescription(Types.PLUS));
+ assertNotNull(Types.getDescription(Types.KEYWORD_IF));
+ assertNotNull(Types.getDescription(Types.STRING));
+ }
+
+ // lookup tests
+ @Test
+ void testLookupKeywords() {
+ assertEquals(Types.KEYWORD_IF, Types.lookup("if", Types.UNKNOWN));
+ assertEquals(Types.KEYWORD_ELSE, Types.lookup("else", Types.UNKNOWN));
+ assertEquals(Types.KEYWORD_CLASS, Types.lookup("class",
Types.UNKNOWN));
+ assertEquals(Types.KEYWORD_TRUE, Types.lookup("true", Types.UNKNOWN));
+ assertEquals(Types.KEYWORD_FALSE, Types.lookup("false",
Types.UNKNOWN));
+ assertEquals(Types.KEYWORD_NULL, Types.lookup("null", Types.UNKNOWN));
+ }
+
+ @Test
+ void testLookupReturnsUnknownForNotFound() {
+ // lookup returns UNKNOWN when text is not in LOOKUP map
+ // second param is a filter, not a default value
+ assertEquals(Types.UNKNOWN, Types.lookup("notAKeyword",
Types.UNKNOWN));
+ assertEquals(Types.UNKNOWN, Types.lookup("xyz", Types.KEYWORD)); //
not in map
+ // when filter doesn't match, also returns UNKNOWN
+ assertEquals(Types.UNKNOWN, Types.lookup("if", Types.SYMBOL)); // "if"
is keyword, not symbol
+ }
+
+ // lookupKeyword tests
+ @Test
+ void testLookupKeyword() {
+ assertEquals(Types.KEYWORD_IF, Types.lookupKeyword("if"));
+ assertEquals(Types.KEYWORD_CLASS, Types.lookupKeyword("class"));
+ assertEquals(Types.UNKNOWN, Types.lookupKeyword("notAKeyword"));
+ }
+
+ // lookupSymbol tests
+ @Test
+ void testLookupSymbol() {
+ assertEquals(Types.LEFT_CURLY_BRACE, Types.lookupSymbol("{"));
+ assertEquals(Types.RIGHT_CURLY_BRACE, Types.lookupSymbol("}"));
+ assertEquals(Types.PLUS, Types.lookupSymbol("+"));
+ assertEquals(Types.MINUS, Types.lookupSymbol("-"));
+ assertEquals(Types.COMPARE_EQUAL, Types.lookupSymbol("=="));
+ assertEquals(Types.UNKNOWN, Types.lookupSymbol("xyz"));
+ }
+
+ // Synthetic type tests
+ @Test
+ void testOfTypeSynthetic() {
+ assertTrue(Types.ofType(Types.SYNTH_COMPILATION_UNIT,
Types.SYNTHETIC));
+ assertTrue(Types.ofType(Types.SYNTH_CLASS, Types.SYNTHETIC));
+ assertTrue(Types.ofType(Types.SYNTH_METHOD, Types.SYNTHETIC));
+ assertTrue(Types.ofType(Types.SYNTH_CLOSURE, Types.SYNTHETIC));
+ assertTrue(Types.ofType(Types.SYNTH_VARIABLE_DECLARATION,
Types.SYNTHETIC));
+ assertFalse(Types.ofType(Types.KEYWORD_CLASS, Types.SYNTHETIC));
+ }
+}
diff --git
a/src/test/java/org/codehaus/groovy/tools/LoaderConfigurationJUnit5Test.java
b/src/test/java/org/codehaus/groovy/tools/LoaderConfigurationJUnit5Test.java
new file mode 100644
index 0000000000..ce69b6afad
--- /dev/null
+++ b/src/test/java/org/codehaus/groovy/tools/LoaderConfigurationJUnit5Test.java
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.codehaus.groovy.tools;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for LoaderConfiguration class.
+ */
+class LoaderConfigurationJUnit5Test {
+
+ private LoaderConfiguration config;
+
+ @BeforeEach
+ void setUp() {
+ config = new LoaderConfiguration();
+ }
+
+ // Basic configuration tests
+ @Test
+ void testNewConfigurationHasNoClassPath() {
+ assertEquals(0, config.getClassPathUrls().length);
+ }
+
+ @Test
+ void testNewConfigurationHasNoMainClass() {
+ assertNull(config.getMainClass());
+ }
+
+ @Test
+ void testNewConfigurationHasNoGrabUrls() {
+ assertTrue(config.getGrabUrls().isEmpty());
+ }
+
+ // setMainClass tests
+ @Test
+ void testSetMainClass() {
+ config.setMainClass("com.example.Main");
+ assertEquals("com.example.Main", config.getMainClass());
+ }
+
+ @Test
+ void testSetMainClassDisablesRequireMain() throws IOException {
+ config.setMainClass("com.example.Main");
+ // Configure without main should now work
+ String configContent = "# just a comment\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+ assertEquals("com.example.Main", config.getMainClass());
+ }
+
+ // setRequireMain tests
+ @Test
+ void testSetRequireMainFalse() throws IOException {
+ config.setRequireMain(false);
+ String configContent = "# just a comment\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+ assertNull(config.getMainClass());
+ }
+
+ @Test
+ void testRequireMainTrueThrowsWithoutMain() {
+ String configContent = "# just a comment\n";
+ assertThrows(IOException.class, () ->
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8))));
+ }
+
+ // configure with main is tests
+ @Test
+ void testConfigureWithMainIs() throws IOException {
+ String configContent = "main is com.example.Main\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+ assertEquals("com.example.Main", config.getMainClass());
+ }
+
+ @Test
+ void testConfigureDuplicateMainThrows() {
+ String configContent = "main is com.example.Main\nmain is
com.example.Other\n";
+ assertThrows(IOException.class, () ->
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8))));
+ }
+
+ // configure with comments and empty lines
+ @Test
+ void testConfigureIgnoresComments() throws IOException {
+ String configContent = "# this is a comment\nmain is
com.example.Main\n# another comment\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+ assertEquals("com.example.Main", config.getMainClass());
+ }
+
+ @Test
+ void testConfigureIgnoresEmptyLines() throws IOException {
+ String configContent = "\n\nmain is com.example.Main\n\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+ assertEquals("com.example.Main", config.getMainClass());
+ }
+
+ // configure with load tests
+ @Test
+ void testConfigureWithLoadExistingFile(@TempDir Path tempDir) throws
IOException {
+ Path jarFile = tempDir.resolve("test.jar");
+ Files.createFile(jarFile);
+
+ String configContent = "main is com.example.Main\nload " +
jarFile.toAbsolutePath() + "\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(1, urls.length);
+ assertTrue(urls[0].toString().contains("test.jar"));
+ }
+
+ @Test
+ void testConfigureWithLoadNonExistingFile() throws IOException {
+ String configContent = "main is com.example.Main\nload
/non/existent/path.jar\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ // Non-existent files are silently ignored
+ assertEquals(0, config.getClassPathUrls().length);
+ }
+
+ // configure with grab tests
+ @Test
+ void testConfigureWithGrab() throws IOException {
+ String configContent = "main is com.example.Main\ngrab
org.example:lib:1.0\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ assertEquals(1, config.getGrabUrls().size());
+ assertEquals("org.example:lib:1.0", config.getGrabUrls().get(0));
+ }
+
+ // configure with invalid line tests
+ @Test
+ void testConfigureWithInvalidLineThrows() {
+ String configContent = "main is com.example.Main\ninvalid line here\n";
+ assertThrows(IOException.class, () ->
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8))));
+ }
+
+ // addFile tests
+ @Test
+ void testAddFileWithExistingFile(@TempDir Path tempDir) throws IOException
{
+ Path jarFile = tempDir.resolve("test.jar");
+ Files.createFile(jarFile);
+
+ config.addFile(jarFile.toFile());
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(1, urls.length);
+ }
+
+ @Test
+ void testAddFileWithNonExistingFile() {
+ config.addFile(new File("/non/existent/file.jar"));
+ assertEquals(0, config.getClassPathUrls().length);
+ }
+
+ @Test
+ void testAddFileWithNullFile() {
+ config.addFile((File) null);
+ assertEquals(0, config.getClassPathUrls().length);
+ }
+
+ @Test
+ void testAddFileWithFilename(@TempDir Path tempDir) throws IOException {
+ Path jarFile = tempDir.resolve("test.jar");
+ Files.createFile(jarFile);
+
+ config.addFile(jarFile.toAbsolutePath().toString());
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(1, urls.length);
+ }
+
+ @Test
+ void testAddFileWithNullFilename() {
+ config.addFile((String) null);
+ assertEquals(0, config.getClassPathUrls().length);
+ }
+
+ // addClassPath tests
+ @Test
+ void testAddClassPath(@TempDir Path tempDir) throws IOException {
+ Path jarFile1 = tempDir.resolve("test1.jar");
+ Path jarFile2 = tempDir.resolve("test2.jar");
+ Files.createFile(jarFile1);
+ Files.createFile(jarFile2);
+
+ String classpath = jarFile1.toAbsolutePath() + File.pathSeparator +
jarFile2.toAbsolutePath();
+ config.addClassPath(classpath);
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(2, urls.length);
+ }
+
+ @Test
+ void testAddClassPathWithWildcard(@TempDir Path tempDir) throws
IOException {
+ Path dir = tempDir.resolve("lib");
+ Files.createDirectory(dir);
+ Files.createFile(dir.resolve("a.jar"));
+ Files.createFile(dir.resolve("b.jar"));
+ Files.createFile(dir.resolve("not-a-jar.txt"));
+
+ config.addClassPath(dir.toAbsolutePath() + "/*");
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(2, urls.length); // only .jar files
+ }
+
+ // Property expansion tests
+ @Test
+ void testConfigureWithPropertyExpansion(@TempDir Path tempDir) throws
IOException {
+ Path jarFile = tempDir.resolve("test.jar");
+ Files.createFile(jarFile);
+
+ String originalValue = System.getProperty("user.dir");
+ try {
+ System.setProperty("test.loader.path",
tempDir.toAbsolutePath().toString());
+
+ String configContent = "main is com.example.Main\nload
${test.loader.path}/test.jar\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(1, urls.length);
+ } finally {
+ System.clearProperty("test.loader.path");
+ }
+ }
+
+ @Test
+ void testConfigureWithMissingOptionalProperty() throws IOException {
+ // ${nonexistent} - optional property that doesn't exist should cause
line to be skipped
+ String configContent = "main is com.example.Main\nload
${nonexistent.property}/test.jar\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ // Line should be skipped, no files loaded
+ assertEquals(0, config.getClassPathUrls().length);
+ }
+
+ @Test
+ void testConfigureWithMissingRequiredPropertyThrows() {
+ // !{nonexistent} - required property that doesn't exist should throw
+ String configContent = "main is com.example.Main\nload
!{nonexistent.required.property}/test.jar\n";
+ assertThrows(IllegalArgumentException.class, () ->
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8))));
+ }
+
+ // Wildcard tests
+ @Test
+ void testConfigureWithWildcardLoad(@TempDir Path tempDir) throws
IOException {
+ Path dir = tempDir.resolve("libs");
+ Files.createDirectory(dir);
+ Files.createFile(dir.resolve("a.jar"));
+ Files.createFile(dir.resolve("b.jar"));
+
+ String configContent = "main is com.example.Main\nload " +
dir.toAbsolutePath() + "/*.jar\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(2, urls.length);
+ }
+
+ @Test
+ void testConfigureWithRecursiveWildcard(@TempDir Path tempDir) throws
IOException {
+ Path dir = tempDir.resolve("libs");
+ Path subdir = dir.resolve("subdir");
+ Files.createDirectories(subdir);
+ Files.createFile(dir.resolve("a.jar"));
+ Files.createFile(subdir.resolve("b.jar"));
+
+ // ** matches one or more directories, so only subdir/b.jar should
match
+ String configContent = "main is com.example.Main\nload " +
dir.toAbsolutePath() + "/**/*.jar\n";
+ config.configure(new
ByteArrayInputStream(configContent.getBytes(StandardCharsets.UTF_8)));
+
+ URL[] urls = config.getClassPathUrls();
+ assertEquals(1, urls.length); // Only b.jar in subdir matches
+ }
+
+ // Multiple files test
+ @Test
+ void testAddMultipleFiles(@TempDir Path tempDir) throws IOException {
+ for (int i = 0; i < 5; i++) {
+ Path jarFile = tempDir.resolve("test" + i + ".jar");
+ Files.createFile(jarFile);
+ config.addFile(jarFile.toFile());
+ }
+
+ assertEquals(5, config.getClassPathUrls().length);
+ }
+
+ // Directory test
+ @Test
+ void testAddDirectory(@TempDir Path tempDir) {
+ config.addFile(tempDir.toFile());
+
+ // Directories can be added to classpath
+ assertEquals(1, config.getClassPathUrls().length);
+ }
+}
diff --git
a/subprojects/groovy-json/src/test/java/groovy/json/StringEscapeUtilsJUnit5Test.java
b/subprojects/groovy-json/src/test/java/groovy/json/StringEscapeUtilsJUnit5Test.java
new file mode 100644
index 0000000000..0de2fc25d9
--- /dev/null
+++
b/subprojects/groovy-json/src/test/java/groovy/json/StringEscapeUtilsJUnit5Test.java
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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 groovy.json;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for StringEscapeUtils class.
+ */
+class StringEscapeUtilsJUnit5Test {
+
+ // escapeJava tests
+ @Test
+ void testEscapeJavaNull() {
+ assertNull(StringEscapeUtils.escapeJava(null));
+ }
+
+ @Test
+ void testEscapeJavaEmpty() {
+ assertEquals("", StringEscapeUtils.escapeJava(""));
+ }
+
+ @Test
+ void testEscapeJavaSimpleText() {
+ assertEquals("hello", StringEscapeUtils.escapeJava("hello"));
+ }
+
+ @Test
+ void testEscapeJavaDoubleQuotes() {
+ assertEquals("They didn't say, \\\"Stop!\\\"",
+ StringEscapeUtils.escapeJava("They didn't say, \"Stop!\""));
+ }
+
+ @Test
+ void testEscapeJavaBackslash() {
+ assertEquals("path\\\\to\\\\file",
StringEscapeUtils.escapeJava("path\\to\\file"));
+ }
+
+ @Test
+ void testEscapeJavaNewline() {
+ assertEquals("line1\\nline2",
StringEscapeUtils.escapeJava("line1\nline2"));
+ }
+
+ @Test
+ void testEscapeJavaTab() {
+ assertEquals("col1\\tcol2",
StringEscapeUtils.escapeJava("col1\tcol2"));
+ }
+
+ @Test
+ void testEscapeJavaCarriageReturn() {
+ assertEquals("line1\\rline2",
StringEscapeUtils.escapeJava("line1\rline2"));
+ }
+
+ @Test
+ void testEscapeJavaBackspace() {
+ assertEquals("back\\bspace",
StringEscapeUtils.escapeJava("back\bspace"));
+ }
+
+ @Test
+ void testEscapeJavaFormFeed() {
+ assertEquals("form\\ffeed",
StringEscapeUtils.escapeJava("form\ffeed"));
+ }
+
+ @Test
+ void testEscapeJavaUnicodeHigh() {
+ // Characters > 0xfff - uses uppercase hex
+ assertEquals("\\u4E2D", StringEscapeUtils.escapeJava("\u4e2d")); //
Chinese character
+ }
+
+ @Test
+ void testEscapeJavaUnicodeMedium() {
+ // Characters > 0xff and <= 0xfff - uses uppercase hex
+ assertEquals("\\u03B1", StringEscapeUtils.escapeJava("\u03b1")); //
Greek alpha
+ }
+
+ @Test
+ void testEscapeJavaUnicodeLow() {
+ // Characters >= 0x7f and <= 0xff - uses uppercase hex
+ assertEquals("\\u00A9", StringEscapeUtils.escapeJava("\u00a9")); //
Copyright symbol
+ }
+
+ @Test
+ void testEscapeJavaControlChars() {
+ // Control chars < 32 that aren't special - uses uppercase hex
+ assertEquals("\\u0001", StringEscapeUtils.escapeJava("\u0001"));
+ assertEquals("\\u001F", StringEscapeUtils.escapeJava("\u001f"));
+ }
+
+ @Test
+ void testEscapeJavaSingleQuoteNotEscaped() {
+ // In Java, single quotes are not escaped
+ assertEquals("don't", StringEscapeUtils.escapeJava("don't"));
+ }
+
+ @Test
+ void testEscapeJavaForwardSlashNotEscaped() {
+ assertEquals("path/to/file",
StringEscapeUtils.escapeJava("path/to/file"));
+ }
+
+ // escapeJava with Writer tests
+ @Test
+ void testEscapeJavaToWriter() throws IOException {
+ StringWriter writer = new StringWriter();
+ StringEscapeUtils.escapeJava(writer, "test\\string\n");
+ assertEquals("test\\\\string\\n", writer.toString());
+ }
+
+ @Test
+ void testEscapeJavaToWriterNull() throws IOException {
+ StringWriter writer = new StringWriter();
+ StringEscapeUtils.escapeJava(writer, null);
+ assertEquals("", writer.toString());
+ }
+
+ @Test
+ void testEscapeJavaToWriterNullWriter() {
+ assertThrows(IllegalArgumentException.class, () ->
+ StringEscapeUtils.escapeJava(null, "test"));
+ }
+
+ // escapeJavaScript tests
+ @Test
+ void testEscapeJavaScriptNull() {
+ assertNull(StringEscapeUtils.escapeJavaScript(null));
+ }
+
+ @Test
+ void testEscapeJavaScriptEmpty() {
+ assertEquals("", StringEscapeUtils.escapeJavaScript(""));
+ }
+
+ @Test
+ void testEscapeJavaScriptSingleQuotes() {
+ // In JavaScript, single quotes ARE escaped
+ assertEquals("don\\'t", StringEscapeUtils.escapeJavaScript("don't"));
+ }
+
+ @Test
+ void testEscapeJavaScriptDoubleQuotes() {
+ assertEquals("\\\"quoted\\\"",
StringEscapeUtils.escapeJavaScript("\"quoted\""));
+ }
+
+ @Test
+ void testEscapeJavaScriptForwardSlash() {
+ // In JavaScript, forward slashes ARE escaped
+ assertEquals("path\\/to\\/file",
StringEscapeUtils.escapeJavaScript("path/to/file"));
+ }
+
+ @Test
+ void testEscapeJavaScriptBackslash() {
+ assertEquals("back\\\\slash",
StringEscapeUtils.escapeJavaScript("back\\slash"));
+ }
+
+ @Test
+ void testEscapeJavaScriptControlChars() {
+ assertEquals("line\\nbreak",
StringEscapeUtils.escapeJavaScript("line\nbreak"));
+ assertEquals("tab\\tstop",
StringEscapeUtils.escapeJavaScript("tab\tstop"));
+ }
+
+ // escapeJavaScript with Writer tests
+ @Test
+ void testEscapeJavaScriptToWriter() throws IOException {
+ StringWriter writer = new StringWriter();
+ StringEscapeUtils.escapeJavaScript(writer, "test'string/path");
+ assertEquals("test\\'string\\/path", writer.toString());
+ }
+
+ @Test
+ void testEscapeJavaScriptToWriterNullWriter() {
+ assertThrows(IllegalArgumentException.class, () ->
+ StringEscapeUtils.escapeJavaScript(null, "test"));
+ }
+
+ // unescapeJava tests
+ @Test
+ void testUnescapeJavaNull() {
+ assertNull(StringEscapeUtils.unescapeJava(null));
+ }
+
+ @Test
+ void testUnescapeJavaEmpty() {
+ assertEquals("", StringEscapeUtils.unescapeJava(""));
+ }
+
+ @Test
+ void testUnescapeJavaSimpleText() {
+ assertEquals("hello", StringEscapeUtils.unescapeJava("hello"));
+ }
+
+ @Test
+ void testUnescapeJavaDoubleQuotes() {
+ assertEquals("\"quoted\"",
StringEscapeUtils.unescapeJava("\\\"quoted\\\""));
+ }
+
+ @Test
+ void testUnescapeJavaBackslash() {
+ assertEquals("path\\to\\file",
StringEscapeUtils.unescapeJava("path\\\\to\\\\file"));
+ }
+
+ @Test
+ void testUnescapeJavaNewline() {
+ assertEquals("line1\nline2",
StringEscapeUtils.unescapeJava("line1\\nline2"));
+ }
+
+ @Test
+ void testUnescapeJavaTab() {
+ assertEquals("col1\tcol2",
StringEscapeUtils.unescapeJava("col1\\tcol2"));
+ }
+
+ @Test
+ void testUnescapeJavaCarriageReturn() {
+ assertEquals("line1\rline2",
StringEscapeUtils.unescapeJava("line1\\rline2"));
+ }
+
+ @Test
+ void testUnescapeJavaBackspace() {
+ assertEquals("back\bspace",
StringEscapeUtils.unescapeJava("back\\bspace"));
+ }
+
+ @Test
+ void testUnescapeJavaFormFeed() {
+ assertEquals("form\ffeed",
StringEscapeUtils.unescapeJava("form\\ffeed"));
+ }
+
+ @Test
+ void testUnescapeJavaSingleQuote() {
+ assertEquals("don't", StringEscapeUtils.unescapeJava("don\\'t"));
+ }
+
+ @Test
+ void testUnescapeJavaUnicode() {
+ assertEquals("\u4e2d", StringEscapeUtils.unescapeJava("\\u4e2d"));
+ }
+
+ @Test
+ void testUnescapeJavaUnicodeLowerCase() {
+ assertEquals("\u00a9", StringEscapeUtils.unescapeJava("\\u00a9"));
+ }
+
+ @Test
+ void testUnescapeJavaTrailingBackslash() {
+ assertEquals("trailing\\",
StringEscapeUtils.unescapeJava("trailing\\"));
+ }
+
+ @Test
+ void testUnescapeJavaUnknownEscape() {
+ // Unknown escapes are passed through
+ assertEquals("x", StringEscapeUtils.unescapeJava("\\x"));
+ }
+
+ @Test
+ void testUnescapeJavaInvalidUnicode() {
+ assertThrows(RuntimeException.class, () ->
+ StringEscapeUtils.unescapeJava("\\uZZZZ"));
+ }
+
+ // unescapeJava with Writer tests
+ @Test
+ void testUnescapeJavaToWriter() throws IOException {
+ StringWriter writer = new StringWriter();
+ StringEscapeUtils.unescapeJava(writer, "test\\\\string\\n");
+ assertEquals("test\\string\n", writer.toString());
+ }
+
+ @Test
+ void testUnescapeJavaToWriterNull() throws IOException {
+ StringWriter writer = new StringWriter();
+ StringEscapeUtils.unescapeJava(writer, null);
+ assertEquals("", writer.toString());
+ }
+
+ @Test
+ void testUnescapeJavaToWriterNullWriter() {
+ assertThrows(IllegalArgumentException.class, () ->
+ StringEscapeUtils.unescapeJava(null, "test"));
+ }
+
+ // unescapeJavaScript tests
+ @Test
+ void testUnescapeJavaScriptNull() {
+ assertNull(StringEscapeUtils.unescapeJavaScript(null));
+ }
+
+ @Test
+ void testUnescapeJavaScriptSameAsJava() {
+ assertEquals(StringEscapeUtils.unescapeJava("test\\nstring"),
+ StringEscapeUtils.unescapeJavaScript("test\\nstring"));
+ }
+
+ @Test
+ void testUnescapeJavaScriptToWriter() throws IOException {
+ StringWriter writer = new StringWriter();
+ StringEscapeUtils.unescapeJavaScript(writer, "test\\nstring");
+ assertEquals("test\nstring", writer.toString());
+ }
+
+ // Round-trip tests
+ @Test
+ void testRoundTripJava() {
+ String original = "Hello\nWorld\t\"quoted\"\\backslash";
+ String escaped = StringEscapeUtils.escapeJava(original);
+ String unescaped = StringEscapeUtils.unescapeJava(escaped);
+ assertEquals(original, unescaped);
+ }
+
+ @Test
+ void testRoundTripJavaScript() {
+ String original = "Hello\nWorld\t'quoted'/slash";
+ String escaped = StringEscapeUtils.escapeJavaScript(original);
+ String unescaped = StringEscapeUtils.unescapeJavaScript(escaped);
+ assertEquals(original, unescaped);
+ }
+
+ @Test
+ void testRoundTripUnicode() {
+ String original = "Hello \u4e2d\u6587 World";
+ String escaped = StringEscapeUtils.escapeJava(original);
+ String unescaped = StringEscapeUtils.unescapeJava(escaped);
+ assertEquals(original, unescaped);
+ }
+
+ // Constructor test
+ @Test
+ void testConstructor() {
+ // Public constructor is allowed
+ assertDoesNotThrow(() -> new StringEscapeUtils());
+ }
+
+ // Edge cases
+ @Test
+ void testEscapeJavaAllControlChars() {
+ String controlChars = "\b\n\t\f\r";
+ String escaped = StringEscapeUtils.escapeJava(controlChars);
+ assertEquals("\\b\\n\\t\\f\\r", escaped);
+ }
+
+ @Test
+ void testUnescapeJavaConsecutiveEscapes() {
+ assertEquals("\n\n\n", StringEscapeUtils.unescapeJava("\\n\\n\\n"));
+ }
+
+ @Test
+ void testEscapeMixedContent() {
+ String mixed = "Line 1\nLine 2\tTabbed \"quoted\"";
+ String escaped = StringEscapeUtils.escapeJava(mixed);
+ assertTrue(escaped.contains("\\n"));
+ assertTrue(escaped.contains("\\t"));
+ assertTrue(escaped.contains("\\\""));
+ }
+}
diff --git
a/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/CharSequenceValueJUnit5Test.java
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/CharSequenceValueJUnit5Test.java
new file mode 100644
index 0000000000..af8d8278a8
--- /dev/null
+++
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/CharSequenceValueJUnit5Test.java
@@ -0,0 +1,431 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.groovy.json.internal;
+
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for CharSequenceValue class.
+ */
+class CharSequenceValueJUnit5Test {
+
+ // Constructor tests
+ @Test
+ void testConstructorWithChop() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(true, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals("hello", value.toString());
+ }
+
+ @Test
+ void testConstructorWithoutChop() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals("hello", value.toString());
+ }
+
+ @Test
+ void testConstructorPartialRange() {
+ char[] buffer = "xxxhelloyyy".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 3,
8, buffer, false, false);
+ assertEquals("hello", value.toString());
+ }
+
+ @Test
+ void testConstructorPartialRangeWithChop() {
+ char[] buffer = "xxxhelloyyy".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(true, Type.STRING, 3,
8, buffer, false, false);
+ assertEquals("hello", value.toString());
+ }
+
+ // CharSequence interface tests
+ @Test
+ void testLength() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(true, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals(5, value.length());
+ }
+
+ @Test
+ void testCharAt() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(true, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals('h', value.charAt(0));
+ assertEquals('e', value.charAt(1));
+ assertEquals('o', value.charAt(4));
+ }
+
+ @Test
+ void testSubSequence() {
+ char[] buffer = "hello world".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ CharSequence sub = value.subSequence(0, 5);
+ assertEquals("hello", sub.toString());
+ }
+
+ // stringValue tests
+ @Test
+ void testStringValueSimple() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals("hello", value.stringValue());
+ }
+
+ @Test
+ void testStringValueWithDecodeStrings() {
+ char[] buffer = "hello\\nworld".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, true, false);
+ // When decodeStrings is true, it should decode escape sequences
+ assertNotNull(value.stringValue());
+ }
+
+ @Test
+ void testStringValueEncoded() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals("hello", value.stringValueEncoded());
+ }
+
+ // intValue tests
+ @Test
+ void testIntValuePositive() {
+ char[] buffer = "42".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(42, value.intValue());
+ }
+
+ @Test
+ void testIntValueNegative() {
+ char[] buffer = "-42".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(-42, value.intValue());
+ }
+
+ @Test
+ void testIntValueZero() {
+ char[] buffer = "0".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(0, value.intValue());
+ }
+
+ // longValue tests
+ @Test
+ void testLongValueLargeNumber() {
+ char[] buffer = "9876543210".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(9876543210L, value.longValue());
+ }
+
+ @Test
+ void testLongValueSmallNumber() {
+ char[] buffer = "100".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(100L, value.longValue());
+ }
+
+ // doubleValue tests
+ @Test
+ void testDoubleValue() {
+ char[] buffer = "3.14159".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.DOUBLE, 0,
buffer.length, buffer, false, false);
+ assertEquals(3.14159, value.doubleValue(), 0.00001);
+ }
+
+ @Test
+ void testDoubleValueNegative() {
+ char[] buffer = "-2.5".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.DOUBLE, 0,
buffer.length, buffer, false, false);
+ assertEquals(-2.5, value.doubleValue(), 0.0001);
+ }
+
+ // floatValue tests
+ @Test
+ void testFloatValue() {
+ char[] buffer = "3.14".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.DOUBLE, 0,
buffer.length, buffer, false, false);
+ assertEquals(3.14f, value.floatValue(), 0.01f);
+ }
+
+ // byteValue tests
+ @Test
+ void testByteValue() {
+ char[] buffer = "100".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals((byte) 100, value.byteValue());
+ }
+
+ // shortValue tests
+ @Test
+ void testShortValue() {
+ char[] buffer = "1000".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals((short) 1000, value.shortValue());
+ }
+
+ // charValue tests
+ @Test
+ void testCharValue() {
+ char[] buffer = "ABC".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals('A', value.charValue());
+ }
+
+ // booleanValue tests
+ @Test
+ void testBooleanValueTrue() {
+ char[] buffer = "true".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertTrue(value.booleanValue());
+ }
+
+ @Test
+ void testBooleanValueFalse() {
+ char[] buffer = "false".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertFalse(value.booleanValue());
+ }
+
+ @Test
+ void testBooleanValueOther() {
+ char[] buffer = "something".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertFalse(value.booleanValue()); // parseBoolean returns false for
non-"true" strings
+ }
+
+ // bigDecimalValue tests
+ @Test
+ void testBigDecimalValue() {
+ char[] buffer = "123.456".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.DOUBLE, 0,
buffer.length, buffer, false, false);
+ assertEquals(new BigDecimal("123.456"), value.bigDecimalValue());
+ }
+
+ // bigIntegerValue tests
+ @Test
+ void testBigIntegerValue() {
+ char[] buffer = "123456789012345678901234567890".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(new BigInteger("123456789012345678901234567890"),
value.bigIntegerValue());
+ }
+
+ // toValue tests
+ @Test
+ void testToValueInteger() {
+ char[] buffer = "42".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(42, value.toValue());
+ }
+
+ @Test
+ void testToValueLong() {
+ char[] buffer = "9876543210".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertEquals(9876543210L, value.toValue());
+ }
+
+ @Test
+ void testToValueDouble() {
+ char[] buffer = "3.14".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.DOUBLE, 0,
buffer.length, buffer, false, false);
+ assertEquals(3.14, value.toValue());
+ }
+
+ @Test
+ void testToValueString() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals("hello", value.toValue());
+ }
+
+ @Test
+ void testToValueCached() {
+ char[] buffer = "42".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ Object first = value.toValue();
+ Object second = value.toValue();
+ assertSame(first, second);
+ }
+
+ // isContainer test
+ @Test
+ void testIsContainer() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertFalse(value.isContainer());
+ }
+
+ // toEnum tests
+ @Test
+ void testToEnumFromString() {
+ char[] buffer = "VALUE2".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ TestEnum result = value.toEnum(TestEnum.class);
+ assertEquals(TestEnum.VALUE2, result);
+ }
+
+ @Test
+ void testToEnumFromInteger() {
+ char[] buffer = "1".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ TestEnum result = value.toEnum(TestEnum.class);
+ assertEquals(TestEnum.VALUE2, result);
+ }
+
+ @Test
+ void testToEnumStaticFromString() {
+ assertEquals(TestEnum.VALUE1, CharSequenceValue.toEnum(TestEnum.class,
"VALUE1"));
+ assertEquals(TestEnum.VALUE2, CharSequenceValue.toEnum(TestEnum.class,
"VALUE2"));
+ }
+
+ @Test
+ void testToEnumStaticFromStringWithHyphens() {
+ // Test conversion of hyphenated names
+ assertEquals(TestEnumWithHyphens.SOME_VALUE,
CharSequenceValue.toEnum(TestEnumWithHyphens.class, "some-value"));
+ }
+
+ @Test
+ void testToEnumStaticFromOrdinal() {
+ assertEquals(TestEnum.VALUE1, CharSequenceValue.toEnum(TestEnum.class,
0));
+ assertEquals(TestEnum.VALUE2, CharSequenceValue.toEnum(TestEnum.class,
1));
+ }
+
+ // chop tests
+ @Test
+ void testChop() {
+ char[] buffer = "xxxhelloyyy".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 3,
8, buffer, false, false);
+ value.chop();
+ assertEquals("hello", value.toString());
+ }
+
+ @Test
+ void testChopMultipleTimes() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ value.chop();
+ value.chop(); // Should be idempotent
+ assertEquals("hello", value.toString());
+ }
+
+ @Test
+ void testChopAlreadyChopped() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(true, Type.STRING, 0,
buffer.length, buffer, false, false);
+ value.chop(); // Already chopped by constructor
+ assertEquals("hello", value.toString());
+ }
+
+ // equals tests
+ @Test
+ void testEqualsSameInstance() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals(value, value);
+ }
+
+ @Test
+ void testEqualsSameValues() {
+ char[] buffer1 = "hello".toCharArray();
+ char[] buffer2 = "hello".toCharArray();
+ CharSequenceValue value1 = new CharSequenceValue(false, Type.STRING,
0, buffer1.length, buffer1, false, false);
+ CharSequenceValue value2 = new CharSequenceValue(false, Type.STRING,
0, buffer2.length, buffer2, false, false);
+ assertEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsDifferentValues() {
+ char[] buffer1 = "hello".toCharArray();
+ char[] buffer2 = "world".toCharArray();
+ CharSequenceValue value1 = new CharSequenceValue(false, Type.STRING,
0, buffer1.length, buffer1, false, false);
+ CharSequenceValue value2 = new CharSequenceValue(false, Type.STRING,
0, buffer2.length, buffer2, false, false);
+ assertNotEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsDifferentTypes() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value1 = new CharSequenceValue(false, Type.STRING,
0, buffer.length, buffer, false, false);
+ CharSequenceValue value2 = new CharSequenceValue(false, Type.INTEGER,
0, buffer.length, buffer, false, false);
+ assertNotEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsDifferentEndIndex() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value1 = new CharSequenceValue(false, Type.STRING,
0, 3, buffer, false, false);
+ CharSequenceValue value2 = new CharSequenceValue(false, Type.STRING,
0, 5, buffer, false, false);
+ assertNotEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsNotValue() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertNotEquals(value, "hello");
+ }
+
+ // hashCode tests
+ @Test
+ void testHashCodeConsistent() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 0,
buffer.length, buffer, false, false);
+ int hash1 = value.hashCode();
+ int hash2 = value.hashCode();
+ assertEquals(hash1, hash2);
+ }
+
+ @Test
+ void testHashCodeEqualObjects() {
+ char[] buffer1 = "hello".toCharArray();
+ char[] buffer2 = "hello".toCharArray();
+ CharSequenceValue value1 = new CharSequenceValue(false, Type.STRING,
0, buffer1.length, buffer1, false, false);
+ CharSequenceValue value2 = new CharSequenceValue(false, Type.STRING,
0, buffer2.length, buffer2, false, false);
+ assertEquals(value1.hashCode(), value2.hashCode());
+ }
+
+ // toString tests
+ @Test
+ void testToStringFullBuffer() {
+ char[] buffer = "hello".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(true, Type.STRING, 0,
buffer.length, buffer, false, false);
+ assertEquals("hello", value.toString());
+ }
+
+ @Test
+ void testToStringPartialBuffer() {
+ char[] buffer = "xxxhelloyyy".toCharArray();
+ CharSequenceValue value = new CharSequenceValue(false, Type.STRING, 3,
8, buffer, false, false);
+ assertEquals("hello", value.toString());
+ }
+
+ // Test enums
+ enum TestEnum {
+ VALUE1, VALUE2, VALUE3
+ }
+
+ enum TestEnumWithHyphens {
+ SOME_VALUE, ANOTHER_VALUE
+ }
+}
diff --git
a/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/DatesJUnit5Test.java
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/DatesJUnit5Test.java
new file mode 100644
index 0000000000..ad04eace42
--- /dev/null
+++
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/DatesJUnit5Test.java
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.groovy.json.internal;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for Dates utility class.
+ */
+class DatesJUnit5Test {
+
+ // utc tests
+ @Test
+ void testUtc() {
+ long time = System.currentTimeMillis();
+ long utcTime = Dates.utc(time);
+ assertNotNull(utcTime);
+ }
+
+ // toDate tests
+ @Test
+ void testToDateWithoutMilliseconds() {
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ Date date = Dates.toDate(tz, 2020, 6, 15, 10, 30, 45);
+
+ assertNotNull(date);
+ java.util.Calendar cal = java.util.Calendar.getInstance(tz);
+ cal.setTime(date);
+ assertEquals(2020, cal.get(java.util.Calendar.YEAR));
+ assertEquals(5, cal.get(java.util.Calendar.MONTH)); // June is 5
(0-indexed), but Dates uses 1-indexed
+ assertEquals(15, cal.get(java.util.Calendar.DAY_OF_MONTH));
+ }
+
+ @Test
+ void testToDateWithMilliseconds() {
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ Date date = Dates.toDate(tz, 2020, 6, 15, 10, 30, 45, 123);
+
+ assertNotNull(date);
+ }
+
+ @Test
+ void testToDateWithDifferentTimezones() {
+ TimeZone gmt = TimeZone.getTimeZone("GMT");
+ TimeZone est = TimeZone.getTimeZone("EST");
+
+ Date gmtDate = Dates.toDate(gmt, 2020, 6, 15, 12, 0, 0);
+ Date estDate = Dates.toDate(est, 2020, 6, 15, 12, 0, 0);
+
+ // Different timezones should produce different times
+ assertNotEquals(gmtDate.getTime(), estDate.getTime());
+ }
+
+ // isISO8601 tests
+ @Test
+ void testIsISO8601ShortFormat() {
+ // Format: 1994-11-05T08:15:30Z
+ char[] chars = "1994-11-05T08:15:30Z".toCharArray();
+ assertTrue(Dates.isISO8601(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601LongFormat() {
+ // Format: 1994-11-05T08:15:30-05:00
+ char[] chars = "1994-11-05T08:15:30-05:00".toCharArray();
+ assertTrue(Dates.isISO8601(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601LongFormatPlus() {
+ // Format: 1994-11-05T08:15:30+05:00
+ char[] chars = "1994-11-05T08:15:30+05:00".toCharArray();
+ assertTrue(Dates.isISO8601(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601InvalidLength() {
+ char[] chars = "1994-11-05".toCharArray();
+ assertFalse(Dates.isISO8601(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601InvalidFormat() {
+ char[] chars = "1994/11/05T08:15:30Z".toCharArray();
+ assertFalse(Dates.isISO8601(chars, 0, chars.length));
+ }
+
+ // isISO8601QuickCheck tests
+ @Test
+ void testIsISO8601QuickCheckJsonTimeLength() {
+ char[] chars = "2013-12-14T01:55:33.412Z".toCharArray();
+ assertTrue(Dates.isISO8601QuickCheck(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601QuickCheckShortLength() {
+ char[] chars = "1994-11-05T08:15:30Z".toCharArray();
+ assertTrue(Dates.isISO8601QuickCheck(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601QuickCheckLongLength() {
+ char[] chars = "1994-11-05T08:15:30-05:00".toCharArray();
+ assertTrue(Dates.isISO8601QuickCheck(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601QuickCheckWithColonAt16() {
+ // Length >= 17 and has colon at position 16
+ char[] chars = "1994-11-05T08:15:30".toCharArray();
+ assertTrue(Dates.isISO8601QuickCheck(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsISO8601QuickCheckTooShort() {
+ char[] chars = "1994-11-05".toCharArray();
+ assertFalse(Dates.isISO8601QuickCheck(chars, 0, chars.length));
+ }
+
+ // isJsonDate tests
+ @Test
+ void testIsJsonDateValid() {
+ // Format: 2013-12-14T01:55:33.412Z
+ char[] chars = "2013-12-14T01:55:33.412Z".toCharArray();
+ assertTrue(Dates.isJsonDate(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsJsonDateWithPlus() {
+ // Format with + for milliseconds separator
+ char[] chars = "2013-12-14T01:55:33+412Z".toCharArray();
+ assertTrue(Dates.isJsonDate(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsJsonDateInvalidLength() {
+ char[] chars = "2013-12-14T01:55:33Z".toCharArray();
+ assertFalse(Dates.isJsonDate(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsJsonDateInvalidFormat() {
+ char[] chars = "2013/12/14T01:55:33.412Z".toCharArray();
+ assertFalse(Dates.isJsonDate(chars, 0, chars.length));
+ }
+
+ @Test
+ void testIsJsonDateInvalidSeparator() {
+ // Neither . nor + at position 19
+ char[] chars = "2013-12-14T01:55:33X412Z".toCharArray();
+ assertFalse(Dates.isJsonDate(chars, 0, chars.length));
+ }
+
+ // fromISO8601 tests
+ @Test
+ void testFromISO8601ShortFormat() {
+ char[] chars = "1994-11-05T08:15:30Z".toCharArray();
+ Date date = Dates.fromISO8601(chars, 0, chars.length);
+
+ assertNotNull(date);
+ }
+
+ @Test
+ void testFromISO8601LongFormat() {
+ char[] chars = "1994-11-05T08:15:30-05:00".toCharArray();
+ Date date = Dates.fromISO8601(chars, 0, chars.length);
+
+ assertNotNull(date);
+ }
+
+ @Test
+ void testFromISO8601InvalidFormat() {
+ char[] chars = "invalid-date-format".toCharArray();
+ Date date = Dates.fromISO8601(chars, 0, chars.length);
+
+ assertNull(date);
+ }
+
+ @Test
+ void testFromISO8601WithOffset() {
+ char[] chars = "2020-06-15T10:30:45".toCharArray();
+ // Too short, should return null
+ Date date = Dates.fromISO8601(chars, 0, chars.length);
+ assertNull(date);
+ }
+
+ // fromJsonDate tests
+ @Test
+ void testFromJsonDateValid() {
+ char[] chars = "2013-12-14T01:55:33.412Z".toCharArray();
+ Date date = Dates.fromJsonDate(chars, 0, chars.length);
+
+ assertNotNull(date);
+ }
+
+ @Test
+ void testFromJsonDateInvalidFormat() {
+ char[] chars = "invalid-json-date!!!".toCharArray();
+ Date date = Dates.fromJsonDate(chars, 0, chars.length);
+
+ assertNull(date);
+ }
+
+ @Test
+ void testFromJsonDateWrongLength() {
+ char[] chars = "2013-12-14T01:55:33Z".toCharArray();
+ Date date = Dates.fromJsonDate(chars, 0, chars.length);
+
+ assertNull(date);
+ }
+
+ // Edge case tests
+ @Test
+ void testFromISO8601WithSubstring() {
+ String fullString = "prefix1994-11-05T08:15:30Zsuffix";
+ char[] chars = fullString.toCharArray();
+ // Parse from position 6 to 26 (the ISO8601 part)
+ Date date = Dates.fromISO8601(chars, 6, 26);
+
+ assertNotNull(date);
+ }
+
+ @Test
+ void testFromJsonDateWithSubstring() {
+ String fullString = "prefix2013-12-14T01:55:33.412Zsuffix";
+ char[] chars = fullString.toCharArray();
+ // Parse from position 6 to 30 (the JSON date part)
+ Date date = Dates.fromJsonDate(chars, 6, 30);
+
+ assertNotNull(date);
+ }
+
+ @Test
+ void testIsISO8601WithSubstring() {
+ String fullString = "prefix1994-11-05T08:15:30Zsuffix";
+ char[] chars = fullString.toCharArray();
+ assertTrue(Dates.isISO8601(chars, 6, 26));
+ }
+
+ @Test
+ void testIsJsonDateWithSubstring() {
+ String fullString = "prefix2013-12-14T01:55:33.412Zsuffix";
+ char[] chars = fullString.toCharArray();
+ assertTrue(Dates.isJsonDate(chars, 6, 30));
+ }
+
+ // Specific date parsing verification
+ @Test
+ void testFromISO8601ParsesCorrectly() {
+ char[] chars = "2020-06-15T10:30:45Z".toCharArray();
+ Date date = Dates.fromISO8601(chars, 0, chars.length);
+
+ assertNotNull(date);
+ java.util.Calendar cal =
java.util.Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+ cal.setTime(date);
+ assertEquals(2020, cal.get(java.util.Calendar.YEAR));
+ assertEquals(5, cal.get(java.util.Calendar.MONTH)); // June is 5
(0-indexed)
+ assertEquals(15, cal.get(java.util.Calendar.DAY_OF_MONTH));
+ assertEquals(10, cal.get(java.util.Calendar.HOUR_OF_DAY));
+ assertEquals(30, cal.get(java.util.Calendar.MINUTE));
+ assertEquals(45, cal.get(java.util.Calendar.SECOND));
+ }
+
+ @Test
+ void testFromJsonDateParsesCorrectly() {
+ char[] chars = "2020-06-15T10:30:45.123Z".toCharArray();
+ Date date = Dates.fromJsonDate(chars, 0, chars.length);
+
+ assertNotNull(date);
+ java.util.Calendar cal =
java.util.Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+ cal.setTime(date);
+ assertEquals(2020, cal.get(java.util.Calendar.YEAR));
+ assertEquals(15, cal.get(java.util.Calendar.DAY_OF_MONTH));
+ }
+
+ // Constants verification
+ @Test
+ void testConstantsHaveCorrectValues() {
+ assertEquals(20, Dates.SHORT_ISO_8601_TIME_LENGTH);
+ assertEquals(25, Dates.LONG_ISO_8601_TIME_LENGTH);
+ assertEquals(24, Dates.JSON_TIME_LENGTH);
+ }
+}
diff --git
a/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/NumberValueJUnit5Test.java
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/NumberValueJUnit5Test.java
new file mode 100644
index 0000000000..da77cdb1de
--- /dev/null
+++
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/NumberValueJUnit5Test.java
@@ -0,0 +1,395 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.groovy.json.internal;
+
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for NumberValue class.
+ */
+class NumberValueJUnit5Test {
+
+ // Constructor tests
+ @Test
+ void testDefaultConstructor() {
+ NumberValue value = new NumberValue();
+ assertNotNull(value);
+ }
+
+ @Test
+ void testTypeConstructor() {
+ NumberValue value = new NumberValue(Type.INTEGER);
+ assertNotNull(value);
+ }
+
+ @Test
+ void testBufferConstructorWithChop() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(true, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(12345, value.intValue());
+ }
+
+ @Test
+ void testBufferConstructorWithoutChop() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(12345, value.intValue());
+ }
+
+ @Test
+ void testBufferConstructorPartialRange() {
+ char[] buffer = "abc12345xyz".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 3, 8, buffer);
+ assertEquals(12345, value.intValue());
+ }
+
+ @Test
+ void testBufferConstructorPartialRangeWithChop() {
+ char[] buffer = "abc12345xyz".toCharArray();
+ NumberValue value = new NumberValue(true, Type.INTEGER, 3, 8, buffer);
+ assertEquals(12345, value.intValue());
+ }
+
+ @Test
+ void testBufferConstructorSingleMinus() {
+ char[] buffer = "-".toCharArray();
+ assertThrows(Exception.class, () ->
+ new NumberValue(false, Type.INTEGER, 0, 1, buffer));
+ }
+
+ // intValue tests
+ @Test
+ void testIntValuePositive() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(42, value.intValue());
+ }
+
+ @Test
+ void testIntValueNegative() {
+ char[] buffer = "-42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(-42, value.intValue());
+ }
+
+ @Test
+ void testIntValueZero() {
+ char[] buffer = "0".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(0, value.intValue());
+ }
+
+ // longValue tests
+ @Test
+ void testLongValuePositive() {
+ char[] buffer = "9876543210".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(9876543210L, value.longValue());
+ }
+
+ @Test
+ void testLongValueNegative() {
+ char[] buffer = "-9876543210".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(-9876543210L, value.longValue());
+ }
+
+ @Test
+ void testLongValueFromSmallInt() {
+ char[] buffer = "100".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(100L, value.longValue());
+ }
+
+ // doubleValue tests
+ @Test
+ void testDoubleValueInteger() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ assertEquals(42.0, value.doubleValue(), 0.0001);
+ }
+
+ @Test
+ void testDoubleValueDecimal() {
+ char[] buffer = "3.14159".toCharArray();
+ NumberValue value = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ assertEquals(3.14159, value.doubleValue(), 0.00001);
+ }
+
+ @Test
+ void testDoubleValueNegative() {
+ char[] buffer = "-2.5".toCharArray();
+ NumberValue value = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ assertEquals(-2.5, value.doubleValue(), 0.0001);
+ }
+
+ // floatValue tests
+ @Test
+ void testFloatValueDecimal() {
+ char[] buffer = "3.14".toCharArray();
+ NumberValue value = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ assertEquals(3.14f, value.floatValue(), 0.01f);
+ }
+
+ // byteValue tests
+ @Test
+ void testByteValue() {
+ char[] buffer = "127".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals((byte) 127, value.byteValue());
+ }
+
+ // shortValue tests
+ @Test
+ void testShortValue() {
+ char[] buffer = "1000".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals((short) 1000, value.shortValue());
+ }
+
+ // charValue tests
+ @Test
+ void testCharValue() {
+ char[] buffer = "65".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals('6', value.charValue()); // First char of buffer
+ }
+
+ // bigDecimalValue tests
+ @Test
+ void testBigDecimalValueInteger() {
+ char[] buffer = "123456789".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(new BigDecimal("123456789"), value.bigDecimalValue());
+ }
+
+ @Test
+ void testBigDecimalValueDecimal() {
+ char[] buffer = "123.456789".toCharArray();
+ NumberValue value = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ assertEquals(new BigDecimal("123.456789"), value.bigDecimalValue());
+ }
+
+ // bigIntegerValue tests
+ @Test
+ void testBigIntegerValue() {
+ char[] buffer = "123456789012345678901234567890".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(new BigInteger("123456789012345678901234567890"),
value.bigIntegerValue());
+ }
+
+ // stringValue tests
+ @Test
+ void testStringValue() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals("12345", value.stringValue());
+ }
+
+ @Test
+ void testStringValueEncoded() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals("12345", value.stringValueEncoded());
+ }
+
+ // booleanValue tests
+ @Test
+ void testBooleanValueTrue() {
+ char[] buffer = "true".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertTrue(value.booleanValue());
+ }
+
+ @Test
+ void testBooleanValueFalse() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertFalse(value.booleanValue());
+ }
+
+ // dateValue tests
+ @Test
+ void testDateValue() {
+ // Use a timestamp
+ long timestamp = 1609459200000L; // 2021-01-01 00:00:00 UTC
+ char[] buffer = String.valueOf(timestamp).toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ Date date = value.dateValue();
+ assertNotNull(date);
+ }
+
+ // toValue tests
+ @Test
+ void testToValueInteger() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(42, value.toValue());
+ }
+
+ @Test
+ void testToValueLong() {
+ char[] buffer = "9876543210".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(9876543210L, value.toValue());
+ }
+
+ @Test
+ void testToValueDouble() {
+ char[] buffer = "3.14".toCharArray();
+ NumberValue value = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ Object result = value.toValue();
+ assertTrue(result instanceof BigDecimal);
+ }
+
+ @Test
+ void testToValueCached() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ Object first = value.toValue();
+ Object second = value.toValue();
+ assertSame(first, second); // Should return cached value
+ }
+
+ // isContainer test
+ @Test
+ void testIsContainer() {
+ NumberValue value = new NumberValue(Type.INTEGER);
+ assertFalse(value.isContainer());
+ }
+
+ // toEnum tests
+ @Test
+ void testToEnumByOrdinal() {
+ char[] buffer = "1".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ TestEnum result = value.toEnum(TestEnum.class);
+ assertEquals(TestEnum.VALUE2, result);
+ }
+
+ @Test
+ void testToEnumStaticByOrdinal() {
+ assertEquals(TestEnum.VALUE1, NumberValue.toEnum(TestEnum.class, 0));
+ assertEquals(TestEnum.VALUE2, NumberValue.toEnum(TestEnum.class, 1));
+ }
+
+ // toString tests
+ @Test
+ void testToStringFullBuffer() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(true, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals("12345", value.toString());
+ }
+
+ @Test
+ void testToStringPartialBuffer() {
+ char[] buffer = "abc12345xyz".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 3, 8, buffer);
+ assertEquals("12345", value.toString());
+ }
+
+ // chop tests
+ @Test
+ void testChop() {
+ char[] buffer = "abc12345xyz".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 3, 8, buffer);
+ value.chop();
+ assertEquals("12345", value.toString());
+ }
+
+ @Test
+ void testChopMultipleTimes() {
+ char[] buffer = "12345".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ value.chop();
+ value.chop(); // Should be idempotent
+ assertEquals("12345", value.toString());
+ }
+
+ // equals tests
+ @Test
+ void testEqualsSameInstance() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertEquals(value, value);
+ }
+
+ @Test
+ void testEqualsSameValues() {
+ char[] buffer1 = "42".toCharArray();
+ char[] buffer2 = "42".toCharArray();
+ NumberValue value1 = new NumberValue(false, Type.INTEGER, 0,
buffer1.length, buffer1);
+ NumberValue value2 = new NumberValue(false, Type.INTEGER, 0,
buffer2.length, buffer2);
+ assertEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsDifferentValues() {
+ char[] buffer1 = "42".toCharArray();
+ char[] buffer2 = "43".toCharArray();
+ NumberValue value1 = new NumberValue(false, Type.INTEGER, 0,
buffer1.length, buffer1);
+ NumberValue value2 = new NumberValue(false, Type.INTEGER, 0,
buffer2.length, buffer2);
+ assertNotEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsDifferentTypes() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value1 = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ NumberValue value2 = new NumberValue(false, Type.DOUBLE, 0,
buffer.length, buffer);
+ assertNotEquals(value1, value2);
+ }
+
+ @Test
+ void testEqualsNotValue() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ assertNotEquals(value, "42");
+ }
+
+ // hashCode tests
+ @Test
+ void testHashCodeConsistent() {
+ char[] buffer = "42".toCharArray();
+ NumberValue value = new NumberValue(false, Type.INTEGER, 0,
buffer.length, buffer);
+ int hash1 = value.hashCode();
+ int hash2 = value.hashCode();
+ assertEquals(hash1, hash2);
+ }
+
+ @Test
+ void testHashCodeEqualObjects() {
+ char[] buffer1 = "42".toCharArray();
+ char[] buffer2 = "42".toCharArray();
+ NumberValue value1 = new NumberValue(false, Type.INTEGER, 0,
buffer1.length, buffer1);
+ NumberValue value2 = new NumberValue(false, Type.INTEGER, 0,
buffer2.length, buffer2);
+ assertEquals(value1.hashCode(), value2.hashCode());
+ }
+
+ // Test enum for toEnum tests
+ enum TestEnum {
+ VALUE1, VALUE2, VALUE3
+ }
+}
diff --git
a/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/ValueContainerJUnit5Test.java
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/ValueContainerJUnit5Test.java
new file mode 100644
index 0000000000..9bb576bac9
--- /dev/null
+++
b/subprojects/groovy-json/src/test/java/org/apache/groovy/json/internal/ValueContainerJUnit5Test.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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
+ *
+ * http://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.apache.groovy.json.internal;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * JUnit 5 tests for ValueContainer class.
+ */
+class ValueContainerJUnit5Test {
+
+ // Static constant tests
+ @Test
+ void testTrueConstant() {
+ assertNotNull(ValueContainer.TRUE);
+ assertTrue(ValueContainer.TRUE.booleanValue());
+ assertEquals(true, ValueContainer.TRUE.toValue());
+ }
+
+ @Test
+ void testFalseConstant() {
+ assertNotNull(ValueContainer.FALSE);
+ assertFalse(ValueContainer.FALSE.booleanValue());
+ assertEquals(false, ValueContainer.FALSE.toValue());
+ }
+
+ @Test
+ void testNullConstant() {
+ assertNotNull(ValueContainer.NULL);
+ assertNull(ValueContainer.NULL.toValue());
+ assertNull(ValueContainer.NULL.stringValue());
+ }
+
+ // Constructor tests
+ @Test
+ void testConstructorWithType() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertTrue(vc.booleanValue());
+ }
+
+ @Test
+ void testConstructorWithMap() {
+ Map<String, Object> map = new HashMap<>();
+ map.put("key", "value");
+ ValueContainer vc = new ValueContainer(map);
+
+ assertTrue(vc.isContainer());
+ assertEquals(map, vc.toValue());
+ }
+
+ @Test
+ void testConstructorWithList() {
+ List<Object> list = Arrays.asList("a", "b", "c");
+ ValueContainer vc = new ValueContainer(list);
+
+ assertTrue(vc.isContainer());
+ assertEquals(list, vc.toValue());
+ }
+
+ @Test
+ void testConstructorWithValueAndType() {
+ ValueContainer vc = new ValueContainer("test", Type.STRING, false);
+ assertEquals("test", vc.value);
+ assertEquals(Type.STRING, vc.type);
+ assertFalse(vc.decodeStrings);
+ }
+
+ // booleanValue tests
+ @Test
+ void testBooleanValueTrue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertTrue(vc.booleanValue());
+ }
+
+ @Test
+ void testBooleanValueFalse() {
+ ValueContainer vc = new ValueContainer(Type.FALSE);
+ assertFalse(vc.booleanValue());
+ }
+
+ // stringValue tests
+ @Test
+ void testStringValueNull() {
+ ValueContainer vc = new ValueContainer(Type.NULL);
+ assertNull(vc.stringValue());
+ }
+
+ @Test
+ void testStringValueTrue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals("TRUE", vc.stringValue());
+ }
+
+ @Test
+ void testStringValueFalse() {
+ ValueContainer vc = new ValueContainer(Type.FALSE);
+ assertEquals("FALSE", vc.stringValue());
+ }
+
+ // stringValueEncoded tests
+ @Test
+ void testStringValueEncoded() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals("TRUE", vc.stringValueEncoded());
+ }
+
+ // toString tests
+ @Test
+ void testToStringTrue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals("TRUE", vc.toString());
+ }
+
+ @Test
+ void testToStringFalse() {
+ ValueContainer vc = new ValueContainer(Type.FALSE);
+ assertEquals("FALSE", vc.toString());
+ }
+
+ @Test
+ void testToStringNull() {
+ ValueContainer vc = new ValueContainer(Type.NULL);
+ assertEquals("NULL", vc.toString());
+ }
+
+ // toValue tests
+ @Test
+ void testToValueWithExistingValue() {
+ Map<String, Object> map = new HashMap<>();
+ ValueContainer vc = new ValueContainer(map);
+ assertSame(map, vc.toValue());
+ }
+
+ @Test
+ void testToValueTrue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals(true, vc.toValue());
+ }
+
+ @Test
+ void testToValueFalse() {
+ ValueContainer vc = new ValueContainer(Type.FALSE);
+ assertEquals(false, vc.toValue());
+ }
+
+ @Test
+ void testToValueNull() {
+ ValueContainer vc = new ValueContainer(Type.NULL);
+ assertNull(vc.toValue());
+ }
+
+ // toEnum tests
+ @Test
+ void testToEnum() {
+ ValueContainer vc = new ValueContainer(TestEnum.VALUE_A, Type.STRING,
false);
+ assertEquals(TestEnum.VALUE_A, vc.toEnum(TestEnum.class));
+ }
+
+ enum TestEnum { VALUE_A, VALUE_B }
+
+ // isContainer tests
+ @Test
+ void testIsContainerMap() {
+ ValueContainer vc = new ValueContainer(new HashMap<String, Object>());
+ assertTrue(vc.isContainer());
+ }
+
+ @Test
+ void testIsContainerList() {
+ ValueContainer vc = new ValueContainer(Arrays.asList("a", "b"));
+ assertTrue(vc.isContainer());
+ }
+
+ @Test
+ void testIsContainerFalseForPrimitive() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertFalse(vc.isContainer());
+ }
+
+ // chop tests - should do nothing
+ @Test
+ void testChop() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ vc.chop(); // Should not throw
+ assertTrue(vc.booleanValue()); // State unchanged
+ }
+
+ // CharSequence methods tests
+ @Test
+ void testCharValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals('\0', vc.charValue());
+ }
+
+ @Test
+ void testLength() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals(0, vc.length());
+ }
+
+ @Test
+ void testCharAt() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals('0', vc.charAt(0));
+ }
+
+ @Test
+ void testSubSequence() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals("", vc.subSequence(0, 0));
+ }
+
+ // dateValue tests
+ @Test
+ void testDateValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertNull(vc.dateValue());
+ }
+
+ // Numeric value tests
+ @Test
+ void testByteValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals(0, vc.byteValue());
+ }
+
+ @Test
+ void testShortValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals(0, vc.shortValue());
+ }
+
+ @Test
+ void testBigDecimalValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertNull(vc.bigDecimalValue());
+ }
+
+ @Test
+ void testBigIntegerValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertNull(vc.bigIntegerValue());
+ }
+
+ @Test
+ void testDoubleValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals(0.0, vc.doubleValue());
+ }
+
+ @Test
+ void testFloatValue() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertEquals(0.0f, vc.floatValue());
+ }
+
+ // intValue and longValue throw exceptions by design
+ @Test
+ void testIntValueThrows() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertThrows(Exceptions.JsonInternalException.class, () ->
vc.intValue());
+ }
+
+ @Test
+ void testLongValueThrows() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ assertThrows(Exceptions.JsonInternalException.class, () ->
vc.longValue());
+ }
+
+ // Multiple toValue calls cache the result
+ @Test
+ void testToValueCachesResult() {
+ ValueContainer vc = new ValueContainer(Type.TRUE);
+ Object first = vc.toValue();
+ Object second = vc.toValue();
+ assertSame(first, second);
+ }
+}