22// SPDX-License-Identifier: Apache-2.0
33package com.amazon.ion.bytecode.bin11
44
5- import com.amazon.ion.TextToBinaryUtils.decimalStringToIntArray
65import com.amazon.ion.TextToBinaryUtils.hexStringToByteArray
76import com.amazon.ion.Timestamp
8- import com.amazon.ion.bytecode.GeneratorTestUtil.shouldGenerate
9- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.BOOLEAN_OPCODE_CASES
10- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.FLOAT0_OPCODE_CASES
11- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.FLOAT16_OPCODE_CASES
12- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.FLOAT32_OPCODE_CASES
13- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.FLOAT64_OPCODE_CASES
14- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.INT0_OPCODE_CASES
15- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.INT16_OPCODE_CASES
16- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.INT24_OPCODE_CASES
17- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.INT32_OPCODE_CASES
18- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.INT64_EMITTING_OPCODE_CASES
19- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.INT8_OPCODE_CASES
20- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.LOB_REFERENCE_OPCODE_CASES
21- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.NULL_OPCODE_CASES
22- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.REFERENCE_OPCODE_CASES
23- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.SHORT_TIMESTAMP_OPCODE_CASES
24- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.STRING_REFERENCE_OPCODE_CASES
25- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.TYPED_NULL_OPCODE_CASES
26- import com.amazon.ion.bytecode.bin11.OpcodeTestCases.replacePositionTemplates
27- import com.amazon.ion.bytecode.bin11.bytearray.PrimitiveDecoder
28- import com.amazon.ion.bytecode.ir.Instructions
7+ import com.amazon.ion.impl.bin.PrimitiveEncoder
298import org.junit.jupiter.api.Assertions.assertArrayEquals
309import org.junit.jupiter.api.Assertions.assertEquals
3110import org.junit.jupiter.params.ParameterizedTest
32- import org.junit.jupiter.params.provider.MethodSource
11+ import org.junit.jupiter.params.provider.CsvSource
12+ import org.junit.jupiter.params.provider.ValueSource
13+ import java.nio.charset.StandardCharsets
3314
34- class ByteArrayBytecodeGenerator11Test {
15+ internal object ByteArrayBytecodeGenerator11Test {
3516
3617 @ParameterizedTest
37- @MethodSource(
38- BOOLEAN_OPCODE_CASES , NULL_OPCODE_CASES , TYPED_NULL_OPCODE_CASES , FLOAT0_OPCODE_CASES ,
39- FLOAT16_OPCODE_CASES , FLOAT32_OPCODE_CASES , FLOAT64_OPCODE_CASES , SHORT_TIMESTAMP_OPCODE_CASES ,
40- REFERENCE_OPCODE_CASES , INT0_OPCODE_CASES , INT8_OPCODE_CASES , INT16_OPCODE_CASES , INT24_OPCODE_CASES ,
41- INT32_OPCODE_CASES , INT64_EMITTING_OPCODE_CASES , STRING_REFERENCE_OPCODE_CASES , LOB_REFERENCE_OPCODE_CASES
18+ @CsvSource(
19+ " 80 35, 2023T" ,
20+ " 81 35 05, 2023-10T" ,
21+ " 82 35 7D, 2023-10-15T" ,
22+ " 83 35 7D CB 0A, 2023-10-15T11:22Z" ,
23+ " 84 35 7D CB 1A 02, 2023-10-15T11:22:33Z" ,
24+ " 84 35 7D CB 12 02, 2023-10-15T11:22:33-00:00" ,
25+ " 85 35 7D CB 12 F2 06, 2023-10-15T11:22:33.444-00:00" ,
26+ " 86 35 7D CB 12 2E 22 1B, 2023-10-15T11:22:33.444555-00:00" ,
27+ " 87 35 7D CB 12 4A 86 FD 69, 2023-10-15T11:22:33.444555666-00:00" ,
28+ " 88 35 7D CB EA 01, 2023-10-15T11:22+01:15" ,
29+ " 89 35 7D CB EA 85, 2023-10-15T11:22:33+01:15" ,
30+ " 8A 35 7D CB EA 85 BC 01, 2023-10-15T11:22:33.444+01:15" ,
31+ " 8B 35 7D CB EA 85 8B C8 06, 2023-10-15T11:22:33.444555+01:15" ,
32+ " 8C 35 7D CB EA 85 92 61 7F 1A, 2023-10-15T11:22:33.444555666+01:15" ,
4233 )
43- fun `generator produces correct bytecode for all supported opcodes` (inputBytesString : String , expectedBytecodeString : String ) {
44- val inputData = inputBytesString.hexStringToByteArray()
45- val generator = ByteArrayBytecodeGenerator11 (inputData, 0 )
46-
47- generator.shouldGenerate(
48- intArrayOf(
49- * replacePositionTemplates(expectedBytecodeString, 0 ).decimalStringToIntArray(),
50- Instructions .I_END_OF_INPUT
51- )
52- )
53- }
54-
55- @ParameterizedTest
56- @MethodSource(SHORT_TIMESTAMP_OPCODE_CASES )
57- fun `generator can read short timestamp references` (encodedTimestampBytes : String , expectedBytecodeString : String , expectedTimestampString : String ) {
58- val bytes = encodedTimestampBytes.hexStringToByteArray()
34+ fun `generator can read short timestamp references` (inputBytesString : String , expectedTimestampString : String ) {
35+ val bytes = inputBytesString.hexStringToByteArray()
5936 val generator = ByteArrayBytecodeGenerator11 (bytes, 0 )
6037 val opcode = bytes[0 ].toInt().and (0xFF )
6138 val expectedTimestamp = Timestamp .valueOf(expectedTimestampString)
@@ -64,26 +41,62 @@ class ByteArrayBytecodeGenerator11Test {
6441 }
6542
6643 @ParameterizedTest
67- @MethodSource(STRING_REFERENCE_OPCODE_CASES )
68- fun `generator can read string references` (encodedStringBytes : String , expectedBytecodeString : String , expectedString : String ) {
69- val bytes = encodedStringBytes.hexStringToByteArray()
44+ @ValueSource(
45+ strings = [
46+ " Hello world" ,
47+ " <?xml version=\" 1.0\" encoding=\" UTF-8\" ?>\n <root>\n <elem>hello</elem>\n </root>\n " ,
48+ " Love it! \uD83D\uDE0D ❤\uFE0F\uD83D\uDC95\uD83D\uDE3B\uD83D\uDC96 " ,
49+ " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~!@#\$ %^&*()-_=+[{]}\\ |;:'\" ,<.>/?" ,
50+ " Ἀνέβην δέ με σῖτος εὐρυβίοιο Ἰλιάδης τε καὶ Ὀδυσσείας καὶ Φοινικίων" ,
51+ " " ,
52+ " \u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\" #$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\ ]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f " ,
53+ " \t leading and trailing whitespace\u000c \r\n "
54+ ]
55+ )
56+ fun `generator can read string references` (expectedString : String ) {
57+ val utf8Buffer = StandardCharsets .UTF_8 .encode(expectedString)
58+ val utf8Bytes = ByteArray (utf8Buffer.remaining())
59+ utf8Buffer.get(utf8Bytes)
60+ val flexUIntBytes = generateFlexUIntBytes(utf8Bytes.size)
61+ val bytes = byteArrayOf(0xF8 .toByte(), * flexUIntBytes, * utf8Bytes)
62+
7063 val generator = ByteArrayBytecodeGenerator11 (bytes, 0 )
7164 // Size of input minus the opcode and FlexUInt length prefix
72- val length = bytes.size - PrimitiveDecoder .lengthOfFlexIntOrUIntAt(bytes, 1 ) - 1
73- val position = bytes.size - length
74- val readString = generator.readTextReference(position, length)
65+ val position = flexUIntBytes.size + 1
66+ val readString = generator.readTextReference(position, utf8Bytes.size)
7567 assertEquals(expectedString, readString)
7668 }
7769
7870 @ParameterizedTest
79- @MethodSource(LOB_REFERENCE_OPCODE_CASES )
80- fun `generator can read lob references` (encodedLobBytes : String , expectedBytecodeString : String , expectedLobBytes : String ) {
81- val bytes = encodedLobBytes.hexStringToByteArray()
71+ @ValueSource(
72+ strings = [
73+ " 00 00 00 00 00 00 00 00 00 00" ,
74+ " FF FF FF FF FF FF FF FF FF FF" ,
75+ " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF" ,
76+ " A5" ,
77+ " "
78+ ]
79+ )
80+ fun `generator can read lob references` (expectedLobBytes : String ) {
81+ val lobBytes = expectedLobBytes.hexStringToByteArray()
82+ val flexUIntBytes = generateFlexUIntBytes(lobBytes.size)
83+ val bytes = byteArrayOf(0xFE .toByte(), * flexUIntBytes, * lobBytes)
84+
8285 val generator = ByteArrayBytecodeGenerator11 (bytes, 0 )
83- val length = bytes.size - PrimitiveDecoder .lengthOfFlexIntOrUIntAt(bytes, 1 ) - 1
84- val position = bytes.size - length
85- val expectedLob = expectedLobBytes.hexStringToByteArray()
86- val readLob = generator.readBytesReference(position, length).newByteArray()
87- assertArrayEquals(expectedLob, readLob)
86+ val position = flexUIntBytes.size + 1
87+ val readLob = generator.readBytesReference(position, lobBytes.size).newByteArray()
88+ assertArrayEquals(lobBytes, readLob)
89+ }
90+
91+ /* *
92+ * Helper function for generating FlexUInt bytes from an unsigned integer. Useful for test
93+ * cases that programmatically generate length-prefixed payloads.
94+ */
95+ private fun generateFlexUIntBytes (value : Int ): ByteArray {
96+ val asLong = value.toLong()
97+ val length = PrimitiveEncoder .flexUIntLength(asLong)
98+ val bytes = ByteArray (length)
99+ PrimitiveEncoder .writeFlexIntOrUIntInto(bytes, 0 , asLong, length)
100+ return bytes
88101 }
89102}
0 commit comments