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);
+    }
+}

Reply via email to