@@ -183,9 +183,13 @@ func TestDecimalBytesLogicalTypeInRecordDecodeWithDefault(t *testing.T) {
183183 testBinaryCodecPass (t , schema , map [string ]interface {}{"mydecimal" : big .NewRat (617 , 50 )}, []byte ("\x04 \x04 \xd2 " ))
184184}
185185
186- func TestDecimalBytesTextualRoundTrip (t * testing.T ) {
186+ func TestDecimalBytesSpecCompliantTextualRoundTrip (t * testing.T ) {
187+ // Test spec-compliant textual encoding with human-readable decimal strings
187188 schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
188- codec , err := NewCodec (schema )
189+
190+ // Create codec with spec-compliant encoding enabled
191+ opt := & CodecOption {EnableDecimalBinarySpecCompliantEncoding : true }
192+ codec , err := NewCodecWithOptions (schema , opt )
189193 if err != nil {
190194 t .Fatal (err )
191195 }
@@ -229,9 +233,13 @@ func TestDecimalBytesTextualRoundTrip(t *testing.T) {
229233 }
230234}
231235
232- func TestDecimalFixedTextualRoundTrip (t * testing.T ) {
236+ func TestDecimalFixedSpecCompliantTextualRoundTrip (t * testing.T ) {
237+ // Test spec-compliant textual encoding with human-readable decimal strings
233238 schema := `{"type": "fixed", "size": 12, "logicalType": "decimal", "precision": 4, "scale": 2}`
234- codec , err := NewCodec (schema )
239+
240+ // Create codec with spec-compliant encoding enabled
241+ opt := & CodecOption {EnableDecimalBinarySpecCompliantEncoding : true }
242+ codec , err := NewCodecWithOptions (schema , opt )
235243 if err != nil {
236244 t .Fatal (err )
237245 }
@@ -274,40 +282,8 @@ func TestDecimalFixedTextualRoundTrip(t *testing.T) {
274282 }
275283}
276284
277- func TestDecimalBytesBackwardsCompatibility (t * testing.T ) {
278- // Test that binary data incorrectly encoded as ASCII decimal strings
279- // can still be decoded correctly when backwards compatibility is enabled
280- schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
281-
282- // Create codec with backwards compatibility enabled
283- opt := & CodecOption {EnableDecimalBinaryToTextualBackwardsCompatASCIIDecoding : true }
284- codec , err := NewCodecWithOptions (schema , opt )
285- if err != nil {
286- t .Fatal (err )
287- }
288-
289- // Simulate incorrectly encoded data: "40.20" as ASCII bytes
290- // Length prefix (10 = 0x0a in varint) + ASCII bytes for "40.20"
291- incorrectlyEncodedBytes := append ([]byte {0x0a }, []byte ("40.20" )... )
292-
293- native , _ , err := codec .NativeFromBinary (incorrectlyEncodedBytes )
294- if err != nil {
295- t .Fatalf ("NativeFromBinary (backwards compat): %v" , err )
296- }
297-
298- rat , ok := native .(* big.Rat )
299- if ! ok {
300- t .Fatalf ("NativeFromBinary: expected *big.Rat, got %T" , native )
301- }
302-
303- expected := big .NewRat (4020 , 100 )
304- if rat .Cmp (expected ) != 0 {
305- t .Errorf ("NativeFromBinary (backwards compat): got %v, want %v" , rat , expected )
306- }
307- }
308-
309285func TestDecimalBytesCorrectBinaryEncoding (t * testing.T ) {
310- // Test that correctly encoded binary data ( two's complement) still works
286+ // Test that binary encoding uses two's complement (same for both legacy and spec-compliant)
311287 schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
312288 codec , err := NewCodec (schema )
313289 if err != nil {
@@ -335,10 +311,13 @@ func TestDecimalBytesCorrectBinaryEncoding(t *testing.T) {
335311 }
336312}
337313
338- func TestDecimalTextualToBinaryRoundTrip (t * testing.T ) {
339- // Test the full flow: textual -> native -> binary -> native -> textual
314+ func TestDecimalSpecCompliantTextualToBinaryRoundTrip (t * testing.T ) {
315+ // Test the full flow with spec-compliant encoding : textual -> native -> binary -> native -> textual
340316 schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
341- codec , err := NewCodec (schema )
317+
318+ // Create codec with spec-compliant encoding enabled
319+ opt := & CodecOption {EnableDecimalBinarySpecCompliantEncoding : true }
320+ codec , err := NewCodecWithOptions (schema , opt )
342321 if err != nil {
343322 t .Fatal (err )
344323 }
@@ -357,7 +336,7 @@ func TestDecimalTextualToBinaryRoundTrip(t *testing.T) {
357336 t .Fatalf ("BinaryFromNative: %v" , err )
358337 }
359338
360- // Verify binary is two's complement, not ASCII string
339+ // Verify binary is two's complement
361340 // 4020 = 0x0FB4 in hex
362341 expectedBinary := []byte {0x04 , 0x0f , 0xb4 }
363342 if string (binary ) != string (expectedBinary ) {
@@ -381,102 +360,6 @@ func TestDecimalTextualToBinaryRoundTrip(t *testing.T) {
381360 }
382361}
383362
384- func TestLooksLikeASCIIDecimal (t * testing.T ) {
385- testCases := []struct {
386- input []byte
387- expected bool
388- }{
389- {[]byte ("40.20" ), true },
390- {[]byte ("-40.20" ), true },
391- {[]byte ("+40.20" ), true },
392- {[]byte (".5" ), true },
393- {[]byte ("5." ), true },
394- {[]byte ("0.0" ), true },
395- {[]byte ("0" ), false }, // no decimal point - could be valid two's complement
396- {[]byte ("123456" ), false }, // no decimal point - could be valid two's complement
397- {[]byte ("" ), false }, // empty
398- {[]byte ("-" ), false }, // no digit
399- {[]byte ("." ), false }, // no digit
400- {[]byte ("40.20.30" ), false }, // multiple dots
401- {[]byte ("40-20" ), false }, // sign not at start
402- {[]byte ("40a20" ), false }, // non-decimal char
403- {[]byte ("\x0f \xb4 " ), false }, // binary data (two's complement)
404- {[]byte {0x00 }, false }, // null byte
405- {[]byte {0xff , 0xff }, false }, // high bytes (negative two's complement)
406- {[]byte ("12.34e5" ), false }, // scientific notation not supported
407- }
408-
409- for _ , tc := range testCases {
410- result := looksLikeASCIIDecimal (tc .input )
411- if result != tc .expected {
412- t .Errorf ("looksLikeASCIIDecimal(%q): got %v, want %v" , tc .input , result , tc .expected )
413- }
414- }
415- }
416-
417- func TestDecimalDefaultNoBackwardsCompat (t * testing.T ) {
418- // Test that by default, ASCII-looking bytes are NOT interpreted as ASCII
419- // but rather as two's-complement (which is the correct spec behavior)
420- schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
421-
422- // Create codec with default options (no backwards compat)
423- codec , err := NewCodec (schema )
424- if err != nil {
425- t .Fatal (err )
426- }
427-
428- // "09" as ASCII bytes is [0x30, 0x39] which is 12345 in decimal
429- // This could be misinterpreted as the string "09" if backwards compat were on
430- // But with default settings, it should be decoded as 12345/100 = 123.45
431- asciiLookingBytes := []byte {0x04 , 0x30 , 0x39 } // length=2, bytes="09"
432-
433- native , _ , err := codec .NativeFromBinary (asciiLookingBytes )
434- if err != nil {
435- t .Fatalf ("NativeFromBinary: %v" , err )
436- }
437-
438- rat , ok := native .(* big.Rat )
439- if ! ok {
440- t .Fatalf ("NativeFromBinary: expected *big.Rat, got %T" , native )
441- }
442-
443- // 0x3039 = 12345, with scale 2 = 123.45 = 12345/100
444- expected := big .NewRat (12345 , 100 )
445- if rat .Cmp (expected ) != 0 {
446- t .Errorf ("NativeFromBinary (default, no backwards compat): got %v, want %v" , rat , expected )
447- }
448- }
449-
450- func TestDecimalNegativeBackwardsCompatibility (t * testing.T ) {
451- // Test backwards compatibility with negative numbers encoded as ASCII
452- schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
453-
454- // Create codec with backwards compatibility enabled
455- opt := & CodecOption {EnableDecimalBinaryToTextualBackwardsCompatASCIIDecoding : true }
456- codec , err := NewCodecWithOptions (schema , opt )
457- if err != nil {
458- t .Fatal (err )
459- }
460-
461- // Simulate incorrectly encoded data: "-40.20" as ASCII bytes
462- incorrectlyEncodedBytes := append ([]byte {0x0c }, []byte ("-40.20" )... )
463-
464- native , _ , err := codec .NativeFromBinary (incorrectlyEncodedBytes )
465- if err != nil {
466- t .Fatalf ("NativeFromBinary (backwards compat): %v" , err )
467- }
468-
469- rat , ok := native .(* big.Rat )
470- if ! ok {
471- t .Fatalf ("NativeFromBinary: expected *big.Rat, got %T" , native )
472- }
473-
474- expected := big .NewRat (- 4020 , 100 )
475- if rat .Cmp (expected ) != 0 {
476- t .Errorf ("NativeFromBinary (backwards compat): got %v, want %v" , rat , expected )
477- }
478- }
479-
480363func TestValidatedStringLogicalTypeInRecordEncode (t * testing.T ) {
481364 schema := `{
482365 "type": "record",
0 commit comments