Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
"@probitas/reporter": "jsr:@probitas/reporter@^0.7.0",
"@probitas/runner": "jsr:@probitas/runner@^0.5.0",
"@std/assert": "jsr:@std/assert@^1.0.16",
"@std/cbor": "jsr:@std/cbor@^0.1.9",
"@std/cli": "jsr:@std/cli@^1.0.25",
"@std/collections": "jsr:@std/collections@^1.1.3",
"@std/dotenv": "jsr:@std/dotenv@^0.225.6",
Expand Down
11 changes: 11 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions probitas/80-bigint.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* BigInt Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("BigInt Serialization")
.step("Return BigInt value", () => {
// BigInt cannot be serialized by JSON.stringify
return {
value: BigInt(9007199254740991),
timestamp: BigInt(Date.now()),
};
})
.step("This step should also run", (ctx) => {
// This step accesses the BigInt values
return {
received: typeof ctx.previous.value === "bigint",
};
Comment on lines +14 to +18
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test only checks the type of ctx.previous.value but doesn't verify that the actual BigInt values were preserved correctly. The test should validate that ctx.previous.value equals the original value and that ctx.previous.timestamp is also a bigint. Additionally, the test comment on line 8 claims "CBOR natively supports BigInt" but according to the serializer tests (lines 71-86 in serializer_test.ts), small BigInts are converted to numbers by CBOR, which may not be the expected behavior for this scenario.

Copilot uses AI. Check for mistakes.
})
.build();
25 changes: 25 additions & 0 deletions probitas/81-function.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Function Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Function Serialization")
.step("Return Function value", () => {
// Functions are omitted when serialized by JSON.stringify
return {
callback: () => "hello",
method: function namedFn() {
return 42;
},
arrow: (x: number) => x * 2,
};
})
.step("This step should also run", (ctx) => {
// This step accesses the Function values
return {
hasCallback: typeof ctx.previous.callback === "function",
hasMethod: typeof ctx.previous.method === "function",
hasArrow: typeof ctx.previous.arrow === "function",
};
})
.build();
23 changes: 23 additions & 0 deletions probitas/82-symbol.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Symbol Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Symbol Serialization")
.step("Return Symbol value", () => {
// Symbols are omitted when serialized by JSON.stringify
return {
id: Symbol("unique-id"),
tag: Symbol.for("global-tag"),
iterator: Symbol.iterator,
};
Comment on lines +12 to +13
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test includes Symbol.iterator which is a well-known symbol from the global registry. However, looking at the serializer implementation (lines 159-165 in serializer.ts), well-known symbols like Symbol.iterator will be serialized using Symbol.keyFor(). Since Symbol.keyFor(Symbol.iterator) returns undefined (well-known symbols are not registered in the global symbol registry), they will be serialized as local symbols with their description. This means Symbol.iterator will not round-trip correctly - it will become a new local symbol with the description "Symbol.iterator" instead of the original well-known symbol. The test should verify that the deserialized symbol is actually Symbol.iterator, not just any symbol.

Copilot uses AI. Check for mistakes.
})
.step("This step should also run", (ctx) => {
// This step accesses the Symbol values
return {
hasId: typeof ctx.previous.id === "symbol",
hasTag: typeof ctx.previous.tag === "symbol",
hasIterator: typeof ctx.previous.iterator === "symbol",
};
})
.build();
20 changes: 20 additions & 0 deletions probitas/83-circular.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Circular Reference Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Circular Reference Serialization")
.step("Return circular reference", () => {
// Circular references cause TypeError in JSON.stringify
const obj: Record<string, unknown> = { name: "parent" };
obj.self = obj;
return obj;
})
.step("This step should also run", (ctx) => {
// This step accesses the circular reference
return {
hasName: ctx.previous.name === "parent",
hasSelf: ctx.previous.self === ctx.previous,
};
})
.build();
29 changes: 29 additions & 0 deletions probitas/84-undefined.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Undefined Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Undefined Serialization")
.step("Return undefined values", () => {
// undefined values in object properties are omitted by JSON.stringify
// undefined in arrays becomes null
return {
explicit: undefined,
nested: {
value: undefined,
defined: "exists",
},
array: [1, undefined, 3],
};
})
.step("This step should also run", (ctx) => {
// This step accesses the undefined values
return {
hasExplicit: "explicit" in ctx.previous,
explicitIsUndefined: ctx.previous.explicit === undefined,
nestedValueIsUndefined: ctx.previous.nested.value === undefined,
nestedDefinedExists: ctx.previous.nested.defined === "exists",
arraySecondIsUndefined: ctx.previous.array[1] === undefined,
};
})
.build();
30 changes: 30 additions & 0 deletions probitas/85-map-set.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Map/Set Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Map/Set Serialization")
.step("Return Map and Set values", () => {
// Map and Set are serialized as empty objects {} by JSON.stringify
const map = new Map<string, number>([
["a", 1],
["b", 2],
]);
const set = new Set([1, 2, 3]);
return {
map,
set,
weakMap: new WeakMap(),
weakSet: new WeakSet(),
};
})
.step("This step should also run", (ctx) => {
// This step accesses the Map and Set values
return {
mapIsMap: ctx.previous.map instanceof Map,
mapSize: ctx.previous.map.size,
setIsSet: ctx.previous.set instanceof Set,
setSize: ctx.previous.set.size,
};
})
.build();
24 changes: 24 additions & 0 deletions probitas/86-regexp.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* RegExp Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("RegExp Serialization")
.step("Return RegExp values", () => {
// RegExp is serialized as empty object {} by JSON.stringify
return {
pattern: /hello\s+world/gi,
email: new RegExp("^[a-z]+@[a-z]+\\.[a-z]+$", "i"),
unicode: /\p{Script=Hiragana}+/u,
};
})
.step("This step should also run", (ctx) => {
// This step accesses the RegExp values
return {
patternIsRegExp: ctx.previous.pattern instanceof RegExp,
patternSource: ctx.previous.pattern.source,
emailIsRegExp: ctx.previous.email instanceof RegExp,
unicodeFlags: ctx.previous.unicode.flags,
};
})
.build();
32 changes: 32 additions & 0 deletions probitas/87-error.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Error Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Error Serialization")
.step("Return Error values", () => {
// Error objects lose most properties when serialized by JSON.stringify
// Only enumerable own properties are kept (message, name, stack are not enumerable)
const error = new Error("Something went wrong");
const typeError = new TypeError("Invalid type");
const customError = Object.assign(new Error("Custom"), {
code: "ERR_CUSTOM",
details: { foo: "bar" },
});
return {
error,
typeError,
customError,
};
})
.step("This step should also run", (ctx) => {
// This step accesses the Error values
return {
errorIsError: ctx.previous.error instanceof Error,
errorMessage: ctx.previous.error.message,
errorHasStack: typeof ctx.previous.error.stack === "string",
typeErrorName: ctx.previous.typeError.name,
customErrorCode: ctx.previous.customError.code,
};
})
.build();
27 changes: 27 additions & 0 deletions probitas/88-date.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Date Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("Date Serialization")
.step("Return Date values", () => {
// Date is serialized as ISO string by JSON.stringify (loses type info)
return {
now: new Date(),
epoch: new Date(0),
specific: new Date("2024-01-15T12:00:00Z"),
invalid: new Date("invalid"),
};
})
.step("This step should also run", (ctx) => {
// This step accesses the Date values
return {
nowIsDate: ctx.previous.now instanceof Date,
nowTime: ctx.previous.now.getTime(),
epochIsDate: ctx.previous.epoch instanceof Date,
epochTime: ctx.previous.epoch.getTime(),
specificYear: ctx.previous.specific.getUTCFullYear(),
invalidIsNaN: Number.isNaN(ctx.previous.invalid.getTime()),
};
})
.build();
30 changes: 30 additions & 0 deletions probitas/89-typed-array.probitas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* TypedArray Serialization Test Scenario
*/
import { scenario } from "jsr:@probitas/probitas@^0";

export default scenario("TypedArray Serialization")
.step("Return TypedArray values", () => {
// TypedArray is serialized as object with numeric keys by JSON.stringify
// ArrayBuffer cannot be directly serialized
return {
uint8: new Uint8Array([1, 2, 3, 4]),
int32: new Int32Array([100, 200, -300]),
float64: new Float64Array([1.5, 2.5, 3.5]),
buffer: new ArrayBuffer(8),
dataView: new DataView(new ArrayBuffer(4)),
};
})
.step("This step should also run", (ctx) => {
// This step accesses the TypedArray values
return {
uint8IsTypedArray: ctx.previous.uint8 instanceof Uint8Array,
uint8Length: ctx.previous.uint8.length,
uint8FirstValue: ctx.previous.uint8[0],
int32IsTypedArray: ctx.previous.int32 instanceof Int32Array,
float64Sum: ctx.previous.float64[0] + ctx.previous.float64[1],
bufferIsArrayBuffer: ctx.previous.buffer instanceof ArrayBuffer,
bufferByteLength: ctx.previous.buffer.byteLength,
};
})
.build();
Loading