test: cover Decodal 0.4 parity contracts
This commit is contained in:
@@ -1360,6 +1360,82 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn workspace_typed_associative_values_remain_closed_and_typed() {
|
||||||
|
let schema = || {
|
||||||
|
WorkspaceConfigSchemaBundle::compose([ConfigSchemaContribution::new(
|
||||||
|
"builtin:features",
|
||||||
|
"features",
|
||||||
|
"1",
|
||||||
|
"{ features = {...{ enabled = Bool; }}; }",
|
||||||
|
)
|
||||||
|
.unwrap()])
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
for (source, expected_kind) in [
|
||||||
|
(
|
||||||
|
"{ features = { web = { enabled = \"yes\"; }; }; }",
|
||||||
|
"constraintviolation",
|
||||||
|
),
|
||||||
|
("{ features = { web = {}; }; }", "materialize"),
|
||||||
|
(
|
||||||
|
"{ features = { web = { enabled = true; typo = 1; }; }; }",
|
||||||
|
"constraintviolation",
|
||||||
|
),
|
||||||
|
] {
|
||||||
|
let snapshot =
|
||||||
|
ConfigTreeSnapshot::from_entries(1, [entry("main.dcdl", source)]).unwrap();
|
||||||
|
let diagnostics = SnapshotEnvironment::new(snapshot)
|
||||||
|
.evaluate_contract(&ToolchainContract::with_schema_bundle(
|
||||||
|
1,
|
||||||
|
vec![path("main.dcdl")],
|
||||||
|
1,
|
||||||
|
schema(),
|
||||||
|
))
|
||||||
|
.unwrap_err();
|
||||||
|
assert_eq!(diagnostics[0].path, path("main.dcdl"));
|
||||||
|
assert_eq!(diagnostics[0].kind, expected_kind);
|
||||||
|
assert!(diagnostics[0].span.end_byte > diagnostics[0].span.start_byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn language_service_and_formatter_accept_decodal_0_4_schema_syntax() {
|
||||||
|
let source =
|
||||||
|
"{} as { features = {...{ enabled = Bool; }}; web = { enabled = Bool; ...Unknown }; }";
|
||||||
|
let snapshot = ConfigTreeSnapshot::from_entries(1, [entry("schema.dcdl", source)]).unwrap();
|
||||||
|
let environment = SnapshotEnvironment::new(snapshot);
|
||||||
|
let diagnostics = environment.analyze(&path("schema.dcdl"), None);
|
||||||
|
assert!(
|
||||||
|
diagnostics
|
||||||
|
.iter()
|
||||||
|
.all(|diagnostic| diagnostic.kind != "syntax"),
|
||||||
|
"{diagnostics:#?}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let completion_source = "{} as { web = { enabled = Unk } }";
|
||||||
|
let completion = environment
|
||||||
|
.complete(
|
||||||
|
&path("schema.dcdl"),
|
||||||
|
completion_source,
|
||||||
|
completion_source.find("Unk").unwrap() + "Unk".len(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.expect("explicit completion is available");
|
||||||
|
assert!(format!("{completion:?}").contains("Unknown"));
|
||||||
|
|
||||||
|
let formatted = environment.format(source).unwrap();
|
||||||
|
assert!(formatted.contains(" as "));
|
||||||
|
assert!(formatted.contains("...Unknown"));
|
||||||
|
assert!(
|
||||||
|
environment
|
||||||
|
.analyze(&path("schema.dcdl"), Some(&formatted))
|
||||||
|
.iter()
|
||||||
|
.all(|diagnostic| diagnostic.kind != "syntax")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn workspace_schema_preserves_fields_only_where_rest_is_explicit() {
|
fn workspace_schema_preserves_fields_only_where_rest_is_explicit() {
|
||||||
let snapshot = ConfigTreeSnapshot::from_entries(
|
let snapshot = ConfigTreeSnapshot::from_entries(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"dev": "deno run -A npm:vite@7.2.7 dev",
|
"dev": "deno run -A npm:vite@7.2.7 dev",
|
||||||
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787",
|
"dev:backend": "cd ../.. && cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787",
|
||||||
"check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json",
|
"check": "deno run -A npm:@sveltejs/kit@2.49.4 sync && deno run -A npm:svelte-check@4.3.4 --tsconfig ./tsconfig.json",
|
||||||
"test": "deno test --allow-read=src --allow-env=VSCODE_TEXTMATE_DEBUG src/lib/workspace/auth/model.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts src/lib/workspace/sidebar/repository-nav.test.ts src/lib/workspace/tickets/ticket-panel.test.ts",
|
"test": "deno test --allow-read=src,test --allow-env=LOG,VSCODE_TEXTMATE_DEBUG src/lib/workspace/auth/model.test.ts src/lib/workspace/api/http.test.ts src/lib/workspace/header/breadcrumb-model.test.ts src/lib/workspace/console/chat-submit.test.ts src/lib/workspace/console/composer-command.test.ts src/lib/workspace/console/composer-completion.test.ts src/lib/workspace/console/markdown.test.ts src/lib/workspace/console/model.test.ts src/lib/workspace/console/worker-console.ui.test.ts src/lib/workspace/settings/model.test.ts src/lib/workspace/sidebar/workers.test.ts src/lib/workspace/sidebar/worker-subscription.test.ts src/lib/workspace/sidebar/worker-launch.test.ts src/lib/workspace/sidebar/repository-nav.test.ts src/lib/workspace/tickets/ticket-panel.test.ts test/config-source/decodal-grammar.test.ts test/config-source/wasm-parity.test.ts",
|
||||||
"build": "deno run -A npm:vite@7.2.7 build",
|
"build": "deno run -A npm:vite@7.2.7 build",
|
||||||
"preview": "deno run -A npm:vite@7.2.7 preview"
|
"preview": "deno run -A npm:vite@7.2.7 preview"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import "main.dcdl" as WorkspaceConfigSchema
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
throw new Error(`Decodal 0.4 grammar produced parse errors at ${errors.join(", ")}`);
|
throw new Error(
|
||||||
|
`Decodal 0.4 grammar produced parse errors at ${errors.join(", ")}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,14 +13,20 @@ import type {
|
|||||||
} from "../../src/lib/workspace/config-source/types.ts";
|
} from "../../src/lib/workspace/config-source/types.ts";
|
||||||
|
|
||||||
const bytes = await Deno.readFile(
|
const bytes = await Deno.readFile(
|
||||||
new URL("../../src/lib/workspace/config-source/generated/config_source_wasm_bg.wasm", import.meta.url),
|
new URL(
|
||||||
|
"../../src/lib/workspace/config-source/generated/config_source_wasm_bg.wasm",
|
||||||
|
import.meta.url,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
await init({ module_or_path: bytes });
|
await init({ module_or_path: bytes });
|
||||||
|
|
||||||
async function digestText(text: string): Promise<string> {
|
async function digestText(text: string): Promise<string> {
|
||||||
const bytes = new TextEncoder().encode(text);
|
const bytes = new TextEncoder().encode(text);
|
||||||
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
||||||
return `sha256:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
return `sha256:${
|
||||||
|
Array.from(new Uint8Array(digest), (byte) =>
|
||||||
|
byte.toString(16).padStart(2, "0")).join("")
|
||||||
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toolchainFingerprint(
|
async function toolchainFingerprint(
|
||||||
@@ -56,7 +62,9 @@ const snapshot: ConfigTreeSnapshot = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const emptySchemaBundle = compose_schema_bundle([]) as WorkspaceConfigSchemaBundle;
|
const emptySchemaBundle = compose_schema_bundle(
|
||||||
|
[],
|
||||||
|
) as WorkspaceConfigSchemaBundle;
|
||||||
const contract: ToolchainContract = {
|
const contract: ToolchainContract = {
|
||||||
contract_version: 2,
|
contract_version: 2,
|
||||||
decodal_version: "0.4.0",
|
decodal_version: "0.4.0",
|
||||||
@@ -64,7 +72,10 @@ const contract: ToolchainContract = {
|
|||||||
entrypoints: ["workspace.dcdl"],
|
entrypoints: ["workspace.dcdl"],
|
||||||
import_policy_version: 1,
|
import_policy_version: 1,
|
||||||
schema_bundle: emptySchemaBundle,
|
schema_bundle: emptySchemaBundle,
|
||||||
fingerprint: await toolchainFingerprint(["workspace.dcdl"], emptySchemaBundle),
|
fingerprint: await toolchainFingerprint(
|
||||||
|
["workspace.dcdl"],
|
||||||
|
emptySchemaBundle,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
Deno.test("generated WASM evaluates the same virtual import contract", () => {
|
Deno.test("generated WASM evaluates the same virtual import contract", () => {
|
||||||
@@ -148,15 +159,43 @@ Deno.test("generated WASM applies Decodal 0.4 typed maps and explicit object res
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Deno.test("generated WASM rejects unknown root fields with source provenance", () => {
|
type ProjectedDiagnostic = {
|
||||||
let thrown: unknown;
|
path: string;
|
||||||
|
kind: string;
|
||||||
|
message: string;
|
||||||
|
span: { start_byte: number; end_byte: number };
|
||||||
|
};
|
||||||
|
|
||||||
|
function evaluateFailure(source: string): ProjectedDiagnostic {
|
||||||
try {
|
try {
|
||||||
evaluate_snapshot(schemaSnapshot("{ features = {}; custom = 42; }"), schemaContract);
|
evaluate_snapshot(schemaSnapshot(source), schemaContract);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
thrown = error;
|
const diagnostics = error as ProjectedDiagnostic[];
|
||||||
|
assertEquals(Array.isArray(diagnostics), true);
|
||||||
|
return diagnostics[0];
|
||||||
|
}
|
||||||
|
throw new Error("expected Decodal evaluation to fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
Deno.test("generated WASM preserves native Decodal 0.4 diagnostic semantics", () => {
|
||||||
|
for (
|
||||||
|
const [source, expectedKind] of [
|
||||||
|
["{ features = {}; custom = 42; }", "constraintviolation"],
|
||||||
|
[
|
||||||
|
'{ features = { web = { enabled = "yes"; }; }; }',
|
||||||
|
"constraintviolation",
|
||||||
|
],
|
||||||
|
["{ features = { web = {}; }; }", "materialize"],
|
||||||
|
[
|
||||||
|
"{ features = { web = { enabled = true; typo = 1; }; }; }",
|
||||||
|
"constraintviolation",
|
||||||
|
],
|
||||||
|
] as const
|
||||||
|
) {
|
||||||
|
const diagnostic = evaluateFailure(source);
|
||||||
|
assertEquals(diagnostic.path, "main.dcdl");
|
||||||
|
assertEquals(diagnostic.kind, expectedKind);
|
||||||
|
assertEquals(diagnostic.message.length > 0, true);
|
||||||
|
assertEquals(diagnostic.span.end_byte > diagnostic.span.start_byte, true);
|
||||||
}
|
}
|
||||||
const diagnostics = thrown as Array<{ path: string; kind: string }>;
|
|
||||||
assertEquals(Array.isArray(diagnostics), true);
|
|
||||||
assertEquals(diagnostics[0].path, "main.dcdl");
|
|
||||||
assertEquals(diagnostics[0].kind, "constraintviolation");
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user