Files
reverse-engineering-anything/tests/fixtures/environmentStateMadeValues.ts
T
Edgar ArakelyanandClaude Opus 5.5 2232a53d94 fix(environment): keep a later create's made object only with clocks its request stamped
followsMadeObjects only checked that a made object's clocks parsed, so a
later create whose object showed an older clock still passed, while serving
stamps the write's clock. Its clocks must now be in the rule's format and
within the stamp window of that create's request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:10:57 -07:00

168 lines
5.7 KiB
TypeScript

import type { JsonObject } from "../../src/domain/analysisView/environmentStateRules.js";
import type { TimedCaptureRow } from "./analysisView.js";
import { bookClock } from "./environmentStateWrites.js";
/** How a capture of two task creates departs from Vikunja's. */
interface TaskOptions {
/** Whether tasks carry a `created` clock of their own besides their subscription's. */
readonly clocked?: boolean;
/** Whether each create sends the id the task then holds. */
readonly sentId?: boolean;
/** A third create, whose subscription names this task rather than its own. */
readonly thirdSubscribes?: number;
/** The first create's `identifier`, when not `#` and its index. */
readonly firstIdentifier?: string;
/** Whether lists show each task's subscription, as item reads do. */
readonly listsSubscriptions?: boolean;
/** A third create of its own task whose subscription shows a clock from before its request. */
readonly staleThird?: boolean;
}
const seed = (id: number, index: number, clocked: boolean): JsonObject => ({
id,
title: `Seeded task ${String(id)}`,
project_id: 5,
index,
identifier: `#${String(index)}`,
subscription: null,
...(clocked ? { created: "2026-10-01T09:00:00Z" } : {}),
});
/** Two task creates at a project path, numbered past tasks deleted before the capture and read back with the subscription the application made, then the list. */
const taskRows = (options: TaskOptions = {}): TimedCaptureRow[] => {
const clocked = options.clocked ?? true;
const seeds = [seed(1, 1, clocked), seed(2, 2, clocked)];
const made = (
id: number,
index: number,
title: string,
row: number,
identifier = `#${String(index)}`,
): JsonObject => ({
id,
title,
project_id: 5,
index,
identifier,
subscription: null,
...(clocked ? { created: bookClock(row) } : {}),
});
const subscribed = (
task: JsonObject,
subscription: number,
row: number,
entity = task["id"]!,
): JsonObject => ({
...task,
subscription: {
id: subscription,
entity: "task",
entity_id: entity,
created: bookClock(row),
},
});
const first = made(
20,
15,
"Replace the lens gasket",
2,
options.firstIdentifier,
);
const second = made(21, 16, "Log the fog-signal tests", 5);
const sent = (task: JsonObject) => ({
...(options.sentId === true ? { id: task["id"]! } : {}),
title: task["title"]!,
});
const firstRead = subscribed(first, 21, 2);
const secondRead = subscribed(second, 22, 5);
const listed = (task: JsonObject): JsonObject => {
if (options.listsSubscriptions !== false) return task;
const { subscription: _subscription, ...rest } = task;
return rest;
};
return [
["GET", "/api/tasks", seeds.map(listed)],
["GET", "/api/tasks/1", seeds[0]!],
["POST", "/api/projects/5/tasks", first, 201, sent(first)],
["GET", "/api/tasks/20", firstRead],
["GET", "/api/tasks", [...seeds, firstRead].map(listed)],
["POST", "/api/projects/5/tasks", second, 201, sent(second)],
["GET", "/api/tasks/21", secondRead],
["GET", "/api/tasks", [...seeds, firstRead, secondRead].map(listed)],
...(options.thirdSubscribes === undefined && options.staleThird !== true
? []
: thirdRows(
made(22, 17, "Paint the gallery rail", 8),
subscribed(
made(22, 17, "Paint the gallery rail", 8),
23,
options.staleThird === true ? 4 : 8,
options.thirdSubscribes,
),
[...seeds, firstRead, secondRead].map(listed),
listed,
sent,
)),
];
};
/** A third create, its read-back and the list after it. */
const thirdRows = (
third: JsonObject,
read: JsonObject,
before: readonly JsonObject[],
listed: (task: JsonObject) => JsonObject,
sent: (task: JsonObject) => JsonObject,
): TimedCaptureRow[] => [
["POST", "/api/projects/5/tasks", third, 201, sent(third)],
["GET", "/api/tasks/22", read],
["GET", "/api/tasks", [...before, listed(read)]],
];
/** Vikunja's two task creates, each read back with a made subscription, then the list. */
export const COUNTED_TASK_ROWS: readonly TimedCaptureRow[] = taskRows();
/** As COUNTED_TASK_ROWS, through a bulk path whose body and answer wrap the one task in `tasks`. */
export const BULK_TASK_ROWS: readonly TimedCaptureRow[] = COUNTED_TASK_ROWS.map(
(row) =>
row[0] === "POST"
? [
"POST",
`${row[1]}/bulk`,
{ tasks: [row[2]!] },
201,
{ tasks: [row[4]!] },
]
: row,
);
/** COUNTED_TASK_ROWS up to the first create's reads: one create alone shows no counter. */
export const ONE_TASK_ROWS: readonly TimedCaptureRow[] =
COUNTED_TASK_ROWS.slice(0, 5);
/** Tasks with no clock of their own, so the subscription's is the only one the creates write. */
export const UNCLOCKED_TASK_ROWS: readonly TimedCaptureRow[] = taskRows({
clocked: false,
});
/** Creates that send the id the task takes. */
export const CHOSEN_ID_TASK_ROWS: readonly TimedCaptureRow[] = taskRows({
sentId: true,
});
/** A third create whose subscription names the second task, not its own, in a capture whose lists show no subscription. */
export const MISLINKED_TASK_ROWS: readonly TimedCaptureRow[] = taskRows({
thirdSubscribes: 21,
listsSubscriptions: false,
});
/** A first create spelling its identifier `TASK-15`, where the second spells `#16`. */
export const RESPELLED_TASK_ROWS: readonly TimedCaptureRow[] = taskRows({
firstIdentifier: "TASK-15",
});
/** A third create read back with a subscription whose clock is from before its request. */
export const STALE_MADE_TASK_ROWS: readonly TimedCaptureRow[] = taskRows({
staleThird: true,
});