@@ -276,15 +276,18 @@ func TestDecimalFixedTextualRoundTrip(t *testing.T) {
276276
277277func TestDecimalBytesBackwardsCompatibility (t * testing.T ) {
278278 // Test that binary data incorrectly encoded as ASCII decimal strings
279- // can still be decoded correctly ( backwards compatibility)
279+ // can still be decoded correctly when backwards compatibility is enabled
280280 schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
281- codec , err := NewCodec (schema )
281+
282+ // Create codec with backwards compatibility enabled
283+ opt := & CodecOption {EnableDecimalBinaryToTextualBackwardsCompatASCIIDecoding : true }
284+ codec , err := NewCodecWithOptions (schema , opt )
282285 if err != nil {
283286 t .Fatal (err )
284287 }
285288
286289 // Simulate incorrectly encoded data: "40.20" as ASCII bytes
287- // Length prefix (10 = 0x14 in varint) + ASCII bytes for "40.20"
290+ // Length prefix (10 = 0x0a in varint) + ASCII bytes for "40.20"
288291 incorrectlyEncodedBytes := append ([]byte {0x0a }, []byte ("40.20" )... )
289292
290293 native , _ , err := codec .NativeFromBinary (incorrectlyEncodedBytes )
@@ -386,12 +389,14 @@ func TestLooksLikeASCIIDecimal(t *testing.T) {
386389 {[]byte ("40.20" ), true },
387390 {[]byte ("-40.20" ), true },
388391 {[]byte ("+40.20" ), true },
389- {[]byte ("0" ), true },
390- {[]byte ("123456" ), true },
391392 {[]byte (".5" ), true },
392393 {[]byte ("5." ), true },
393- {[]byte ("" ), false },
394- {[]byte ("-" ), false },
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
395400 {[]byte ("40.20.30" ), false }, // multiple dots
396401 {[]byte ("40-20" ), false }, // sign not at start
397402 {[]byte ("40a20" ), false }, // non-decimal char
@@ -409,10 +414,46 @@ func TestLooksLikeASCIIDecimal(t *testing.T) {
409414 }
410415}
411416
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+
412450func TestDecimalNegativeBackwardsCompatibility (t * testing.T ) {
413451 // Test backwards compatibility with negative numbers encoded as ASCII
414452 schema := `{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}`
415- codec , err := NewCodec (schema )
453+
454+ // Create codec with backwards compatibility enabled
455+ opt := & CodecOption {EnableDecimalBinaryToTextualBackwardsCompatASCIIDecoding : true }
456+ codec , err := NewCodecWithOptions (schema , opt )
416457 if err != nil {
417458 t .Fatal (err )
418459 }
0 commit comments