Skip to content

Commit

Permalink
Merge pull request #1866 from DISSINET/1854-bugs-in-data-validation
Browse files Browse the repository at this point in the history
1854 bugs in data validation
  • Loading branch information
jancimertel authored Oct 29, 2023
2 parents c42c30e + 8354e8d commit 3967435
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 72 deletions.
84 changes: 84 additions & 0 deletions packages/server/src/models/statement/PositionRules.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { EntityEnums } from "@shared/enums";
import "ts-jest";
import { PositionRules } from "./PositionRules";

describe("models/statement/PositionRules", function () {
test("test PositionRules.intersectRules", function () {
// undefined rules - without intersection
expect(PositionRules.hasIntersection([undefined, undefined])).toEqual(
false
);

// no actions - should return true
expect(PositionRules.hasIntersection([])).toEqual(true);

// single action with single rule -> true
expect(
PositionRules.hasIntersection([[EntityEnums.Extension.Empty]])
).toEqual(true);

// two actions both with empty
expect(
PositionRules.hasIntersection([
[EntityEnums.Extension.Empty],
[EntityEnums.Extension.Empty],
])
).toEqual(true);

// two actions both with empty intersected
expect(
PositionRules.hasIntersection([
[EntityEnums.Extension.Empty],
[EntityEnums.Extension.Empty, EntityEnums.Class.Statement],
])
).toEqual(true);

expect(
PositionRules.hasIntersection([
[EntityEnums.Class.Concept],
[EntityEnums.Class.Concept],
])
).toEqual(true);

expect(
PositionRules.hasIntersection([
[EntityEnums.Class.Concept, EntityEnums.Class.Action],
[EntityEnums.Class.Concept, EntityEnums.Class.Action],
])
).toEqual(true);

expect(
PositionRules.hasIntersection([
[EntityEnums.Class.Resource, EntityEnums.Class.Action],
[EntityEnums.Class.Location, EntityEnums.Class.Concept],
])
).toEqual(false);

expect(
PositionRules.hasIntersection([
[EntityEnums.Extension.Empty],
[EntityEnums.Class.Action],
[EntityEnums.Class.Location],
[EntityEnums.Class.Concept],
[EntityEnums.Class.Concept],
])
).toEqual(false);
});

test("test PositionRules.allowsOnlyEmpty", function () {
expect(PositionRules.allowsOnlyEmpty([])).toEqual(false);
expect(PositionRules.allowsOnlyEmpty(undefined)).toEqual(false);
expect(PositionRules.allowsOnlyEmpty([EntityEnums.Class.Concept])).toEqual(
false
);
expect(
PositionRules.allowsOnlyEmpty([
EntityEnums.Class.Concept,
EntityEnums.Extension.Empty,
])
).toEqual(false);
expect(
PositionRules.allowsOnlyEmpty([EntityEnums.Extension.Empty])
).toEqual(true);
});
});
69 changes: 50 additions & 19 deletions packages/server/src/models/statement/PositionRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,70 @@ import { IAction } from "@shared/types";
export class PositionRules {
classes: EntityEnums.ExtendedClass[] = [];
undefinedActions: string[] = [];
allEmpty = true;
allUndefined = true;
mismatch = false;

constructor(actions: IAction[], position: EntityEnums.Position) {
for (const action of actions) {
const rules = ActionEntity.toRules(action.data.entities)[position];
if (!rules) {
const undefinedRules = !rules || !rules.length;
if (undefinedRules) {
this.undefinedActions.push(action.id);
}
this.allEmpty = this.allEmpty && PositionRules.isRuleEmpty(rules);

if (!this.mismatch) {
if (this.classes.length) {
this.mismatch = true;
for (const rule of rules || []) {
if (this.classes.indexOf(rule) !== -1) {
this.mismatch = false;
break;
}
}
}
}

this.allUndefined = this.allUndefined && undefinedRules;

this.classes = this.classes.concat(rules || []);
}

this.mismatch = !PositionRules.hasIntersection(
actions.map((a) => ActionEntity.toRules(a.data.entities)[position])
);
}

/**
* Predicate for testing if current rules-set allows empty actant
* @returns
*/
allowsEmpty(): boolean {
return this.classes.includes(EntityEnums.Extension.Empty);
}

static isRuleEmpty(rules: EntityEnums.ExtendedClass[] | undefined): boolean {
if (!rules) {
return false;
/**
* Tests if arrays of allowed classes across actions has any intersection
* @param rules
* @returns
*/
static hasIntersection(
rules: (EntityEnums.ExtendedClass[] | undefined)[]
): boolean {
if (!Array.isArray(rules) || rules.length < 2) {
return true;
}

let intersection = rules[0] || [];

for (let i = 1; i < rules.length; i++) {
const currentArray = rules[i] || [];

intersection = (intersection || []).filter((element) =>
currentArray.includes(element)
);
}

return intersection.length > 0;
}

/**
* Tests if some rule disallows any actant
* @param rules
* @returns
*/
static allowsOnlyEmpty(
rules: EntityEnums.ExtendedClass[] | undefined
): boolean {
return (
!rules.length || !!rules.find((r) => r === EntityEnums.Extension.Empty)
!!rules && rules.length === 1 && rules[0] === EntityEnums.Extension.Empty
);
}
}
Loading

0 comments on commit 3967435

Please sign in to comment.