var Blob = use('blob'); var os = use('os'); function assert(condition, message) { if (!condition) disrupt } function assertEqual(actual, expected, message) { if (actual != expected) disrupt } return { test_create_empty_blob: function() { var b = Blob(); assertEqual(length(b), 0, "Empty blob should have length 0"); }, test_create_blob_with_capacity: function() { var b = Blob(100); assertEqual(length(b), 0, "New blob with capacity should still have length 0"); }, test_write_and_read_single_bit: function() { var b = Blob(); b.write_bit(true); b.write_bit(false); b.write_bit(1); b.write_bit(0); assertEqual(length(b), 4, "Should have 4 bits after writing"); stone(b); assertEqual(b.read_logical(0), true, "First bit should be true"); assertEqual(b.read_logical(1), false, "Second bit should be false"); assertEqual(b.read_logical(2), true, "Third bit should be true (1)"); assertEqual(b.read_logical(3), false, "Fourth bit should be false (0)"); }, test_out_of_range_read_throws_error: function() { var b = Blob(); var threw = false; b.write_bit(true); stone(b); threw = false; var _try1 = function() { b.read_logical(100); } disruption { threw = true; } _try1(); assert(threw, "Out of range read should disrupt"); threw = false; var _try2 = function() { b.read_logical(-1); } disruption { threw = true; } _try2(); assert(threw, "Negative index read should disrupt"); }, test_write_and_read_numbers: function() { var b = Blob(); b.write_number(3.14159); b.write_number(-42); b.write_number(0); b.write_number(1e20); stone(b); assertEqual(b.read_number(0), 3.14159, "First number should match"); assertEqual(b.read_number(64), -42, "Second number should match"); assertEqual(b.read_number(128), 0, "Third number should match"); assertEqual(b.read_number(192), 1e20, "Fourth number should match"); }, test_write_and_read_text: function() { var b = Blob(); b.write_text("Hello"); b.write_text("World"); b.write_text("🎉"); stone(b); assertEqual(b.read_text(0), "Hello", "First text should match"); }, test_write_and_read_blobs: function() { var b1 = Blob(); b1.write_bit(true); b1.write_bit(false); b1.write_bit(true); var b2 = Blob(10); b2.write_blob(b1); b2.write_bit(false); assertEqual(length(b2), 4, "Combined blob should have 4 bits"); stone(b2); assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(1), false); assertEqual(b2.read_logical(2), true); assertEqual(b2.read_logical(3), false); }, test_blob_copy_constructor: function() { var b1 = Blob(); b1.write_bit(true); b1.write_bit(false); b1.write_bit(true); b1.write_bit(true); stone(b1); var b2 = Blob(b1); stone(b2); assertEqual(length(b2), 4, "Copied blob should have same length"); assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(3), true); }, test_blob_partial_copy_constructor: function() { var b1 = Blob(); var i = 0; for (i = 0; i < 10; i++) { b1.write_bit(i % 2 == 0); } stone(b1); var b2 = Blob(b1, 2, 7); stone(b2); assertEqual(length(b2), 5, "Partial copy should have 5 bits"); assertEqual(b2.read_logical(0), true); assertEqual(b2.read_logical(2), true); }, test_create_blob_with_fill: function() { var b1 = Blob(8, true); var b2 = Blob(8, false); var i = 0; stone(b1); stone(b2); for (i = 0; i < 8; i++) { assertEqual(b1.read_logical(i), true, "Bit " + i + " should be true"); assertEqual(b2.read_logical(i), false, "Bit " + i + " should be false"); } }, test_create_blob_with_random_function: function() { var sequence = [true, false, true, true, false]; var index = 0; var i = 0; var b = Blob(5, function() { return sequence[index++] ? 1 : 0; }); stone(b); for (i = 0; i < 5; i++) { assertEqual(b.read_logical(i), sequence[i], "Bit " + i + " should match sequence"); } }, test_write_pad_and_check_padding: function() { var b = Blob(); b.write_bit(true); b.write_bit(false); b.write_bit(true); b.write_pad(8); assertEqual(length(b), 8, "Should be padded to 8 bits"); stone(b); assert(b['pad?'](3, 8), "Should detect valid padding at position 3"); assert(!b['pad?'](2, 8), "Should detect invalid padding at position 2"); }, test_read_blob_from_stone_blob: function() { var b1 = Blob(); var i = 0; for (i = 0; i < 16; i++) { b1.write_bit(i % 3 == 0); } stone(b1); var b2 = b1.read_blob(4, 12); stone(b2); assertEqual(length(b2), 8, "Read blob should have 8 bits"); assertEqual(b2.read_logical(2), true); assertEqual(b2.read_logical(5), true); }, test_stone_blob_is_immutable: function() { var b = Blob(); var threw = false; b.write_bit(true); stone(b); var _try = function() { b.write_bit(false); } disruption { threw = true; } _try(); assert(threw, "Writing to stone blob should disrupt"); }, test_multiple_stone_calls_are_safe: function() { var b = Blob(); b.write_bit(true); assert(!stone.p(b), "Blob should not be a stone before stone() call"); stone(b); assert(stone.p(b), "Blob should be a stone after stone() call"); stone(b); assertEqual(b.read_logical(0), true, "Blob data should remain intact"); assert(b.stone == null, "blob.stone should not be available as a method"); }, test_invalid_constructor_arguments: function() { var threw = false; var _try = function() { var b = Blob("invalid"); } disruption { threw = true; } _try(); assert(threw, "Invalid constructor arguments should disrupt"); }, test_write_bit_validation: function() { var b = Blob(); var threw = false; b.write_bit(0); b.write_bit(1); var _try = function() { b.write_bit(2); } disruption { threw = true; } _try(); assert(threw, "write_bit with value 2 should disrupt"); }, test_complex_data_round_trip: function() { var b = Blob(); b.write_text("Test"); b.write_number(123.456); b.write_bit(true); b.write_bit(false); b.write_number(-999.999); var originalLength = length(b); stone(b); var b2 = Blob(b); stone(b2); assertEqual(length(b2), originalLength, "Copy should have same length"); assertEqual(b2.read_text(0), "Test", "First text should match"); }, test_zero_capacity_blob: function() { var b = Blob(0); assertEqual(length(b), 0, "Zero capacity blob should have length 0"); b.write_bit(true); assertEqual(length(b), 1, "Should expand when writing"); }, test_large_blob_handling: function() { var b = Blob(); var testSize = 1000; var i = 0; for (i = 0; i < testSize; i++) { b.write_bit(i % 7 == 0); } assertEqual(length(b), testSize, "Should have " + testSize + " bits"); stone(b); assertEqual(b.read_logical(0), true, "Bit 0 should be true"); assertEqual(b.read_logical(7), true, "Bit 7 should be true"); assertEqual(b.read_logical(14), true, "Bit 14 should be true"); assertEqual(b.read_logical(15), false, "Bit 15 should be false"); }, test_non_stone_blob_read_methods_should_throw: function() { var b = Blob(); var threw = false; b.write_bit(true); b.write_number(42); b.write_text("test"); threw = false; var _try1 = function() { b.read_logical(0); } disruption { threw = true; } _try1(); assert(threw, "read_logical on non-stone blob should disrupt"); threw = false; var _try2 = function() { b.read_number(0); } disruption { threw = true; } _try2(); assert(threw, "read_number on non-stone blob should disrupt"); threw = false; var _try3 = function() { b.read_text(0); } disruption { threw = true; } _try3(); assert(threw, "read_text on non-stone blob should disrupt"); threw = false; var _try4 = function() { b.read_blob(0, 10); } disruption { threw = true; } _try4(); assert(threw, "read_blob on non-stone blob should disrupt"); threw = false; var _try5 = function() { b['pad?'](0, 8); } disruption { threw = true; } _try5(); assert(threw, "pad? on non-stone blob should disrupt"); }, test_empty_text_write_and_read: function() { var b = Blob(); b.write_text(""); stone(b); assertEqual(b.read_text(0), "", "Empty string should round-trip"); }, test_invalid_read_positions: function() { var b = Blob(); var threw = false; b.write_number(42); stone(b); threw = false; var _try1 = function() { b.read_number(-10); } disruption { threw = true; } _try1(); assert(threw, "Negative position should disrupt"); threw = false; var _try2 = function() { b.read_number(1000); } disruption { threw = true; } _try2(); assert(threw, "Position beyond length should disrupt"); } }