@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
1,766 lines (1,529 loc) • 63.3 kB
text/typescript
// Copyright Inrupt Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import { describe, it, expect } from "@jest/globals";
import { DataFactory } from "n3";
import type { Thing } from "../interfaces";
import {
addUrl,
addBoolean,
addDatetime,
addDate,
addTime,
addDecimal,
addInteger,
addStringEnglish,
addStringWithLocale,
addStringNoLocale,
addNamedNode,
addLiteral,
addTerm,
} from "./add";
import { mockThingFrom } from "./mock";
import {
ValidPropertyUrlExpectedError,
ValidValueUrlExpectedError,
} from "./thing";
import { localNodeSkolemPrefix } from "../rdf.internal";
describe("addIri", () => {
it("adds the given IRI value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
"https://some.pod/other-resource#object",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("accepts values as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object"),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("accepts values as ThingPersisteds", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const targetThing = mockThingFrom("https://some.pod/other-resource#object");
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
targetThing,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("accepts values as ThingLocals", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const thingLocal = mockThingFrom(`${localNodeSkolemPrefix}localObject`);
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
thingLocal,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: [`${localNodeSkolemPrefix}localObject`],
});
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addUrl(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"https://some.pod/other-resource#object",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
"https://some.pod/other-resource#object",
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates["https://some.vocab/predicate"]).toBeUndefined();
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}arbitrary-subject-name`;
const updatedThing = addUrl(
thingLocal,
"https://some.vocab/predicate",
"https://some.pod/other-resource#object",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
namedNodes: ["https://some.pod/other-resource#object"],
},
},
};
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
"https://some.pod/yet-another-resource#object",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: [
"https://some.pod/other-resource#object",
"https://some.pod/yet-another-resource#object",
],
});
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
namedNodes: ["https://some.pod/other-resource#object"],
},
},
};
const updatedThing = addUrl(
thing,
"https://some.vocab/predicate",
"https://some.pod/other-resource#object",
);
expect(updatedThing.predicates).toStrictEqual({
"https://some-other.vocab/predicate": {
namedNodes: ["https://some.pod/other-resource#object"],
},
"https://some.vocab/predicate": {
namedNodes: ["https://some.pod/other-resource#object"],
},
});
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addUrl(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
"https://arbitrary.url",
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"https://arbitrary.url",
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"https://arbitrary.url",
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
it("throws an error when passed an invalid URL value", () => {
expect(() =>
addUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"https://arbitrary.vocab/predicate",
"not-a-url",
),
).toThrow("Expected a valid URL value, but received: [not-a-url].");
});
it("throws an instance of ValidValueUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addUrl(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"https://arbitrary.vocab/predicate",
"not-a-url",
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidValueUrlExpectedError);
});
});
describe("addBoolean", () => {
it("adds the given boolean value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addBoolean(
thing,
"https://some.vocab/predicate",
true,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["true"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addBoolean(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
false,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["false"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addBoolean(
thing,
"https://some.vocab/predicate",
true,
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates).toStrictEqual({});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["true"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addBoolean(
thingLocal,
"https://some.vocab/predicate",
true,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["true"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: { "http://www.w3.org/2001/XMLSchema#boolean": ["false"] },
},
},
};
const updatedThing = addBoolean(
thing,
"https://some.vocab/predicate",
true,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["false", "true"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: { "http://www.w3.org/2001/XMLSchema#boolean": ["false"] },
},
},
};
const updatedThing = addBoolean(
thing,
"https://some.vocab/predicate",
true,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["true"]);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#boolean"
],
).toStrictEqual(["false"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addBoolean(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
true,
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addBoolean(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
true,
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addBoolean(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
true,
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addDatetime", () => {
it("adds the given datetime value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDatetime(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#dateTime"
],
).toStrictEqual(["1990-11-12T13:37:42.000Z"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDatetime(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#dateTime"
],
).toStrictEqual(["1990-11-12T13:37:42.000Z"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDatetime(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates["https://some.vocab/predicate"]).toBeUndefined();
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#dateTime"
],
).toStrictEqual(["1990-11-12T13:37:42.000Z"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addDatetime(
thingLocal,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#dateTime"
],
).toStrictEqual(["1990-11-12T13:37:42.000Z"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#dateTime": [
"1955-06-08T13:37:42.000Z",
],
},
},
},
};
const updatedThing = addDatetime(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#dateTime"
],
).toStrictEqual(["1955-06-08T13:37:42.000Z", "1990-11-12T13:37:42.000Z"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": ["Some other value"],
},
},
},
};
const updatedThing = addDatetime(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other value"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#dateTime"
],
).toStrictEqual(["1990-11-12T13:37:42.000Z"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addDatetime(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addDatetime(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addDatetime(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
new Date(Date.UTC(1990, 10, 12, 13, 37, 42, 0)),
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addDate", () => {
it("adds the given date value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDate(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#date"
],
).toStrictEqual(["1990-11-12Z"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDate(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
new Date(Date.UTC(1990, 10, 12)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#date"
],
).toStrictEqual(["1990-11-12Z"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDate(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12)),
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates["https://some.vocab/predicate"]).toBeUndefined();
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#date"
],
).toStrictEqual(["1990-11-12Z"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addDate(
thingLocal,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#date"
],
).toStrictEqual(["1990-11-12Z"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#date": ["1955-06-08Z"],
},
},
},
};
const updatedThing = addDate(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12)),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#date"
],
).toStrictEqual(["1955-06-08Z", "1990-11-12Z"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": ["Some other value"],
},
},
},
};
const updatedThing = addDate(
thing,
"https://some.vocab/predicate",
new Date(Date.UTC(1990, 10, 12)),
);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other value"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#date"
],
).toStrictEqual(["1990-11-12Z"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addDate(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
new Date(Date.UTC(1990, 10, 12)),
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addDate(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
new Date(Date.UTC(1990, 10, 12)),
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addDate(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
new Date(Date.UTC(1990, 10, 12)),
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addTime", () => {
it("adds the given time value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addTime(thing, "https://some.vocab/predicate", {
hour: 13,
minute: 37,
second: 42,
});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42"]);
});
it("accepts milliseconds", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addTime(thing, "https://some.vocab/predicate", {
hour: 13,
minute: 37,
second: 42,
millisecond: 367,
});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42.367"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addTime(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
{
hour: 13,
minute: 37,
second: 42,
},
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addTime(thing, "https://some.vocab/predicate", {
hour: 13,
minute: 37,
second: 42,
});
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates["https://some.vocab/predicate"]).toBeUndefined();
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addTime(thingLocal, "https://some.vocab/predicate", {
hour: 13,
minute: 37,
second: 42,
});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#time": ["13:37:42"],
},
},
},
};
const updatedThing = addTime(thing, "https://some.vocab/predicate", {
hour: 13,
minute: 40,
second: 42,
});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42", "13:40:42"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": ["Some other value"],
},
},
},
};
const updatedThing = addTime(thing, "https://some.vocab/predicate", {
hour: 13,
minute: 37,
second: 42,
});
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other value"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#time"
],
).toStrictEqual(["13:37:42"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addTime(null as unknown as Thing, "https://arbitrary.vocab/predicate", {
hour: 13,
minute: 37,
second: 42,
}),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addTime(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
{
hour: 13,
minute: 37,
second: 42,
},
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addTime(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
{
hour: 13,
minute: 37,
second: 42,
},
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addDecimal", () => {
it("adds the given decimal value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDecimal(
thing,
"https://some.vocab/predicate",
13.37,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#decimal"
],
).toStrictEqual(["13.37"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDecimal(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
13.37,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#decimal"
],
).toStrictEqual(["13.37"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addDecimal(
thing,
"https://some.vocab/predicate",
13.37,
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates).toStrictEqual({});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#decimal"
],
).toStrictEqual(["13.37"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addDecimal(
thingLocal,
"https://some.vocab/predicate",
13.37,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#decimal"
],
).toStrictEqual(["13.37"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: { "http://www.w3.org/2001/XMLSchema#decimal": ["4.2"] },
},
},
};
const updatedThing = addDecimal(
thing,
"https://some.vocab/predicate",
13.37,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#decimal"
],
).toStrictEqual(["4.2", "13.37"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": ["Some other value"],
},
},
},
};
const updatedThing = addDecimal(
thing,
"https://some.vocab/predicate",
13.37,
);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other value"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#decimal"
],
).toStrictEqual(["13.37"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addDecimal(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
13.37,
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addDecimal(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
13.37,
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addDecimal(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
13.37,
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addInteger", () => {
it("adds the given integer value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addInteger(thing, "https://some.vocab/predicate", 42);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["42"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addInteger(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
42,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["42"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addInteger(thing, "https://some.vocab/predicate", 42);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates).toStrictEqual({});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["42"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addInteger(
thingLocal,
"https://some.vocab/predicate",
42,
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["42"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: { "http://www.w3.org/2001/XMLSchema#integer": ["1337"] },
},
},
};
const updatedThing = addInteger(thing, "https://some.vocab/predicate", 42);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["1337", "42"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": ["Some other value"],
},
},
},
};
const updatedThing = addInteger(thing, "https://some.vocab/predicate", 42);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other value"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["42"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addInteger(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
42,
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addInteger(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
42,
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addInteger(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
42,
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addStringEnglish", () => {
it("adds the given value as an English string for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringEnglish(
thing,
"https://some.vocab/predicate",
"Some string",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
en: ["Some string"],
});
});
});
describe("addStringWithLocale", () => {
it("adds the given localised string value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringWithLocale(
thing,
"https://some.vocab/predicate",
"Some string",
"en-GB",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"en-gb": ["Some string"],
});
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringWithLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string",
"en-GB",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"en-gb": ["Some string"],
});
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringWithLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string",
"en-GB",
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates).toStrictEqual({});
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"en-gb": ["Some string"],
});
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addStringWithLocale(
thingLocal,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string",
"en-GB",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"en-gb": ["Some string"],
});
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
langStrings: { "nl-nl": ["Some string"] },
},
},
};
const updatedThing = addStringWithLocale(
thing,
"https://some.vocab/predicate",
"Some string",
"en-GB",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"nl-nl": ["Some string"],
"en-gb": ["Some string"],
});
});
it("preserves existing values for the same Predicate and locale", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
langStrings: { "nl-nl": ["Some string"] },
},
},
};
const updatedThing = addStringWithLocale(
thing,
"https://some.vocab/predicate",
"Some other string",
"nl-nl",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"nl-nl": ["Some string", "Some other string"],
});
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": ["Some other value"],
},
},
},
};
const updatedThing = addStringWithLocale(
thing,
"https://some.vocab/predicate",
"Some string",
"en-GB",
);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other value"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].langStrings,
).toStrictEqual({
"en-gb": ["Some string"],
});
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addStringWithLocale(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
"Arbitrary string",
"nl-NL",
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addStringWithLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string",
"nl-NL",
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addStringWithLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string",
"nl-NL",
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addStringNoLocale", () => {
it("adds the given unlocalised string value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringNoLocale(
thing,
"https://some.vocab/predicate",
"Some string value",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some string value"]);
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringNoLocale(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
"Some string value",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some string value"]);
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addStringNoLocale(
thing,
"https://some.vocab/predicate",
"Some string value",
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates).toStrictEqual({});
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some string value"]);
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addStringNoLocale(
thingLocal,
"https://some.vocab/predicate",
"Some string value",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some string value"]);
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchema#string": [
"Some other string value",
],
},
},
},
};
const updatedThing = addStringNoLocale(
thing,
"https://some.vocab/predicate",
"Some string value",
);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some other string value", "Some string value"]);
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: { "http://www.w3.org/2001/XMLSchema#integer": ["42"] },
},
},
};
const updatedThing = addStringNoLocale(
thing,
"https://some.vocab/predicate",
"Some string value",
);
expect(
updatedThing.predicates["https://some-other.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#integer"
],
).toStrictEqual(["42"]);
expect(
updatedThing.predicates["https://some.vocab/predicate"].literals![
"http://www.w3.org/2001/XMLSchema#string"
],
).toStrictEqual(["Some string value"]);
});
it("throws an error when passed something other than a Thing", () => {
expect(() =>
addStringNoLocale(
null as unknown as Thing,
"https://arbitrary.vocab/predicate",
"Arbitrary string",
),
).toThrow("Expected a Thing, but received: [null].");
});
it("throws an error when passed an invalid property URL", () => {
expect(() =>
addStringNoLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string",
),
).toThrow(
"Expected a valid URL to identify a property, but received: [not-a-url].",
);
});
it("throws an instance of ValidPropertyUrlExpectedError when passed an invalid property URL", () => {
let thrownError;
try {
addStringNoLocale(
mockThingFrom("https://arbitrary.pod/resource#thing"),
"not-a-url",
"Arbitrary string",
);
} catch (e) {
thrownError = e;
}
expect(thrownError).toBeInstanceOf(ValidPropertyUrlExpectedError);
});
});
describe("addNamedNode", () => {
it("adds the given NamedNode value for the given predicate", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addNamedNode(
thing,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object"),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("accepts Properties as Named Nodes", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addNamedNode(
thing,
DataFactory.namedNode("https://some.vocab/predicate"),
DataFactory.namedNode("https://some.pod/other-resource#object"),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("does not modify the input Thing", () => {
const thing = mockThingFrom("https://some.pod/resource#subject");
const updatedThing = addNamedNode(
thing,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object"),
);
expect(thing).not.toStrictEqual(updatedThing);
expect(thing.predicates).toStrictEqual({});
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("also works on ThingLocals", () => {
const thingLocal = mockThingFrom(
"https://arbitrary.pod/will-be-replaced-by-local-url",
);
(thingLocal.url as string) = `${localNodeSkolemPrefix}localSubject`;
const updatedThing = addNamedNode(
thingLocal,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/other-resource#object"),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: ["https://some.pod/other-resource#object"],
});
});
it("preserves existing values for the same Predicate", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some.vocab/predicate": {
namedNodes: ["https://some.pod/other-resource#object"],
},
},
};
const updatedThing = addNamedNode(
thing,
"https://some.vocab/predicate",
DataFactory.namedNode("https://some.pod/yet-another-resource#object"),
);
expect(
updatedThing.predicates["https://some.vocab/predicate"],
).toStrictEqual({
namedNodes: [
"https://some.pod/other-resource#object",
"https://some.pod/yet-another-resource#object",
],
});
});
it("preserves existing Quads with different Predicates", () => {
const thing: Thing = {
type: "Subject",
url: "https://some.pod/resource#subject",
predicates: {
"https://some-other.vocab/predicate": {
literals: {
"http://www.w3.org/2001/XMLSchem