Skip to content

Commit

Permalink
More tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dahlia committed Mar 3, 2024
1 parent d37bc50 commit 89c78d3
Show file tree
Hide file tree
Showing 17 changed files with 25,075 additions and 363 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.cov.lcov
.DS_Store
.test-report.xml
coverage/
deno.lock
docs/*.css
docs/*.html
Expand Down
17,499 changes: 17,499 additions & 0 deletions codegen/__snapshots__/class.test.ts.snap

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion codegen/class.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { assertEquals } from "jsr:@std/assert@^0.218.2";
import { sortTopologically } from "./class.ts";
import { dirname, join } from "jsr:@std/path@^0.218.2";
import { assertSnapshot } from "jsr:@std/testing@^0.218.2/snapshot";
import { generateClasses, sortTopologically } from "./class.ts";
import { loadSchemaFiles } from "./schema.ts";

Deno.test("sortTopologically()", () => {
const sorted = sortTopologically({
Expand Down Expand Up @@ -59,3 +62,14 @@ Deno.test("sortTopologically()", () => {
],
);
});

Deno.test("generateClasses()", async (t) => {
const schemaDir = join(dirname(import.meta.dirname!), "vocab");
const runtimePath = join(dirname(import.meta.dirname!), "runtime");
const types = await loadSchemaFiles(schemaDir);
let entireCode = "";
for await (const code of generateClasses(types, runtimePath)) {
entireCode += code;
}
await assertSnapshot(t, entireCode);
});
19 changes: 14 additions & 5 deletions codegen/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ export async function* generateEncoder(
if (!areAllScalarTypes(property.range, types)) {
yield 'v instanceof URL ? { "@id": v.href } : ';
}
for (const code of getEncoders(property.range, types, "v")) yield code;
for (const code of getEncoders(property.range, types, "v", "options")) {
yield code;
}
yield `
);
}
Expand Down Expand Up @@ -100,9 +102,12 @@ export async function* generateDecoder(
if (globalThis.Object.keys(json).length == 0) {
values = {};
} else {
const expanded = await jsonld.expand(json, options);
const expanded = await jsonld.expand(json, {
...options,
keepFreeFloatingNodes: true,
});
// deno-lint-ignore no-explicit-any
values = expanded[0] as (Record<string, any[]> & { "@id"?: string });
values = (expanded[0] ?? {}) as (Record<string, any[]> & { "@id"?: string });
}
`;
const subtypes = getSubtypes(typeUri, types, true);
Expand Down Expand Up @@ -154,12 +159,16 @@ export async function* generateDecoder(
`;
}
if (property.range.length == 1) {
yield `${variable}.push(${getDecoder(property.range[0], types, "v")})`;
yield `${variable}.push(${
getDecoder(property.range[0], types, "v", "options")
})`;
} else {
yield `
const decoded =
`;
for (const code of getDecoders(property.range, types, "v")) yield code;
for (const code of getDecoders(property.range, types, "v", "options")) {
yield code;
}
yield `
;
if (typeof decoded === "undefined") continue;
Expand Down
12 changes: 12 additions & 0 deletions codegen/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,19 @@ export async function* generateConstructor(
yield `
if ("${property.pluralName}" in values && \
values.${property.pluralName} != null) {
`;
if (property.singularAccessor) {
yield `
if ("${property.singularName}" in values &&
values.${property.singularName} != null) {
throw new TypeError(
"Cannot initialize both ${property.singularName} and " +
"${property.pluralName} at the same time.",
);
}
`;
}
yield `
this.${fieldName} = values.${property.pluralName};
}
`;
Expand Down Expand Up @@ -144,13 +150,19 @@ export async function* generateCloner(
yield `
if ("${property.pluralName}" in values && \
values.${property.pluralName} != null) {
`;
if (property.singularAccessor) {
yield `
if ("${property.singularName}" in values &&
values.${property.singularName} != null) {
throw new TypeError(
"Cannot update both ${property.singularName} and " +
"${property.pluralName} at the same time.",
);
}
`;
}
yield `
clone.${fieldName} = values.${property.pluralName};
}
`;
Expand Down
13 changes: 9 additions & 4 deletions codegen/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,10 @@ export function getEncoder(
typeUri: string,
types: Record<string, TypeSchema>,
variable: string,
optionsVariable: string,
): string {
if (typeUri in scalarTypes) return scalarTypes[typeUri].encoder(variable);
if (typeUri in types) return `await ${variable}.toJsonLd()`;
if (typeUri in types) return `await ${variable}.toJsonLd(${optionsVariable})`;
throw new Error(`Unknown type: ${typeUri}`);
}

Expand All @@ -308,14 +309,15 @@ export function* getEncoders(
typeUris: string[],
types: Record<string, TypeSchema>,
variable: string,
optionsVariable: string,
): Iterable<string> {
let i = typeUris.length;
for (const typeUri of typeUris) {
if (--i > 0) {
yield getTypeGuard(typeUri, types, variable);
yield " ? ";
}
yield getEncoder(typeUri, types, variable);
yield getEncoder(typeUri, types, variable, optionsVariable);
if (i > 0) yield " : ";
}
}
Expand All @@ -324,10 +326,12 @@ export function getDecoder(
typeUri: string,
types: Record<string, TypeSchema>,
variable: string,
optionsVariable: string,
): string {
if (typeUri in scalarTypes) return scalarTypes[typeUri].decoder(variable);
if (typeUri in types) {
return `await ${types[typeUri].name}.fromJsonLd(${variable})`;
return `await ${types[typeUri].name}.fromJsonLd(
${variable}, ${optionsVariable})`;
}
throw new Error(`Unknown type: ${typeUri}`);
}
Expand All @@ -354,11 +358,12 @@ export function* getDecoders(
typeUris: string[],
types: Record<string, TypeSchema>,
variable: string,
optionsVariable: string,
): Iterable<string> {
for (const typeUri of typeUris) {
yield getDataCheck(typeUri, types, variable);
yield " ? ";
yield getDecoder(typeUri, types, variable);
yield getDecoder(typeUri, types, variable, optionsVariable);
yield " : ";
}
yield "undefined";
Expand Down
4 changes: 3 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
"tasks": {
"check": "deno task codegen && deno fmt --check && deno lint && deno check */*.ts",
"codegen": "deno run --allow-read --allow-write --check codegen/main.ts vocab/ ../runtime/ > vocab/vocab.ts && deno fmt vocab/vocab.ts && deno cache vocab/vocab.ts && deno check vocab/vocab.ts",
"test-without-codegen": "deno test --check --doc --allow-read --allow-write --unstable-temporal",
"test-without-codegen": "deno test --check --doc --allow-read --allow-write --unstable-temporal --unstable-kv",
"test": "deno task codegen && deno task test-without-codegen",
"coverage": "rm -rf coverage/ && deno task test --coverage && deno coverage --html coverage",
"publish": "deno task codegen && deno publish"
},
"unstable": [
"kv",
"temporal"
],
"lock": false
Expand Down
86 changes: 86 additions & 0 deletions runtime/docloader.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { assertEquals, assertThrows } from "jsr:@std/assert@^0.218.2";
import { mockDocumentLoader } from "../testing/docloader.ts";
import { FetchError, kvCache } from "./docloader.ts";

