From 85b36263a28faae0c20e6c92f653642098b26e5e Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 13 Mar 2026 16:32:17 -0400 Subject: [PATCH 1/4] Use TableTest in dd-trace-api --- dd-trace-api/build.gradle.kts | 1 + .../java/datadog/trace/api/DDSpanIdTest.java | 163 ++++------ .../java/datadog/trace/api/DDTraceIdTest.java | 300 +++++++----------- .../trace/api/IdGenerationStrategyTest.java | 27 +- .../api/internal/util/HexStringUtilsTest.java | 37 +-- 5 files changed, 213 insertions(+), 315 deletions(-) diff --git a/dd-trace-api/build.gradle.kts b/dd-trace-api/build.gradle.kts index bc05a8753a4..c715fb62bdd 100644 --- a/dd-trace-api/build.gradle.kts +++ b/dd-trace-api/build.gradle.kts @@ -75,5 +75,6 @@ dependencies { api(libs.slf4j) testImplementation(libs.guava) testImplementation(libs.bundles.mockito) + testImplementation(libs.tabletest) testImplementation(project(":utils:test-utils")) } diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java index e6cc4719b88..39f2ccbd160 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java @@ -7,58 +7,57 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.math.BigInteger; import java.util.HashSet; import java.util.Set; -import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.params.provider.ValueSource; +import org.tabletest.junit.TableTest; class DDSpanIdTest { - @ParameterizedTest(name = "convert ids from/to String {0}") - @MethodSource("convertIdsFromToStringArguments") - void convertIdsFromToString(String displayName, String stringId, long expectedId) { + @TableTest({ + "scenario | stringId | expectedId ", + "zero | '0' | 0 ", + "one | '1' | 1 ", + "max | '18446744073709551615' | -1 ", + "long max | '9223372036854775807' | 9223372036854775807 ", + "long max plus one | '9223372036854775808' | -9223372036854775808" + }) + @ParameterizedTest + void convertIdsFromToString(String stringId, long expectedId) { long ddid = DDSpanId.from(stringId); assertEquals(expectedId, ddid); assertEquals(stringId, DDSpanId.toString(ddid)); } - static Stream convertIdsFromToStringArguments() { - return Stream.of( - Arguments.of("zero", "0", 0L), - Arguments.of("one", "1", 1L), - Arguments.of("max", "18446744073709551615", DDSpanId.MAX), - Arguments.of("long max", String.valueOf(Long.MAX_VALUE), Long.MAX_VALUE), - Arguments.of( - "long max plus one", - BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).toString(), - Long.MIN_VALUE)); - } - - @ParameterizedTest(name = "fail on illegal String {0}") - @MethodSource("failOnIllegalStringArguments") + @TableTest({ + "scenario | stringId ", + "null | ", + "empty | '' ", + "negative one | '-1' ", + "too large | '18446744073709551616'", + "too large variant | '18446744073709551625'", + "too large long | '184467440737095516150'", + "contains alpha first | '18446744073709551a1' ", + "contains alpha last | '184467440737095511a' " + }) + @ParameterizedTest void failOnIllegalString(String stringId) { assertThrows(NumberFormatException.class, () -> DDSpanId.from(stringId)); } - static Stream failOnIllegalStringArguments() { - return Stream.of( - Arguments.of((Object) null), - Arguments.of(""), - Arguments.of("-1"), - Arguments.of("18446744073709551616"), - Arguments.of("18446744073709551625"), - Arguments.of("184467440737095516150"), - Arguments.of("18446744073709551a1"), - Arguments.of("184467440737095511a")); - } - - @ParameterizedTest(name = "convert ids from/to hex String {0}") - @MethodSource("convertIdsFromToHexStringArguments") + @TableTest({ + "scenario | hexId | expectedId ", + "zero | '0' | 0 ", + "one | '1' | 1 ", + "max | 'ffffffffffffffff' | -1 ", + "long max | '7fffffffffffffff' | 9223372036854775807 ", + "long min | '8000000000000000' | -9223372036854775808", + "long min with leading zeros | '00008000000000000000' | -9223372036854775808", + "cafebabe | 'cafebabe' | 3405691582 ", + "fifteen hex digits | '123456789abcdef' | 81985529216486895 " + }) + @ParameterizedTest void convertIdsFromToHexString(String hexId, long expectedId) { long ddid = DDSpanId.fromHex(hexId); String padded16 = @@ -73,27 +72,22 @@ void convertIdsFromToHexString(String hexId, long expectedId) { assertEquals(padded16, DDSpanId.toHexStringPadded(ddid)); } - static Stream convertIdsFromToHexStringArguments() { - return Stream.of( - Arguments.of("0", 0L), - Arguments.of("1", 1L), - Arguments.of(repeat("f", 16), DDSpanId.MAX), - Arguments.of("7" + repeat("f", 15), Long.MAX_VALUE), - Arguments.of("8" + repeat("0", 15), Long.MIN_VALUE), - Arguments.of(repeat("0", 4) + "8" + repeat("0", 15), Long.MIN_VALUE), - Arguments.of("cafebabe", 3405691582L), - Arguments.of("123456789abcdef", 81985529216486895L)); - } - - @ParameterizedTest(name = "convert ids from part of hex String {0}") - @MethodSource("convertIdsFromPartOfHexStringArguments") + @TableTest({ + "scenario | hexId | start | length | lowerCaseOnly | expectedId", + "null input | | 1 | 1 | false | ", + "empty input | '' | 1 | 1 | false | ", + "negative start | '00' | -1 | 1 | false | ", + "zero length | '00' | 0 | 0 | false | ", + "single zero at index 0 | '00' | 0 | 1 | false | 0 ", + "single zero at index 1 | '00' | 1 | 1 | false | 0 ", + "single zero at index 1 duplicate | '00' | 1 | 1 | false | 0 ", + "max lower-case | 'ffffffffffffffff' | 0 | 16 | true | -1 ", + "upper-case rejected when lower-case only| 'ffffffffffffFfff' | 0 | 16 | true | ", + "upper-case accepted when lower disabled | 'ffffffffffffFfff' | 0 | 16 | false | -1 " + }) + @ParameterizedTest void convertIdsFromPartOfHexString( - String displayName, - String hexId, - int start, - int length, - boolean lowerCaseOnly, - Long expectedId) { + String hexId, int start, int length, boolean lowerCaseOnly, Long expectedId) { Long parsedId = null; try { parsedId = DDSpanId.fromHex(hexId, start, length, lowerCaseOnly); @@ -108,50 +102,27 @@ void convertIdsFromPartOfHexString( } } - static Stream convertIdsFromPartOfHexStringArguments() { - return Stream.of( - Arguments.of("null input", null, 1, 1, false, null), - Arguments.of("empty input", "", 1, 1, false, null), - Arguments.of("negative start", "00", -1, 1, false, null), - Arguments.of("zero length", "00", 0, 0, false, null), - Arguments.of("single zero at index 0", "00", 0, 1, false, DDSpanId.ZERO), - Arguments.of("single zero at index 1", "00", 1, 1, false, DDSpanId.ZERO), - Arguments.of("single zero at index 1 duplicate", "00", 1, 1, false, DDSpanId.ZERO), - Arguments.of("max lower-case", repeat("f", 16), 0, 16, true, DDSpanId.MAX), - Arguments.of( - "upper-case rejected when lower-case only", - repeat("f", 12) + "Ffff", - 0, - 16, - true, - null), - Arguments.of( - "upper-case accepted when lower-case disabled", - repeat("f", 12) + "Ffff", - 0, - 16, - false, - DDSpanId.MAX)); - } - - @ParameterizedTest(name = "fail on illegal hex String {0}") - @MethodSource("failOnIllegalHexStringArguments") + @TableTest({ + "scenario | hexId ", + "null | ", + "empty | '' ", + "negative one | '-1' ", + "too long | '10000000000000000'", + "invalid middle | 'ffffffffffffffzf' ", + "invalid tail | 'fffffffffffffffz' " + }) + @ParameterizedTest void failOnIllegalHexString(String hexId) { assertThrows(NumberFormatException.class, () -> DDSpanId.fromHex(hexId)); } - static Stream failOnIllegalHexStringArguments() { - return Stream.of( - Arguments.of((Object) null), - Arguments.of(""), - Arguments.of("-1"), - Arguments.of("1" + repeat("0", 16)), - Arguments.of(repeat("f", 14) + "zf"), - Arguments.of(repeat("f", 15) + "z")); - } - - @ParameterizedTest(name = "generate id with {0}") - @ValueSource(strings = {"RANDOM", "SEQUENTIAL", "SECURE_RANDOM"}) + @TableTest({ + "scenario | strategyName ", + "random | RANDOM ", + "sequential | SEQUENTIAL ", + "secure random | SECURE_RANDOM" + }) + @ParameterizedTest void generateIdWithStrategy(String strategyName) { IdGenerationStrategy strategy = IdGenerationStrategy.fromName(strategyName); Set checked = new HashSet(); diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java index 176b0aeed3f..384084b2077 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java @@ -5,24 +5,25 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import java.math.BigInteger; -import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; +import org.tabletest.junit.TableTest; class DDTraceIdTest { - @ParameterizedTest(name = "convert 64-bit ids from/to long {1} and check strings") - @MethodSource("convert64BitIdsFromToLongAndCheckStringsArguments") + @TableTest({ + "scenario | longId | expectedString | expectedHex ", + "zero | 0 | '0' | '00000000000000000000000000000000'", + "one | 1 | '1' | '00000000000000000000000000000001'", + "minus one | -1 | '18446744073709551615'| '0000000000000000ffffffffffffffff'", + "long max | 9223372036854775807 | '9223372036854775807' | '00000000000000007fffffffffffffff'", + "long min | -9223372036854775808 | '9223372036854775808' | '00000000000000008000000000000000'" + }) + @ParameterizedTest void convert64BitIdsFromToLongAndCheckStrings( - String displayName, - long longId, - DD64bTraceId expectedId, - String expectedString, - String expectedHex) { + long longId, String expectedString, String expectedHex) { DD64bTraceId ddid = DD64bTraceId.from(longId); + DD64bTraceId expectedId = DD64bTraceId.from(expectedString); DDTraceId defaultDdid = DDTraceId.from(longId); assertEquals(expectedId, ddid); @@ -33,74 +34,54 @@ void convert64BitIdsFromToLongAndCheckStrings( assertEquals(expectedHex, ddid.toHexString()); } - static Stream convert64BitIdsFromToLongAndCheckStringsArguments() { - return Stream.of( - Arguments.of("zero", 0L, DD64bTraceId.ZERO, "0", repeat("0", 32)), - Arguments.of("one", 1L, DD64bTraceId.ONE, "1", repeat("0", 31) + "1"), - Arguments.of( - "minus one", - -1L, - DD64bTraceId.MAX, - "18446744073709551615", - repeat("0", 16) + repeat("f", 16)), - Arguments.of( - "long max", - Long.MAX_VALUE, - DD64bTraceId.from(Long.MAX_VALUE), - "9223372036854775807", - repeat("0", 16) + "7" + repeat("f", 15)), - Arguments.of( - "long min", - Long.MIN_VALUE, - DD64bTraceId.from(Long.MIN_VALUE), - "9223372036854775808", - repeat("0", 16) + "8" + repeat("0", 15))); - } - - @ParameterizedTest(name = "convert 64-bit ids from/to String representation: {1}") - @MethodSource("convert64BitIdsFromToStringRepresentationArguments") - void convert64BitIdsFromToStringRepresentation( - String displayName, String stringId, DD64bTraceId expectedId) { + @TableTest({ + "scenario | stringId | expectedLongId ", + "zero | '0' | 0 ", + "one | '1' | 1 ", + "max | '18446744073709551615' | -1 ", + "long max | '9223372036854775807' | 9223372036854775807 ", + "long max plus one | '9223372036854775808' | -9223372036854775808" + }) + @ParameterizedTest + void convert64BitIdsFromToStringRepresentation(String stringId, long expectedLongId) { DD64bTraceId ddid = DD64bTraceId.from(stringId); - assertEquals(expectedId, ddid); + assertEquals(DD64bTraceId.from(expectedLongId), ddid); + assertEquals(expectedLongId, ddid.toLong()); assertEquals(stringId, ddid.toString()); } - static Stream convert64BitIdsFromToStringRepresentationArguments() { - return Stream.of( - Arguments.of("zero", "0", DD64bTraceId.ZERO), - Arguments.of("one", "1", DD64bTraceId.ONE), - Arguments.of("max", "18446744073709551615", DD64bTraceId.MAX), - Arguments.of("long max", String.valueOf(Long.MAX_VALUE), DD64bTraceId.from(Long.MAX_VALUE)), - Arguments.of( - "long max plus one", - BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).toString(), - DD64bTraceId.from(Long.MIN_VALUE))); - } - - @ParameterizedTest(name = "fail parsing illegal 64-bit id String representation: {0}") - @MethodSource("failParsingIllegal64BitIdStringRepresentationArguments") + @TableTest({ + "scenario | stringId ", + "null | ", + "empty | '' ", + "negative one | '-1' ", + "too large | '18446744073709551616'", + "too large variant | '18446744073709551625'", + "too large long | '184467440737095516150'", + "contains alpha first | '18446744073709551a1' ", + "contains alpha last | '184467440737095511a' " + }) + @ParameterizedTest void failParsingIllegal64BitIdStringRepresentation(String stringId) { assertThrows(NumberFormatException.class, () -> DD64bTraceId.from(stringId)); } - static Stream failParsingIllegal64BitIdStringRepresentationArguments() { - return Stream.of( - Arguments.of((Object) null), - Arguments.of(""), - Arguments.of("-1"), - Arguments.of("18446744073709551616"), - Arguments.of("18446744073709551625"), - Arguments.of("184467440737095516150"), - Arguments.of("18446744073709551a1"), - Arguments.of("184467440737095511a")); - } - - @ParameterizedTest(name = "convert 64-bit ids from/to hex String representation: {0}") - @MethodSource("convert64BitIdsFromToHexStringRepresentationArguments") - void convert64BitIdsFromToHexStringRepresentation(String hexId, DD64bTraceId expectedId) { + @TableTest({ + "scenario | hexId | expectedLongId ", + "zero | '0' | 0 ", + "one | '1' | 1 ", + "max | 'ffffffffffffffff' | -1 ", + "long max | '7fffffffffffffff' | 9223372036854775807 ", + "long min | '8000000000000000' | -9223372036854775808", + "long min with leading zeros | '00008000000000000000' | -9223372036854775808", + "cafebabe | 'cafebabe' | 3405691582 ", + "fifteen hex digits | '123456789abcdef' | 81985529216486895 " + }) + @ParameterizedTest + void convert64BitIdsFromToHexStringRepresentation(String hexId, long expectedLongId) { DD64bTraceId ddid = DD64bTraceId.fromHex(hexId); + DD64bTraceId expectedId = DD64bTraceId.from(expectedLongId); String padded16 = hexId.length() <= 16 ? leftPadWithZeros(hexId, 16) : hexId.substring(hexId.length() - 16); String padded32 = leftPadWithZeros(hexId, 32); @@ -111,38 +92,44 @@ void convert64BitIdsFromToHexStringRepresentation(String hexId, DD64bTraceId exp assertEquals(padded32, ddid.toHexStringPadded(32)); } - static Stream convert64BitIdsFromToHexStringRepresentationArguments() { - return Stream.of( - Arguments.of("0", DD64bTraceId.ZERO), - Arguments.of("1", DD64bTraceId.ONE), - Arguments.of(repeat("f", 16), DD64bTraceId.MAX), - Arguments.of("7" + repeat("f", 15), DD64bTraceId.from(Long.MAX_VALUE)), - Arguments.of("8" + repeat("0", 15), DD64bTraceId.from(Long.MIN_VALUE)), - Arguments.of(repeat("0", 4) + "8" + repeat("0", 15), DD64bTraceId.from(Long.MIN_VALUE)), - Arguments.of("cafebabe", DD64bTraceId.from(3405691582L)), - Arguments.of("123456789abcdef", DD64bTraceId.from(81985529216486895L))); - } - - @ParameterizedTest(name = "fail parsing illegal 64-bit hexadecimal String representation: {0}") - @MethodSource("failParsingIllegal64BitHexadecimalStringRepresentationArguments") + @TableTest({ + "scenario | hexId ", + "null | ", + "empty | '' ", + "negative one | '-1' ", + "too long | '10000000000000000'", + "invalid middle | 'ffffffffffffffzf' ", + "invalid tail | 'fffffffffffffffz' " + }) + @ParameterizedTest void failParsingIllegal64BitHexadecimalStringRepresentation(String hexId) { assertThrows(NumberFormatException.class, () -> DD64bTraceId.fromHex(hexId)); } - static Stream failParsingIllegal64BitHexadecimalStringRepresentationArguments() { - return Stream.of( - Arguments.of((Object) null), - Arguments.of(""), - Arguments.of("-1"), - Arguments.of("1" + repeat("0", 16)), - Arguments.of(repeat("f", 14) + "zf"), - Arguments.of(repeat("f", 15) + "z")); - } - - @ParameterizedTest(name = "convert 128-bit ids from/to hexadecimal String representation {3}") - @MethodSource("convert128BitIdsFromToHexadecimalStringRepresentationArguments") + @TableTest({ + "scenario | highOrderBits | lowOrderBits | hexId ", + "both long min | -9223372036854775808 | -9223372036854775808 | '80000000000000008000000000000000'", + "high long min low one | -9223372036854775808 | 1 | '80000000000000000000000000000001'", + "high long min low long max | -9223372036854775808 | 9223372036854775807 | '80000000000000007fffffffffffffff'", + "high one low long min | 1 | -9223372036854775808 | '00000000000000018000000000000000'", + "high one low one | 1 | 1 | '00000000000000010000000000000001'", + "high one low long max | 1 | 9223372036854775807 | '00000000000000017fffffffffffffff'", + "high long max low long min | 9223372036854775807 | -9223372036854775808 | '7fffffffffffffff8000000000000000'", + "high long max low one | 9223372036854775807 | 1 | '7fffffffffffffff0000000000000001'", + "high long max low long max | 9223372036854775807 | 9223372036854775807 | '7fffffffffffffff7fffffffffffffff'", + "all zeros length one | 0 | 0 | '0' ", + "all zeros length sixteen | 0 | 0 | '0000000000000000' ", + "all zeros length seventeen | 0 | 0 | '00000000000000000' ", + "all zeros length thirty-two | 0 | 0 | '00000000000000000000000000000000'", + "low fifteen | 0 | 15 | 'f' ", + "low minus one | 0 | -1 | 'ffffffffffffffff' ", + "high fifteen low minus one | 15 | -1 | 'fffffffffffffffff' ", + "all f | -1 | -1 | 'ffffffffffffffffffffffffffffffff'", + "hex literal | 1311768467463790320 | 1311768467463790320 | '123456789abcdef0123456789abcdef0'" + }) + @ParameterizedTest void convert128BitIdsFromToHexadecimalStringRepresentation( - String displayName, long highOrderBits, long lowOrderBits, String hexId) { + long highOrderBits, long lowOrderBits, String hexId) { DDTraceId parsedId = DD128bTraceId.fromHex(hexId); DDTraceId id = DD128bTraceId.from(highOrderBits, lowOrderBits); String paddedHexId = leftPadWithZeros(hexId, 32); @@ -156,110 +143,43 @@ void convert128BitIdsFromToHexadecimalStringRepresentation( assertEquals(Long.toUnsignedString(lowOrderBits), parsedId.toString()); } - static Stream convert128BitIdsFromToHexadecimalStringRepresentationArguments() { - return Stream.of( - Arguments.of( - "both long min", - Long.MIN_VALUE, - Long.MIN_VALUE, - "8" + repeat("0", 15) + "8" + repeat("0", 15)), - Arguments.of( - "high long min low one", - Long.MIN_VALUE, - 1L, - "8" + repeat("0", 15) + repeat("0", 15) + "1"), - Arguments.of( - "high long min low long max", - Long.MIN_VALUE, - Long.MAX_VALUE, - "8" + repeat("0", 15) + "7" + repeat("f", 15)), - Arguments.of( - "high one low long min", - 1L, - Long.MIN_VALUE, - repeat("0", 15) + "1" + "8" + repeat("0", 15)), - Arguments.of("high one low one", 1L, 1L, repeat("0", 15) + "1" + repeat("0", 15) + "1"), - Arguments.of( - "high one low long max", - 1L, - Long.MAX_VALUE, - repeat("0", 15) + "1" + "7" + repeat("f", 15)), - Arguments.of( - "high long max low long min", - Long.MAX_VALUE, - Long.MIN_VALUE, - "7" + repeat("f", 15) + "8" + repeat("0", 15)), - Arguments.of( - "high long max low one", - Long.MAX_VALUE, - 1L, - "7" + repeat("f", 15) + repeat("0", 15) + "1"), - Arguments.of( - "high long max low long max", - Long.MAX_VALUE, - Long.MAX_VALUE, - "7" + repeat("f", 15) + "7" + repeat("f", 15)), - Arguments.of("all zeros length one", 0L, 0L, repeat("0", 1)), - Arguments.of("all zeros length sixteen", 0L, 0L, repeat("0", 16)), - Arguments.of("all zeros length seventeen", 0L, 0L, repeat("0", 17)), - Arguments.of("all zeros length thirty-two", 0L, 0L, repeat("0", 32)), - Arguments.of("low fifteen", 0L, 15L, repeat("f", 1)), - Arguments.of("low minus one", 0L, -1L, repeat("f", 16)), - Arguments.of("high fifteen low minus one", 15L, -1L, repeat("f", 17)), - Arguments.of("all f", -1L, -1L, repeat("f", 32)), - Arguments.of( - "hex literal", - 1311768467463790320L, - 1311768467463790320L, - "123456789abcdef0123456789abcdef0")); - } - - @ParameterizedTest( - name = "fail parsing illegal 128-bit id hexadecimal String representation: {0}") - @MethodSource("failParsingIllegal128BitIdHexadecimalStringRepresentationArguments") + @TableTest({ + "scenario | hexId ", + "null | ", + "empty | '' ", + "negative one | '-1' ", + "negative A | '-A' ", + "too long | '111111111111111111111111111111111' ", + "upper case allowed? | '123ABC' ", + "invalid character | '123abcg' " + }) + @ParameterizedTest void failParsingIllegal128BitIdHexadecimalStringRepresentation(String hexId) { assertThrows(NumberFormatException.class, () -> DD128bTraceId.fromHex(hexId)); } - static Stream failParsingIllegal128BitIdHexadecimalStringRepresentationArguments() { - return Stream.of( - Arguments.of((Object) null), - Arguments.of(""), - Arguments.of("-1"), - Arguments.of("-A"), - Arguments.of(repeat("1", 33)), - Arguments.of("123ABC"), - Arguments.of("123abcg")); - } - - @ParameterizedTest( - name = - "fail parsing illegal 128-bit id hexadecimal String representation from partial String: {1}") - @MethodSource( - "failParsingIllegal128BitIdHexadecimalStringRepresentationFromPartialStringArguments") + @TableTest({ + "scenario | hexId | start | length | lowerCaseOnly", + "null string | | 0 | 0 | true ", + "empty string | '' | 0 | 0 | true ", + "out of bound length | '123456789abcdef0' | 0 | 17 | true ", + "out of bound end | '123456789abcdef0' | 7 | 10 | true ", + "out of bound start | '123456789abcdef0' | 17 | 0 | true ", + "invalid minus one | '-1' | 0 | 1 | true ", + "invalid minus a | '-a' | 0 | 1 | true ", + "invalid character | '123abcg' | 0 | 7 | true ", + "invalid upper case A | 'A' | 0 | 1 | true ", + "invalid upper case | '123ABC' | 0 | 6 | true ", + "too long | '111111111111111111111111111111111' | 0 | 33 | true" + }) + @ParameterizedTest void failParsingIllegal128BitIdHexadecimalStringRepresentationFromPartialString( - String displayName, String hexId, int start, int length, boolean lowerCaseOnly) { + String hexId, int start, int length, boolean lowerCaseOnly) { assertThrows( NumberFormatException.class, () -> DD128bTraceId.fromHex(hexId, start, length, lowerCaseOnly)); } - static Stream - failParsingIllegal128BitIdHexadecimalStringRepresentationFromPartialStringArguments() { - return Stream.of( - Arguments.of("null string", null, 0, 0, true), - Arguments.of("empty string", "", 0, 0, true), - Arguments.of("out of bound length", "123456789abcdef0", 0, 17, true), - Arguments.of("out of bound end", "123456789abcdef0", 7, 10, true), - Arguments.of("out of bound start", "123456789abcdef0", 17, 0, true), - Arguments.of("invalid minus one", "-1", 0, 1, true), - Arguments.of("invalid minus a", "-a", 0, 1, true), - Arguments.of("invalid character", "123abcg", 0, 7, true), - Arguments.of("invalid upper case A", "A", 0, 1, true), - Arguments.of("invalid upper case ABC", "123ABC", 0, 6, true), - Arguments.of("too long", repeat("1", 33), 0, 33, true)); - } - @Test void checkZeroConstantInitialization() { DDTraceId zero = DDTraceId.ZERO; diff --git a/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java b/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java index 2177dcef1d5..bca172c5c5c 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java @@ -12,20 +12,20 @@ import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; -import org.junit.jupiter.params.provider.ValueSource; +import org.tabletest.junit.TableTest; class IdGenerationStrategyTest { - @ParameterizedTest(name = "generate id with {1} and {0} bits") - @CsvSource({ - "false,RANDOM", - "false,SEQUENTIAL", - "false,SECURE_RANDOM", - "true,RANDOM", - "true,SEQUENTIAL", - "true,SECURE_RANDOM" + @TableTest({ + "scenario | traceId128BitGenerationEnabled | strategyName ", + "random-64-bit | false | RANDOM ", + "sequential-64-bit | false | SEQUENTIAL ", + "secure-random-64-bit | false | SECURE_RANDOM", + "random-128-bit | true | RANDOM ", + "sequential-128-bit | true | SEQUENTIAL ", + "secure-random-128-bit | true | SECURE_RANDOM" }) + @ParameterizedTest(name = "generate id with {1} and {0} bits") void generateIdWithStrategyAndBitSize( boolean traceId128BitGenerationEnabled, String strategyName) { IdGenerationStrategy strategy = @@ -52,8 +52,13 @@ void generateIdWithStrategyAndBitSize( } } + @TableTest({ + "scenario | strategyName", + "some-strategy | SOME ", + "unknown-strategy | UNKNOWN ", + "plural-strategies | STRATEGIES " + }) @ParameterizedTest(name = "return null for non existing strategy {0}") - @ValueSource(strings = {"SOME", "UNKNOWN", "STRATEGIES"}) void returnNullForNonExistingStrategy(String strategyName) { assertNull(IdGenerationStrategy.fromName(strategyName)); } diff --git a/dd-trace-api/src/test/java/datadog/trace/api/internal/util/HexStringUtilsTest.java b/dd-trace-api/src/test/java/datadog/trace/api/internal/util/HexStringUtilsTest.java index 53fd9ac485e..f6ae06c716e 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/internal/util/HexStringUtilsTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/internal/util/HexStringUtilsTest.java @@ -3,28 +3,29 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; +import org.tabletest.junit.TableTest; class HexStringUtilsTest { - @ParameterizedTest(name = "test hexadecimal String representations high={0} low={1} size={2}") - @CsvSource({ - "0,0,10", - "0,0,16", - "0,0,20", - "0,0,32", - "0,0,40", - "1,2,10", - "1,2,16", - "1,2,20", - "1,2,32", - "1,2,40", - "6536977903480360123,3270264562721133536,10", - "6536977903480360123,3270264562721133536,16", - "6536977903480360123,3270264562721133536,20", - "6536977903480360123,3270264562721133536,32", - "6536977903480360123,3270264562721133536,40" + @TableTest({ + "scenario | highOrderBits | lowOrderBits | size", + "zero-size-10 | 0 | 0 | 10 ", + "zero-size-16 | 0 | 0 | 16 ", + "zero-size-20 | 0 | 0 | 20 ", + "zero-size-32 | 0 | 0 | 32 ", + "zero-size-40 | 0 | 0 | 40 ", + "one-two-10 | 1 | 2 | 10 ", + "one-two-16 | 1 | 2 | 16 ", + "one-two-20 | 1 | 2 | 20 ", + "one-two-32 | 1 | 2 | 32 ", + "one-two-40 | 1 | 2 | 40 ", + "large-size-10 | 6536977903480360123 | 3270264562721133536 | 10 ", + "large-size-16 | 6536977903480360123 | 3270264562721133536 | 16 ", + "large-size-20 | 6536977903480360123 | 3270264562721133536 | 20 ", + "large-size-32 | 6536977903480360123 | 3270264562721133536 | 32 ", + "large-size-40 | 6536977903480360123 | 3270264562721133536 | 40 " }) + @ParameterizedTest(name = "test hexadecimal String representations high={0} low={1} size={2}") void testHexadecimalStringRepresentations(long highOrderBits, long lowOrderBits, int size) { int highOrderSize = Math.min(16, Math.max(0, size - 16)); int lowOrderSize = Math.min(16, size); From 2f706c9be414db302ef30ccd7d9b09942cd6286e Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Fri, 13 Mar 2026 17:21:02 -0400 Subject: [PATCH 2/4] Fix test formatting and add tabletest to java_deps --- .../SKILL.md | 5 ++-- dd-trace-api/build.gradle.kts | 1 - .../java/datadog/trace/api/DDTraceIdTest.java | 24 +++++++++---------- gradle/java_deps.gradle | 1 + 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md b/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md index ae4008039c5..75fac116dc6 100644 --- a/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md +++ b/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md @@ -12,9 +12,8 @@ Process (do in this order): 5) Run module tests once and verify "BUILD SUCCESSFUL". If failed, inspect JUnit XML report. Dependency: -- If missing, add: - - Groovy: testImplementation libs.tabletest - - Kotlin: testImplementation(libs.tabletest) +- @TableTest should be in `gradle/java_deps.gradle` as `testImplementation libs.tabletest` where Java modules inherit it via `gradle/java.gradle`. +- As a fallback, add module-specific `testImplementation(libs.tabletest)` or `testImplementation libs.tabletest`. Import: `import org.tabletest.junit.TableTest;` diff --git a/dd-trace-api/build.gradle.kts b/dd-trace-api/build.gradle.kts index c715fb62bdd..bc05a8753a4 100644 --- a/dd-trace-api/build.gradle.kts +++ b/dd-trace-api/build.gradle.kts @@ -75,6 +75,5 @@ dependencies { api(libs.slf4j) testImplementation(libs.guava) testImplementation(libs.bundles.mockito) - testImplementation(libs.tabletest) testImplementation(project(":utils:test-utils")) } diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java index 384084b2077..14febcf7408 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java @@ -159,18 +159,18 @@ void failParsingIllegal128BitIdHexadecimalStringRepresentation(String hexId) { } @TableTest({ - "scenario | hexId | start | length | lowerCaseOnly", - "null string | | 0 | 0 | true ", - "empty string | '' | 0 | 0 | true ", - "out of bound length | '123456789abcdef0' | 0 | 17 | true ", - "out of bound end | '123456789abcdef0' | 7 | 10 | true ", - "out of bound start | '123456789abcdef0' | 17 | 0 | true ", - "invalid minus one | '-1' | 0 | 1 | true ", - "invalid minus a | '-a' | 0 | 1 | true ", - "invalid character | '123abcg' | 0 | 7 | true ", - "invalid upper case A | 'A' | 0 | 1 | true ", - "invalid upper case | '123ABC' | 0 | 6 | true ", - "too long | '111111111111111111111111111111111' | 0 | 33 | true" + "scenario | hexId | start | length | lowerCaseOnly", + "null string | | 0 | 0 | true ", + "empty string | '' | 0 | 0 | true ", + "out of bound length | '123456789abcdef0' | 0 | 17 | true ", + "out of bound end | '123456789abcdef0' | 7 | 10 | true ", + "out of bound start | '123456789abcdef0' | 17 | 0 | true ", + "invalid minus one | '-1' | 0 | 1 | true ", + "invalid minus a | '-a' | 0 | 1 | true ", + "invalid character | '123abcg' | 0 | 7 | true ", + "invalid upper case A | 'A' | 0 | 1 | true ", + "invalid upper case | '123ABC' | 0 | 6 | true ", + "too long | '111111111111111111111111111111111' | 0 | 33 | true " }) @ParameterizedTest void failParsingIllegal128BitIdHexadecimalStringRepresentationFromPartialString( diff --git a/gradle/java_deps.gradle b/gradle/java_deps.gradle index cb0762bf10c..80c4eda9aa3 100644 --- a/gradle/java_deps.gradle +++ b/gradle/java_deps.gradle @@ -3,6 +3,7 @@ apply plugin: 'groovy' dependencies { testImplementation libs.bundles.spock testImplementation libs.bundles.groovy + testImplementation libs.tabletest testImplementation libs.bundles.test.logging From 93ab93404efdf891f0b0c4c6e6ba696edfe914bc Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Tue, 17 Mar 2026 15:53:56 -0400 Subject: [PATCH 3/4] Address review comments --- .../skills/migrate-groovy-to-java/SKILL.md | 4 - .../SKILL.md | 12 +-- components/json/build.gradle.kts | 4 - .../java/datadog/json/JsonMapperTest.java | 29 ++----- .../java/datadog/trace/api/DDSpanIdTest.java | 81 +++++++++--------- .../java/datadog/trace/api/DDTraceIdTest.java | 83 ++++++++----------- .../trace/api/IdGenerationStrategyTest.java | 8 +- utils/test-utils/build.gradle.kts | 1 + .../test/util/TableTestTypeConverters.java | 29 +++++++ 9 files changed, 119 insertions(+), 132 deletions(-) create mode 100644 utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java diff --git a/.claude/skills/migrate-groovy-to-java/SKILL.md b/.claude/skills/migrate-groovy-to-java/SKILL.md index d75b8134607..c603bf227b6 100644 --- a/.claude/skills/migrate-groovy-to-java/SKILL.md +++ b/.claude/skills/migrate-groovy-to-java/SKILL.md @@ -32,10 +32,6 @@ When converting Groovy code to Java code, make sure that: - When translating Spock `Mock(...)` usage, use `libs.bundles.mockito` instead of writing manual recording/stub implementations TableTest usage - Dependency, if missing add: - - Groovy: testImplementation libs.tabletest - - Kotlin: testImplementation(libs.tabletest) - Import: `import org.tabletest.junit.TableTest;` JDK 8 rules: diff --git a/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md b/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md index 75fac116dc6..797abfe6fbf 100644 --- a/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md +++ b/.claude/skills/migrate-junit-source-to-tabletest/SKILL.md @@ -11,10 +11,6 @@ Process (do in this order): 4) Write each modified file once in full using Write (no incremental per-test edits). 5) Run module tests once and verify "BUILD SUCCESSFUL". If failed, inspect JUnit XML report. -Dependency: -- @TableTest should be in `gradle/java_deps.gradle` as `testImplementation libs.tabletest` where Java modules inherit it via `gradle/java.gradle`. -- As a fallback, add module-specific `testImplementation(libs.tabletest)` or `testImplementation libs.tabletest`. - Import: `import org.tabletest.junit.TableTest;` JDK 8 rules: @@ -41,7 +37,8 @@ A) @CsvSource - If delimiter is ',' (default): replace ',' with '|' in rows. B) @ValueSource -- Convert to @TableTest with header from parameter name. +- Keep single-parameter tests on `@ValueSource` (and `@NullSource` when null cases are needed). +- Otherwise convert to @TableTest with header from parameter name. - Each value becomes one row. - Add "scenario" column using common sense for name. @@ -59,6 +56,11 @@ C) @MethodSource (convert only if values are representable as strings) - '' = empty string. - For String params that start with '[' or '{', quote to avoid collection parsing (prefer '[]'/'{}'). +D) @TypeConverter +- Use `@TypeConverter` for symbolic constants used by migrated table rows (e.g. `Long.MAX_VALUE`, `DDSpanId.MAX`). +- Prefer explicit one-case-one-return mappings. +- Prefer shared converter utilities (e.g. in `utils/test-utils`) when reuse across modules is likely. + Scenario handling: - If MethodSource includes a leading description string OR @ParameterizedTest(name=...) uses {0}, convert that to a scenario column and remove that parameter from method signature. diff --git a/components/json/build.gradle.kts b/components/json/build.gradle.kts index fda68a66ba8..ce67f74ff29 100644 --- a/components/json/build.gradle.kts +++ b/components/json/build.gradle.kts @@ -7,7 +7,3 @@ apply(from = "$rootDir/gradle/java.gradle") jmh { jmhVersion = libs.versions.jmh.get() } - -dependencies { - testImplementation(libs.tabletest) -} diff --git a/components/json/src/test/java/datadog/json/JsonMapperTest.java b/components/json/src/test/java/datadog/json/JsonMapperTest.java index d6cacd83b25..ffe973e52ca 100644 --- a/components/json/src/test/java/datadog/json/JsonMapperTest.java +++ b/components/json/src/test/java/datadog/json/JsonMapperTest.java @@ -17,6 +17,8 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.Scenario; import org.tabletest.junit.TableTest; @@ -77,28 +79,16 @@ static Stream testMappingToJsonObjectArguments() { "{\"key1\":null,\"key2\":\"bar\",\"key3\":3,\"key4\":3456789123,\"key5\":3.142,\"key6\":3.141592653589793,\"key7\":true,\"key8\":\"toString\"}")); } - @TableTest({ - "Scenario | Json ", - "null | ", - "null string | 'null'", - "empty string | '' ", - "empty object | '{}' " - }) @ParameterizedTest(name = "test mapping to Map from empty JSON object: {0}") + @NullSource + @ValueSource(strings = {"null", "", "{}"}) void testMappingToMapFromEmptyJsonObject(String json) throws IOException { Map parsed = JsonMapper.fromJsonToMap(json); assertEquals(emptyMap(), parsed); } - // temporary disable spotless, will open issue to fix this. - // spotless:off - @TableTest({ - "Scenario | Json ", - "integer | 1 ", - "array | [1, 2]" - }) - // spotless:on @ParameterizedTest(name = "test mapping to Map from non-object JSON: {0}") + @ValueSource(strings = {"1", "[1, 2]"}) void testMappingToMapFromNonObjectJson(String json) { assertThrows(IOException.class, () -> JsonMapper.fromJsonToMap(json)); } @@ -138,14 +128,9 @@ void testMappingArrayToJsonArray(String ignoredScenario, String[] input, String assertArrayEquals(input != null ? input : new String[] {}, parsed); } - @TableTest({ - "Scenario | Json ", - "null | ", - "null string | 'null'", - "empty string | '' ", - "empty array | '[]' " - }) @ParameterizedTest(name = "test mapping to List from empty JSON object: {0}") + @NullSource + @ValueSource(strings = {"null", "", "[]"}) void testMappingToListFromEmptyJsonObject(String json) throws IOException { List parsed = JsonMapper.fromJsonToList(json); assertEquals(emptyList(), parsed); diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java index 39f2ccbd160..c70f818a889 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java @@ -7,20 +7,25 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import datadog.trace.test.util.TableTestTypeConverters; import java.util.HashSet; import java.util.Set; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.TableTest; +import org.tabletest.junit.TypeConverterSources; +@TypeConverterSources(TableTestTypeConverters.class) class DDSpanIdTest { @TableTest({ "scenario | stringId | expectedId ", "zero | '0' | 0 ", "one | '1' | 1 ", - "max | '18446744073709551615' | -1 ", - "long max | '9223372036854775807' | 9223372036854775807 ", - "long max plus one | '9223372036854775808' | -9223372036854775808" + "max | '18446744073709551615' | DDSpanId.MAX ", + "long max | '9223372036854775807' | Long.MAX_VALUE ", + "long max plus one | '9223372036854775808' | Long.MIN_VALUE " }) @ParameterizedTest void convertIdsFromToString(String stringId, long expectedId) { @@ -30,18 +35,18 @@ void convertIdsFromToString(String stringId, long expectedId) { assertEquals(stringId, DDSpanId.toString(ddid)); } - @TableTest({ - "scenario | stringId ", - "null | ", - "empty | '' ", - "negative one | '-1' ", - "too large | '18446744073709551616'", - "too large variant | '18446744073709551625'", - "too large long | '184467440737095516150'", - "contains alpha first | '18446744073709551a1' ", - "contains alpha last | '184467440737095511a' " - }) @ParameterizedTest + @NullSource + @ValueSource( + strings = { + "", + "-1", + "18446744073709551616", + "18446744073709551625", + "184467440737095516150", + "18446744073709551a1", + "184467440737095511a" + }) void failOnIllegalString(String stringId) { assertThrows(NumberFormatException.class, () -> DDSpanId.from(stringId)); } @@ -50,10 +55,10 @@ void failOnIllegalString(String stringId) { "scenario | hexId | expectedId ", "zero | '0' | 0 ", "one | '1' | 1 ", - "max | 'ffffffffffffffff' | -1 ", - "long max | '7fffffffffffffff' | 9223372036854775807 ", - "long min | '8000000000000000' | -9223372036854775808", - "long min with leading zeros | '00008000000000000000' | -9223372036854775808", + "max | 'ffffffffffffffff' | DDSpanId.MAX ", + "long max | '7fffffffffffffff' | Long.MAX_VALUE ", + "long min | '8000000000000000' | Long.MIN_VALUE ", + "long min with leading zeros | '00008000000000000000' | Long.MIN_VALUE ", "cafebabe | 'cafebabe' | 3405691582 ", "fifteen hex digits | '123456789abcdef' | 81985529216486895 " }) @@ -73,17 +78,17 @@ void convertIdsFromToHexString(String hexId, long expectedId) { } @TableTest({ - "scenario | hexId | start | length | lowerCaseOnly | expectedId", - "null input | | 1 | 1 | false | ", - "empty input | '' | 1 | 1 | false | ", - "negative start | '00' | -1 | 1 | false | ", - "zero length | '00' | 0 | 0 | false | ", - "single zero at index 0 | '00' | 0 | 1 | false | 0 ", - "single zero at index 1 | '00' | 1 | 1 | false | 0 ", - "single zero at index 1 duplicate | '00' | 1 | 1 | false | 0 ", - "max lower-case | 'ffffffffffffffff' | 0 | 16 | true | -1 ", - "upper-case rejected when lower-case only| 'ffffffffffffFfff' | 0 | 16 | true | ", - "upper-case accepted when lower disabled | 'ffffffffffffFfff' | 0 | 16 | false | -1 " + "scenario | hexId | start | length | lowerCaseOnly | expectedId ", + "null input | | 1 | 1 | false | ", + "empty input | '' | 1 | 1 | false | ", + "negative start | '00' | -1 | 1 | false | ", + "zero length | '00' | 0 | 0 | false | ", + "single zero at index 0 | '00' | 0 | 1 | false | DDSpanId.ZERO", + "single zero at index 1 | '00' | 1 | 1 | false | DDSpanId.ZERO", + "single zero at index 1 duplicate | '00' | 1 | 1 | false | DDSpanId.ZERO", + "max lower-case | 'ffffffffffffffff' | 0 | 16 | true | DDSpanId.MAX ", + "upper-case rejected when lower-case only| 'ffffffffffffFfff' | 0 | 16 | true | ", + "upper-case accepted when lower disabled | 'ffffffffffffFfff' | 0 | 16 | false | DDSpanId.MAX " }) @ParameterizedTest void convertIdsFromPartOfHexString( @@ -102,27 +107,15 @@ void convertIdsFromPartOfHexString( } } - @TableTest({ - "scenario | hexId ", - "null | ", - "empty | '' ", - "negative one | '-1' ", - "too long | '10000000000000000'", - "invalid middle | 'ffffffffffffffzf' ", - "invalid tail | 'fffffffffffffffz' " - }) @ParameterizedTest + @NullSource + @ValueSource(strings = {"", "-1", "10000000000000000", "ffffffffffffffzf", "fffffffffffffffz"}) void failOnIllegalHexString(String hexId) { assertThrows(NumberFormatException.class, () -> DDSpanId.fromHex(hexId)); } - @TableTest({ - "scenario | strategyName ", - "random | RANDOM ", - "sequential | SEQUENTIAL ", - "secure random | SECURE_RANDOM" - }) @ParameterizedTest + @ValueSource(strings = {"RANDOM", "SEQUENTIAL", "SECURE_RANDOM"}) void generateIdWithStrategy(String strategyName) { IdGenerationStrategy strategy = IdGenerationStrategy.fromName(strategyName); Set checked = new HashSet(); diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java index 14febcf7408..c8958bfff22 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java @@ -5,19 +5,24 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; +import datadog.trace.test.util.TableTestTypeConverters; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.TableTest; +import org.tabletest.junit.TypeConverterSources; +@TypeConverterSources(TableTestTypeConverters.class) class DDTraceIdTest { @TableTest({ - "scenario | longId | expectedString | expectedHex ", + "scenario | longId | expectedString | expectedHex ", "zero | 0 | '0' | '00000000000000000000000000000000'", "one | 1 | '1' | '00000000000000000000000000000001'", "minus one | -1 | '18446744073709551615'| '0000000000000000ffffffffffffffff'", - "long max | 9223372036854775807 | '9223372036854775807' | '00000000000000007fffffffffffffff'", - "long min | -9223372036854775808 | '9223372036854775808' | '00000000000000008000000000000000'" + "long max | Long.MAX_VALUE | '9223372036854775807' | '00000000000000007fffffffffffffff'", + "long min | Long.MIN_VALUE | '9223372036854775808' | '00000000000000008000000000000000'" }) @ParameterizedTest void convert64BitIdsFromToLongAndCheckStrings( @@ -39,30 +44,29 @@ void convert64BitIdsFromToLongAndCheckStrings( "zero | '0' | 0 ", "one | '1' | 1 ", "max | '18446744073709551615' | -1 ", - "long max | '9223372036854775807' | 9223372036854775807 ", - "long max plus one | '9223372036854775808' | -9223372036854775808" + "long max | '9223372036854775807' | Long.MAX_VALUE ", + "long max plus one | '9223372036854775808' | Long.MIN_VALUE " }) @ParameterizedTest void convert64BitIdsFromToStringRepresentation(String stringId, long expectedLongId) { DD64bTraceId ddid = DD64bTraceId.from(stringId); assertEquals(DD64bTraceId.from(expectedLongId), ddid); - assertEquals(expectedLongId, ddid.toLong()); assertEquals(stringId, ddid.toString()); } - @TableTest({ - "scenario | stringId ", - "null | ", - "empty | '' ", - "negative one | '-1' ", - "too large | '18446744073709551616'", - "too large variant | '18446744073709551625'", - "too large long | '184467440737095516150'", - "contains alpha first | '18446744073709551a1' ", - "contains alpha last | '184467440737095511a' " - }) @ParameterizedTest + @NullSource + @ValueSource( + strings = { + "", + "-1", + "18446744073709551616", + "18446744073709551625", + "184467440737095516150", + "18446744073709551a1", + "184467440737095511a" + }) void failParsingIllegal64BitIdStringRepresentation(String stringId) { assertThrows(NumberFormatException.class, () -> DD64bTraceId.from(stringId)); } @@ -72,9 +76,9 @@ void failParsingIllegal64BitIdStringRepresentation(String stringId) { "zero | '0' | 0 ", "one | '1' | 1 ", "max | 'ffffffffffffffff' | -1 ", - "long max | '7fffffffffffffff' | 9223372036854775807 ", - "long min | '8000000000000000' | -9223372036854775808", - "long min with leading zeros | '00008000000000000000' | -9223372036854775808", + "long max | '7fffffffffffffff' | Long.MAX_VALUE ", + "long min | '8000000000000000' | Long.MIN_VALUE ", + "long min with leading zeros | '00008000000000000000' | Long.MIN_VALUE ", "cafebabe | 'cafebabe' | 3405691582 ", "fifteen hex digits | '123456789abcdef' | 81985529216486895 " }) @@ -92,31 +96,24 @@ void convert64BitIdsFromToHexStringRepresentation(String hexId, long expectedLon assertEquals(padded32, ddid.toHexStringPadded(32)); } - @TableTest({ - "scenario | hexId ", - "null | ", - "empty | '' ", - "negative one | '-1' ", - "too long | '10000000000000000'", - "invalid middle | 'ffffffffffffffzf' ", - "invalid tail | 'fffffffffffffffz' " - }) @ParameterizedTest + @NullSource + @ValueSource(strings = {"", "-1", "10000000000000000", "ffffffffffffffzf", "fffffffffffffffz"}) void failParsingIllegal64BitHexadecimalStringRepresentation(String hexId) { assertThrows(NumberFormatException.class, () -> DD64bTraceId.fromHex(hexId)); } @TableTest({ "scenario | highOrderBits | lowOrderBits | hexId ", - "both long min | -9223372036854775808 | -9223372036854775808 | '80000000000000008000000000000000'", - "high long min low one | -9223372036854775808 | 1 | '80000000000000000000000000000001'", - "high long min low long max | -9223372036854775808 | 9223372036854775807 | '80000000000000007fffffffffffffff'", - "high one low long min | 1 | -9223372036854775808 | '00000000000000018000000000000000'", + "both long min | Long.MIN_VALUE | Long.MIN_VALUE | '80000000000000008000000000000000'", + "high long min low one | Long.MIN_VALUE | 1 | '80000000000000000000000000000001'", + "high long min low long max | Long.MIN_VALUE | Long.MAX_VALUE | '80000000000000007fffffffffffffff'", + "high one low long min | 1 | Long.MIN_VALUE | '00000000000000018000000000000000'", "high one low one | 1 | 1 | '00000000000000010000000000000001'", - "high one low long max | 1 | 9223372036854775807 | '00000000000000017fffffffffffffff'", - "high long max low long min | 9223372036854775807 | -9223372036854775808 | '7fffffffffffffff8000000000000000'", - "high long max low one | 9223372036854775807 | 1 | '7fffffffffffffff0000000000000001'", - "high long max low long max | 9223372036854775807 | 9223372036854775807 | '7fffffffffffffff7fffffffffffffff'", + "high one low long max | 1 | Long.MAX_VALUE | '00000000000000017fffffffffffffff'", + "high long max low long min | Long.MAX_VALUE | Long.MIN_VALUE | '7fffffffffffffff8000000000000000'", + "high long max low one | Long.MAX_VALUE | 1 | '7fffffffffffffff0000000000000001'", + "high long max low long max | Long.MAX_VALUE | Long.MAX_VALUE | '7fffffffffffffff7fffffffffffffff'", "all zeros length one | 0 | 0 | '0' ", "all zeros length sixteen | 0 | 0 | '0000000000000000' ", "all zeros length seventeen | 0 | 0 | '00000000000000000' ", @@ -143,17 +140,9 @@ void convert128BitIdsFromToHexadecimalStringRepresentation( assertEquals(Long.toUnsignedString(lowOrderBits), parsedId.toString()); } - @TableTest({ - "scenario | hexId ", - "null | ", - "empty | '' ", - "negative one | '-1' ", - "negative A | '-A' ", - "too long | '111111111111111111111111111111111' ", - "upper case allowed? | '123ABC' ", - "invalid character | '123abcg' " - }) @ParameterizedTest + @NullSource + @ValueSource(strings = {"", "-1", "-A", "111111111111111111111111111111111", "123ABC", "123abcg"}) void failParsingIllegal128BitIdHexadecimalStringRepresentation(String hexId) { assertThrows(NumberFormatException.class, () -> DD128bTraceId.fromHex(hexId)); } diff --git a/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java b/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java index bca172c5c5c..b9b855d0849 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java @@ -12,6 +12,7 @@ import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.TableTest; class IdGenerationStrategyTest { @@ -52,13 +53,8 @@ void generateIdWithStrategyAndBitSize( } } - @TableTest({ - "scenario | strategyName", - "some-strategy | SOME ", - "unknown-strategy | UNKNOWN ", - "plural-strategies | STRATEGIES " - }) @ParameterizedTest(name = "return null for non existing strategy {0}") + @ValueSource(strings = {"SOME", "UNKNOWN", "STRATEGIES"}) void returnNullForNonExistingStrategy(String strategyName) { assertNull(IdGenerationStrategy.fromName(strategyName)); } diff --git a/utils/test-utils/build.gradle.kts b/utils/test-utils/build.gradle.kts index 2e9f00058c3..1f975c4ad45 100644 --- a/utils/test-utils/build.gradle.kts +++ b/utils/test-utils/build.gradle.kts @@ -12,6 +12,7 @@ dependencies { api(group = "commons-fileupload", name = "commons-fileupload", version = "1.5") compileOnly(libs.junit.jupiter) + compileOnly(libs.tabletest) compileOnly(libs.logback.core) compileOnly(libs.logback.classic) diff --git a/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java b/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java new file mode 100644 index 00000000000..cdf2a00e426 --- /dev/null +++ b/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java @@ -0,0 +1,29 @@ +package datadog.trace.test.util; + +import org.tabletest.junit.TypeConverter; + +/** Shared converters for TableTest numeric cells, including symbolic constants. */ +public final class TableTestTypeConverters { + + private TableTestTypeConverters() {} + + @TypeConverter + public static long toLong(String value) { + if (value == null) { + throw new IllegalArgumentException("Value cannot be null"); + } + String token = value.trim(); + switch (token) { + case "Long.MAX_VALUE": + return Long.MAX_VALUE; + case "Long.MIN_VALUE": + return Long.MIN_VALUE; + case "DDSpanId.MAX": + return -1L; + case "DDSpanId.ZERO": + return 0L; + default: + return Long.decode(token); + } + } +} From d4e8ad83a681ce8a943fad8015f6605c7f728aea Mon Sep 17 00:00:00 2001 From: Sarah Chen Date: Tue, 17 Mar 2026 16:40:59 -0400 Subject: [PATCH 4/4] Add params and re-org converters --- .../java/datadog/trace/api/DDSpanIdTest.java | 17 +++--- .../api/DDTraceApiTableTestConverters.java | 51 ++++++++++++++++ .../java/datadog/trace/api/DDTraceIdTest.java | 61 ++++++++++--------- .../test/util/TableTestTypeConverters.java | 6 +- 4 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 dd-trace-api/src/test/java/datadog/trace/api/DDTraceApiTableTestConverters.java diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java index c70f818a889..38d30987c91 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDSpanIdTest.java @@ -7,7 +7,6 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import datadog.trace.test.util.TableTestTypeConverters; import java.util.HashSet; import java.util.Set; import org.junit.jupiter.params.ParameterizedTest; @@ -16,7 +15,7 @@ import org.tabletest.junit.TableTest; import org.tabletest.junit.TypeConverterSources; -@TypeConverterSources(TableTestTypeConverters.class) +@TypeConverterSources(DDTraceApiTableTestConverters.class) class DDSpanIdTest { @TableTest({ @@ -27,7 +26,7 @@ class DDSpanIdTest { "long max | '9223372036854775807' | Long.MAX_VALUE ", "long max plus one | '9223372036854775808' | Long.MIN_VALUE " }) - @ParameterizedTest + @ParameterizedTest(name = "convert ids from/to String [{index}]") void convertIdsFromToString(String stringId, long expectedId) { long ddid = DDSpanId.from(stringId); @@ -35,7 +34,7 @@ void convertIdsFromToString(String stringId, long expectedId) { assertEquals(stringId, DDSpanId.toString(ddid)); } - @ParameterizedTest + @ParameterizedTest(name = "fail on illegal String [{index}]") @NullSource @ValueSource( strings = { @@ -59,10 +58,10 @@ void failOnIllegalString(String stringId) { "long max | '7fffffffffffffff' | Long.MAX_VALUE ", "long min | '8000000000000000' | Long.MIN_VALUE ", "long min with leading zeros | '00008000000000000000' | Long.MIN_VALUE ", - "cafebabe | 'cafebabe' | 3405691582 ", + "hex sample | 'cafebabe' | 3405691582 ", "fifteen hex digits | '123456789abcdef' | 81985529216486895 " }) - @ParameterizedTest + @ParameterizedTest(name = "convert ids from/to hex String [{index}]") void convertIdsFromToHexString(String hexId, long expectedId) { long ddid = DDSpanId.fromHex(hexId); String padded16 = @@ -90,7 +89,7 @@ void convertIdsFromToHexString(String hexId, long expectedId) { "upper-case rejected when lower-case only| 'ffffffffffffFfff' | 0 | 16 | true | ", "upper-case accepted when lower disabled | 'ffffffffffffFfff' | 0 | 16 | false | DDSpanId.MAX " }) - @ParameterizedTest + @ParameterizedTest(name = "convert ids from part of hex String [{index}]") void convertIdsFromPartOfHexString( String hexId, int start, int length, boolean lowerCaseOnly, Long expectedId) { Long parsedId = null; @@ -107,14 +106,14 @@ void convertIdsFromPartOfHexString( } } - @ParameterizedTest + @ParameterizedTest(name = "fail on illegal hex String [{index}]") @NullSource @ValueSource(strings = {"", "-1", "10000000000000000", "ffffffffffffffzf", "fffffffffffffffz"}) void failOnIllegalHexString(String hexId) { assertThrows(NumberFormatException.class, () -> DDSpanId.fromHex(hexId)); } - @ParameterizedTest + @ParameterizedTest(name = "generate id with {0}") @ValueSource(strings = {"RANDOM", "SEQUENTIAL", "SECURE_RANDOM"}) void generateIdWithStrategy(String strategyName) { IdGenerationStrategy strategy = IdGenerationStrategy.fromName(strategyName); diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceApiTableTestConverters.java b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceApiTableTestConverters.java new file mode 100644 index 00000000000..e277fe8e2e7 --- /dev/null +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceApiTableTestConverters.java @@ -0,0 +1,51 @@ +package datadog.trace.api; + +import datadog.trace.test.util.TableTestTypeConverters; +import org.tabletest.junit.TypeConverter; + +/** TableTest converters shared by dd-trace-api test classes for unparsable constants. */ +public final class DDTraceApiTableTestConverters { + + private DDTraceApiTableTestConverters() {} + + @TypeConverter + public static long toLong(String value) { + if (value == null) { + throw new IllegalArgumentException("Value cannot be null"); + } + String token = value.trim(); + switch (token) { + case "DDSpanId.MAX": + return DDSpanId.MAX; + case "DDSpanId.ZERO": + return DDSpanId.ZERO; + default: + return TableTestTypeConverters.toLong(token); + } + } + + @TypeConverter + public static DD64bTraceId toDD64bTraceId(String value) { + if (value == null) { + throw new IllegalArgumentException("Value cannot be null"); + } + switch (value.trim()) { + case "DD64bTraceId.ZERO": + return DD64bTraceId.from(0L); + case "DD64bTraceId.ONE": + return DD64bTraceId.from(1L); + case "DD64bTraceId.MAX": + return DD64bTraceId.MAX; + case "DD64bTraceId.LONG_MAX": + return DD64bTraceId.from(Long.MAX_VALUE); + case "DD64bTraceId.LONG_MIN": + return DD64bTraceId.from(Long.MIN_VALUE); + case "DD64bTraceId.CAFEBABE": + return DD64bTraceId.from(3405691582L); + case "DD64bTraceId.HEX": + return DD64bTraceId.from(81985529216486895L); + default: + throw new IllegalArgumentException("Unsupported DD64bTraceId token: " + value); + } + } +} diff --git a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java index c8958bfff22..3dcec4d583b 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/DDTraceIdTest.java @@ -5,7 +5,6 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; -import datadog.trace.test.util.TableTestTypeConverters; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.NullSource; @@ -13,7 +12,7 @@ import org.tabletest.junit.TableTest; import org.tabletest.junit.TypeConverterSources; -@TypeConverterSources(TableTestTypeConverters.class) +@TypeConverterSources(DDTraceApiTableTestConverters.class) class DDTraceIdTest { @TableTest({ @@ -24,7 +23,7 @@ class DDTraceIdTest { "long max | Long.MAX_VALUE | '9223372036854775807' | '00000000000000007fffffffffffffff'", "long min | Long.MIN_VALUE | '9223372036854775808' | '00000000000000008000000000000000'" }) - @ParameterizedTest + @ParameterizedTest(name = "convert 64-bit ids from/to long and check strings [{index}]") void convert64BitIdsFromToLongAndCheckStrings( long longId, String expectedString, String expectedHex) { DD64bTraceId ddid = DD64bTraceId.from(longId); @@ -40,22 +39,22 @@ void convert64BitIdsFromToLongAndCheckStrings( } @TableTest({ - "scenario | stringId | expectedLongId ", - "zero | '0' | 0 ", - "one | '1' | 1 ", - "max | '18446744073709551615' | -1 ", - "long max | '9223372036854775807' | Long.MAX_VALUE ", - "long max plus one | '9223372036854775808' | Long.MIN_VALUE " + "scenario | stringId | expectedId ", + "zero | '0' | DD64bTraceId.ZERO ", + "one | '1' | DD64bTraceId.ONE ", + "max | '18446744073709551615' | DD64bTraceId.MAX ", + "long max | '9223372036854775807' | DD64bTraceId.LONG_MAX", + "long max plus one | '9223372036854775808' | DD64bTraceId.LONG_MIN" }) - @ParameterizedTest - void convert64BitIdsFromToStringRepresentation(String stringId, long expectedLongId) { + @ParameterizedTest(name = "convert 64-bit ids from/to String representation [{index}]") + void convert64BitIdsFromToStringRepresentation(String stringId, DD64bTraceId expectedId) { DD64bTraceId ddid = DD64bTraceId.from(stringId); - assertEquals(DD64bTraceId.from(expectedLongId), ddid); + assertEquals(expectedId, ddid); assertEquals(stringId, ddid.toString()); } - @ParameterizedTest + @ParameterizedTest(name = "fail parsing illegal 64-bit id String representation [{index}]") @NullSource @ValueSource( strings = { @@ -72,20 +71,19 @@ void failParsingIllegal64BitIdStringRepresentation(String stringId) { } @TableTest({ - "scenario | hexId | expectedLongId ", - "zero | '0' | 0 ", - "one | '1' | 1 ", - "max | 'ffffffffffffffff' | -1 ", - "long max | '7fffffffffffffff' | Long.MAX_VALUE ", - "long min | '8000000000000000' | Long.MIN_VALUE ", - "long min with leading zeros | '00008000000000000000' | Long.MIN_VALUE ", - "cafebabe | 'cafebabe' | 3405691582 ", - "fifteen hex digits | '123456789abcdef' | 81985529216486895 " + "scenario | hexId | expectedId ", + "zero | '0' | DD64bTraceId.ZERO ", + "one | '1' | DD64bTraceId.ONE ", + "max | 'ffffffffffffffff' | DD64bTraceId.MAX ", + "long max | '7fffffffffffffff' | DD64bTraceId.LONG_MAX", + "long min | '8000000000000000' | DD64bTraceId.LONG_MIN", + "long min with leading zeros | '00008000000000000000' | DD64bTraceId.LONG_MIN", + "hex sample | 'cafebabe' | DD64bTraceId.CAFEBABE", + "fifteen hex digits | '123456789abcdef' | DD64bTraceId.HEX " }) - @ParameterizedTest - void convert64BitIdsFromToHexStringRepresentation(String hexId, long expectedLongId) { + @ParameterizedTest(name = "convert 64-bit ids from/to hex String representation [{index}]") + void convert64BitIdsFromToHexStringRepresentation(String hexId, DD64bTraceId expectedId) { DD64bTraceId ddid = DD64bTraceId.fromHex(hexId); - DD64bTraceId expectedId = DD64bTraceId.from(expectedLongId); String padded16 = hexId.length() <= 16 ? leftPadWithZeros(hexId, 16) : hexId.substring(hexId.length() - 16); String padded32 = leftPadWithZeros(hexId, 32); @@ -96,7 +94,8 @@ void convert64BitIdsFromToHexStringRepresentation(String hexId, long expectedLon assertEquals(padded32, ddid.toHexStringPadded(32)); } - @ParameterizedTest + @ParameterizedTest( + name = "fail parsing illegal 64-bit hexadecimal String representation [{index}]") @NullSource @ValueSource(strings = {"", "-1", "10000000000000000", "ffffffffffffffzf", "fffffffffffffffz"}) void failParsingIllegal64BitHexadecimalStringRepresentation(String hexId) { @@ -124,7 +123,8 @@ void failParsingIllegal64BitHexadecimalStringRepresentation(String hexId) { "all f | -1 | -1 | 'ffffffffffffffffffffffffffffffff'", "hex literal | 1311768467463790320 | 1311768467463790320 | '123456789abcdef0123456789abcdef0'" }) - @ParameterizedTest + @ParameterizedTest( + name = "convert 128-bit ids from/to hexadecimal String representation [{index}]") void convert128BitIdsFromToHexadecimalStringRepresentation( long highOrderBits, long lowOrderBits, String hexId) { DDTraceId parsedId = DD128bTraceId.fromHex(hexId); @@ -140,7 +140,8 @@ void convert128BitIdsFromToHexadecimalStringRepresentation( assertEquals(Long.toUnsignedString(lowOrderBits), parsedId.toString()); } - @ParameterizedTest + @ParameterizedTest( + name = "fail parsing illegal 128-bit id hexadecimal String representation [{index}]") @NullSource @ValueSource(strings = {"", "-1", "-A", "111111111111111111111111111111111", "123ABC", "123abcg"}) void failParsingIllegal128BitIdHexadecimalStringRepresentation(String hexId) { @@ -161,7 +162,9 @@ void failParsingIllegal128BitIdHexadecimalStringRepresentation(String hexId) { "invalid upper case | '123ABC' | 0 | 6 | true ", "too long | '111111111111111111111111111111111' | 0 | 33 | true " }) - @ParameterizedTest + @ParameterizedTest( + name = + "fail parsing illegal 128-bit id hexadecimal String representation from partial String [{index}]") void failParsingIllegal128BitIdHexadecimalStringRepresentationFromPartialString( String hexId, int start, int length, boolean lowerCaseOnly) { assertThrows( diff --git a/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java b/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java index cdf2a00e426..973408cd3fa 100644 --- a/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java +++ b/utils/test-utils/src/main/java/datadog/trace/test/util/TableTestTypeConverters.java @@ -2,7 +2,7 @@ import org.tabletest.junit.TypeConverter; -/** Shared converters for TableTest numeric cells, including symbolic constants. */ +/** Shared converters for JUnit 5 TableTest tests that use unparsable constants. */ public final class TableTestTypeConverters { private TableTestTypeConverters() {} @@ -18,10 +18,6 @@ public static long toLong(String value) { return Long.MAX_VALUE; case "Long.MIN_VALUE": return Long.MIN_VALUE; - case "DDSpanId.MAX": - return -1L; - case "DDSpanId.ZERO": - return 0L; default: return Long.decode(token); }