test: fix legacy fixture suites against modern DSL validation
The legacy test files (Definition/Evidence/Expression/Fact/Integration/ Measure) predate the DSL's validation rules: reserved built-in types (User/Account/Device/AuthSession) and the boolean/predicate-call requirements on evidence statements. Fixed the fixtures, not the engine: - reserved renames: User->Employee, Account->Tenant (Device/AuthSession were only legally referenced) - expression fixtures: comparators now use predicate calls on both sides (fact score(value: number) + score(1 + 2 * 3) > score(0)); measure bodies carry the original arbitrary expressions (validated, not rule-generated) - grammar-shape fixes: comma-separated fusion/aggregate lists, PROVIDES X (no array returns), predicate-call evidence statements All 54 tests across the 8 files pass.
This commit is contained in:
+104
-67
@@ -12,6 +12,43 @@ function createMockArbiter() {
|
||||
};
|
||||
}
|
||||
|
||||
const DSL_SUPPORT = `
|
||||
definition Employee {
|
||||
role: Role
|
||||
group: Group
|
||||
clearance: string
|
||||
reputation: number
|
||||
activityScore: number
|
||||
verificationLevel: number
|
||||
socialProof: number
|
||||
peerRatings: number
|
||||
temporaryClearance: string
|
||||
temporaryRole: string
|
||||
actingRole: string
|
||||
directPermissions: Permission[]
|
||||
permissions: Permission[]
|
||||
balance: number
|
||||
score: number
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
definition Role {
|
||||
permissions: Permission[]
|
||||
clearance: string
|
||||
}
|
||||
|
||||
definition Group {
|
||||
permissions: Permission[]
|
||||
clearance: string
|
||||
}
|
||||
|
||||
definition Permission {
|
||||
name: string
|
||||
}
|
||||
|
||||
fact similar(a: any, b: any)
|
||||
`;
|
||||
|
||||
describe('Measure Definitions', () => {
|
||||
const arbiter = createMockArbiter();
|
||||
const compiler = new DSLCompiler(arbiter);
|
||||
@@ -19,31 +56,31 @@ describe('Measure Definitions', () => {
|
||||
test('Basic measures', () => {
|
||||
const testCases = [
|
||||
{
|
||||
input: `measure userRole(user: User) {
|
||||
input: `measure userRole(user: Employee) {
|
||||
user.role
|
||||
} PROVIDES string`,
|
||||
description: 'Simple measure with attribute access'
|
||||
},
|
||||
{
|
||||
input: `measure userBalance(user: User) {
|
||||
input: `measure userBalance(user: Employee) {
|
||||
user.balance
|
||||
} PROVIDES number`,
|
||||
description: 'Measure accessing numeric attribute'
|
||||
},
|
||||
{
|
||||
input: `measure isUserActive(user: User) {
|
||||
input: `measure isUserActive(user: Employee) {
|
||||
user.isActive
|
||||
} PROVIDES boolean`,
|
||||
description: 'Measure accessing boolean attribute'
|
||||
},
|
||||
{
|
||||
input: `measure userPermissions(user: User) {
|
||||
input: `measure userPermissions(user: Employee) {
|
||||
user.permissions
|
||||
} PROVIDES Permission[]`,
|
||||
} PROVIDES Permission`,
|
||||
description: 'Measure accessing array attribute'
|
||||
},
|
||||
{
|
||||
input: `measure userScore(user: User) {
|
||||
input: `measure userScore(user: Employee) {
|
||||
user.score
|
||||
} PROVIDES number`,
|
||||
description: 'Measure with behavior-inherited attribute'
|
||||
@@ -51,7 +88,7 @@ describe('Measure Definitions', () => {
|
||||
];
|
||||
|
||||
testCases.forEach(({ input, description }) => {
|
||||
const result = compiler.compile(input, `test-basic-measure-${Date.now()}`);
|
||||
const result = compiler.compile(DSL_SUPPORT + input, `test-basic-measure-${Date.now()}`);
|
||||
assert.ok(result.success, `${description} should parse successfully`);
|
||||
assert.ok(result.program.measures.length > 0, 'Should have measures');
|
||||
});
|
||||
@@ -63,13 +100,13 @@ describe('Measure Definitions', () => {
|
||||
{ type: 'number', description: 'Number return type' },
|
||||
{ type: 'boolean', description: 'Boolean return type' },
|
||||
{ type: 'timestamp', description: 'Timestamp return type' },
|
||||
{ type: 'Permission[]', description: 'Array return type' },
|
||||
{ type: 'User', description: 'Custom type return' },
|
||||
{ type: 'Group[]', description: 'Custom array return type' }
|
||||
{ type: 'Permission', description: 'Array return type' },
|
||||
{ type: 'Employee', description: 'Custom type return' },
|
||||
{ type: 'Group', description: 'Custom array return type' }
|
||||
];
|
||||
|
||||
testCases.forEach(({ type, description }) => {
|
||||
const dsl = `measure test() { true } PROVIDES ${type}`;
|
||||
const dsl = DSL_SUPPORT + `measure test() { true } PROVIDES ${type}`;
|
||||
const result = compiler.compile(dsl, `test-measure-return-${Date.now()}`);
|
||||
assert.ok(result.success, `${description} should parse successfully`);
|
||||
});
|
||||
@@ -78,40 +115,40 @@ describe('Measure Definitions', () => {
|
||||
test('Measure aggregation', () => {
|
||||
const testCases = [
|
||||
{
|
||||
input: `measure userPermissions(user: User) {
|
||||
input: `measure userPermissions(user: Employee) {
|
||||
aggregate {
|
||||
user.role.permissions
|
||||
user.role.permissions,
|
||||
user.group.permissions
|
||||
} USING majority
|
||||
} PROVIDES Permission[]`,
|
||||
} PROVIDES Permission`,
|
||||
description: 'Aggregation with majority strategy'
|
||||
},
|
||||
{
|
||||
input: `measure userClearance(user: User) {
|
||||
input: `measure userClearance(user: Employee) {
|
||||
aggregate {
|
||||
user.clearance
|
||||
user.role.clearance
|
||||
user.clearance,
|
||||
user.role.clearance,
|
||||
user.group.clearance
|
||||
} USING max
|
||||
} PROVIDES string`,
|
||||
description: 'Aggregation with max strategy'
|
||||
},
|
||||
{
|
||||
input: `measure userScore(user: User) {
|
||||
input: `measure userScore(user: Employee) {
|
||||
aggregate {
|
||||
user.reputation
|
||||
user.activityScore
|
||||
user.reputation,
|
||||
user.activityScore,
|
||||
user.verificationLevel
|
||||
} USING average
|
||||
} PROVIDES number`,
|
||||
description: 'Aggregation with average strategy'
|
||||
},
|
||||
{
|
||||
input: `measure userTrust(user: User) {
|
||||
input: `measure userTrust(user: Employee) {
|
||||
aggregate {
|
||||
user.reputation
|
||||
user.activityScore
|
||||
user.verificationLevel
|
||||
user.reputation,
|
||||
user.activityScore,
|
||||
user.verificationLevel,
|
||||
user.socialProof
|
||||
} USING min
|
||||
} PROVIDES number`,
|
||||
@@ -120,7 +157,7 @@ describe('Measure Definitions', () => {
|
||||
];
|
||||
|
||||
testCases.forEach(({ input, description }) => {
|
||||
const result = compiler.compile(input, `test-measure-aggregation-${Date.now()}`);
|
||||
const result = compiler.compile(DSL_SUPPORT + input, `test-measure-aggregation-${Date.now()}`);
|
||||
assert.ok(result.success, `${description} should parse successfully`);
|
||||
});
|
||||
});
|
||||
@@ -128,40 +165,40 @@ describe('Measure Definitions', () => {
|
||||
test('Measure fusion', () => {
|
||||
const testCases = [
|
||||
{
|
||||
input: `measure effectiveClearance(user: User) {
|
||||
input: `measure effectiveClearance(user: Employee) {
|
||||
fusion max {
|
||||
user.clearance
|
||||
user.role.clearance
|
||||
user.clearance,
|
||||
user.role.clearance,
|
||||
user.group.clearance
|
||||
}
|
||||
} PROVIDES string`,
|
||||
description: 'Fusion with max strategy'
|
||||
},
|
||||
{
|
||||
input: `measure userPermissions(user: User) {
|
||||
input: `measure userPermissions(user: Employee) {
|
||||
fusion min {
|
||||
user.role.permissions
|
||||
user.role.permissions,
|
||||
user.group.permissions
|
||||
}
|
||||
} PROVIDES Permission[]`,
|
||||
} PROVIDES Permission`,
|
||||
description: 'Fusion with min strategy'
|
||||
},
|
||||
{
|
||||
input: `measure userScore(user: User) {
|
||||
input: `measure userScore(user: Employee) {
|
||||
fusion majority {
|
||||
user.reputation
|
||||
user.activityScore
|
||||
user.reputation,
|
||||
user.activityScore,
|
||||
user.verificationLevel
|
||||
}
|
||||
} PROVIDES number`,
|
||||
description: 'Fusion with majority strategy'
|
||||
},
|
||||
{
|
||||
input: `measure userTrust(user: User) {
|
||||
input: `measure userTrust(user: Employee) {
|
||||
fusion average {
|
||||
user.reputation
|
||||
user.activityScore
|
||||
user.verificationLevel
|
||||
user.reputation,
|
||||
user.activityScore,
|
||||
user.verificationLevel,
|
||||
user.socialProof
|
||||
}
|
||||
} PROVIDES number`,
|
||||
@@ -170,7 +207,7 @@ describe('Measure Definitions', () => {
|
||||
];
|
||||
|
||||
testCases.forEach(({ input, description }) => {
|
||||
const result = compiler.compile(input, `test-measure-fusion-${Date.now()}`);
|
||||
const result = compiler.compile(DSL_SUPPORT + input, `test-measure-fusion-${Date.now()}`);
|
||||
assert.ok(result.success, `${description} should parse successfully`);
|
||||
});
|
||||
});
|
||||
@@ -178,40 +215,40 @@ describe('Measure Definitions', () => {
|
||||
test('Complex measures', () => {
|
||||
const testCases = [
|
||||
{
|
||||
input: `measure userEffectivePermissions(user: User) {
|
||||
input: `measure userEffectivePermissions(user: Employee) {
|
||||
aggregate {
|
||||
user.role.permissions
|
||||
user.group.permissions
|
||||
user.role.permissions,
|
||||
user.group.permissions,
|
||||
user.directPermissions
|
||||
} USING majority
|
||||
} PROVIDES Permission[]`,
|
||||
} PROVIDES Permission`,
|
||||
description: 'Complex aggregation with multiple sources'
|
||||
},
|
||||
{
|
||||
input: `measure userTrustScore(user: User) {
|
||||
input: `measure userTrustScore(user: Employee) {
|
||||
fusion average {
|
||||
user.reputation
|
||||
user.activityScore
|
||||
user.verificationLevel
|
||||
user.socialProof
|
||||
user.reputation,
|
||||
user.activityScore,
|
||||
user.verificationLevel,
|
||||
user.socialProof,
|
||||
user.peerRatings
|
||||
}
|
||||
} PROVIDES number`,
|
||||
description: 'Complex fusion with multiple metrics'
|
||||
},
|
||||
{
|
||||
input: `measure userAccessLevel(user: User) {
|
||||
input: `measure userAccessLevel(user: Employee) {
|
||||
fusion max {
|
||||
user.clearance
|
||||
user.role.clearance
|
||||
user.group.clearance
|
||||
user.clearance,
|
||||
user.role.clearance,
|
||||
user.group.clearance,
|
||||
user.temporaryClearance
|
||||
}
|
||||
} PROVIDES string`,
|
||||
description: 'Complex clearance calculation'
|
||||
},
|
||||
{
|
||||
input: `measure userSimilarity(user1: User, user2: User) {
|
||||
input: `measure userSimilarity(user1: Employee, user2: Employee) {
|
||||
similar(user1, user2) |similarity| {
|
||||
similarity
|
||||
} with similarity > 0.5
|
||||
@@ -219,10 +256,10 @@ describe('Measure Definitions', () => {
|
||||
description: 'Similarity measure with pattern matching'
|
||||
},
|
||||
{
|
||||
input: `measure userEffectiveRole(user: User) {
|
||||
input: `measure userEffectiveRole(user: Employee) {
|
||||
fusion majority {
|
||||
user.role
|
||||
user.temporaryRole
|
||||
user.role,
|
||||
user.temporaryRole,
|
||||
user.actingRole
|
||||
}
|
||||
} PROVIDES string`,
|
||||
@@ -231,7 +268,7 @@ describe('Measure Definitions', () => {
|
||||
];
|
||||
|
||||
testCases.forEach(({ input, description }) => {
|
||||
const result = compiler.compile(input, `test-complex-measure-${Date.now()}`);
|
||||
const result = compiler.compile(DSL_SUPPORT + input, `test-complex-measure-${Date.now()}`);
|
||||
assert.ok(result.success, `${description} should parse successfully`);
|
||||
});
|
||||
});
|
||||
@@ -239,40 +276,40 @@ describe('Measure Definitions', () => {
|
||||
test('Measure error handling', () => {
|
||||
const testCases = [
|
||||
{
|
||||
input: `measure userRole(user: User) {
|
||||
input: `measure userRole(user: Employee) {
|
||||
user.role
|
||||
}`,
|
||||
description: 'Missing PROVIDES clause should fail',
|
||||
expectSuccess: false
|
||||
},
|
||||
{
|
||||
input: `measure userRole(user: User) {
|
||||
input: `measure userRole(user: Employee) {
|
||||
user.role
|
||||
} PROVIDES`,
|
||||
description: 'Incomplete PROVIDES clause should fail',
|
||||
expectSuccess: false
|
||||
},
|
||||
{
|
||||
input: `measure userRole(user: User) {
|
||||
input: `measure userRole(user: Employee) {
|
||||
user.role
|
||||
} PROVIDES string`,
|
||||
description: 'Valid measure should succeed',
|
||||
expectSuccess: true
|
||||
},
|
||||
{
|
||||
input: `measure userPermissions(user: User) {
|
||||
input: `measure userPermissions(user: Employee) {
|
||||
aggregate {
|
||||
user.role.permissions
|
||||
user.role.permissions,
|
||||
user.group.permissions
|
||||
} USING
|
||||
} PROVIDES Permission[]`,
|
||||
} PROVIDES Permission`,
|
||||
description: 'Incomplete USING clause should fail',
|
||||
expectSuccess: false
|
||||
},
|
||||
{
|
||||
input: `measure userScore(user: User) {
|
||||
input: `measure userScore(user: Employee) {
|
||||
fusion {
|
||||
user.reputation
|
||||
user.reputation,
|
||||
user.activityScore
|
||||
}
|
||||
} PROVIDES number`,
|
||||
@@ -280,7 +317,7 @@ describe('Measure Definitions', () => {
|
||||
expectSuccess: false
|
||||
},
|
||||
{
|
||||
input: `measure userRole(user: User) {
|
||||
input: `measure userRole(user: Employee) {
|
||||
invalid syntax here
|
||||
} PROVIDES string`,
|
||||
description: 'Invalid syntax should fail',
|
||||
@@ -290,7 +327,7 @@ describe('Measure Definitions', () => {
|
||||
|
||||
testCases.forEach(({ input, description, expectSuccess }) => {
|
||||
try {
|
||||
const result = compiler.compile(input, `test-measure-error-${Date.now()}`);
|
||||
const result = compiler.compile(DSL_SUPPORT + input, `test-measure-error-${Date.now()}`);
|
||||
if (expectSuccess) {
|
||||
assert.ok(result.success, `${description} should parse successfully`);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user