Skip to content

Commit

Permalink
chore: migrating server tests (#304)
Browse files Browse the repository at this point in the history
  • Loading branch information
d-jeffery authored Aug 6, 2024
2 parents 881c78c + 0ce47ba commit ca86c23
Show file tree
Hide file tree
Showing 5 changed files with 589 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ public void raiseAssignableRelationMustHaveTypes(int lineIndex, String symbol) {

public void raiseInvalidType(int lineIndex, String symbol, String typeName) {
var message = "`" + typeName + "` is not a valid type.";
var errorProperties = buildErrorProperties(message, lineIndex, symbol);
var errorProperties = buildErrorProperties(message, lineIndex, symbol, (wordIdx, rawLine, type) -> {
// Split line at definition as InvalidType should mark the value, not the key
var splitLine = rawLine.split(":");
return splitLine[0].length() + splitLine[1].indexOf(typeName) + 1;
});
var metadata = new ValidationMetadata(symbol, ValidationError.InvalidType);
errors.add(new ModelValidationSingleError(errorProperties, metadata));
}
Expand Down
8 changes: 7 additions & 1 deletion pkg/js/transformer/modules/modules-to-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,14 +293,20 @@ function resolveWordIndex(e: ModelValidationSingleError, line: string): number {
return -1;
}

const re = new RegExp("\\b" + metadata.symbol + "\\b");

let wordIdx;
switch (metadata.errorType) {
case ValidationError.InvalidType:
// Split line at definition as InvalidType should mark the value, not the key
const splitLine = line.split(":");
wordIdx = splitLine[0].length + splitLine[1].search(re) + 1;
break;
case ValidationError.TuplesetNotDirect:
const clauseStartsAt = line.indexOf("from") + "from".length;
wordIdx = clauseStartsAt + line.slice(clauseStartsAt).indexOf(metadata.symbol);
break;
default:
const re = new RegExp("\\b" + metadata.symbol + "\\b");
wordIdx = line?.search(re);
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/js/util/exceptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ const createInvalidTypeError = (props: BaseProps, typeName: string) => {
lines,
lineIndex,
metadata: { symbol, errorType: ValidationError.InvalidType, typeName: typeName, file, module, relation },
customResolver: (wordIndex: number, rawLine: string, symbol: string): number => {
// Split line at definition as InvalidType should mark the value, not the key
const re = new RegExp("\\b" + symbol + "\\b");
const splitLine = rawLine.split(":");
return splitLine[0].length + splitLine[1].search(re) + 1;
},
}),
);
};
Expand Down
90 changes: 38 additions & 52 deletions pkg/js/validator/validate-dsl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,13 @@ function hasEntryPointOrLoop(
relationName: string | undefined,
rewrite: Userset,
visitedRecords: Record<string, Record<string, boolean>>,
): [boolean, boolean] {
): { hasEntry: boolean; loop: boolean } {
// Deep copy
const visited = deepCopy(visitedRecords);

if (!relationName) {
// nothing to do if relation is undefined
return [false, false];
return { hasEntry: false, loop: false };
}

if (!visited[typeName]) {
Expand All @@ -162,13 +162,13 @@ function hasEntryPointOrLoop(

const currentRelation = typeMap[typeName].relations;
if (!currentRelation || !currentRelation[relationName]) {
return [false, false];
return { hasEntry: false, loop: false };
}

const relationMetadata = typeMap[typeName].metadata?.relations;

if (!typeMap[typeName].relations || !typeMap[typeName].relations![relationName]) {
return [false, false];
return { hasEntry: false, loop: false };
}

if (rewrite.this) {
Expand All @@ -177,58 +177,57 @@ function hasEntryPointOrLoop(
)) {
const { decodedType, decodedRelation, isWildcard } = destructTupleToUserset(assignableType);
if (!decodedRelation || isWildcard) {
return [true, false];
return { hasEntry: true, loop: false };
}

const assignableRelation = typeMap[decodedType].relations![decodedRelation];
if (!assignableRelation) {
return [false, false];
return { hasEntry: false, loop: false };
}

if (visited[decodedType]?.[decodedRelation]) {
continue;
}

const [hasEntry] = hasEntryPointOrLoop(typeMap, decodedType, decodedRelation, assignableRelation, visited);
const { hasEntry } = hasEntryPointOrLoop(typeMap, decodedType, decodedRelation, assignableRelation, visited);
if (hasEntry) {
return [true, false];
return { hasEntry: true, loop: false };
}
}

return [false, false];
return { hasEntry: false, loop: false };
} else if (rewrite.computedUserset) {
const computedRelationName = rewrite.computedUserset.relation;
if (!computedRelationName) {
return [false, false];
return { hasEntry: false, loop: false };
}

if (!typeMap[typeName].relations![computedRelationName]) {
return [false, false];
return { hasEntry: false, loop: false };
}

const computedRelation = typeMap[typeName].relations![computedRelationName];
if (!computedRelation) {
return [false, false];
return { hasEntry: false, loop: false };
}

// Loop detected
if (visited[typeName][computedRelationName]) {
return [false, true];
return { hasEntry: false, loop: true };
}

const [hasEntry, loop] = hasEntryPointOrLoop(typeMap, typeName, computedRelationName, computedRelation, visited);
return [hasEntry, loop];
return hasEntryPointOrLoop(typeMap, typeName, computedRelationName, computedRelation, visited);
} else if (rewrite.tupleToUserset) {
const tuplesetRelationName = rewrite.tupleToUserset.tupleset.relation;
const computedRelationName = rewrite.tupleToUserset.computedUserset.relation;

if (!tuplesetRelationName || !computedRelationName) {
return [false, false];
return { hasEntry: false, loop: false };
}

const tuplesetRelation = typeMap[typeName].relations![tuplesetRelationName];
if (!tuplesetRelation) {
return [false, false];
return { hasEntry: false, loop: false };
}

for (const assignableType of getTypeRestrictions(
Expand All @@ -240,68 +239,55 @@ function hasEntryPointOrLoop(
continue;
}

const [hasEntry] = hasEntryPointOrLoop(
const { hasEntry } = hasEntryPointOrLoop(
typeMap,
assignableType,
computedRelationName,
assignableRelation,
visited,
);
if (hasEntry) {
return [true, false];
return { hasEntry: true, loop: false };
}
}
}
return [false, false];
return { hasEntry: false, loop: false };
} else if (rewrite.union) {
let loop = false;
let hasLoop = false;

for (const child of rewrite.union.child) {
const [entryPoint, childLoop] = hasEntryPointOrLoop(typeMap, typeName, relationName, child, deepCopy(visited));
if (entryPoint) {
return [true, false];
const { hasEntry, loop } = hasEntryPointOrLoop(typeMap, typeName, relationName, child, deepCopy(visited));
if (hasEntry) {
return { hasEntry: true, loop: false };
}
loop = loop || childLoop;
hasLoop = hasLoop || loop;
}
return [false, loop];
return { hasEntry: false, loop: hasLoop };
} else if (rewrite.intersection) {
for (const child of rewrite.intersection.child) {
const [hasEntry, childLoop] = hasEntryPointOrLoop(typeMap, typeName, relationName, child, deepCopy(visited));
const { hasEntry, loop } = hasEntryPointOrLoop(typeMap, typeName, relationName, child, deepCopy(visited));
if (!hasEntry) {
return [false, childLoop];
return { hasEntry: false, loop };
}
}

return [true, false];
return { hasEntry: true, loop: false };
} else if (rewrite.difference) {
const visited = deepCopy(visitedRecords);

const [hasEntryBase, loopBase] = hasEntryPointOrLoop(
typeMap,
typeName,
relationName,
rewrite.difference.base,
visited,
);
if (!hasEntryBase) {
return [false, loopBase];
const baseResult = hasEntryPointOrLoop(typeMap, typeName, relationName, rewrite.difference.base, visited);
if (!baseResult.hasEntry) {
return { hasEntry: false, loop: baseResult.loop };
}

const [hasEntrySubtract, loopSubtract] = hasEntryPointOrLoop(
typeMap,
typeName,
relationName,
rewrite.difference.subtract,
visited,
);
if (!hasEntrySubtract) {
return [false, loopSubtract];
const subtractResult = hasEntryPointOrLoop(typeMap, typeName, relationName, rewrite.difference.subtract, visited);
if (!subtractResult.hasEntry) {
return { hasEntry: false, loop: subtractResult.loop };
}

return [true, false];
return { hasEntry: true, loop: false };
}

return [false, false];
return { hasEntry: false, loop: false };
}

const geConditionLineNumber = (conditionName: string, lines?: string[], skipIndex?: number) => {
Expand Down Expand Up @@ -465,7 +451,7 @@ function childDefDefined(
for (const item of fromPossibleTypes) {
const { decodedType, decodedRelation, isWildcard, decodedConditionName } = destructTupleToUserset(item);
if (!typeMap[decodedType]) {
// type is not defined
// Split line at definition as InvalidType should mark the value, not the key
const typeIndex = getTypeLineNumber(type, lines);
const lineIndex = getRelationLineNumber(relation, lines, typeIndex);
collector.raiseInvalidType(decodedType, type, relation, { file, module }, lineIndex);
Expand Down Expand Up @@ -725,7 +711,7 @@ function modelValidation(
fileToModuleMap[file].add(module);
}

const [hasEntry, loop] = hasEntryPointOrLoop(
const { hasEntry, loop } = hasEntryPointOrLoop(
typeMap,
typeName,
relationName,
Expand Down
Loading

0 comments on commit ca86c23

Please sign in to comment.