Deno.test("new FetchError()", () => {
const e = new FetchError("https://example.com/", "An error message.");
assertEquals(e.name, "FetchError");
assertEquals(e.url, new URL("https://example.com/"));
assertEquals(e.message, "https://example.com/: An error message.");

const e2 = new FetchError(new URL("https://example.org/"));
assertEquals(e2.url, new URL("https://example.org/"));
assertEquals(e2.message, "https://example.org/");
});

Deno.test("kvCache()", async (t) => {
const kv = await Deno.openKv(":memory:");

await t.step("cached", async () => {
const loader = kvCache({
kv,
loader: mockDocumentLoader,
rules: [
["https://example.org/", Temporal.Duration.from({ days: 1 })],
[new URL("https://example.net/"), Temporal.Duration.from({ days: 1 })],
[
new URLPattern("https://example.com/*"),
Temporal.Duration.from({ days: 30 }),
],
],
prefix: ["_test"],
});
const result = await loader("https://example.com/object");
assertEquals(result, {
contextUrl: null,
documentUrl: "https://example.com/object",
document: {
"@context": "https://www.w3.org/ns/activitystreams",
id: "https://example.com/object",
name: "Fetched object",
type: "Object",
},
});
const cache = await kv.get(["_test", "https://example.com/object"]);
assertEquals(cache.value, result);

await kv.set(
["_test", "https://example.com/mock"],
{
contextUrl: null,
documentUrl: "https://example.com/mock",
document: {
"id": "https://example.com/mock",
},
},
);
const result2 = await loader("https://example.com/mock");
assertEquals(result2, {
contextUrl: null,
documentUrl: "https://example.com/mock",
document: {
"id": "https://example.com/mock",
},
});
});

await t.step("maximum cache duration", () => {
assertThrows(
() =>
kvCache({
kv,
loader: mockDocumentLoader,
rules: [
[
"https://example.com",
Temporal.Duration.from({ days: 30, seconds: 1 }),
],
],
}),
TypeError,
"The maximum cache duration is 30 days",
);
});

kv.close();
});
2 changes: 1 addition & 1 deletion runtime/docloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class FetchError extends Error {
* @param message Error message.
*/
constructor(url: URL | string, message?: string) {
super(`${url}: ${message}`);
super(message == null ? url.toString() : `${url}: ${message}`);
this.name = "FetchError";
this.url = typeof url === "string" ? new URL(url) : url;
}
Expand Down
3 changes: 3 additions & 0 deletions testing/fixtures/example.com/wrong-type
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"@type": "https://example.com/"
}
Loading

0 comments on commit 89c78d3

Please sign in to comment.