@inrupt/solid-client
Version:
Make your web apps work with Solid Pods.
1,414 lines (1,286 loc) • 55.1 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 type { NamedNode } from "@rdfjs/types";
import { DataFactory } from "n3";
import { createThing, getThing, getThingAll, setThing } from "../thing/thing";
import type { Rule } from "./rule";
import {
addAgent,
addNoneOfRuleUrl,
addGroup,
addAnyOfRuleUrl,
addAllOfRuleUrl,
createRule,
getAgentAll,
getNoneOfRuleUrlAll,
getGroupAll,
getAnyOfRuleUrlAll,
getAllOfRuleUrlAll,
removeNoneOfRuleUrl,
removeAnyOfRuleUrl,
removeAllOfRuleUrl,
getRule,
hasAuthenticated,
hasPublic,
removeAgent,
removeGroup,
setAgent,
setAuthenticated,
setNoneOfRuleUrl,
setGroup,
setAnyOfRuleUrl,
setPublic,
setAllOfRuleUrl,
getRuleAll,
setRule,
hasCreator,
setCreator,
ruleAsMarkdown,
removeRule,
getClientAll,
setClient,
addClient,
removeClient,
hasAnyClient,
setAnyClient,
removePublic,
removeAuthenticated,
removeCreator,
removeAnyClient,
getResourceRule,
getResourceRuleAll,
removeResourceRule,
setResourceRule,
createResourceRuleFor,
} from "./rule";
import type { Policy } from "./policy";
import { createSolidDataset } from "../resource/solidDataset";
import { setUrl } from "../thing/set";
import type { Thing, ThingPersisted, Url } from "../interfaces";
import { acp, rdf } from "../constants";
import {
getIri,
getIriAll,
getSourceUrl,
mockSolidDatasetFrom,
} from "../index";
import { addMockAcrTo, mockAcrFor } from "./mock";
import { internal_getAcr } from "./control.internal";
import { addUrl } from "../thing/add";
import { getUrl, getUrlAll } from "../thing/get";
// Vocabulary terms
const ACP_ANY = DataFactory.namedNode("http://www.w3.org/ns/solid/acp#anyOf");
const ACP_ALL = DataFactory.namedNode("http://www.w3.org/ns/solid/acp#allOf");
const ACP_NONE = DataFactory.namedNode("http://www.w3.org/ns/solid/acp#noneOf");
const RDF_TYPE = DataFactory.namedNode(
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
);
const ACP_RULE = DataFactory.namedNode("http://www.w3.org/ns/solid/acp#Rule");
const ACP_AGENT = DataFactory.namedNode("http://www.w3.org/ns/solid/acp#agent");
const ACP_GROUP = DataFactory.namedNode("http://www.w3.org/ns/solid/acp#group");
const ACP_CLIENT = DataFactory.namedNode(
"http://www.w3.org/ns/solid/acp#client",
);
const ACP_PUBLIC = DataFactory.namedNode(
"http://www.w3.org/ns/solid/acp#PublicAgent",
);
const ACP_AUTHENTICATED = DataFactory.namedNode(
"http://www.w3.org/ns/solid/acp#AuthenticatedAgent",
);
const ACP_CREATOR = DataFactory.namedNode(
"http://www.w3.org/ns/solid/acp#CreatorAgent",
);
const SOLID_PUBLIC_CLIENT = DataFactory.namedNode(
"http://www.w3.org/ns/solid/terms#PublicOidcClient",
);
// Test data
const MOCKED_POLICY_IRI = DataFactory.namedNode(
"https://some.pod/policy-resource#policy",
);
const MOCKED_RULE_IRI = DataFactory.namedNode(
"https://some.pod/rule-resource#a-rule",
);
const OTHER_MOCKED_RULE_IRI = DataFactory.namedNode(
"https://some.pod/rule-resource#another-rule",
);
const ALLOF_RULE_IRI = DataFactory.namedNode(
"https://some.pod/rule-resource#allOf-rule",
);
const ANYOF_RULE_IRI = DataFactory.namedNode(
"https://some.pod/rule-resource#anyOf-rule",
);
const NONEOF_RULE_IRI = DataFactory.namedNode(
"https://some.pod/rule-resource#noneOf-rule",
);
const MOCK_WEBID_ME = DataFactory.namedNode("https://my.pod/profile#me");
const MOCK_WEBID_YOU = DataFactory.namedNode("https://your.pod/profile#you");
const MOCK_GROUP_IRI = DataFactory.namedNode("https://my.pod/group#a-group");
const MOCK_GROUP_OTHER_IRI = DataFactory.namedNode(
"https://my.pod/group#another-group",
);
const MOCK_CLIENT_WEBID_1 = DataFactory.namedNode(
"https://my.app/registration#it",
);
const MOCK_CLIENT_WEBID_2 = DataFactory.namedNode(
"https://your.app/registration#it",
);
const addAllObjects = (
thing: ThingPersisted,
predicate: NamedNode,
objects: Url[],
): ThingPersisted => {
return objects.reduce((thingAcc, object) => {
return addUrl(thingAcc, predicate, object);
}, thing);
};
const addAllThingObjects = (
thing: ThingPersisted,
predicate: NamedNode,
objects: Thing[],
): ThingPersisted => {
return objects.reduce((thingAcc, object) => {
return addUrl(thingAcc, predicate, object);
}, thing);
};
const mockRule = (
url: Url,
content?: {
agents?: Url[];
groups?: Url[];
public?: boolean;
authenticated?: boolean;
creator?: boolean;
clients?: Url[];
publicClient?: boolean;
},
): Rule => {
let mockedRule = createThing({
url: url.value,
});
mockedRule = addUrl(mockedRule, RDF_TYPE, ACP_RULE);
if (content?.agents) {
mockedRule = addAllObjects(mockedRule, ACP_AGENT, content.agents);
}
if (content?.groups) {
mockedRule = addAllObjects(mockedRule, ACP_GROUP, content.groups);
}
if (content?.clients) {
mockedRule = addAllObjects(mockedRule, ACP_CLIENT, content.clients);
}
if (content?.public) {
mockedRule = addUrl(mockedRule, ACP_AGENT, ACP_PUBLIC);
}
if (content?.authenticated) {
mockedRule = addUrl(mockedRule, ACP_AGENT, ACP_AUTHENTICATED);
}
if (content?.creator) {
mockedRule = addUrl(mockedRule, ACP_AGENT, ACP_CREATOR);
}
if (content?.publicClient) {
mockedRule = addUrl(mockedRule, ACP_CLIENT, SOLID_PUBLIC_CLIENT);
}
return mockedRule;
};
const mockPolicy = (
url: NamedNode,
rules?: { allOf?: Rule[]; anyOf?: Rule[]; noneOf?: Rule[] },
): Policy => {
let mockedPolicy = createThing({ url: url.value });
if (rules?.noneOf) {
mockedPolicy = addAllThingObjects(mockedPolicy, ACP_NONE, rules.noneOf);
}
if (rules?.anyOf) {
mockedPolicy = addAllThingObjects(mockedPolicy, ACP_ANY, rules.anyOf);
}
if (rules?.allOf) {
mockedPolicy = addAllThingObjects(mockedPolicy, ACP_ALL, rules.allOf);
}
return mockedPolicy;
};
describe("addNoneOfRuleUrl", () => {
it("adds the rule in the noneOf rules of the policy", () => {
const myPolicy = addNoneOfRuleUrl(
mockPolicy(MOCKED_POLICY_IRI),
mockRule(MOCKED_RULE_IRI),
);
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(MOCKED_RULE_IRI.value);
});
it("does not remove the existing noneOf rules", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(OTHER_MOCKED_RULE_IRI)],
});
const myPolicy = addNoneOfRuleUrl(mockedPolicy, mockRule(MOCKED_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(
OTHER_MOCKED_RULE_IRI.value,
);
});
it("does not change the existing allOf and anyOf rules", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockRule(ANYOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const myPolicy = addNoneOfRuleUrl(mockedPolicy, mockRule(NONEOF_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(ALLOF_RULE_IRI.value);
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(ANYOF_RULE_IRI.value);
});
it("does not change the input policy", () => {
const myPolicy = mockPolicy(MOCKED_POLICY_IRI);
const updatedPolicy = addNoneOfRuleUrl(myPolicy, mockRule(MOCKED_RULE_IRI));
expect(myPolicy).not.toStrictEqual(updatedPolicy);
});
});
describe("addAnyOfRuleUrl", () => {
it("adds the rule in the anyOf rules of the policy", () => {
const myPolicy = addAnyOfRuleUrl(
mockPolicy(MOCKED_POLICY_IRI),
mockRule(MOCKED_RULE_IRI),
);
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(MOCKED_RULE_IRI.value);
});
it("does not remove the existing anyOf rules", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockRule(OTHER_MOCKED_RULE_IRI)],
});
const myPolicy = addAnyOfRuleUrl(mockedPolicy, mockRule(MOCKED_POLICY_IRI));
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(OTHER_MOCKED_RULE_IRI.value);
});
it("does not change the existing allOf and noneOf rules", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const myPolicy = addAnyOfRuleUrl(mockedPolicy, mockRule(ANYOF_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(ALLOF_RULE_IRI.value);
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(NONEOF_RULE_IRI.value);
});
it("does not change the input policy", () => {
const myPolicy = mockPolicy(MOCKED_POLICY_IRI);
const updatedPolicy = addAnyOfRuleUrl(myPolicy, mockRule(MOCKED_RULE_IRI));
expect(myPolicy).not.toStrictEqual(updatedPolicy);
});
});
describe("addAllOfRule", () => {
it("adds the rule in the allOf rules of the policy", () => {
const myPolicy = addAllOfRuleUrl(
mockPolicy(MOCKED_POLICY_IRI),
mockRule(MOCKED_RULE_IRI),
);
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(MOCKED_RULE_IRI.value);
});
it("does not remove the existing allOf rules", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
allOf: [mockRule(OTHER_MOCKED_RULE_IRI)],
});
const myPolicy = addAllOfRuleUrl(mockedPolicy, mockRule(MOCKED_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(OTHER_MOCKED_RULE_IRI.value);
});
it("does not change the existing anyOf and noneOf rules", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
anyOf: [mockRule(ANYOF_RULE_IRI)],
});
const myPolicy = addAllOfRuleUrl(mockedPolicy, mockRule(ANYOF_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(ANYOF_RULE_IRI.value);
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(NONEOF_RULE_IRI.value);
});
it("does not change the input policy", () => {
const myPolicy = mockPolicy(MOCKED_POLICY_IRI);
const updatedPolicy = addAnyOfRuleUrl(myPolicy, mockRule(MOCKED_RULE_IRI));
expect(myPolicy).not.toStrictEqual(updatedPolicy);
});
});
describe("setNoneOfRuleUrl", () => {
it("sets the provided rules as the noneOf rules for the policy", () => {
const myPolicy = setNoneOfRuleUrl(
mockPolicy(MOCKED_POLICY_IRI),
mockRule(MOCKED_RULE_IRI),
);
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(MOCKED_RULE_IRI.value);
});
it("removes any previous noneOf rules for on the policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(OTHER_MOCKED_RULE_IRI)],
});
const myPolicy = setNoneOfRuleUrl(mockedPolicy, mockRule(MOCKED_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_NONE)).not.toContain(
OTHER_MOCKED_RULE_IRI.value,
);
});
it("does not change the existing anyOf and allOf rules on the policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockRule(ANYOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const myPolicy = setNoneOfRuleUrl(mockedPolicy, mockRule(NONEOF_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(ALLOF_RULE_IRI.value);
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(ANYOF_RULE_IRI.value);
});
it("does not change the input policy", () => {
const myPolicy = mockPolicy(MOCKED_POLICY_IRI);
const updatedPolicy = setNoneOfRuleUrl(myPolicy, mockRule(MOCKED_RULE_IRI));
expect(myPolicy).not.toStrictEqual(updatedPolicy);
});
});
describe("setAnyOfRuleUrl", () => {
it("sets the provided rules as the anyOf rules for the policy", () => {
const myPolicy = setAnyOfRuleUrl(
mockPolicy(MOCKED_POLICY_IRI),
mockRule(MOCKED_RULE_IRI),
);
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(MOCKED_RULE_IRI.value);
});
it("removes any previous anyOf rules for on the policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockRule(OTHER_MOCKED_RULE_IRI)],
});
const myPolicy = setAnyOfRuleUrl(mockedPolicy, mockRule(MOCKED_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ANY)).not.toContain(
OTHER_MOCKED_RULE_IRI.value,
);
});
it("does not change the existing noneOf and allOf rules on the policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const myPolicy = setAnyOfRuleUrl(mockedPolicy, mockRule(ANYOF_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(ALLOF_RULE_IRI.value);
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(NONEOF_RULE_IRI.value);
});
it("does not change the input policy", () => {
const myPolicy = mockPolicy(MOCKED_POLICY_IRI);
const updatedPolicy = setAnyOfRuleUrl(myPolicy, mockRule(MOCKED_RULE_IRI));
expect(myPolicy).not.toStrictEqual(updatedPolicy);
});
});
describe("setAllOfRuleUrl", () => {
it("sets the provided rules as the allOf rules for the policy", () => {
const myPolicy = setAllOfRuleUrl(
mockPolicy(MOCKED_POLICY_IRI),
mockRule(MOCKED_RULE_IRI),
);
expect(getUrlAll(myPolicy, ACP_ALL)).toContain(MOCKED_RULE_IRI.value);
});
it("removes any previous allOf rules for on the policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
allOf: [mockRule(OTHER_MOCKED_RULE_IRI)],
});
const myPolicy = setAllOfRuleUrl(mockedPolicy, mockRule(MOCKED_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ALL)).not.toContain(
OTHER_MOCKED_RULE_IRI.value,
);
});
it("does not change the existing noneOf and anyOf rules on the policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
anyOf: [mockRule(ANYOF_RULE_IRI)],
});
const myPolicy = setAllOfRuleUrl(mockedPolicy, mockRule(ALLOF_RULE_IRI));
expect(getUrlAll(myPolicy, ACP_ANY)).toContain(ANYOF_RULE_IRI.value);
expect(getUrlAll(myPolicy, ACP_NONE)).toContain(NONEOF_RULE_IRI.value);
});
it("does not change the input policy", () => {
const myPolicy = mockPolicy(MOCKED_POLICY_IRI);
const updatedPolicy = setAllOfRuleUrl(myPolicy, mockRule(MOCKED_RULE_IRI));
expect(myPolicy).not.toStrictEqual(updatedPolicy);
});
});
describe("getNoneOfRuleurlAll", () => {
it("returns all the noneOf rules for the given policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(MOCKED_RULE_IRI), mockRule(OTHER_MOCKED_RULE_IRI)],
});
const noneOfRules = getNoneOfRuleUrlAll(mockedPolicy);
expect(noneOfRules).toContain(MOCKED_RULE_IRI.value);
expect(noneOfRules).toContain(OTHER_MOCKED_RULE_IRI.value);
expect(noneOfRules).toHaveLength(2);
});
it("returns only the noneOf rules for the given policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
anyOf: [mockRule(ANYOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const noneOfRules = getNoneOfRuleUrlAll(mockedPolicy);
expect(noneOfRules).not.toContain(ANYOF_RULE_IRI.value);
expect(noneOfRules).not.toContain(ALLOF_RULE_IRI.value);
expect(noneOfRules).toHaveLength(1);
});
});
describe("getAnyOfRulesOnPolicyAll", () => {
it("returns all the anyOf rules for the given policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockRule(MOCKED_RULE_IRI), mockRule(OTHER_MOCKED_RULE_IRI)],
});
const anyOfRules = getAnyOfRuleUrlAll(mockedPolicy);
expect(anyOfRules).toContain(MOCKED_RULE_IRI.value);
expect(anyOfRules).toContain(OTHER_MOCKED_RULE_IRI.value);
expect(anyOfRules).toHaveLength(2);
});
it("returns only the anyOf rules for the given policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
anyOf: [mockRule(ANYOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const anyOfRules = getAnyOfRuleUrlAll(mockedPolicy);
expect(anyOfRules).not.toContain(NONEOF_RULE_IRI.value);
expect(anyOfRules).not.toContain(ALLOF_RULE_IRI.value);
expect(anyOfRules).toHaveLength(1);
});
});
describe("getAllOfRulesOnPolicyAll", () => {
it("returns all the allOf rules for the given policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
allOf: [mockRule(MOCKED_RULE_IRI), mockRule(OTHER_MOCKED_RULE_IRI)],
});
const allOfRules = getAllOfRuleUrlAll(mockedPolicy);
expect(allOfRules).toContain(MOCKED_RULE_IRI.value);
expect(allOfRules).toContain(OTHER_MOCKED_RULE_IRI.value);
expect(allOfRules).toHaveLength(2);
});
it("returns only the allOf rules for the given policy", () => {
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockRule(NONEOF_RULE_IRI)],
anyOf: [mockRule(ANYOF_RULE_IRI)],
allOf: [mockRule(ALLOF_RULE_IRI)],
});
const allOfRules = getAllOfRuleUrlAll(mockedPolicy);
expect(allOfRules).not.toContain(NONEOF_RULE_IRI.value);
expect(allOfRules).not.toContain(ANYOF_RULE_IRI.value);
expect(allOfRules).toHaveLength(1);
});
});
describe("removeAllOfRule", () => {
it("removes the rule from the allOf rules for the given policy", () => {
const mockedRule = mockRule(MOCKED_RULE_IRI);
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
allOf: [mockedRule],
});
const result = removeAllOfRuleUrl(mockedPolicy, mockedRule);
expect(getUrlAll(result, ACP_ALL)).not.toContain(MOCKED_RULE_IRI.value);
});
it("does not remove the rule from the anyOf/noneOf rules for the given policy", () => {
const mockedRule = mockRule(MOCKED_RULE_IRI);
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockedRule],
noneOf: [mockedRule],
});
const result = removeAllOfRuleUrl(mockedPolicy, mockedRule);
expect(getUrlAll(result, ACP_ANY)).toContain(MOCKED_RULE_IRI.value);
expect(getUrlAll(result, ACP_NONE)).toContain(MOCKED_RULE_IRI.value);
});
});
describe("removeAnyOfRuleUrl", () => {
it("removes the rule from the allOf rules for the given policy", () => {
const mockedRule = mockRule(MOCKED_RULE_IRI);
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
anyOf: [mockedRule],
});
const result = removeAnyOfRuleUrl(mockedPolicy, mockedRule);
expect(getUrlAll(result, ACP_ANY)).not.toContain(MOCKED_RULE_IRI.value);
});
it("does not remove the rule from the allOf/noneOf rules for the given policy", () => {
const mockedRule = mockRule(MOCKED_RULE_IRI);
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
allOf: [mockedRule],
noneOf: [mockedRule],
});
const result = removeAnyOfRuleUrl(mockedPolicy, mockedRule);
expect(getUrlAll(result, ACP_ALL)).toContain(MOCKED_RULE_IRI.value);
expect(getUrlAll(result, ACP_NONE)).toContain(MOCKED_RULE_IRI.value);
});
});
describe("removeNoneOfRuleUrl", () => {
it("removes the rule from the noneOf rules for the given policy", () => {
const mockedRule = mockRule(MOCKED_RULE_IRI);
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
noneOf: [mockedRule],
});
const result = removeNoneOfRuleUrl(mockedPolicy, mockedRule);
expect(getUrlAll(result, ACP_NONE)).not.toContain(MOCKED_RULE_IRI.value);
});
it("does not remove the rule from the allOf/anyOf rules for the given policy", () => {
const mockedRule = mockRule(MOCKED_RULE_IRI);
const mockedPolicy = mockPolicy(MOCKED_POLICY_IRI, {
allOf: [mockedRule],
anyOf: [mockedRule],
});
const result = removeNoneOfRuleUrl(mockedPolicy, mockedRule);
expect(getUrlAll(result, ACP_ALL)).toContain(MOCKED_RULE_IRI.value);
expect(getUrlAll(result, ACP_ANY)).toContain(MOCKED_RULE_IRI.value);
});
});
describe("createRule", () => {
it("returns a acp:Rule", () => {
const myRule = createRule(MOCKED_RULE_IRI.value);
expect(getUrl(myRule, RDF_TYPE)).toBe(ACP_RULE.value);
});
it("returns an **empty** rule", () => {
const myRule = createRule("https://my.pod/rule-resource#rule");
// The rule should only contain a type triple.
expect(Object.keys(myRule.predicates)).toHaveLength(1);
});
});
describe("createResourceRuleFor", () => {
it("returns a acp:Rule", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const myRule = createResourceRuleFor(mockedResourceWithAcr, "myRule");
expect(getIri(myRule, RDF_TYPE)).toBe(ACP_RULE.value);
});
it("returns an **empty** rule", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const myRule = createResourceRuleFor(mockedResourceWithAcr, "myRule");
// The rule should only contain a type triple.
expect(Object.keys(myRule.predicates)).toHaveLength(1);
});
});
describe("getRule", () => {
it("returns the rule with a matching IRI", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const dataset = setThing(createSolidDataset(), rule);
const result = getRule(dataset, MOCKED_RULE_IRI.value);
expect(result).not.toBeNull();
});
it("does not return a Thing with a matching IRI but the wrong type", () => {
const notARule = createThing({
url: "https://my.pod/rule-resource#not-a-rule",
});
const dataset = setThing(
createSolidDataset(),
setUrl(notARule, RDF_TYPE, "http://example.org/ns#NotRuleType"),
);
const result = getRule(dataset, "https://my.pod/rule-resource#not-a-rule");
expect(result).toBeNull();
});
it("does not return a rule with a mismatching IRI", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const dataset = setThing(createSolidDataset(), rule);
const result = getRule(dataset, OTHER_MOCKED_RULE_IRI);
expect(result).toBeNull();
});
});
describe("getResourceRule", () => {
it("returns the rule with a matching name", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const result = getResourceRule(mockedResourceWithAcr, "rule");
expect(result).not.toBeNull();
});
it("does not return a Thing with a matching IRI but the wrong type", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(
mockedRule,
rdf.type,
"http://example.org/ns#NotRuleType",
);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const result = getResourceRule(mockedResourceWithAcr, "rule");
expect(result).toBeNull();
});
it("does not return a rule with a mismatching IRI", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const result = getResourceRule(mockedResourceWithAcr, "other-rule");
expect(result).toBeNull();
});
});
describe("getRuleAll", () => {
it("returns an empty array if there are no Rules in the given Dataset", () => {
expect(getRuleAll(createSolidDataset())).toHaveLength(0);
});
it("returns all the rules in a rule resource", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const dataset = setThing(createSolidDataset(), rule);
let result = getRuleAll(dataset);
expect(result).toHaveLength(1);
const anotherRule = mockRule(OTHER_MOCKED_RULE_IRI);
const newDataset = setThing(dataset, anotherRule);
result = getRuleAll(newDataset);
expect(result).toHaveLength(2);
});
});
describe("getResourceRuleAll", () => {
it("returns an empty array if there are no Rules in the given Resource's ACR", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
expect(getResourceRuleAll(mockedResourceWithAcr)).toHaveLength(0);
});
it("returns all the rules in a Resource's ACR", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule1 = createThing({
url: `${getSourceUrl(mockedAcr)}#rule1`,
});
mockedRule1 = setUrl(mockedRule1, rdf.type, acp.Rule);
let mockedRule2 = createThing({
url: `${getSourceUrl(mockedAcr)}#rule2`,
});
mockedRule2 = setUrl(mockedRule2, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule1);
mockedAcr = setThing(mockedAcr, mockedRule2);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const result = getResourceRuleAll(mockedResourceWithAcr);
expect(result).toHaveLength(2);
});
});
describe("removeRule", () => {
it("removes the Rule from the given empty Dataset", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const dataset = setThing(createSolidDataset(), rule);
const updatedDataset = removeRule(dataset, MOCKED_RULE_IRI);
expect(getThingAll(updatedDataset)).toHaveLength(0);
});
});
describe("removeResourceRule", () => {
it("removes the Rule from the given Resource's Access control Resource", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const updatedDataset = removeResourceRule(
mockedResourceWithAcr,
mockedRule,
);
expect(getResourceRuleAll(updatedDataset)).toHaveLength(0);
});
it("accepts a plain name to remove a Rule", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const updatedDataset = removeResourceRule(mockedResourceWithAcr, "rule");
expect(getResourceRuleAll(updatedDataset)).toHaveLength(0);
});
it("accepts a full URL to remove a Rule", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const updatedDataset = removeResourceRule(
mockedResourceWithAcr,
`${getSourceUrl(mockedAcr)}#rule`,
);
expect(getResourceRuleAll(updatedDataset)).toHaveLength(0);
});
it("accepts a Named Node to remove a Rule", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const updatedDataset = removeResourceRule(
mockedResourceWithAcr,
DataFactory.namedNode(`${getSourceUrl(mockedAcr)}#rule`),
);
expect(getResourceRuleAll(updatedDataset)).toHaveLength(0);
});
it("does not remove a non-Rule with the same name", () => {
let mockedAcr = mockAcrFor("https://some.pod/resource");
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(
mockedRule,
rdf.type,
"https://example.vocab/not-a-rule",
);
mockedAcr = setThing(mockedAcr, mockedRule);
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
const updatedDataset = removeResourceRule(mockedResourceWithAcr, "rule");
const updatedAcr = internal_getAcr(updatedDataset);
expect(
getThing(updatedAcr, `${getSourceUrl(mockedAcr)}#rule`),
).not.toBeNull();
});
});
describe("setRule", () => {
it("sets the Rule in the given empty Dataset", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const dataset = setRule(createSolidDataset(), rule);
const result = getThing(dataset, MOCKED_RULE_IRI);
expect(result).not.toBeNull();
expect(getIriAll(result as Thing, rdf.type)).toContain(acp.Rule);
});
});
describe("setResourceRule", () => {
it("sets the Rule in the given Resource's ACR", () => {
const mockedAcr = mockAcrFor("https://some.pod/resource");
const mockedResourceWithAcr = addMockAcrTo(
mockSolidDatasetFrom("https://some.pod/resource"),
mockedAcr,
);
let mockedRule = createThing({
url: `${getSourceUrl(mockedAcr)}#rule`,
});
mockedRule = setUrl(mockedRule, rdf.type, acp.Rule);
const updatedResource = setResourceRule(mockedResourceWithAcr, mockedRule);
expect(getResourceRuleAll(updatedResource)).toHaveLength(1);
});
});
describe("getAgentAll", () => {
it("returns all the agents a rule applies to by WebID", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME, MOCK_WEBID_YOU],
});
const agents = getAgentAll(rule);
expect(agents).toContain(MOCK_WEBID_ME.value);
expect(agents).toContain(MOCK_WEBID_YOU.value);
expect(agents).toHaveLength(2);
});
it("does not return the groups/public/authenticated/creator/clients a rule applies to", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_IRI],
public: true,
authenticated: true,
creator: true,
clients: [MOCK_CLIENT_WEBID_1],
});
const agents = getAgentAll(rule);
expect(agents).not.toContain(MOCK_GROUP_IRI.value);
expect(agents).not.toContain(ACP_CREATOR.value);
expect(agents).not.toContain(ACP_AUTHENTICATED.value);
expect(agents).not.toContain(ACP_PUBLIC.value);
expect(agents).toHaveLength(0);
});
});
describe("setAgent", () => {
it("sets the given agents for the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = setAgent(rule, MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
it("deletes any agents previously set for the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_YOU],
});
const result = setAgent(rule, MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).not.toContain(MOCK_WEBID_YOU.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_YOU],
});
setAgent(rule, MOCK_WEBID_ME.value);
expect(getUrlAll(rule, ACP_AGENT)).not.toContain(MOCK_WEBID_ME.value);
expect(getUrlAll(rule, ACP_AGENT)).toContain(MOCK_WEBID_YOU.value);
});
it("does not overwrite public, authenticated and creator agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
authenticated: true,
creator: true,
});
const result = setAgent(rule, MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_CREATOR.value);
});
});
describe("addAgent", () => {
it("adds the given agent to the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = addAgent(rule, MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_YOU.value);
});
it("does not override existing agents/public/authenticated/groups", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME],
groups: [MOCK_GROUP_IRI],
public: true,
authenticated: true,
});
const result = addAgent(rule, MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_IRI.value);
});
});
describe("removeAgent", () => {
it("removes the given agent from the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_YOU],
});
const result = removeAgent(rule, MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).not.toContain(MOCK_WEBID_YOU.value);
});
it("does not delete unrelated agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME, MOCK_WEBID_YOU],
public: true,
authenticated: true,
});
const result = removeAgent(rule, MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).not.toContain(MOCK_WEBID_YOU.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
});
it("does not remove groups, even with matching IRI", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_IRI],
});
const result = removeAgent(rule, MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_IRI.value);
});
});
describe("getGroupAll", () => {
it("returns all the groups a rule applies to", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_IRI, MOCK_GROUP_OTHER_IRI],
});
const groups = getGroupAll(rule);
expect(groups).toContain(MOCK_GROUP_IRI.value);
expect(groups).toContain(MOCK_GROUP_OTHER_IRI.value);
expect(groups).toHaveLength(2);
});
it("does not return the agents/public/authenticated/clients a rule applies to", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME],
public: true,
authenticated: true,
clients: [MOCK_CLIENT_WEBID_1],
});
const groups = getGroupAll(rule);
expect(groups).not.toContain(MOCK_WEBID_ME.value);
expect(groups).not.toContain(ACP_AUTHENTICATED.value);
expect(groups).not.toContain(ACP_PUBLIC.value);
expect(groups).toHaveLength(0);
});
});
describe("setGroup", () => {
it("sets the given groups for the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = setGroup(rule, MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_IRI.value);
});
it("deletes any groups previously set for the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_OTHER_IRI],
});
const result = setGroup(rule, MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).not.toContain(
MOCK_GROUP_OTHER_IRI.value,
);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_OTHER_IRI],
});
setGroup(rule, MOCK_GROUP_IRI.value);
expect(getUrlAll(rule, ACP_GROUP)).not.toContain(MOCK_GROUP_IRI.value);
expect(getUrlAll(rule, ACP_GROUP)).toContain(MOCK_GROUP_OTHER_IRI.value);
});
});
describe("addGroup", () => {
it("adds the given group to the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = addGroup(rule, "https://your.pod/groups#a-group");
expect(getUrlAll(result, ACP_GROUP)).toContain(
"https://your.pod/groups#a-group",
);
});
it("does not override existing agents/public/authenticated/groups", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME],
groups: [MOCK_GROUP_IRI],
public: true,
authenticated: true,
});
const result = addGroup(rule, MOCK_GROUP_OTHER_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_OTHER_IRI.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_IRI.value);
});
});
describe("removeGroup", () => {
it("removes the given group from the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_IRI],
});
const result = removeGroup(rule, MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).not.toContain(MOCK_GROUP_IRI.value);
});
it("does not delete unrelated groups", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
groups: [MOCK_GROUP_IRI, MOCK_GROUP_OTHER_IRI],
});
const result = removeGroup(rule, MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).not.toContain(MOCK_GROUP_IRI.value);
expect(getUrlAll(result, ACP_GROUP)).toContain(MOCK_GROUP_OTHER_IRI.value);
});
it("does not remove agents, even with matching IRI", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME],
});
const result = removeGroup(rule, MOCK_WEBID_ME.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
});
describe("hasPublic", () => {
it("returns true if the rule applies to the public agent", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
});
expect(hasPublic(rule)).toBe(true);
});
it("returns false if the rule only applies to other agent", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: false,
authenticated: true,
agents: [MOCK_WEBID_ME],
});
expect(hasPublic(rule)).toBe(false);
});
});
describe("setPublic", () => {
it("applies the given rule to the public agent", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = setPublic(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
setPublic(rule);
expect(getUrlAll(rule, ACP_AGENT)).not.toContain(ACP_PUBLIC.value);
});
it("does not change the other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
authenticated: true,
agents: [MOCK_WEBID_ME],
});
const result = setPublic(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
it("throws an error when you attempt to use the deprecated API", () => {
const rule = mockRule(MOCKED_RULE_IRI);
expect(
// @ts-expect-error The type signature should warn about passing a second argument:
() => setPublic(rule, true),
).toThrow(
"The function `setPublic` no longer takes a second parameter. It is now used together with `removePublic` instead.",
);
});
});
describe("removePublic", () => {
it("prevents the rule from applying to the public agent", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
});
const result = removePublic(rule);
expect(getUrlAll(result, ACP_AGENT)).not.toContain(ACP_PUBLIC.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, { public: true });
removePublic(rule);
expect(getUrlAll(rule, ACP_AGENT)).toContain(ACP_PUBLIC.value);
});
it("does not change the other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
authenticated: true,
agents: [MOCK_WEBID_ME],
public: true,
});
const result = removePublic(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
});
describe("hasAuthenticated", () => {
it("returns true if the rule applies to authenticated agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
authenticated: true,
});
expect(hasAuthenticated(rule)).toBe(true);
});
it("returns false if the rule only applies to other agent", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
authenticated: false,
agents: [MOCK_WEBID_ME],
});
expect(hasAuthenticated(rule)).toBe(false);
});
});
describe("setAuthenticated", () => {
it("applies to given rule to authenticated agents", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = setAuthenticated(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
setAuthenticated(rule);
expect(getUrlAll(rule, ACP_AGENT)).not.toContain(ACP_AUTHENTICATED.value);
});
it("does not change the other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
agents: [MOCK_WEBID_ME],
});
const result = setAuthenticated(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
it("throws an error when you attempt to use the deprecated API", () => {
const rule = mockRule(MOCKED_RULE_IRI);
expect(
// @ts-expect-error The type signature should warn about passing a second argument:
() => setAuthenticated(rule, true),
).toThrow(
"The function `setAuthenticated` no longer takes a second parameter. It is now used together with `removeAuthenticated` instead.",
);
});
});
describe("removeAuthenticated", () => {
it("prevents the rule from applying to authenticated agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
authenticated: true,
});
const result = removeAuthenticated(rule);
expect(getUrlAll(result, ACP_AGENT)).not.toContain(ACP_AUTHENTICATED.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, { authenticated: true });
removeAuthenticated(rule);
expect(getUrlAll(rule, ACP_AGENT)).toContain(ACP_AUTHENTICATED.value);
});
it("does not change the other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
authenticated: true,
agents: [MOCK_WEBID_ME],
});
const result = removeAuthenticated(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
});
describe("hasCreator", () => {
it("returns true if the rule applies to the Resource's creator", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
creator: true,
});
expect(hasCreator(rule)).toBe(true);
});
it("returns false if the rule only applies to other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
creator: false,
agents: [MOCK_WEBID_ME],
});
expect(hasCreator(rule)).toBe(false);
});
});
describe("setCreator", () => {
it("applies the given rule to the Resource's creator", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = setCreator(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_CREATOR.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
setCreator(rule);
expect(getUrlAll(rule, ACP_AGENT)).not.toContain(ACP_CREATOR.value);
});
it("does not change the other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
public: true,
agents: [MOCK_WEBID_ME],
});
const result = setCreator(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
it("throws an error when you attempt to use the deprecated API", () => {
const rule = mockRule(MOCKED_RULE_IRI);
expect(
// @ts-expect-error The type signature should warn about passing a second argument:
() => setCreator(rule, true),
).toThrow(
"The function `setCreator` no longer takes a second parameter. It is now used together with `removeCreator` instead.",
);
});
});
describe("removeCreator", () => {
it("prevents the rule from applying to the Resource's creator", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
creator: true,
});
const result = removeCreator(rule);
expect(getUrlAll(result, ACP_AGENT)).not.toContain(ACP_CREATOR.value);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, { creator: true });
removeCreator(rule);
expect(getUrlAll(rule, ACP_AGENT)).toContain(ACP_CREATOR.value);
});
it("does not change the other agents", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
creator: true,
public: true,
agents: [MOCK_WEBID_ME],
});
const result = removeCreator(rule);
expect(getUrlAll(result, ACP_AGENT)).toContain(ACP_PUBLIC.value);
expect(getUrlAll(result, ACP_AGENT)).toContain(MOCK_WEBID_ME.value);
});
});
describe("getClientAll", () => {
it("returns all the clients a rule applies to by WebID", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
clients: [MOCK_CLIENT_WEBID_1, MOCK_CLIENT_WEBID_2],
});
const clients = getClientAll(rule);
expect(clients).toContain(MOCK_CLIENT_WEBID_1.value);
expect(clients).toContain(MOCK_CLIENT_WEBID_2.value);
expect(clients).toHaveLength(2);
});
it("does not return the agents/groups/public client a rule applies to", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
agents: [MOCK_WEBID_ME],
groups: [MOCK_GROUP_IRI],
public: true,
authenticated: true,
creator: true,
publicClient: true,
});
const clients = getClientAll(rule);
expect(clients).not.toContain(MOCK_GROUP_IRI.value);
expect(clients).not.toContain(ACP_CREATOR.value);
expect(clients).not.toContain(ACP_AUTHENTICATED.value);
expect(clients).not.toContain(ACP_PUBLIC.value);
expect(clients).toHaveLength(0);
});
});
describe("setClient", () => {
it("sets the given clients for the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = setClient(rule, MOCK_CLIENT_WEBID_1.value);
expect(getUrlAll(result, ACP_CLIENT)).toContain(MOCK_CLIENT_WEBID_1.value);
});
it("deletes any clients previously set for the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
clients: [MOCK_CLIENT_WEBID_1],
});
const result = setClient(rule, MOCK_CLIENT_WEBID_2.value);
expect(getUrlAll(result, ACP_CLIENT)).toContain(MOCK_CLIENT_WEBID_2.value);
expect(getUrlAll(result, ACP_CLIENT)).not.toContain(
MOCK_CLIENT_WEBID_1.value,
);
});
it("does not change the input rule", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
clients: [MOCK_CLIENT_WEBID_1],
});
setClient(rule, MOCK_CLIENT_WEBID_2.value);
expect(getUrlAll(rule, ACP_CLIENT)).not.toContain(
MOCK_CLIENT_WEBID_2.value,
);
expect(getUrlAll(rule, ACP_CLIENT)).toContain(MOCK_CLIENT_WEBID_1.value);
});
it("does not overwrite the public client class", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
publicClient: true,
});
const result = setClient(rule, MOCK_CLIENT_WEBID_1.value);
expect(getUrlAll(result, ACP_CLIENT)).toContain(SOLID_PUBLIC_CLIENT.value);
});
});
describe("addClient", () => {
it("adds the given client to the rule", () => {
const rule = mockRule(MOCKED_RULE_IRI);
const result = addClient(rule, MOCK_CLIENT_WEBID_1.value);
expect(getUrlAll(result, ACP_CLIENT)).toContain(MOCK_CLIENT_WEBID_1.value);
});
it("does not override existing clients/the public client class", () => {
const rule = mockRule(MOCKED_RULE_IRI, {
clients: [MOCK_CLIENT_WEBID_1],
publicClie