expand qjs_blob

This commit is contained in:
2025-05-28 14:38:43 -05:00
parent a39f287a88
commit f334a2ad56
2 changed files with 1178 additions and 223 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,11 @@
// //
// Attempt to "use" the blob module as if it was installed or compiled in. // Attempt to "use" the blob module as if it was installed or compiled in.
var blob = use('blob'); var Blob = use('blob')
var pp = new Blob()
console.log(pp.length)
// If you're testing in an environment without a 'use' loader, you might do // If you're testing in an environment without a 'use' loader, you might do
// something like importing the compiled C module or linking it differently. // something like importing the compiled C module or linking it differently.
@@ -141,14 +145,14 @@ let tests = [
// 1) Ensure we can create a blank blob // 1) Ensure we can create a blank blob
{ {
name: "make() should produce an empty antestone blob of length 0", name: "new Blob() should produce an empty antestone blob of length 0",
run() { run() {
let b = blob.make(); let b = new Blob();
let isBlob = blob["isblob"](b); let length = b.length;
let length = blob.length(b); let passed = (b instanceof Blob && length === 0);
let passed = (isBlob === true && length === 0); console.log(`blob len: ${b.length}, is blob? ${b instanceof Blob}`)
let messages = []; let messages = [];
if (!isBlob) messages.push("Returned object is not recognized as a blob"); if (!(b instanceof Blob)) messages.push("Returned object is not recognized as a blob");
if (length !== 0) messages.push(`Expected length 0, got ${length}`); if (length !== 0) messages.push(`Expected length 0, got ${length}`);
return { passed, messages }; return { passed, messages };
} }
@@ -156,11 +160,11 @@ let tests = [
// 2) Make a blob with some capacity // 2) Make a blob with some capacity
{ {
name: "make(16) should create a blob with capacity >=16 bits and length=0", name: "new Blob(16) should create a blob with capacity >=16 bits and length=0",
run() { run() {
let b = blob.make(16); let b = new Blob(16);
let isBlob = blob["isblob"](b); let isBlob = b instanceof Blob;
let length = blob.length(b); let length = b.length;
let passed = isBlob && length === 0; let passed = isBlob && length === 0;
let messages = []; let messages = [];
if (!isBlob) messages.push("Not recognized as a blob"); if (!isBlob) messages.push("Not recognized as a blob");
@@ -169,21 +173,34 @@ let tests = [
} }
}, },
// 3) Make a blob with (length, logical) // 3) Make a blob with (length, logical) - but can't read until stone
{ {
name: "make(5, true) should create a blob of length=5 bits, all 1s (antestone)", name: "new Blob(5, true) should create a blob of length=5 bits, all 1s - needs stone to read",
run() { run() {
let b = blob.make(5, true); let b = new Blob(5, true);
let len = blob.length(b); let len = b.length;
if (len !== 5) { if (len !== 5) {
return { return {
passed: false, passed: false,
messages: [`Expected length=5, got ${len}`] messages: [`Expected length=5, got ${len}`]
}; };
} }
// Check bits
// Try to read before stone - should return null
let bitVal = b.read_logical(0);
if (bitVal !== null) {
return {
passed: false,
messages: [`Expected null when reading antestone blob, got ${bitVal}`]
};
}
// Stone it
b.stone();
// Now check bits
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
let bitVal = blob.read_logical(b, i); let bitVal = b.read_logical(i);
if (bitVal !== true) { if (bitVal !== true) {
return { return {
passed: false, passed: false,
@@ -195,26 +212,30 @@ let tests = [
} }
}, },
// 4) Write bits to an empty blob // 4) Write bits to an empty blob, then stone and read
{ {
name: "write_bit() on an empty blob, then read_logical() to verify bits", name: "write_bit() on an empty blob, then stone and read_logical() to verify bits",
run() { run() {
let b = blob.make(); // starts length=0 let b = new Blob(); // starts length=0
// write bits: true, false, true // write bits: true, false, true
blob.write_bit(b, true); // bit #0 b.write_bit(true); // bit #0
blob.write_bit(b, false); // bit #1 b.write_bit(false); // bit #1
blob.write_bit(b, true); // bit #2 b.write_bit(true); // bit #2
let len = blob.length(b); let len = b.length;
if (len !== 3) { if (len !== 3) {
return { return {
passed: false, passed: false,
messages: [`Expected length=3, got ${len}`] messages: [`Expected length=3, got ${len}`]
}; };
} }
// Must stone before reading
b.stone();
let bits = [ let bits = [
blob.read_logical(b, 0), b.read_logical(0),
blob.read_logical(b, 1), b.read_logical(1),
blob.read_logical(b, 2) b.read_logical(2)
]; ];
let compare = deepCompare([true, false, true], bits); let compare = deepCompare([true, false, true], bits);
return compare; return compare;
@@ -225,14 +246,14 @@ let tests = [
{ {
name: "Stoning a blob should prevent further writes", name: "Stoning a blob should prevent further writes",
run() { run() {
let b = blob.make(5, false); let b = new Blob(5, false);
// Stone it // Stone it
blob.stone(b); b.stone();
// Try to write // Try to write
let passed = true; let passed = true;
let messages = []; let messages = [];
try { try {
blob.write_bit(b, true); b.write_bit(true);
passed = false; passed = false;
messages.push("Expected an error or refusal when writing to a stone blob, but none occurred"); messages.push("Expected an error or refusal when writing to a stone blob, but none occurred");
} catch (e) { } catch (e) {
@@ -242,51 +263,344 @@ let tests = [
} }
}, },
// 6) make(blob, from, to) - copying range from an existing blob // 6) make(blob, from, to) - copying range from an existing blob (copy doesn't need source to be stone)
{ {
name: "make(existing_blob, from, to) can copy partial range", name: "new Blob(existing_blob, from, to) can copy partial range",
run() { run() {
// Create a 10-bit blob: pattern T F T F T F T F T F // Create a 10-bit blob: pattern T F T F T F T F T F
let original = blob.make(); let original = new Blob();
for (let i = 0; i < 10; i++) { for (let i = 0; i < 10; i++) {
blob.write_bit(original, i % 2 === 0); original.write_bit(i % 2 === 0);
} }
// Copy bits [2..7) // Copy bits [2..7)
// That slice is bits #2..6: T, F, T, F, T // That slice is bits #2..6: T, F, T, F, T
// indices: 2: T(1), 3: F(0), 4: T(1), 5: F(0), 6: T(1) // indices: 2: T(1), 3: F(0), 4: T(1), 5: F(0), 6: T(1)
// so length=5 // so length=5
let copy = blob.make(original, 2, 7); let copy = new Blob(original, 2, 7);
let len = blob.length(copy); let len = copy.length;
if (len !== 5) { if (len !== 5) {
return { return {
passed: false, passed: false,
messages: [`Expected length=5, got ${len}`] messages: [`Expected length=5, got ${len}`]
}; };
} }
// Stone the copy to read from it
copy.stone();
let bits = []; let bits = [];
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
bits.push(blob.read_logical(copy, i)); bits.push(copy.read_logical(i));
} }
let compare = deepCompare([true, false, true, false, true], bits); let compare = deepCompare([true, false, true, false, true], bits);
return compare; return compare;
} }
}, },
// 7) Checking isblob(something) // 7) Checking instanceof
{ {
name: "isblob should correctly identify blob vs. non-blob", name: "instanceof should correctly identify blob vs. non-blob",
run() { run() {
let b = blob.make(); let b = new Blob();
let isB = blob["isblob"](b); let isB = b instanceof Blob;
let isNum = blob["isblob"](42); let isNum = 42 instanceof Blob;
let isObj = blob["isblob"]({ length: 3 }); let isObj = { length: 3 } instanceof Blob;
let passed = (isB === true && isNum === false && isObj === false); let passed = (isB === true && isNum === false && isObj === false);
let messages = []; let messages = [];
if (!passed) { if (!passed) {
messages.push(`Expected isblob(b)=true, isblob(42)=false, isblob({})=false; got ${isB}, ${isNum}, ${isObj}`); messages.push(`Expected (b instanceof Blob)=true, (42 instanceof Blob)=false, ({} instanceof Blob)=false; got ${isB}, ${isNum}, ${isObj}`);
} }
return { passed, messages }; return { passed, messages };
} }
},
// 8) Test write_blob
{
name: "write_blob() should append one blob to another",
run() {
let b1 = new Blob();
b1.write_bit(true);
b1.write_bit(false);
let b2 = new Blob();
b2.write_bit(true);
b2.write_bit(true);
b1.write_blob(b2);
if (b1.length !== 4) {
return {
passed: false,
messages: [`Expected length=4 after write_blob, got ${b1.length}`]
};
}
b1.stone();
let bits = [];
for (let i = 0; i < 4; i++) {
bits.push(b1.read_logical(i));
}
return deepCompare([true, false, true, true], bits);
}
},
// 9) Test write_fit and read_fit
{
name: "write_fit() and read_fit() should handle fixed-size bit fields",
run() {
let b = new Blob();
b.write_fit(5, 3); // Write value 5 in 3 bits (101)
b.write_fit(7, 4); // Write value 7 in 4 bits (0111)
if (b.length !== 7) {
return {
passed: false,
messages: [`Expected length=7, got ${b.length}`]
};
}
b.stone();
let val1 = b.read_fit(0, 3);
let val2 = b.read_fit(3, 4);
if (val1 !== 5 || val2 !== 7) {
return {
passed: false,
messages: [`Expected read_fit to return 5 and 7, got ${val1} and ${val2}`]
};
}
return { passed: true, messages: [] };
}
},
// 10) Test write_kim and read_kim
{
name: "write_kim() and read_kim() should handle kim encoding",
run() {
let b = new Blob();
b.write_kim(42); // Small positive number
b.write_kim(-1); // Small negative number
b.write_kim(1000); // Larger number
b.stone();
let result1 = b.read_kim(0);
let result2 = b.read_kim(result1.bits_read);
let result3 = b.read_kim(result1.bits_read + result2.bits_read);
if (result1.value !== 42 || result2.value !== -1 || result3.value !== 1000) {
return {
passed: false,
messages: [`Expected kim values 42, -1, 1000, got ${result1.value}, ${result2.value}, ${result3.value}`]
};
}
return { passed: true, messages: [] };
}
},
// 11) Test write_text and read_text
{
name: "write_text() and read_text() should handle text encoding",
run() {
let b = new Blob();
b.write_text("Hello");
b.stone();
let result = b.read_text(0);
if (result.text !== "Hello") {
return {
passed: false,
messages: [`Expected text "Hello", got "${result.text}"`]
};
}
return { passed: true, messages: [] };
}
},
// 12) Test write_dec64 and read_dec64
{
name: "write_dec64() and read_dec64() should handle decimal encoding",
run() {
let b = new Blob();
b.write_dec64(3.14159);
b.write_dec64(-42.5);
b.stone();
let val1 = b.read_dec64(0);
let val2 = b.read_dec64(64);
// Allow small floating point differences
let diff1 = Math.abs(val1 - 3.14159);
let diff2 = Math.abs(val2 - (-42.5));
if (diff1 > EPSILON || diff2 > EPSILON) {
return {
passed: false,
messages: [`Expected dec64 values 3.14159 and -42.5, got ${val1} and ${val2}`]
};
}
return { passed: true, messages: [] };
}
},
// 13) Test write_pad and pad?
{
name: "write_pad() and pad?() should handle block padding",
run() {
let b = new Blob();
b.write_bit(true);
b.write_bit(false);
b.write_bit(true);
// Length is now 3
b.write_pad(8); // Pad to multiple of 8
if (b.length !== 8) {
return {
passed: false,
messages: [`Expected length=8 after padding, got ${b.length}`]
};
}
b.stone();
// Check pad? function
let isPadded = b["pad?"](3, 8);
if (!isPadded) {
return {
passed: false,
messages: [`Expected pad?(3, 8) to return true`]
};
}
// Verify padding pattern: original bits, then 1, then 0s
let bits = [];
for (let i = 0; i < 8; i++) {
bits.push(b.read_logical(i));
}
return deepCompare([true, false, true, true, false, false, false, false], bits);
}
},
// 14) Test Blob.kim_length static function
{
name: "Blob.kim_length() should calculate correct kim encoding lengths",
run() {
let len1 = Blob.kim_length(42); // Should be 8 bits
let len2 = Blob.kim_length(1000); // Should be 16 bits
let len3 = Blob.kim_length("Hello"); // 8 bits for length + 8*5 for chars = 48
if (len1 !== 8) {
return {
passed: false,
messages: [`Expected kim_length(42)=8, got ${len1}`]
};
}
if (len2 !== 16) {
return {
passed: false,
messages: [`Expected kim_length(1000)=16, got ${len2}`]
};
}
if (len3 !== 48) {
return {
passed: false,
messages: [`Expected kim_length("Hello")=48, got ${len3}`]
};
}
return { passed: true, messages: [] };
}
},
// 15) Test write_bit with numeric 0 and 1
{
name: "write_bit() should accept 0, 1, true, false",
run() {
let b = new Blob();
b.write_bit(1);
b.write_bit(0);
b.write_bit(true);
b.write_bit(false);
b.stone();
let bits = [];
for (let i = 0; i < 4; i++) {
bits.push(b.read_logical(i));
}
return deepCompare([true, false, true, false], bits);
}
},
// 16) Test read_blob to create copies
{
name: "read_blob() should create partial copies of stone blobs",
run() {
let b = new Blob();
for (let i = 0; i < 10; i++) {
b.write_bit(i % 3 === 0); // Pattern: T,F,F,T,F,F,T,F,F,T
}
b.stone();
let copy = b.read_blob(3, 7); // Extract bits 3-6
copy.stone(); // Need to stone the copy to read
if (copy.length !== 4) {
return {
passed: false,
messages: [`Expected copy length=4, got ${copy.length}`]
};
}
let bits = [];
for (let i = 0; i < 4; i++) {
bits.push(copy.read_logical(i));
}
// Bits 3-6 from original: T,F,F,T
return deepCompare([true, false, false, true], bits);
}
},
// 17) Test random blob creation
{
name: "new Blob(length, random_func) should create random blob",
run() {
// Simple random function that alternates
let counter = 0;
let randomFunc = () => counter++;
let b = new Blob(8, randomFunc);
b.stone();
if (b.length !== 8) {
return {
passed: false,
messages: [`Expected length=8, got ${b.length}`]
};
}
// Check pattern matches counter LSB: 0,1,0,1,0,1,0,1
let bits = [];
for (let i = 0; i < 8; i++) {
bits.push(b.read_logical(i));
}
return deepCompare([false, true, false, true, false, true, false, true], bits);
}
} }
]; ];