@@ -1413,3 +1413,138 @@ test "Buffer: keys accept runtime []const u8 slices" {
14131413 try testing .expectEqual (@as (i64 , 42 ), val );
14141414 try testing .expect (try buf .exists (lite3 .root , key ));
14151415}
1416+
1417+ // =========================================================================
1418+ // Fuzz / property-based tests
1419+ // =========================================================================
1420+
1421+ test "Fuzz: random set/get round-trip preserves values" {
1422+ // Generate many key-value pairs and verify all survive insertion.
1423+ var mem : [65536 ]u8 align (4 ) = undefined ;
1424+ var buf = try lite3 .Buffer .initObj (& mem );
1425+
1426+ var prng = std .Random .DefaultPrng .init (0xdeadbeef );
1427+ const rand = prng .random ();
1428+
1429+ const num_keys = 50 ;
1430+ var keys : [num_keys ][16 ]u8 = undefined ;
1431+ var values : [num_keys ]i64 = undefined ;
1432+
1433+ for (0.. num_keys ) | i | {
1434+ // Generate a random 8-char key
1435+ for (& keys [i ]) | * byte | {
1436+ byte .* = rand .intRangeAtMost (u8 , 'a' , 'z' );
1437+ }
1438+ values [i ] = rand .int (i64 );
1439+ try buf .setI64 (lite3 .root , & keys [i ], values [i ]);
1440+ }
1441+
1442+ // Verify all values are retrievable
1443+ for (0.. num_keys ) | i | {
1444+ const val = try buf .getI64 (lite3 .root , & keys [i ]);
1445+ try testing .expectEqual (values [i ], val );
1446+ }
1447+ }
1448+
1449+ test "Fuzz: JSON decode of random valid documents" {
1450+ if (! lite3 .json_enabled ) return ;
1451+
1452+ // Test that well-formed JSON documents decode and re-encode consistently.
1453+ const test_jsons = [_ ][]const u8 {
1454+ \\{"a":1,"b":2,"c":3}
1455+ ,
1456+ \\{"nested":{"x":true,"y":false},"arr":[1,2,3]}
1457+ ,
1458+ \\{"empty_obj":{},"empty_arr":[],"null_val":null}
1459+ ,
1460+ \\{"str":"hello \"world\"","num":-42,"float":3.14}
1461+ ,
1462+ \\[1,2,3,"four",true,null,{"key":"val"}]
1463+ ,
1464+ \\{"unicode":"caf\u00e9","escape":"line\nbreak"}
1465+ ,
1466+ };
1467+
1468+ for (test_jsons ) | json | {
1469+ var mem : [16384 ]u8 align (4 ) = undefined ;
1470+ var buf = lite3 .Buffer .jsonDecode (& mem , json ) catch continue ;
1471+
1472+ // Re-encode should succeed
1473+ const encoded = try buf .jsonEncode (lite3 .root );
1474+ defer encoded .deinit ();
1475+ try testing .expect (encoded .slice ().len > 0 );
1476+
1477+ // Decode the re-encoded JSON and re-encode again — should be stable
1478+ var mem2 : [16384 ]u8 align (4 ) = undefined ;
1479+ var buf2 = try lite3 .Buffer .jsonDecode (& mem2 , encoded .slice ());
1480+ const encoded2 = try buf2 .jsonEncode (lite3 .root );
1481+ defer encoded2 .deinit ();
1482+
1483+ try testing .expectEqualStrings (encoded .slice (), encoded2 .slice ());
1484+ }
1485+ }
1486+
1487+ test "Fuzz: oversized key returns InvalidArgument" {
1488+ var mem : [8192 ]u8 align (4 ) = undefined ;
1489+ var buf = try lite3 .Buffer .initObj (& mem );
1490+
1491+ // Key exactly at max (255 bytes) should work
1492+ const max_key = "k" ** 255 ;
1493+ try buf .setI64 (lite3 .root , max_key , 1 );
1494+ try testing .expectEqual (@as (i64 , 1 ), try buf .getI64 (lite3 .root , max_key ));
1495+
1496+ // Key at 256 bytes should fail
1497+ const too_long = "k" ** 256 ;
1498+ try testing .expectError (lite3 .Error .InvalidArgument , buf .setI64 (lite3 .root , too_long , 2 ));
1499+ try testing .expectError (lite3 .Error .InvalidArgument , buf .getI64 (lite3 .root , too_long ));
1500+ try testing .expectError (lite3 .Error .InvalidArgument , buf .exists (lite3 .root , too_long ));
1501+ }
1502+
1503+ test "Fuzz: many types in single object" {
1504+ // Stress test: insert every type into one object and verify.
1505+ var mem : [65536 ]u8 align (4 ) = undefined ;
1506+ var buf = try lite3 .Buffer .initObj (& mem );
1507+
1508+ try buf .setNull (lite3 .root , "null_val" );
1509+ try buf .setBool (lite3 .root , "bool_val" , true );
1510+ try buf .setI64 (lite3 .root , "i64_val" , std .math .minInt (i64 ));
1511+ try buf .setF64 (lite3 .root , "f64_val" , std .math .floatMax (f64 ));
1512+ try buf .setStr (lite3 .root , "str_val" , "hello" );
1513+ try buf .setBytes (lite3 .root , "bytes_val" , &[_ ]u8 { 0x00 , 0xFF , 0x80 });
1514+ const obj = try buf .setObj (lite3 .root , "obj_val" );
1515+ try buf .setI64 (obj , "inner" , 42 );
1516+ const arr = try buf .setArr (lite3 .root , "arr_val" );
1517+ try buf .arrAppendI64 (arr , 1 );
1518+ try buf .arrAppendStr (arr , "two" );
1519+
1520+ try testing .expectEqual (lite3 .Type .null , try buf .getType (lite3 .root , "null_val" ));
1521+ try testing .expectEqual (true , try buf .getBool (lite3 .root , "bool_val" ));
1522+ try testing .expectEqual (std .math .minInt (i64 ), try buf .getI64 (lite3 .root , "i64_val" ));
1523+ try testing .expectEqual (std .math .floatMax (f64 ), try buf .getF64 (lite3 .root , "f64_val" ));
1524+ try testing .expectEqualStrings ("hello" , try buf .getStr (lite3 .root , "str_val" ));
1525+ try testing .expectEqualSlices (u8 , &[_ ]u8 { 0x00 , 0xFF , 0x80 }, try buf .getBytes (lite3 .root , "bytes_val" ));
1526+ try testing .expectEqual (@as (i64 , 42 ), try buf .getI64 (obj , "inner" ));
1527+ try testing .expectEqual (@as (i64 , 1 ), try buf .arrGetI64 (arr , 0 ));
1528+ try testing .expectEqualStrings ("two" , try buf .arrGetStr (arr , 1 ));
1529+ try testing .expectEqual (@as (u32 , 8 ), try buf .count (lite3 .root ));
1530+ }
1531+
1532+ test "Fuzz: Context rapid grow/shrink cycle" {
1533+ // Repeatedly add and overwrite keys to exercise Context's realloc path.
1534+ var ctx = try lite3 .Context .create ();
1535+ defer ctx .destroy ();
1536+ try ctx .initObj ();
1537+
1538+ for (0.. 20) | round | {
1539+ // Add many keys with large values to force growth
1540+ for (0.. 50) | i | {
1541+ var key_buf : [16 ]u8 = undefined ;
1542+ const key = std .fmt .bufPrint (& key_buf , "k{d}_{d}" , .{ round , i }) catch unreachable ;
1543+ try ctx .setStr (lite3 .root , key , "x" ** 200 );
1544+ }
1545+ }
1546+
1547+ // Verify the context is still usable
1548+ try ctx .setI64 (lite3 .root , "final" , 999 );
1549+ try testing .expectEqual (@as (i64 , 999 ), try ctx .getI64 (lite3 .root , "final" ));
1550+ }
0 commit comments