From f8f6c5cb1b2653842c1b17f6e911094b32c70a27 Mon Sep 17 00:00:00 2001 From: John Dvorak Date: Sun, 2 Aug 2026 21:03:37 -0700 Subject: [PATCH] cleanup: remove dead code, stale shipped scaffolding, internal docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dead code with zero callers (deprecation notes promised removal): - RelationCSR index: always-off option (useRelationCsrIndex), never enabled in production, wired through RelationManager/RelationUpdates/ RelationLookup. Removed the module and all wiring. - getAggregatedBlurredValue (RelationManager) and aggregateBlurredValues (ValueManager): @deprecated shims, zero callers. - QualitativeRelationalComparatorRule._aggregateBlurredValues: @deprecated shim, zero callers. Kept compareRelationValues: non-deprecated public API, coherent and clock-threaded, just currently callerless. Stale scaffolding shipping in the published artifact (files: src/): - src/ast/tests/* and src/ast/examples/*: orphaned duplicates of tests/ast/, zero references anywhere, 11 files in the tarball. Removed; the live copies live in tests/ast/. Internal docs moved out of the shipped surface (1266 lines) to docs/internal/: VALUE_OPTIMIZATION_SUMMARY, rules API_SPECIFICATION, ast README, qualitative README — repo-kept, not packaged. Tarball .md count: 11 -> 1. Rigor 251/251, full suite 853/791/0. --- .../internal}/VALUE_OPTIMIZATION_SUMMARY.md | 0 .../README.md => docs/internal/ast-README.md | 0 .../internal/qualitative-README.md | 0 .../internal/rules-API_SPECIFICATION.md | 0 src/ast/examples/ProgressiveTestSuite.js | 352 ---------- src/ast/examples/SimpleEvidenceTest.js | 53 -- src/ast/tests/DefinitionTests.js | 381 ----------- src/ast/tests/EvidenceTests.js | 464 ------------- src/ast/tests/ExpressionTests.js | 347 ---------- src/ast/tests/FactTests.js | 330 --------- src/ast/tests/IntegrationTests.js | 635 ------------------ src/ast/tests/MeasureTests.js | 393 ----------- src/ast/tests/README.md | 249 ------- src/ast/tests/StructuralLinguisticTests.js | 0 src/ast/tests/TestRunner.js | 413 ------------ .../QualitativeRelationalComparatorRule.js | 11 - src/core/RelationManager.js | 39 -- src/core/ValueManager.js | 11 - src/core/relation/RelationCSR.js | 154 ----- src/core/relation/RelationLookup.js | 8 - src/core/relation/RelationUpdates.js | 3 - 21 files changed, 3843 deletions(-) rename {src/authorization => docs/internal}/VALUE_OPTIMIZATION_SUMMARY.md (100%) rename src/ast/README.md => docs/internal/ast-README.md (100%) rename src/qualitative/README.md => docs/internal/qualitative-README.md (100%) rename src/authorization/rules/API_SPECIFICATION.md => docs/internal/rules-API_SPECIFICATION.md (100%) delete mode 100644 src/ast/examples/ProgressiveTestSuite.js delete mode 100644 src/ast/examples/SimpleEvidenceTest.js delete mode 100644 src/ast/tests/DefinitionTests.js delete mode 100644 src/ast/tests/EvidenceTests.js delete mode 100644 src/ast/tests/ExpressionTests.js delete mode 100644 src/ast/tests/FactTests.js delete mode 100644 src/ast/tests/IntegrationTests.js delete mode 100644 src/ast/tests/MeasureTests.js delete mode 100644 src/ast/tests/README.md delete mode 100644 src/ast/tests/StructuralLinguisticTests.js delete mode 100644 src/ast/tests/TestRunner.js delete mode 100644 src/core/relation/RelationCSR.js diff --git a/src/authorization/VALUE_OPTIMIZATION_SUMMARY.md b/docs/internal/VALUE_OPTIMIZATION_SUMMARY.md similarity index 100% rename from src/authorization/VALUE_OPTIMIZATION_SUMMARY.md rename to docs/internal/VALUE_OPTIMIZATION_SUMMARY.md diff --git a/src/ast/README.md b/docs/internal/ast-README.md similarity index 100% rename from src/ast/README.md rename to docs/internal/ast-README.md diff --git a/src/qualitative/README.md b/docs/internal/qualitative-README.md similarity index 100% rename from src/qualitative/README.md rename to docs/internal/qualitative-README.md diff --git a/src/authorization/rules/API_SPECIFICATION.md b/docs/internal/rules-API_SPECIFICATION.md similarity index 100% rename from src/authorization/rules/API_SPECIFICATION.md rename to docs/internal/rules-API_SPECIFICATION.md diff --git a/src/ast/examples/ProgressiveTestSuite.js b/src/ast/examples/ProgressiveTestSuite.js deleted file mode 100644 index 9d21ca2..0000000 --- a/src/ast/examples/ProgressiveTestSuite.js +++ /dev/null @@ -1,352 +0,0 @@ -import { DSLCompiler } from '../DSLCompiler.js'; -import { Arbiter } from '../../core/Arbiter.js'; - -/** - * Progressive Test Suite - Tests each language feature incrementally - */ -export function runProgressiveTestSuite() { - console.log('=== Progressive DSL Test Suite ===\n'); - - const arbiter = new Arbiter(); - const compiler = new DSLCompiler(arbiter); - - const tests = [ - { - name: '1. Basic Definitions', - dsl: ` -definition User { - name: string - age: number -}`, - expected: { definitions: 1, facts: 0, evidence: 0, measures: 0 } - }, - { - name: '2. Definitions with Arrays', - dsl: ` -definition User { - name: string - roles: string[] - permissions: Permission[] -}`, - expected: { definitions: 1, facts: 0, evidence: 0, measures: 0 } - }, - { - name: '3. Definitions with Behaviors', - dsl: ` -definition User { - name: string - lastActive: timestamp BEHAVES { - decaying down hourly - } - score: number BEHAVES { - blurring adaptive confidence_95 - } - session: string BEHAVES { - ttl 24h - } -}`, - expected: { definitions: 1, facts: 0, evidence: 0, measures: 0 } - }, - { - name: '4. Definitions with Cache Directives', - dsl: ` -definition User { - name: string - lastActive: timestamp BEHAVES { - decaying down hourly - } CACHE lazy - score: number BEHAVES { - blurring adaptive confidence_95 - } CACHE eager -}`, - expected: { definitions: 1, facts: 0, evidence: 0, measures: 0 } - }, - { - name: '5. Basic Facts', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) -fact isActive(user: User)`, - expected: { definitions: 1, facts: 2, evidence: 0, measures: 0 } - }, - { - name: '6. Facts with Properties', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) CACHE eager -fact isMember(user: User, group: Group) transitive CACHE lazy -fact isFriend(user: User, friend: User) symmetrical`, - expected: { definitions: 1, facts: 3, evidence: 0, measures: 0 } - }, - { - name: '7. Facts with Limits', - dsl: ` -definition User { - name: string -} - -fact isMember(user: User, group: Group) transitive limit 10 -fact isFriend(user: User, friend: User) symmetrical limit 100`, - expected: { definitions: 1, facts: 2, evidence: 0, measures: 0 } - }, - { - name: '8. Simple Evidence', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) - -evidence canRead(user: User, doc: Document) { - hasRole(user, 'admin') -}`, - expected: { definitions: 1, facts: 1, evidence: 1, measures: 0 } - }, - { - name: '9. Evidence with Multiple Statements', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) -fact owns(user: User, doc: Document) - -evidence canRead(user: User, doc: Document) { - owns(user, doc) - hasRole(user, 'admin') -}`, - expected: { definitions: 1, facts: 2, evidence: 1, measures: 0 } - }, - { - name: '10. Evidence with ALWAYS', - dsl: ` -definition User { - name: string -} - -fact isActive(user: User) - -evidence canRead(user: User, doc: Document) { - ALWAYS isActive(user) -}`, - expected: { definitions: 1, facts: 1, evidence: 1, measures: 0 } - }, - { - name: '11. Evidence with REQUIRES', - dsl: ` -definition User { - name: string -} - -fact hasClearance(user: User, level: string) - -evidence canRead(user: User, doc: Document) { - REQUIRES hasClearance(user, doc.level) -}`, - expected: { definitions: 1, facts: 1, evidence: 1, measures: 0 } - }, - { - name: '12. Evidence with WHEN', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) - -evidence canRead(user: User, doc: Document) { - WHEN hasRole(user, 'admin') -}`, - expected: { definitions: 1, facts: 1, evidence: 1, measures: 0 } - }, - { - name: '13. Evidence with WHEN UNLESS', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) -fact isSuspended(user: User) - -evidence canRead(user: User, doc: Document) { - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) -}`, - expected: { definitions: 1, facts: 2, evidence: 1, measures: 0 } - }, - { - name: '14. Evidence with Pattern Matching', - dsl: ` -definition User { - name: string -} - -fact isMember(user: User, group: Group) - -evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - canRead(group, doc) - } -}`, - expected: { definitions: 1, facts: 1, evidence: 1, measures: 0 } - }, - { - name: '15. Evidence with Pattern Matching and Limits', - dsl: ` -definition User { - name: string -} - -fact isMember(user: User, group: Group) - -evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - canRead(group, doc) - } limit 5 -}`, - expected: { definitions: 1, facts: 1, evidence: 1, measures: 0 } - }, - { - name: '16. Evidence with Fusion', - dsl: ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) -fact isMember(user: User, group: Group) - -evidence canRead(user: User, doc: Document) { - fusion max { - hasRole(user, 'admin') - isMember(user, *group) { - canRead(group, doc) - } - } -}`, - expected: { definitions: 1, facts: 2, evidence: 1, measures: 0 } - }, - { - name: '17. Basic Measures', - dsl: ` -definition User { - name: string - role: string -} - -measure userRole(user: User) { - user.role -} PROVIDES string`, - expected: { definitions: 1, facts: 0, evidence: 0, measures: 1 } - }, - { - name: '18. Measures with Fusion', - dsl: ` -definition User { - name: string - role: string -} - -fact hasRole(user: User, role: string) - -measure userPermissions(user: User) { - fusion max { - user.role.permissions - hasRole(user, 'admin') - } -} PROVIDES Permission[]`, - expected: { definitions: 1, facts: 1, evidence: 0, measures: 1 } - }, - { - name: '19. Complete Example', - dsl: ` -definition User { - role: string - isActive: boolean - lastActive: timestamp BEHAVES { - decaying down hourly - } CACHE lazy -} - -definition Document { - level: string - owner: User -} - -fact hasRole(user: User, role: string) CACHE eager -fact owns(user: User, doc: Document) CACHE eager - -evidence canRead(user: User, doc: Document) { - owns(user, doc) - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) -} - -measure userRole(user: User) { - user.role -} PROVIDES string`, - expected: { definitions: 2, facts: 2, evidence: 1, measures: 1 } - } - ]; - - let passed = 0; - let failed = 0; - - for (const test of tests) { - console.log(`\n--- ${test.name} ---`); - - try { - const result = compiler.compile(test.dsl, `test-${passed + failed + 1}`); - - const actual = { - definitions: result.program.definitions.length, - facts: result.program.facts.length, - evidence: result.program.evidence.length, - measures: result.program.measures.length - }; - - const success = result.success && - actual.definitions === test.expected.definitions && - actual.facts === test.expected.facts && - actual.evidence === test.expected.evidence && - actual.measures === test.expected.measures; - - if (success) { - console.log('✅ PASSED'); - console.log(` Definitions: ${actual.definitions}, Facts: ${actual.facts}, Evidence: ${actual.evidence}, Measures: ${actual.measures}`); - passed++; - } else { - console.log('❌ FAILED'); - console.log(` Expected: ${JSON.stringify(test.expected)}`); - console.log(` Actual: ${JSON.stringify(actual)}`); - if (result.errors.length > 0) { - console.log(` Errors: ${result.errors.join(', ')}`); - } - failed++; - } - } catch (error) { - console.log('❌ FAILED'); - console.log(` Error: ${error.message}`); - failed++; - } - } - - console.log(`\n=== Test Suite Results ===`); - console.log(`Total Tests: ${passed + failed}`); - console.log(`Passed: ${passed}`); - console.log(`Failed: ${failed}`); - console.log(`Success Rate: ${((passed / (passed + failed)) * 100).toFixed(1)}%`); - - return { passed, failed, total: passed + failed }; -} - -// Run the test suite -runProgressiveTestSuite(); diff --git a/src/ast/examples/SimpleEvidenceTest.js b/src/ast/examples/SimpleEvidenceTest.js deleted file mode 100644 index 259a133..0000000 --- a/src/ast/examples/SimpleEvidenceTest.js +++ /dev/null @@ -1,53 +0,0 @@ -import { DSLCompiler } from '../DSLCompiler.js'; -import { Arbiter } from '../../core/Arbiter.js'; - -/** - * Test with simple evidence containing predicate calls - */ -export function runSimpleEvidenceTest() { - console.log('=== Simple Evidence Test ===\n'); - - // Create arbiter instance - const arbiter = new Arbiter(); - - // Create compiler - const compiler = new DSLCompiler(arbiter); - - // Simple evidence with predicate call - const dsl = ` -definition User { - name: string -} - -fact hasRole(user: User, role: string) - -evidence canRead(user: User, doc: Document) { - hasRole(user, 'admin') -} - `; - - console.log('1. Compiling DSL with simple evidence...'); - try { - const result = compiler.compile(dsl, 'simple-evidence'); - - console.log('Result:', result.success ? 'SUCCESS' : 'FAILED'); - console.log('Generated rules:', result.generatedRules.size); - console.log('Program evidence:', result.program.evidence.length); - - if (result.errors.length > 0) { - console.log('Errors:', result.errors); - } - - if (result.warnings.length > 0) { - console.log('Warnings:', result.warnings); - } - - return result; - } catch (error) { - console.error('Compilation failed:', error.message); - return { success: false, error: error.message }; - } -} - -// Run the test -runSimpleEvidenceTest(); diff --git a/src/ast/tests/DefinitionTests.js b/src/ast/tests/DefinitionTests.js deleted file mode 100644 index 3957490..0000000 --- a/src/ast/tests/DefinitionTests.js +++ /dev/null @@ -1,381 +0,0 @@ -/** - * Type Definition Tests - * - * Tests the type definition system of the Evidence DSL, - * including fields, behaviors, caching, and complex type structures. - */ - -import { DSLCompiler } from '../DSLCompiler.js'; - -export class DefinitionTests { - constructor() { - this.arbiter = null; - this.compiler = null; - this.testResults = []; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.compiler = new DSLCompiler(arbiter); - } - - runAllTests() { - console.log('=== Type Definition Tests ===\n'); - - this.testBasicDefinitions(); - this.testFieldTypes(); - this.testArrayTypes(); - this.testBehaviors(); - this.testCaching(); - this.testComplexDefinitions(); - this.testDefinitionErrors(); - - return this.getTestResults(); - } - - testBasicDefinitions() { - console.log('Testing Basic Definitions...'); - - const testCases = [ - { - input: `definition User { role: string }`, - description: 'Simple definition with one field' - }, - { - input: `definition User { - role: string - isActive: boolean - }`, - description: 'Definition with multiple fields' - }, - { - input: `definition Group { - name: string - description: string - created: timestamp - }`, - description: 'Definition with different field types' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-basic-def-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - this.assert(result.program.definitions.length > 0, 'Should have definitions'); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Basic definition test: ${description}`, error); - } - }); - } - - testFieldTypes() { - console.log('Testing Field Types...'); - - const testCases = [ - { type: 'string', description: 'String field type' }, - { type: 'number', description: 'Number field type' }, - { type: 'boolean', description: 'Boolean field type' }, - { type: 'timestamp', description: 'Timestamp field type' }, - { type: 'User', description: 'Custom type field' }, - { type: 'Permission', description: 'Another custom type field' } - ]; - - testCases.forEach(({ type, description }) => { - try { - const dsl = `definition Test { field: ${type} }`; - const result = this.compiler.compile(dsl, `test-field-type-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Field type test: ${description}`, error); - } - }); - } - - testArrayTypes() { - console.log('Testing Array Types...'); - - const testCases = [ - { type: 'string[]', description: 'String array' }, - { type: 'number[]', description: 'Number array' }, - { type: 'boolean[]', description: 'Boolean array' }, - { type: 'Permission[]', description: 'Custom type array' }, - { type: 'User[]', description: 'User array' } - ]; - - testCases.forEach(({ type, description }) => { - try { - const dsl = `definition Test { items: ${type} }`; - const result = this.compiler.compile(dsl, `test-array-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Array type test: ${description}`, error); - } - }); - } - - testBehaviors() { - console.log('Testing Behaviors...'); - - const testCases = [ - { - input: `definition User { - balance: number BEHAVES { decaying down hourly } - }`, - description: 'Decay behavior - down hourly' - }, - { - input: `definition User { - reputation: number BEHAVES { decaying up daily } - }`, - description: 'Decay behavior - up daily' - }, - { - input: `definition User { - score: number BEHAVES { decaying neutral weekly } - }`, - description: 'Decay behavior - neutral weekly' - }, - { - input: `definition User { - stability: number BEHAVES { decaying stable monthly } - }`, - description: 'Decay behavior - stable monthly' - }, - { - input: `definition User { - confidence: number BEHAVES { blurring fixed } - }`, - description: 'Blur behavior - fixed' - }, - { - input: `definition User { - accuracy: number BEHAVES { blurring adaptive } - }`, - description: 'Blur behavior - adaptive' - }, - { - input: `definition User { - precision: number BEHAVES { blurring confidence confidence_90 } - }`, - description: 'Blur behavior - confidence with level' - }, - { - input: `definition User { - session: string BEHAVES { ttl 1h } - }`, - description: 'TTL behavior - hours' - }, - { - input: `definition User { - token: string BEHAVES { ttl 24h } - }`, - description: 'TTL behavior - 24 hours' - }, - { - input: `definition User { - cache: string BEHAVES { ttl 7d } - }`, - description: 'TTL behavior - days' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-behavior-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Behavior test: ${description}`, error); - } - }); - } - - testCaching() { - console.log('Testing Caching...'); - - const testCases = [ - { - input: `definition User { - role: string CACHE eager - }`, - description: 'Eager caching' - }, - { - input: `definition User { - score: number CACHE lazy - }`, - description: 'Lazy caching' - }, - { - input: `definition User { - balance: number BEHAVES { decaying down hourly } CACHE eager - }`, - description: 'Behavior with eager caching' - }, - { - input: `definition User { - reputation: number BEHAVES { blurring adaptive } CACHE lazy - }`, - description: 'Behavior with lazy caching' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-cache-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Cache test: ${description}`, error); - } - }); - } - - testComplexDefinitions() { - console.log('Testing Complex Definitions...'); - - const testCases = [ - { - input: `definition User { - role: string - isActive: boolean - lastActive: timestamp BEHAVES { - decaying down hourly - } CACHE lazy - isSuspended: boolean - balance: number BEHAVES { - decaying down hourly - } CACHE eager - score: number BEHAVES { - blurring adaptive confidence_95 - } CACHE lazy - session: string BEHAVES { - ttl 24h - } CACHE eager - }`, - description: 'Complex definition with multiple behaviors and caching' - }, - { - input: `definition Group { - name: string - permissions: Permission[] - members: User[] - created: timestamp BEHAVES { - decaying stable monthly - } CACHE lazy - isPublic: boolean CACHE eager - }`, - description: 'Definition with arrays and mixed behaviors' - }, - { - input: `definition Document { - level: string - owner: User - tags: string[] - content: string BEHAVES { - blurring fixed - } CACHE lazy - accessCount: number BEHAVES { - decaying up daily - } CACHE eager - expiresAt: timestamp BEHAVES { - ttl 30d - } CACHE eager - }`, - description: 'Definition with all behavior types' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-complex-def-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - this.assert(result.program.definitions.length > 0, 'Should have definitions'); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Complex definition test: ${description}`, error); - } - }); - } - - testDefinitionErrors() { - console.log('Testing Definition Error Handling...'); - - const testCases = [ - { - input: `definition User { role: string`, - description: 'Missing closing brace should fail' - }, - { - input: `definition User { role: }`, - description: 'Missing field type should fail' - }, - { - input: `definition User { : string }`, - description: 'Missing field name should fail' - }, - { - input: `definition User { role: string BEHAVES { }`, - description: 'Incomplete behavior should fail' - }, - { - input: `definition User { role: string CACHE }`, - description: 'Incomplete cache directive should fail' - }, - { - input: `definition User { role: string BEHAVES { invalid } }`, - description: 'Invalid behavior should fail' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-def-error-${Date.now()}`); - this.assert(!result.success, `${description} should fail to parse`); - console.log(` ✓ ${description} (correctly failed)`); - } catch (error) { - // Expected to fail - console.log(` ✓ ${description} (correctly failed)`); - } - }); - } - - assert(condition, message) { - if (!condition) { - throw new Error(`Assertion failed: ${message}`); - } - } - - fail(testName, error) { - console.log(` ✗ ${testName} failed: ${error.message}`); - this.testResults.push({ - test: testName, - status: 'FAILED', - error: error.message - }); - } - - getTestResults() { - const passed = this.testResults.filter(r => r.status === 'PASSED').length; - const failed = this.testResults.filter(r => r.status === 'FAILED').length; - const total = this.testResults.length; - - return { - total: total, - passed: passed, - failed: failed, - success: failed === 0, - results: this.testResults - }; - } -} - -export function runDefinitionTests(arbiter) { - const test = new DefinitionTests(); - test.setup(arbiter); - return test.runAllTests(); -} diff --git a/src/ast/tests/EvidenceTests.js b/src/ast/tests/EvidenceTests.js deleted file mode 100644 index fd5cce3..0000000 --- a/src/ast/tests/EvidenceTests.js +++ /dev/null @@ -1,464 +0,0 @@ -/** - * Evidence Rule Tests - * - * Tests the evidence rule system of the Evidence DSL, - * including defeasible logic, pattern matching, fusion, and complex evidence composition. - */ - -import { DSLCompiler } from '../DSLCompiler.js'; - -export class EvidenceTests { - constructor() { - this.arbiter = null; - this.compiler = null; - this.testResults = []; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.compiler = new DSLCompiler(arbiter); - } - - runAllTests() { - console.log('=== Evidence Rule Tests ===\n'); - - this.testBasicEvidence(); - this.testDefeasibleLogic(); - this.testPatternMatching(); - this.testFusion(); - this.testComplexEvidence(); - this.testEvidenceErrors(); - - return this.getTestResults(); - } - - testBasicEvidence() { - console.log('Testing Basic Evidence...'); - - const testCases = [ - { - input: `evidence canRead(user: User, doc: Document) { - hasRole(user, 'admin') - }`, - description: 'Simple evidence with function call' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - user.isActive - }`, - description: 'Evidence with attribute access' - }, - { - input: `evidence canModify(user: User, doc: Document) { - user.isActive - hasRole(user, 'admin') - }`, - description: 'Evidence with multiple conditions' - }, - { - input: `evidence canDelete(user: User, doc: Document) { - owns(user, doc) - user.isActive - }`, - description: 'Evidence with ownership and status' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-basic-evidence-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - this.assert(result.program.evidence.length > 0, 'Should have evidence'); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Basic evidence test: ${description}`, error); - } - }); - } - - testDefeasibleLogic() { - console.log('Testing Defeasible Logic...'); - - const testCases = [ - { - input: `evidence canAccess(user: User, resource: Resource) { - ALWAYS user.isActive - }`, - description: 'ALWAYS rule - strict requirement' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - WHEN hasRole(user, 'admin') - }`, - description: 'WHEN rule - defeasible condition' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - }`, - description: 'WHEN/UNLESS rule - defeasible with defeater' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - REQUIRES hasClearance(user, resource.level) - }`, - description: 'REQUIRES rule - inverse defeater' - }, - { - input: `evidence canAccessCritical(user: User, resource: Resource) { - ALWAYS user.isActive - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - - REQUIRES hasClearance(user, resource.level) - }`, - description: 'Complex defeasible logic with all rule types' - }, - { - input: `evidence canAccessSensitive(user: User, doc: Document) { - ALWAYS user.isActive - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - - REQUIRES hasClearance(user, doc.level) - - fusion majority { - user.isTrusted - user.hasRecentActivity - } - }`, - description: 'Defeasible logic with fusion' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-defeasible-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Defeasible logic test: ${description}`, error); - } - }); - } - - testPatternMatching() { - console.log('Testing Pattern Matching...'); - - const testCases = [ - { - input: `evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - canRead(group, doc) - } - }`, - description: 'Basic pattern matching with wildcard' - }, - { - input: `evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - canRead(group, doc) - } limit 5 - }`, - description: 'Pattern matching with limit' - }, - { - input: `evidence canRead(user: User, doc: Document) { - similar(doc, *similar) |similarity| { - canRead(user, similar) - } with similarity > 0.7 - }`, - description: 'Pattern matching with binding and condition' - }, - { - input: `evidence canRead(user: User, doc: Document) { - similar(doc, *similar) |similarity| { - canRead(user, similar) - } with similarity > 0.7 limit 5 - }`, - description: 'Pattern matching with binding, condition, and limit' - }, - { - input: `evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - isMember(group, *parentGroup) { - canRead(parentGroup, doc) - } limit 2 - } limit 3 - }`, - description: 'Nested pattern matching' - }, - { - input: `evidence canRead(user: User, doc: Document) { - isFriend(user, *friend) { - isMember(friend, *group) { - canRead(group, doc) - } limit 1 - } limit 5 - }`, - description: 'Multi-hop pattern matching' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-pattern-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Pattern matching test: ${description}`, error); - } - }); - } - - testFusion() { - console.log('Testing Fusion...'); - - const testCases = [ - { - input: `evidence canAccess(user: User, resource: Resource) { - fusion min { - hasClearance(user, resource.level) - user.isActive - } - }`, - description: 'Min fusion - all conditions must be true' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - fusion max { - hasRole(user, 'admin') - hasRole(user, 'superuser') - } - }`, - description: 'Max fusion - any condition can be true' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - fusion majority { - hasClearance(user, 'secret') - user.isTrusted - user.hasRecentActivity - } - }`, - description: 'Majority fusion - most conditions must be true' - }, - { - input: `evidence canAccessCritical(user: User, resource: Resource) { - fusion min { - hasClearance(user, resource.level) - user.isActive - NOT user.isBlacklisted - } - - fusion max { - hasRole(user, 'admin') - fusion majority { - hasClearance(user, 'secret') - user.isTrusted - user.lastActive within 1hr - } - } - }`, - description: 'Nested fusion with different strategies' - }, - { - input: `evidence canAccess(user: User, resource: Resource) { - fusion average { - user.reputation - user.activityScore - user.verificationLevel - } - }`, - description: 'Average fusion for numeric values' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-fusion-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Fusion test: ${description}`, error); - } - }); - } - - testComplexEvidence() { - console.log('Testing Complex Evidence...'); - - const testCases = [ - { - input: `evidence canRead(user: User, doc: Document) { - owns(user, doc) - - isMember(user, *group) { - canRead(group, doc) - } limit 5 - - parentOf(user, *parent) { - canRead(parent, doc) - } limit 3 - - similar(doc, *similar) |similarity| { - canRead(user, similar) - } with similarity > 0.7 limit 5 - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - }`, - description: 'Complex evidence with all features' - }, - { - input: `evidence canAccessCritical(user: User, resource: Resource) { - ALWAYS user.isActive - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - - REQUIRES hasClearance(user, resource.level) - - fusion min { - hasClearance(user, resource.level) - user.isActive - NOT user.isBlacklisted - } - - fusion max { - hasRole(user, 'admin') - fusion majority { - hasClearance(user, 'secret') - user.isTrusted - user.lastActive within 1hr - } - } - }`, - description: 'Critical access with all rule types and fusion' - }, - { - input: `evidence canModify(user: User, doc: Document) { - owns(user, doc) - - isMember(user, *group) { - canModify(group, doc) - } limit 3 - - similar(doc, *similar) |similarity| { - canModify(user, similar) - similar.isEditable - } with similarity > 0.8 limit 2 - - fusion majority { - user.isTrusted - user.hasRecentActivity - doc.isPublic - } - }`, - description: 'Modification access with similarity and fusion' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-complex-evidence-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Complex evidence test: ${description}`, error); - } - }); - } - - testEvidenceErrors() { - console.log('Testing Evidence Error Handling...'); - - const testCases = [ - { - input: `evidence canRead(user: User, doc: Document) { - hasRole(user, 'admin' - }`, - description: 'Missing closing parenthesis should fail' - }, - { - input: `evidence canRead(user: User, doc: Document) { - WHEN hasRole(user, 'admin') UNLESS - }`, - description: 'Incomplete UNLESS condition should fail' - }, - { - input: `evidence canRead(user: User, doc: Document) { - fusion min { - hasRole(user, 'admin') - }`, - description: 'Incomplete fusion should fail' - }, - { - input: `evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - canRead(group, doc) - } with - }`, - description: 'Incomplete with clause should fail' - }, - { - input: `evidence canRead(user: User, doc: Document) { - isMember(user, *group) { - canRead(group, doc) - } limit - }`, - description: 'Incomplete limit should fail' - }, - { - input: `evidence canRead(user: User, doc: Document) { - invalid syntax here - }`, - description: 'Invalid syntax should fail' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-evidence-error-${Date.now()}`); - this.assert(!result.success, `${description} should fail to parse`); - console.log(` ✓ ${description} (correctly failed)`); - } catch (error) { - // Expected to fail - console.log(` ✓ ${description} (correctly failed)`); - } - }); - } - - assert(condition, message) { - if (!condition) { - throw new Error(`Assertion failed: ${message}`); - } - } - - fail(testName, error) { - console.log(` ✗ ${testName} failed: ${error.message}`); - this.testResults.push({ - test: testName, - status: 'FAILED', - error: error.message - }); - } - - getTestResults() { - const passed = this.testResults.filter(r => r.status === 'PASSED').length; - const failed = this.testResults.filter(r => r.status === 'FAILED').length; - const total = this.testResults.length; - - return { - total: total, - passed: passed, - failed: failed, - success: failed === 0, - results: this.testResults - }; - } -} - -export function runEvidenceTests(arbiter) { - const test = new EvidenceTests(); - test.setup(arbiter); - return test.runAllTests(); -} diff --git a/src/ast/tests/ExpressionTests.js b/src/ast/tests/ExpressionTests.js deleted file mode 100644 index 984bef6..0000000 --- a/src/ast/tests/ExpressionTests.js +++ /dev/null @@ -1,347 +0,0 @@ -/** - * Expression Parsing Tests - * - * Tests the expression parsing capabilities of the Evidence DSL, - * focusing on operator precedence, associativity, and complex expressions. - */ - -import { DSLCompiler } from '../DSLCompiler.js'; - -export class ExpressionTests { - constructor() { - this.arbiter = null; - this.compiler = null; - this.testResults = []; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.compiler = new DSLCompiler(arbiter); - } - - runAllTests() { - console.log('=== Expression Parsing Tests ===\n'); - - this.testArithmeticPrecedence(); - this.testLogicalPrecedence(); - this.testComparisonOperators(); - this.testTemporalExpressions(); - this.testUnaryOperators(); - this.testAttributeAccess(); - this.testFunctionCalls(); - this.testComplexExpressions(); - this.testExpressionErrors(); - - return this.getTestResults(); - } - - testArithmeticPrecedence() { - console.log('Testing Arithmetic Operator Precedence...'); - - const testCases = [ - { - input: '1 + 2 * 3', - expected: 'Should evaluate as 1 + (2 * 3) = 7', - description: 'Multiplication before addition' - }, - { - input: '10 - 3 * 2', - expected: 'Should evaluate as 10 - (3 * 2) = 4', - description: 'Multiplication before subtraction' - }, - { - input: '8 / 2 * 4', - expected: 'Should evaluate as (8 / 2) * 4 = 16', - description: 'Left-associative division and multiplication' - }, - { - input: '2 + 3 * 4 - 5', - expected: 'Should evaluate as 2 + (3 * 4) - 5 = 9', - description: 'Mixed arithmetic with correct precedence' - }, - { - input: '(1 + 2) * 3', - expected: 'Should evaluate as (1 + 2) * 3 = 9', - description: 'Parentheses override precedence' - } - ]; - - testCases.forEach(({ input, expected, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-arithmetic-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Arithmetic precedence test: ${description}`, error); - } - }); - } - - testLogicalPrecedence() { - console.log('Testing Logical Operator Precedence...'); - - const testCases = [ - { - input: 'true && false || true', - expected: 'Should evaluate as (true && false) || true = true', - description: 'AND before OR' - }, - { - input: 'false || true && false', - expected: 'Should evaluate as false || (true && false) = false', - description: 'AND before OR (alternative)' - }, - { - input: 'NOT true && false', - expected: 'Should evaluate as (NOT true) && false = false', - description: 'NOT before AND' - }, - { - input: 'true && NOT false', - expected: 'Should evaluate as true && (NOT false) = true', - description: 'NOT before AND (alternative)' - }, - { - input: '(true || false) && true', - expected: 'Should evaluate as (true || false) && true = true', - description: 'Parentheses override logical precedence' - } - ]; - - testCases.forEach(({ input, expected, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-logical-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Logical precedence test: ${description}`, error); - } - }); - } - - testComparisonOperators() { - console.log('Testing Comparison Operators...'); - - const testCases = [ - { input: '1 == 1', description: 'Equality comparison' }, - { input: '1 != 2', description: 'Inequality comparison' }, - { input: '5 > 3', description: 'Greater than' }, - { input: '3 < 5', description: 'Less than' }, - { input: '4 >= 4', description: 'Greater than or equal' }, - { input: '4 <= 4', description: 'Less than or equal' }, - { input: '1 == 1 && 2 > 1', description: 'Comparison with logical operators' }, - { input: '1 + 2 == 3', description: 'Arithmetic in comparison' } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-comparison-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Comparison test: ${description}`, error); - } - }); - } - - testTemporalExpressions() { - console.log('Testing Temporal Expressions...'); - - const testCases = [ - { input: 'user.lastActive within 1h', description: 'Temporal within expression' }, - { input: 'user.lastLogin within 24h', description: 'Temporal within with hours' }, - { input: 'user.createdAt within 7d', description: 'Temporal within with days' }, - { input: 'user.lastActivity within 1h && user.isActive', description: 'Temporal with logical operators' } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-temporal-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Temporal test: ${description}`, error); - } - }); - } - - testUnaryOperators() { - console.log('Testing Unary Operators...'); - - const testCases = [ - { input: 'NOT true', description: 'NOT operator' }, - { input: '!false', description: 'Alternative NOT operator' }, - { input: 'NOT (true && false)', description: 'NOT with parenthesized expression' }, - { input: 'NOT user.isSuspended', description: 'NOT with attribute access' } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-unary-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Unary test: ${description}`, error); - } - }); - } - - testAttributeAccess() { - console.log('Testing Attribute Access...'); - - const testCases = [ - { input: 'user.role', description: 'Simple attribute access' }, - { input: 'user.profile.name', description: 'Nested attribute access' }, - { input: 'user.permissions[0]', description: 'Array access' }, - { input: 'user.role.permissions[0]', description: 'Nested attribute with array access' }, - { input: 'user.isActive && user.role == "admin"', description: 'Attribute access in logical expression' } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-attribute-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Attribute access test: ${description}`, error); - } - }); - } - - testFunctionCalls() { - console.log('Testing Function Calls...'); - - const testCases = [ - { input: 'hasRole(user, "admin")', description: 'Simple function call' }, - { input: 'isMember(user, group)', description: 'Function call with variables' }, - { input: 'hasPermission(user, resource, "read")', description: 'Function call with multiple arguments' }, - { input: 'hasRole(user, "admin") && isActive(user)', description: 'Multiple function calls' }, - { input: 'hasRole(user, user.role)', description: 'Function call with attribute access' } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-function-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Function call test: ${description}`, error); - } - }); - } - - testComplexExpressions() { - console.log('Testing Complex Expressions...'); - - const testCases = [ - { - input: 'user.isActive && (hasRole(user, "admin") || hasPermission(user, resource, "read"))', - description: 'Complex logical expression with function calls' - }, - { - input: 'user.balance > 100 && user.isActive && NOT user.isSuspended', - description: 'Multiple conditions with NOT' - }, - { - input: 'user.lastActive within 1h && (user.role == "admin" || user.hasEmergencyAccess)', - description: 'Temporal with logical conditions' - }, - { - input: 'hasRole(user, "admin") && user.isActive && NOT (user.isSuspended || user.isBlacklisted)', - description: 'Complex negation with multiple conditions' - }, - { - input: 'user.score > 0.8 && user.isTrusted && user.lastActivity within 24h', - description: 'Multiple attribute conditions with temporal' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-complex-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Complex expression test: ${description}`, error); - } - }); - } - - testExpressionErrors() { - console.log('Testing Expression Error Handling...'); - - const testCases = [ - { - input: 'user.role ==', - description: 'Incomplete comparison should fail' - }, - { - input: 'user.role &&', - description: 'Incomplete logical expression should fail' - }, - { - input: 'hasRole(user,)', - description: 'Function call with missing argument should fail' - }, - { - input: 'user.role == "admin" &&', - description: 'Incomplete logical expression should fail' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const dsl = `evidence test() { ${input} }`; - const result = this.compiler.compile(dsl, `test-error-${Date.now()}`); - this.assert(!result.success, `${description} should fail to parse`); - console.log(` ✓ ${description} (correctly failed)`); - } catch (error) { - // Expected to fail - console.log(` ✓ ${description} (correctly failed)`); - } - }); - } - - assert(condition, message) { - if (!condition) { - throw new Error(`Assertion failed: ${message}`); - } - } - - fail(testName, error) { - console.log(` ✗ ${testName} failed: ${error.message}`); - this.testResults.push({ - test: testName, - status: 'FAILED', - error: error.message - }); - } - - getTestResults() { - const passed = this.testResults.filter(r => r.status === 'PASSED').length; - const failed = this.testResults.filter(r => r.status === 'FAILED').length; - const total = this.testResults.length; - - return { - total: total, - passed: passed, - failed: failed, - success: failed === 0, - results: this.testResults - }; - } -} - -export function runExpressionTests(arbiter) { - const test = new ExpressionTests(); - test.setup(arbiter); - return test.runAllTests(); -} diff --git a/src/ast/tests/FactTests.js b/src/ast/tests/FactTests.js deleted file mode 100644 index 18abce1..0000000 --- a/src/ast/tests/FactTests.js +++ /dev/null @@ -1,330 +0,0 @@ -/** - * Fact Declaration Tests - * - * Tests the fact declaration system of the Evidence DSL, - * including properties, caching, limits, and parameter types. - */ - -import { DSLCompiler } from '../DSLCompiler.js'; - -export class FactTests { - constructor() { - this.arbiter = null; - this.compiler = null; - this.testResults = []; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.compiler = new DSLCompiler(arbiter); - } - - runAllTests() { - console.log('=== Fact Declaration Tests ===\n'); - - this.testBasicFacts(); - this.testFactProperties(); - this.testFactCaching(); - this.testFactLimits(); - this.testParameterTypes(); - this.testComplexFacts(); - this.testFactErrors(); - - return this.getTestResults(); - } - - testBasicFacts() { - console.log('Testing Basic Facts...'); - - const testCases = [ - { - input: `fact hasRole(user: User, role: string)`, - description: 'Simple fact with two parameters' - }, - { - input: `fact isMember(user: User, group: Group)`, - description: 'Fact with custom types' - }, - { - input: `fact owns(user: User, doc: Document)`, - description: 'Fact with multiple custom types' - }, - { - input: `fact isActive(user: User)`, - description: 'Fact with single parameter' - }, - { - input: `fact hasPermission(user: User, resource: Resource, action: string)`, - description: 'Fact with three parameters' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-basic-fact-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - this.assert(result.program.facts.length > 0, 'Should have facts'); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Basic fact test: ${description}`, error); - } - }); - } - - testFactProperties() { - console.log('Testing Fact Properties...'); - - const testCases = [ - { - input: `fact isMember(user: User, group: Group) transitive`, - description: 'Transitive fact' - }, - { - input: `fact isFriend(user: User, friend: User) symmetrical`, - description: 'Symmetrical fact' - }, - { - input: `fact isMember(user: User, group: Group) transitive symmetrical`, - description: 'Fact with multiple properties' - }, - { - input: `fact isColleague(user: User, colleague: User) symmetrical`, - description: 'Symmetrical relationship fact' - }, - { - input: `fact isParentOf(parent: User, child: User) transitive`, - description: 'Transitive hierarchical fact' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-fact-property-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Fact property test: ${description}`, error); - } - }); - } - - testFactCaching() { - console.log('Testing Fact Caching...'); - - const testCases = [ - { - input: `fact hasRole(user: User, role: string) CACHE eager`, - description: 'Eager cached fact' - }, - { - input: `fact isMember(user: User, group: Group) CACHE lazy`, - description: 'Lazy cached fact' - }, - { - input: `fact isMember(user: User, group: Group) transitive CACHE eager`, - description: 'Transitive fact with eager caching' - }, - { - input: `fact isFriend(user: User, friend: User) symmetrical CACHE lazy`, - description: 'Symmetrical fact with lazy caching' - }, - { - input: `fact hasPermission(user: User, resource: Resource, action: string) CACHE eager`, - description: 'Multi-parameter fact with eager caching' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-fact-cache-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Fact cache test: ${description}`, error); - } - }); - } - - testFactLimits() { - console.log('Testing Fact Limits...'); - - const testCases = [ - { - input: `fact isMember(user: User, group: Group) limit 10`, - description: 'Fact with simple limit' - }, - { - input: `fact isFriend(user: User, friend: User) limit 100`, - description: 'Fact with higher limit' - }, - { - input: `fact isMember(user: User, group: Group) transitive limit 5`, - description: 'Transitive fact with limit' - }, - { - input: `fact isFriend(user: User, friend: User) symmetrical limit 50`, - description: 'Symmetrical fact with limit' - }, - { - input: `fact isMember(user: User, group: Group) transitive CACHE lazy limit 3`, - description: 'Fact with properties, caching, and limit' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-fact-limit-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Fact limit test: ${description}`, error); - } - }); - } - - testParameterTypes() { - console.log('Testing Parameter Types...'); - - const testCases = [ - { type: 'string', description: 'String parameter' }, - { type: 'number', description: 'Number parameter' }, - { type: 'boolean', description: 'Boolean parameter' }, - { type: 'timestamp', description: 'Timestamp parameter' }, - { type: 'User', description: 'Custom type parameter' }, - { type: 'Group', description: 'Another custom type parameter' }, - { type: 'Permission[]', description: 'Array type parameter' } - ]; - - testCases.forEach(({ type, description }) => { - try { - const dsl = `fact test(param: ${type})`; - const result = this.compiler.compile(dsl, `test-param-type-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Parameter type test: ${description}`, error); - } - }); - } - - testComplexFacts() { - console.log('Testing Complex Facts...'); - - const testCases = [ - { - input: `fact hasRole(user: User, role: string) CACHE eager - fact isMember(user: User, group: Group) transitive CACHE lazy limit 10 - fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100 - fact owns(user: User, doc: Document) CACHE eager - fact isSuspended(user: User) CACHE lazy`, - description: 'Multiple facts with different configurations' - }, - { - input: `fact hasPermission(user: User, resource: Resource, action: string) CACHE eager - fact isAdmin(user: User) CACHE eager - fact isOwner(user: User, resource: Resource) CACHE eager - fact hasAccess(user: User, resource: Resource, level: string) CACHE lazy`, - description: 'Permission-related facts' - }, - { - input: `fact isMember(user: User, group: Group) transitive CACHE lazy limit 5 - fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 50 - fact isColleague(user: User, colleague: User) symmetrical CACHE lazy limit 20 - fact isParentOf(parent: User, child: User) transitive CACHE eager limit 3`, - description: 'Relationship facts with various properties' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-complex-facts-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - this.assert(result.program.facts.length > 0, 'Should have facts'); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Complex facts test: ${description}`, error); - } - }); - } - - testFactErrors() { - console.log('Testing Fact Error Handling...'); - - const testCases = [ - { - input: `fact hasRole(user: User, role: string`, - description: 'Missing closing parenthesis should fail' - }, - { - input: `fact hasRole(user: User, )`, - description: 'Missing parameter name should fail' - }, - { - input: `fact hasRole(user: User, role: )`, - description: 'Missing parameter type should fail' - }, - { - input: `fact hasRole(, role: string)`, - description: 'Missing parameter name should fail' - }, - { - input: `fact hasRole(user: User, role: string) CACHE`, - description: 'Incomplete cache directive should fail' - }, - { - input: `fact hasRole(user: User, role: string) limit`, - description: 'Incomplete limit should fail' - }, - { - input: `fact hasRole(user: User, role: string) invalid`, - description: 'Invalid property should fail' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-fact-error-${Date.now()}`); - this.assert(!result.success, `${description} should fail to parse`); - console.log(` ✓ ${description} (correctly failed)`); - } catch (error) { - // Expected to fail - console.log(` ✓ ${description} (correctly failed)`); - } - }); - } - - assert(condition, message) { - if (!condition) { - throw new Error(`Assertion failed: ${message}`); - } - } - - fail(testName, error) { - console.log(` ✗ ${testName} failed: ${error.message}`); - this.testResults.push({ - test: testName, - status: 'FAILED', - error: error.message - }); - } - - getTestResults() { - const passed = this.testResults.filter(r => r.status === 'PASSED').length; - const failed = this.testResults.filter(r => r.status === 'FAILED').length; - const total = this.testResults.length; - - return { - total: total, - passed: passed, - failed: failed, - success: failed === 0, - results: this.testResults - }; - } -} - -export function runFactTests(arbiter) { - const test = new FactTests(); - test.setup(arbiter); - return test.runAllTests(); -} diff --git a/src/ast/tests/IntegrationTests.js b/src/ast/tests/IntegrationTests.js deleted file mode 100644 index 2373754..0000000 --- a/src/ast/tests/IntegrationTests.js +++ /dev/null @@ -1,635 +0,0 @@ -/** - * Integration Tests - * - * Tests complex combinations of multiple language features, - * simulating real-world authorization scenarios. - */ - -import { DSLCompiler } from '../DSLCompiler.js'; - -export class IntegrationTests { - constructor() { - this.arbiter = null; - this.compiler = null; - this.testResults = []; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.compiler = new DSLCompiler(arbiter); - } - - runAllTests() { - console.log('=== Integration Tests ===\n'); - - this.testCompleteAuthorizationSystem(); - this.testMultiDomainSystem(); - this.testHierarchicalAccess(); - this.testSimilarityBasedAccess(); - this.testTemporalAccess(); - this.testComplexBehaviors(); - this.testPerformanceScenarios(); - - return this.getTestResults(); - } - - testCompleteAuthorizationSystem() { - console.log('Testing Complete Authorization System...'); - - const completeSystem = ` - // Type definitions with complex behaviors - definition User { - role: string - isActive: boolean - lastActive: timestamp BEHAVES { - decaying down hourly - } CACHE lazy - isSuspended: boolean - balance: number BEHAVES { - decaying down hourly - } CACHE eager - score: number BEHAVES { - blurring adaptive confidence_95 - } CACHE lazy - session: string BEHAVES { - ttl 24h - } CACHE eager - clearance: string BEHAVES { - blurring fixed - } CACHE eager - reputation: number BEHAVES { - decaying up daily - } CACHE lazy - } - - definition Group { - name: string - permissions: Permission[] - level: string - isPublic: boolean CACHE eager - created: timestamp BEHAVES { - decaying stable monthly - } CACHE lazy - } - - definition Document { - level: string - owner: User - tags: string[] - content: string BEHAVES { - blurring fixed - } CACHE lazy - accessCount: number BEHAVES { - decaying up daily - } CACHE eager - expiresAt: timestamp BEHAVES { - ttl 30d - } CACHE eager - isPublic: boolean CACHE eager - } - - definition Resource { - level: string - owner: User - permissions: Permission[] - isPublic: boolean CACHE eager - accessCount: number BEHAVES { - decaying up daily - } CACHE eager - } - - // Facts with various properties and caching - fact hasRole(user: User, role: string) CACHE eager - fact isMember(user: User, group: Group) transitive CACHE lazy limit 10 - fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100 - fact owns(user: User, doc: Document) CACHE eager - fact isSuspended(user: User) CACHE lazy - fact hasPermission(user: User, resource: Resource, action: string) CACHE eager - fact isAdmin(user: User) CACHE eager - fact isOwner(user: User, resource: Resource) CACHE eager - fact hasAccess(user: User, resource: Resource, level: string) CACHE lazy - fact isColleague(user: User, colleague: User) symmetrical CACHE lazy limit 50 - fact isParentOf(parent: User, child: User) transitive CACHE eager limit 3 - - // Evidence rules with complex logic - evidence canRead(user: User, doc: Document) { - owns(user, doc) - - isMember(user, *group) { - canRead(group, doc) - } limit 5 - - parentOf(user, *parent) { - canRead(parent, doc) - } limit 3 - - similar(doc, *similar) |similarity| { - canRead(user, similar) - } with similarity > 0.7 limit 5 - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - } - - evidence canWrite(user: User, doc: Document) { - owns(user, doc) - - isMember(user, *group) { - canWrite(group, doc) - } limit 3 - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - - REQUIRES user.isActive - } - - evidence canDelete(user: User, doc: Document) { - owns(user, doc) - - ALWAYS user.isActive - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - - REQUIRES user.isActive - } - - evidence canAccessCritical(user: User, resource: Resource) { - fusion min { - hasClearance(user, resource.level) - user.isActive - NOT user.isBlacklisted - } - - fusion max { - hasRole(user, 'admin') - fusion majority { - hasClearance(user, 'secret') - user.isTrusted - user.lastActive within 1hr - } - } - } - - evidence canAccessSensitive(user: User, doc: Document) { - ALWAYS user.isActive - - WHEN hasRole(user, 'admin') UNLESS isSuspended(user) - - REQUIRES hasClearance(user, doc.level) - - fusion majority { - user.isTrusted - user.hasRecentActivity - } - } - - // Measures for computed values - measure userRole(user: User) { - user.role - } PROVIDES string - - measure userPermissions(user: User) { - fusion max { - user.role.permissions - user.group.permissions - } - } PROVIDES Permission[] - - measure effectiveClearance(user: User) { - fusion majority { - user.clearance - user.role.clearance - user.group.clearance - } - } PROVIDES string - - measure userTrustScore(user: User) { - fusion average { - user.reputation - user.activityScore - user.verificationLevel - } - } PROVIDES number - - measure userBalance(user: User) { - user.balance - } PROVIDES number - - measure userScore(user: User) { - user.score - } PROVIDES number - `; - - try { - const result = this.compiler.compile(completeSystem, 'test-complete-system'); - this.assert(result.success, 'Complete authorization system should compile successfully'); - this.assert(result.program.definitions.length >= 4, 'Should have multiple definitions'); - this.assert(result.program.facts.length >= 10, 'Should have multiple facts'); - this.assert(result.program.evidence.length >= 5, 'Should have multiple evidence rules'); - this.assert(result.program.measures.length >= 6, 'Should have multiple measures'); - console.log(' ✓ Complete authorization system'); - } catch (error) { - this.fail('Complete authorization system test', error); - } - } - - testMultiDomainSystem() { - console.log('Testing Multi-Domain System...'); - - const multiDomain = ` - // Authentication domain - definition User { - role: string - isActive: boolean - lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy - session: string BEHAVES { ttl 24h } CACHE eager - } - - fact hasRole(user: User, role: string) CACHE eager - fact isActive(user: User) CACHE eager - - evidence canAuthenticate(user: User) { - user.isActive - user.session within 24h - } - - // Authorization domain - definition Resource { - level: string - owner: User - permissions: Permission[] - } - - fact owns(user: User, resource: Resource) CACHE eager - fact hasPermission(user: User, resource: Resource, action: string) CACHE eager - - evidence canAccess(user: User, resource: Resource) { - owns(user, resource) - hasPermission(user, resource, 'read') - } - - // Finance domain - definition Account { - balance: number BEHAVES { decaying down hourly } CACHE eager - owner: User - isActive: boolean CACHE eager - } - - fact hasAccount(user: User, account: Account) CACHE eager - fact hasBalance(user: User, amount: number) CACHE eager - - evidence canWithdraw(user: User, amount: number) { - hasBalance(user, amount) - user.isActive - } - - // Social domain - definition Group { - name: string - members: User[] - isPublic: boolean CACHE eager - } - - fact isMember(user: User, group: Group) transitive CACHE lazy limit 10 - fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100 - - evidence canAccessGroup(user: User, group: Group) { - isMember(user, group) - group.isPublic - } - `; - - try { - const result = this.compiler.compile(multiDomain, 'test-multi-domain'); - this.assert(result.success, 'Multi-domain system should compile successfully'); - this.assert(result.program.definitions.length >= 4, 'Should have multiple domain definitions'); - this.assert(result.program.facts.length >= 8, 'Should have multiple domain facts'); - this.assert(result.program.evidence.length >= 4, 'Should have multiple domain evidence rules'); - console.log(' ✓ Multi-domain system'); - } catch (error) { - this.fail('Multi-domain system test', error); - } - } - - testHierarchicalAccess() { - console.log('Testing Hierarchical Access...'); - - const hierarchicalSystem = ` - definition User { - role: string - level: string - isActive: boolean - clearance: string - } - - definition Organization { - name: string - level: string - parent: Organization - } - - fact isMember(user: User, org: Organization) transitive CACHE lazy limit 5 - fact isParentOf(parent: Organization, child: Organization) transitive CACHE eager limit 3 - fact hasRole(user: User, role: string) CACHE eager - fact hasClearance(user: User, level: string) CACHE eager - - evidence canAccessOrg(user: User, org: Organization) { - isMember(user, org) - - isParentOf(org, *parentOrg) { - canAccessOrg(user, parentOrg) - } limit 3 - - WHEN hasRole(user, 'admin') UNLESS user.isSuspended - } - - evidence canAccessResource(user: User, resource: Resource) { - isMember(user, *org) { - canAccessResource(org, resource) - } limit 5 - - parentOf(user, *parent) { - canAccessResource(parent, resource) - } limit 2 - } - `; - - try { - const result = this.compiler.compile(hierarchicalSystem, 'test-hierarchical'); - this.assert(result.success, 'Hierarchical access system should compile successfully'); - console.log(' ✓ Hierarchical access system'); - } catch (error) { - this.fail('Hierarchical access test', error); - } - } - - testSimilarityBasedAccess() { - console.log('Testing Similarity-Based Access...'); - - const similaritySystem = ` - definition User { - profile: string - interests: string[] - isActive: boolean - } - - definition Document { - content: string - tags: string[] - isPublic: boolean - owner: User - } - - fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100 - fact hasInterest(user: User, interest: string) CACHE lazy - fact hasTag(doc: Document, tag: string) CACHE lazy - - evidence canRead(user: User, doc: Document) { - owns(user, doc) - - similar(doc, *similar) |similarity| { - canRead(user, similar) - similar.isPublic - } with similarity > 0.7 limit 10 - - isFriend(user, *friend) { - canRead(friend, doc) - } limit 5 - - fusion majority { - user.interests - doc.tags - } - } - - evidence canRecommend(user: User, doc: Document) { - similar(user, *similarUser) |similarity| { - canRead(similarUser, doc) - } with similarity > 0.8 limit 20 - - fusion average { - user.profile - doc.content - } - } - `; - - try { - const result = this.compiler.compile(similaritySystem, 'test-similarity'); - this.assert(result.success, 'Similarity-based access system should compile successfully'); - console.log(' ✓ Similarity-based access system'); - } catch (error) { - this.fail('Similarity-based access test', error); - } - } - - testTemporalAccess() { - console.log('Testing Temporal Access...'); - - const temporalSystem = ` - definition User { - lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy - session: string BEHAVES { ttl 24h } CACHE eager - isActive: boolean - } - - definition Event { - startTime: timestamp - endTime: timestamp - isPublic: boolean - } - - fact hasAccess(user: User, event: Event) CACHE lazy - fact isParticipant(user: User, event: Event) CACHE eager - - evidence canAccessEvent(user: User, event: Event) { - user.lastActive within 1h - - isParticipant(user, event) - - WHEN event.isPublic UNLESS user.isSuspended - - fusion min { - user.session within 24h - user.isActive - } - } - - evidence canAccessHistorical(user: User, event: Event) { - user.lastActive within 24h - - fusion majority { - user.isActive - user.session within 24h - event.isPublic - } - } - `; - - try { - const result = this.compiler.compile(temporalSystem, 'test-temporal'); - this.assert(result.success, 'Temporal access system should compile successfully'); - console.log(' ✓ Temporal access system'); - } catch (error) { - this.fail('Temporal access test', error); - } - } - - testComplexBehaviors() { - console.log('Testing Complex Behaviors...'); - - const behaviorSystem = ` - definition User { - balance: number BEHAVES { decaying down hourly } CACHE eager - score: number BEHAVES { blurring adaptive confidence_95 } CACHE lazy - session: string BEHAVES { ttl 24h } CACHE eager - reputation: number BEHAVES { decaying up daily } CACHE lazy - clearance: string BEHAVES { blurring fixed } CACHE eager - lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy - } - - definition Document { - content: string BEHAVES { blurring fixed } CACHE lazy - accessCount: number BEHAVES { decaying up daily } CACHE eager - expiresAt: timestamp BEHAVES { ttl 30d } CACHE eager - isPublic: boolean CACHE eager - } - - fact hasBalance(user: User, amount: number) CACHE eager - fact hasScore(user: User, score: number) CACHE lazy - fact hasReputation(user: User, reputation: number) CACHE lazy - - evidence canAccessDocument(user: User, doc: Document) { - user.balance > 0 - - user.score > 0.5 - - user.reputation > 0.3 - - doc.accessCount < 1000 - - fusion majority { - user.isActive - user.lastActive within 1h - doc.isPublic - } - } - - measure userEffectiveScore(user: User) { - fusion average { - user.score - user.reputation - user.balance - } - } PROVIDES number - - measure documentPopularity(doc: Document) { - doc.accessCount - } PROVIDES number - `; - - try { - const result = this.compiler.compile(behaviorSystem, 'test-behaviors'); - this.assert(result.success, 'Complex behaviors system should compile successfully'); - console.log(' ✓ Complex behaviors system'); - } catch (error) { - this.fail('Complex behaviors test', error); - } - } - - testPerformanceScenarios() { - console.log('Testing Performance Scenarios...'); - - const performanceSystem = ` - definition User { - role: string - isActive: boolean - permissions: Permission[] CACHE eager - } - - definition Resource { - level: string - owner: User - permissions: Permission[] CACHE eager - } - - // High-frequency facts with limits - fact isMember(user: User, group: Group) transitive CACHE lazy limit 5 - fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 50 - fact hasPermission(user: User, resource: Resource, action: string) CACHE eager - fact owns(user: User, resource: Resource) CACHE eager - - // Optimized evidence rules - evidence canAccess(user: User, resource: Resource) { - owns(user, resource) - - isMember(user, *group) { - canAccess(group, resource) - } limit 3 - - WHEN hasPermission(user, resource, 'read') - } - - evidence canModify(user: User, resource: Resource) { - owns(user, resource) - - isMember(user, *group) { - canModify(group, resource) - } limit 2 - - WHEN hasPermission(user, resource, 'write') - } - - // Efficient measures - measure userEffectivePermissions(user: User) { - user.permissions - } PROVIDES Permission[] - - measure resourceAccessLevel(resource: Resource) { - resource.level - } PROVIDES string - `; - - try { - const result = this.compiler.compile(performanceSystem, 'test-performance'); - this.assert(result.success, 'Performance scenarios should compile successfully'); - console.log(' ✓ Performance scenarios'); - } catch (error) { - this.fail('Performance scenarios test', error); - } - } - - assert(condition, message) { - if (!condition) { - throw new Error(`Assertion failed: ${message}`); - } - } - - fail(testName, error) { - console.log(` ✗ ${testName} failed: ${error.message}`); - this.testResults.push({ - test: testName, - status: 'FAILED', - error: error.message - }); - } - - getTestResults() { - const passed = this.testResults.filter(r => r.status === 'PASSED').length; - const failed = this.testResults.filter(r => r.status === 'FAILED').length; - const total = this.testResults.length; - - return { - total: total, - passed: passed, - failed: failed, - success: failed === 0, - results: this.testResults - }; - } -} - -export function runIntegrationTests(arbiter) { - const test = new IntegrationTests(); - test.setup(arbiter); - return test.runAllTests(); -} diff --git a/src/ast/tests/MeasureTests.js b/src/ast/tests/MeasureTests.js deleted file mode 100644 index 38189e2..0000000 --- a/src/ast/tests/MeasureTests.js +++ /dev/null @@ -1,393 +0,0 @@ -/** - * Measure Definition Tests - * - * Tests the measure system of the Evidence DSL, - * including aggregation, fusion, return types, and value computation. - */ - -import { DSLCompiler } from '../DSLCompiler.js'; - -export class MeasureTests { - constructor() { - this.arbiter = null; - this.compiler = null; - this.testResults = []; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.compiler = new DSLCompiler(arbiter); - } - - runAllTests() { - console.log('=== Measure Definition Tests ===\n'); - - this.testBasicMeasures(); - this.testMeasureReturnTypes(); - this.testMeasureAggregation(); - this.testMeasureFusion(); - this.testComplexMeasures(); - this.testMeasureErrors(); - - return this.getTestResults(); - } - - testBasicMeasures() { - console.log('Testing Basic Measures...'); - - const testCases = [ - { - input: `measure userRole(user: User) { - user.role - } PROVIDES string`, - description: 'Simple measure with attribute access' - }, - { - input: `measure userBalance(user: User) { - user.balance - } PROVIDES number`, - description: 'Measure accessing numeric attribute' - }, - { - input: `measure isUserActive(user: User) { - user.isActive - } PROVIDES boolean`, - description: 'Measure accessing boolean attribute' - }, - { - input: `measure userPermissions(user: User) { - user.permissions - } PROVIDES Permission[]`, - description: 'Measure accessing array attribute' - }, - { - input: `measure userScore(user: User) { - user.score - } PROVIDES number`, - description: 'Measure with behavior-inherited attribute' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-basic-measure-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - this.assert(result.program.measures.length > 0, 'Should have measures'); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Basic measure test: ${description}`, error); - } - }); - } - - testMeasureReturnTypes() { - console.log('Testing Measure Return Types...'); - - const testCases = [ - { type: 'string', description: 'String return type' }, - { 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' } - ]; - - testCases.forEach(({ type, description }) => { - try { - const dsl = `measure test() { true } PROVIDES ${type}`; - const result = this.compiler.compile(dsl, `test-measure-return-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Measure return type test: ${description}`, error); - } - }); - } - - testMeasureAggregation() { - console.log('Testing Measure Aggregation...'); - - const testCases = [ - { - input: `measure userPermissions(user: User) { - aggregate { - user.role.permissions - user.group.permissions - } USING majority - } PROVIDES Permission[]`, - description: 'Aggregation with majority strategy' - }, - { - input: `measure userClearance(user: User) { - aggregate { - user.clearance - user.role.clearance - user.group.clearance - } USING max - } PROVIDES string`, - description: 'Aggregation with max strategy' - }, - { - input: `measure userScore(user: User) { - aggregate { - user.reputation - user.activityScore - user.verificationLevel - } USING average - } PROVIDES number`, - description: 'Aggregation with average strategy' - }, - { - input: `measure userTrust(user: User) { - aggregate { - user.reputation - user.activityScore - user.verificationLevel - user.socialProof - } USING min - } PROVIDES number`, - description: 'Aggregation with min strategy' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-measure-aggregation-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Measure aggregation test: ${description}`, error); - } - }); - } - - testMeasureFusion() { - console.log('Testing Measure Fusion...'); - - const testCases = [ - { - input: `measure effectiveClearance(user: User) { - fusion max { - user.clearance - user.role.clearance - user.group.clearance - } - } PROVIDES string`, - description: 'Fusion with max strategy' - }, - { - input: `measure userPermissions(user: User) { - fusion min { - user.role.permissions - user.group.permissions - } - } PROVIDES Permission[]`, - description: 'Fusion with min strategy' - }, - { - input: `measure userScore(user: User) { - fusion majority { - user.reputation - user.activityScore - user.verificationLevel - } - } PROVIDES number`, - description: 'Fusion with majority strategy' - }, - { - input: `measure userTrust(user: User) { - fusion average { - user.reputation - user.activityScore - user.verificationLevel - user.socialProof - } - } PROVIDES number`, - description: 'Fusion with average strategy' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-measure-fusion-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Measure fusion test: ${description}`, error); - } - }); - } - - testComplexMeasures() { - console.log('Testing Complex Measures...'); - - const testCases = [ - { - input: `measure userEffectivePermissions(user: User) { - aggregate { - user.role.permissions - user.group.permissions - user.directPermissions - } USING majority - } PROVIDES Permission[]`, - description: 'Complex aggregation with multiple sources' - }, - { - input: `measure userTrustScore(user: User) { - fusion average { - user.reputation - user.activityScore - user.verificationLevel - user.socialProof - user.peerRatings - } - } PROVIDES number`, - description: 'Complex fusion with multiple metrics' - }, - { - input: `measure userAccessLevel(user: User) { - fusion max { - user.clearance - user.role.clearance - user.group.clearance - user.temporaryClearance - } - } PROVIDES string`, - description: 'Complex clearance calculation' - }, - { - input: `measure userSimilarity(user1: User, user2: User) { - similar(user1, user2) |similarity| { - similarity - } with similarity > 0.5 - } PROVIDES number`, - description: 'Similarity measure with pattern matching' - }, - { - input: `measure userEffectiveRole(user: User) { - fusion majority { - user.role - user.temporaryRole - user.actingRole - } - } PROVIDES string`, - description: 'Role determination with multiple sources' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-complex-measure-${Date.now()}`); - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } catch (error) { - this.fail(`Complex measure test: ${description}`, error); - } - }); - } - - testMeasureErrors() { - console.log('Testing Measure Error Handling...'); - - const testCases = [ - { - input: `measure userRole(user: User) { - user.role - }`, - description: 'Missing PROVIDES clause should fail' - }, - { - input: `measure userRole(user: User) { - user.role - } PROVIDES`, - description: 'Incomplete PROVIDES clause should fail' - }, - { - input: `measure userRole(user: User) { - user.role - } PROVIDES string`, - description: 'Valid measure should succeed' - }, - { - input: `measure userPermissions(user: User) { - aggregate { - user.role.permissions - user.group.permissions - } USING - } PROVIDES Permission[]`, - description: 'Incomplete USING clause should fail' - }, - { - input: `measure userScore(user: User) { - fusion { - user.reputation - user.activityScore - } - } PROVIDES number`, - description: 'Missing fusion strategy should fail' - }, - { - input: `measure userRole(user: User) { - invalid syntax here - } PROVIDES string`, - description: 'Invalid syntax should fail' - } - ]; - - testCases.forEach(({ input, description }) => { - try { - const result = this.compiler.compile(input, `test-measure-error-${Date.now()}`); - if (description.includes('should succeed')) { - this.assert(result.success, `${description} should parse successfully`); - console.log(` ✓ ${description}`); - } else { - this.assert(!result.success, `${description} should fail to parse`); - console.log(` ✓ ${description} (correctly failed)`); - } - } catch (error) { - if (description.includes('should succeed')) { - this.fail(`Measure error test: ${description}`, error); - } else { - // Expected to fail - console.log(` ✓ ${description} (correctly failed)`); - } - } - }); - } - - assert(condition, message) { - if (!condition) { - throw new Error(`Assertion failed: ${message}`); - } - } - - fail(testName, error) { - console.log(` ✗ ${testName} failed: ${error.message}`); - this.testResults.push({ - test: testName, - status: 'FAILED', - error: error.message - }); - } - - getTestResults() { - const passed = this.testResults.filter(r => r.status === 'PASSED').length; - const failed = this.testResults.filter(r => r.status === 'FAILED').length; - const total = this.testResults.length; - - return { - total: total, - passed: passed, - failed: failed, - success: failed === 0, - results: this.testResults - }; - } -} - -export function runMeasureTests(arbiter) { - const test = new MeasureTests(); - test.setup(arbiter); - return test.runAllTests(); -} diff --git a/src/ast/tests/README.md b/src/ast/tests/README.md deleted file mode 100644 index 72970a1..0000000 --- a/src/ast/tests/README.md +++ /dev/null @@ -1,249 +0,0 @@ -# Evidence DSL Test Suite - -## Overview - -This comprehensive test suite follows a **structural linguistic approach** to validate the Evidence DSL (Domain Specific Language) for authorization policies. The tests are organized incrementally from basic language primitives to complex integration scenarios. - -## Test Structure - -### 1. Structural Linguistic Tests (`StructuralLinguisticTests.js`) -**Level: Comprehensive** -- **Lexical Primitives**: Identifiers, literals, keywords, whitespace -- **Basic Expressions**: Arithmetic, logical, comparison, temporal -- **Type System**: Definitions, fields, behaviors, caching -- **Fact System**: Declarations, properties, caching, limits -- **Evidence System**: Rules, defeasible logic, pattern matching -- **Measure System**: Aggregation, fusion, return types -- **Complex Integration**: Multi-feature combinations - -### 2. Expression Tests (`ExpressionTests.js`) -**Level: Focused** -- Arithmetic operator precedence -- Logical operator precedence -- Comparison operators -- Temporal expressions -- Unary operators -- Attribute access -- Function calls -- Complex expressions -- Error handling - -### 3. Definition Tests (`DefinitionTests.js`) -**Level: Focused** -- Basic type definitions -- Field types (string, number, boolean, timestamp, custom) -- Array types -- Behaviors (decay, blur, TTL) -- Caching (eager, lazy) -- Complex definitions -- Error handling - -### 4. Fact Tests (`FactTests.js`) -**Level: Focused** -- Basic fact declarations -- Fact properties (transitive, symmetrical) -- Fact caching -- Fact limits -- Parameter types -- Complex facts -- Error handling - -### 5. Evidence Tests (`EvidenceTests.js`) -**Level: Focused** -- Basic evidence rules -- Defeasible logic (ALWAYS, WHEN/UNLESS, REQUIRES) -- Pattern matching with wildcards -- Fusion strategies (min, max, majority, average) -- Complex evidence composition -- Error handling - -### 6. Measure Tests (`MeasureTests.js`) -**Level: Focused** -- Basic measure definitions -- Return types -- Aggregation with different strategies -- Fusion with different strategies -- Complex measures -- Error handling - -### 7. Integration Tests (`IntegrationTests.js`) -**Level: Integration** -- Complete authorization systems -- Multi-domain systems -- Hierarchical access patterns -- Similarity-based access -- Temporal access patterns -- Complex behaviors -- Performance scenarios - -## Test Runner (`TestRunner.js`) - -The test runner orchestrates all test suites and provides: -- **Comprehensive Testing**: Run all test suites -- **Selective Testing**: Run specific test suites -- **Level-based Testing**: Run tests by complexity level -- **Detailed Reporting**: Summary and detailed results -- **Coverage Analysis**: Language feature coverage - -## Usage - -### Run All Tests -```javascript -import { runAllTests } from './tests/TestRunner.js'; - -const results = runAllTests(arbiter); -console.log(`Tests: ${results.passed}/${results.total} passed`); -``` - -### Run Specific Test Suites -```javascript -import { runSpecificTests } from './tests/TestRunner.js'; - -const results = runSpecificTests(arbiter, [ - 'Expression Tests', - 'Definition Tests' -]); -``` - -### Run Tests by Level -```javascript -import { runTestsByLevel } from './tests/TestRunner.js'; - -// Run only focused tests -const results = runTestsByLevel(arbiter, 'focused'); - -// Run only integration tests -const results = runTestsByLevel(arbiter, 'integration'); -``` - -## Language Feature Coverage - -### ✅ Lexical Primitives -- Identifiers (simple, with underscores, with numbers) -- Literals (string, number, boolean, duration) -- Keywords (reserved words) -- Whitespace and comments - -### ✅ Expression System -- Arithmetic operators (+, -, *, /) with precedence -- Logical operators (&&, ||, NOT) with precedence -- Comparison operators (==, !=, >, <, >=, <=) -- Temporal expressions (within) -- Unary operators (NOT, !) -- Attribute access (object.attribute) -- Function calls (predicate(args)) - -### ✅ Type System -- Type definitions with fields -- Field types (string, number, boolean, timestamp, custom) -- Array types (Type[]) -- Behaviors (decay, blur, TTL) -- Caching directives (eager, lazy) - -### ✅ Fact System -- Fact declarations with parameters -- Fact properties (transitive, symmetrical) -- Caching directives -- Limits for performance -- Parameter types - -### ✅ Evidence System -- Basic evidence rules -- Defeasible logic (ALWAYS, WHEN/UNLESS, REQUIRES) -- Pattern matching with wildcards (*) -- Binding clauses (|variable|) -- With clauses (with condition) -- Limits for pattern matching -- Fusion strategies (min, max, majority, average) - -### ✅ Measure System -- Measure definitions -- Return type specifications (PROVIDES) -- Aggregation with strategies (USING) -- Fusion with strategies -- Complex value computation - -### ✅ Integration Features -- Multi-domain systems -- Hierarchical access patterns -- Similarity-based access -- Temporal access patterns -- Complex behavior combinations -- Performance optimization scenarios - -## Test Philosophy - -### Structural Linguistic Approach -The tests follow a structural linguistic methodology: - -1. **Phonological Level**: Basic lexical elements (identifiers, literals) -2. **Morphological Level**: Word formation (operators, keywords) -3. **Syntactic Level**: Grammar rules (expressions, statements) -4. **Semantic Level**: Meaning (types, behaviors, logic) -5. **Pragmatic Level**: Usage (integration, real-world scenarios) - -### Incremental Complexity -Tests progress from simple to complex: -- **Level 1**: Lexical primitives -- **Level 2**: Basic expressions -- **Level 3**: Type system -- **Level 4**: Fact system -- **Level 5**: Evidence system -- **Level 6**: Measure system -- **Level 7**: Complex integration - -### Comprehensive Coverage -Each language feature is tested for: -- **Valid cases**: Correct syntax and semantics -- **Invalid cases**: Error handling and recovery -- **Edge cases**: Boundary conditions -- **Integration**: Multi-feature combinations - -## Running Tests - -### Prerequisites -- Node.js environment -- Arbiter instance for testing -- All dependencies installed - -### Basic Usage -```bash -# Run all tests -npm test - -# Run specific test file -node src/ast/tests/StructuralLinguisticTests.js - -# Run with specific arbiter -node -e " -import { runAllTests } from './src/ast/tests/TestRunner.js'; -const results = runAllTests(arbiter); -console.log(results); -" -``` - -### Test Output -The test runner provides: -- **Progress indicators**: Real-time test execution -- **Detailed results**: Pass/fail status for each test -- **Error reporting**: Specific error messages for failures -- **Performance metrics**: Execution time for each suite -- **Coverage analysis**: Language feature coverage - -## Contributing - -When adding new tests: -1. Follow the structural linguistic approach -2. Test both valid and invalid cases -3. Include error handling tests -4. Document test purpose and expected behavior -5. Maintain incremental complexity -6. Update coverage documentation - -## Test Maintenance - -- **Regular Updates**: Keep tests current with language changes -- **Performance Monitoring**: Track test execution time -- **Coverage Analysis**: Ensure comprehensive feature coverage -- **Error Handling**: Validate error messages and recovery -- **Integration Testing**: Test real-world scenarios diff --git a/src/ast/tests/StructuralLinguisticTests.js b/src/ast/tests/StructuralLinguisticTests.js deleted file mode 100644 index e69de29..0000000 diff --git a/src/ast/tests/TestRunner.js b/src/ast/tests/TestRunner.js deleted file mode 100644 index 02a2221..0000000 --- a/src/ast/tests/TestRunner.js +++ /dev/null @@ -1,413 +0,0 @@ -/** - * Comprehensive Test Runner for Evidence DSL - * - * Orchestrates all test suites in a structural linguistic approach, - * from basic primitives to complex integration scenarios. - */ - -import { runStructuralLinguisticTests } from './StructuralLinguisticTests.js'; -import { runExpressionTests } from './ExpressionTests.js'; -import { runDefinitionTests } from './DefinitionTests.js'; -import { runFactTests } from './FactTests.js'; -import { runEvidenceTests } from './EvidenceTests.js'; -import { runMeasureTests } from './MeasureTests.js'; -import { runIntegrationTests } from './IntegrationTests.js'; - -export class TestRunner { - constructor() { - this.arbiter = null; - this.testSuites = []; - this.results = { - total: 0, - passed: 0, - failed: 0, - success: false, - suites: [] - }; - } - - setup(arbiter) { - this.arbiter = arbiter; - this.testSuites = [ - { - name: 'Structural Linguistic Tests', - description: 'Comprehensive tests from basic primitives to complex features', - runner: runStructuralLinguisticTests, - level: 'comprehensive' - }, - { - name: 'Expression Tests', - description: 'Expression parsing, operator precedence, and complex expressions', - runner: runExpressionTests, - level: 'focused' - }, - { - name: 'Definition Tests', - description: 'Type definitions, fields, behaviors, and caching', - runner: runDefinitionTests, - level: 'focused' - }, - { - name: 'Fact Tests', - description: 'Fact declarations, properties, and caching', - runner: runFactTests, - level: 'focused' - }, - { - name: 'Evidence Tests', - description: 'Evidence rules, defeasible logic, and pattern matching', - runner: runEvidenceTests, - level: 'focused' - }, - { - name: 'Measure Tests', - description: 'Measure definitions, aggregation, and fusion', - runner: runMeasureTests, - level: 'focused' - }, - { - name: 'Integration Tests', - description: 'Complex multi-feature integration scenarios', - runner: runIntegrationTests, - level: 'integration' - } - ]; - } - - /** - * Run all test suites - * @returns {Object} Comprehensive test results - */ - runAllTests() { - console.log('='.repeat(80)); - console.log('EVIDENCE DSL COMPREHENSIVE TEST SUITE'); - console.log('='.repeat(80)); - console.log('Structural Linguistic Approach: Testing from primitives to integration\n'); - - const startTime = Date.now(); - - for (const suite of this.testSuites) { - console.log(`\n${'='.repeat(60)}`); - console.log(`Running: ${suite.name}`); - console.log(`Level: ${suite.level.toUpperCase()}`); - console.log(`Description: ${suite.description}`); - console.log(`${'='.repeat(60)}`); - - try { - const suiteStartTime = Date.now(); - const suiteResults = suite.runner(this.arbiter); - const suiteEndTime = Date.now(); - const suiteDuration = suiteEndTime - suiteStartTime; - - this.results.suites.push({ - name: suite.name, - level: suite.level, - duration: suiteDuration, - results: suiteResults - }); - - this.results.total += suiteResults.total; - this.results.passed += suiteResults.passed; - this.results.failed += suiteResults.failed; - - console.log(`\n${suite.name} completed in ${suiteDuration}ms`); - console.log(`Results: ${suiteResults.passed}/${suiteResults.total} passed, ${suiteResults.failed} failed`); - - if (suiteResults.success) { - console.log(`✓ ${suite.name} PASSED`); - } else { - console.log(`✗ ${suite.name} FAILED`); - } - - } catch (error) { - console.error(`\n✗ ${suite.name} ERROR: ${error.message}`); - this.results.suites.push({ - name: suite.name, - level: suite.level, - duration: 0, - results: { - total: 0, - passed: 0, - failed: 1, - success: false, - error: error.message - } - }); - this.results.failed += 1; - } - } - - const endTime = Date.now(); - const totalDuration = endTime - startTime; - - this.results.success = this.results.failed === 0; - - this.printSummary(totalDuration); - this.printDetailedResults(); - - return this.results; - } - - /** - * Run specific test suites - * @param {string[]} suiteNames - Names of test suites to run - * @returns {Object} Test results for specified suites - */ - runSpecificTests(suiteNames) { - console.log('='.repeat(80)); - console.log('EVIDENCE DSL SELECTIVE TEST SUITE'); - console.log('='.repeat(80)); - console.log(`Running: ${suiteNames.join(', ')}\n`); - - const startTime = Date.now(); - const selectedSuites = this.testSuites.filter(suite => suiteNames.includes(suite.name)); - - for (const suite of selectedSuites) { - console.log(`\n${'='.repeat(60)}`); - console.log(`Running: ${suite.name}`); - console.log(`${'='.repeat(60)}`); - - try { - const suiteStartTime = Date.now(); - const suiteResults = suite.runner(this.arbiter); - const suiteEndTime = Date.now(); - const suiteDuration = suiteEndTime - suiteStartTime; - - this.results.suites.push({ - name: suite.name, - level: suite.level, - duration: suiteDuration, - results: suiteResults - }); - - this.results.total += suiteResults.total; - this.results.passed += suiteResults.passed; - this.results.failed += suiteResults.failed; - - console.log(`\n${suite.name} completed in ${suiteDuration}ms`); - console.log(`Results: ${suiteResults.passed}/${suiteResults.total} passed, ${suiteResults.failed} failed`); - - } catch (error) { - console.error(`\n✗ ${suite.name} ERROR: ${error.message}`); - this.results.failed += 1; - } - } - - const endTime = Date.now(); - const totalDuration = endTime - startTime; - - this.results.success = this.results.failed === 0; - this.printSummary(totalDuration); - - return this.results; - } - - /** - * Run tests by level - * @param {string} level - Test level to run ('comprehensive', 'focused', 'integration') - * @returns {Object} Test results for specified level - */ - runTestsByLevel(level) { - const levelSuites = this.testSuites.filter(suite => suite.level === level); - const suiteNames = levelSuites.map(suite => suite.name); - return this.runSpecificTests(suiteNames); - } - - /** - * Print test summary - * @param {number} totalDuration - Total test duration in milliseconds - */ - printSummary(totalDuration) { - console.log('\n' + '='.repeat(80)); - console.log('TEST SUMMARY'); - console.log('='.repeat(80)); - console.log(`Total Tests: ${this.results.total}`); - console.log(`Passed: ${this.results.passed}`); - console.log(`Failed: ${this.results.failed}`); - console.log(`Success Rate: ${((this.results.passed / this.results.total) * 100).toFixed(2)}%`); - console.log(`Total Duration: ${totalDuration}ms`); - console.log(`Status: ${this.results.success ? '✓ ALL TESTS PASSED' : '✗ SOME TESTS FAILED'}`); - console.log('='.repeat(80)); - } - - /** - * Print detailed results for each test suite - */ - printDetailedResults() { - console.log('\n' + '='.repeat(80)); - console.log('DETAILED RESULTS'); - console.log('='.repeat(80)); - - this.results.suites.forEach(suite => { - console.log(`\n${suite.name} (${suite.level}):`); - console.log(` Duration: ${suite.duration}ms`); - console.log(` Total: ${suite.results.total}`); - console.log(` Passed: ${suite.results.passed}`); - console.log(` Failed: ${suite.results.failed}`); - console.log(` Success: ${suite.results.success ? '✓' : '✗'}`); - - if (suite.results.error) { - console.log(` Error: ${suite.results.error}`); - } - - if (suite.results.results && suite.results.results.length > 0) { - console.log(' Individual Results:'); - suite.results.results.forEach(result => { - const status = result.status === 'PASSED' ? '✓' : '✗'; - console.log(` ${status} ${result.test}`); - if (result.error) { - console.log(` Error: ${result.error}`); - } - }); - } - }); - } - - /** - * Get test coverage report - * @returns {Object} Coverage report - */ - getCoverageReport() { - const coverage = { - lexical: { - identifiers: 'tested', - literals: 'tested', - keywords: 'tested', - whitespace: 'tested' - }, - expressions: { - arithmetic: 'tested', - logical: 'tested', - comparison: 'tested', - temporal: 'tested', - unary: 'tested', - attributeAccess: 'tested', - functionCalls: 'tested' - }, - types: { - definitions: 'tested', - fields: 'tested', - behaviors: 'tested', - caching: 'tested', - arrays: 'tested' - }, - facts: { - declarations: 'tested', - properties: 'tested', - caching: 'tested', - limits: 'tested', - parameters: 'tested' - }, - evidence: { - basic: 'tested', - defeasibleLogic: 'tested', - patternMatching: 'tested', - fusion: 'tested', - complex: 'tested' - }, - measures: { - basic: 'tested', - aggregation: 'tested', - fusion: 'tested', - returnTypes: 'tested', - complex: 'tested' - }, - integration: { - completeSystems: 'tested', - multiDomain: 'tested', - hierarchical: 'tested', - similarity: 'tested', - temporal: 'tested', - behaviors: 'tested', - performance: 'tested' - } - }; - - return coverage; - } - - /** - * Get language feature coverage - * @returns {Object} Feature coverage report - */ - getFeatureCoverage() { - return { - languagePrimitives: { - identifiers: '✓', - literals: '✓', - keywords: '✓', - operators: '✓', - expressions: '✓' - }, - typeSystem: { - definitions: '✓', - fields: '✓', - behaviors: '✓', - caching: '✓', - arrays: '✓' - }, - factSystem: { - declarations: '✓', - properties: '✓', - caching: '✓', - limits: '✓', - parameters: '✓' - }, - evidenceSystem: { - rules: '✓', - defeasibleLogic: '✓', - patternMatching: '✓', - fusion: '✓', - complex: '✓' - }, - measureSystem: { - definitions: '✓', - aggregation: '✓', - fusion: '✓', - returnTypes: '✓', - complex: '✓' - }, - integration: { - multiFeature: '✓', - realWorld: '✓', - performance: '✓', - scalability: '✓' - } - }; - } -} - -/** - * Run all tests - * @param {Object} arbiter - Arbiter instance for testing - * @returns {Object} Comprehensive test results - */ -export function runAllTests(arbiter) { - const runner = new TestRunner(); - runner.setup(arbiter); - return runner.runAllTests(); -} - -/** - * Run specific test suites - * @param {Object} arbiter - Arbiter instance for testing - * @param {string[]} suiteNames - Names of test suites to run - * @returns {Object} Test results for specified suites - */ -export function runSpecificTests(arbiter, suiteNames) { - const runner = new TestRunner(); - runner.setup(arbiter); - return runner.runSpecificTests(suiteNames); -} - -/** - * Run tests by level - * @param {Object} arbiter - Arbiter instance for testing - * @param {string} level - Test level to run - * @returns {Object} Test results for specified level - */ -export function runTestsByLevel(arbiter, level) { - const runner = new TestRunner(); - runner.setup(arbiter); - return runner.runTestsByLevel(level); -} diff --git a/src/authorization/rules/QualitativeRelationalComparatorRule.js b/src/authorization/rules/QualitativeRelationalComparatorRule.js index d7caec9..9b00d5b 100644 --- a/src/authorization/rules/QualitativeRelationalComparatorRule.js +++ b/src/authorization/rules/QualitativeRelationalComparatorRule.js @@ -579,17 +579,6 @@ export class QualitativeRelationalComparatorRule extends BaseRule { }; } - /** - * @deprecated Use _aggregateCrispValues instead. Removal after Stage 2. - */ - _aggregateBlurredValues(blurredValues, operandConfig, scale) { - if (!this._warnedAggregateBlurredValues) { - this._warnedAggregateBlurredValues = true; - console.warn('[QualitativeRelationalComparatorRule] _aggregateBlurredValues is deprecated; use _aggregateCrispValues instead.'); - } - return this._aggregateCrispValues(blurredValues, operandConfig, scale); - } - /** * Compare blurred qualitative intervals * @private diff --git a/src/core/RelationManager.js b/src/core/RelationManager.js index 4640080..2d5d6c6 100644 --- a/src/core/RelationManager.js +++ b/src/core/RelationManager.js @@ -1,4 +1,3 @@ -import { RelationCSR } from './relation/RelationCSR.js'; import { RelationSnapshotAccess } from './relation/RelationSnapshotAccess.js'; import { RelationCaches } from './relation/RelationCaches.js'; import { RelationLookup } from './relation/RelationLookup.js'; @@ -22,16 +21,10 @@ export class RelationManager { this._relationKeyToIndex = new Map(); this._relationNameToId = new Map(); - this._relationCsr = new RelationCSR(this); this._snapshotAccess = new RelationSnapshotAccess(this); this._lookup = new RelationLookup(this); this._updates = new RelationUpdates(this); this._relationGraph = new RelationGraphTraversal(this); - if (this._relationCsr.enabled && !RelationManager._warnedRelationCsrDeprecated) { - RelationManager._warnedRelationCsrDeprecated = true; - console.warn('[RelationManager] relation CSR index is deprecated; avoid useRelationCsrIndex and related options.'); - } - this._cacheHits = 0; this._cacheMisses = 0; @@ -60,26 +53,6 @@ export class RelationManager { return this._relationGraph.shouldUseTraversal(nodeId, relation, reverse); } - _buildRelationCsrIndex(relation) { - return this._relationCsr.buildIndex(relation); - } - - _getRelationCsrIndex(relation) { - return this._relationCsr.getIndex(relation); - } - - _recordRelationCsrAdd(relationObj) { - this._relationCsr.recordAdd(relationObj); - } - - _recordRelationCsrRemove(srcId, relation, dstId) { - this._relationCsr.recordRemove(srcId, relation, dstId); - } - - _getRelationsFromCsr(csr, nodeId, reverse = false) { - return this._relationCsr.getRelationsFromCsr(csr, nodeId, reverse); - } - _getRelationDegreeFromIndices(nodeId, relation, reverse = false) { this._ensureIndicesBuilt(); const indices = this.arbiter.indices; @@ -525,17 +498,6 @@ export class RelationManager { return this.arbiter.valueManager.aggregateCrispValues(intervalValues, aggregator); } - /** - * @deprecated Use getAggregatedIntervalValue instead. Removal after Stage 2. - */ - getAggregatedBlurredValue(srcId, relation, aggregator = 'max') { - if (!this._warnedAggregatedBlurredValue) { - this._warnedAggregatedBlurredValue = true; - console.warn('[RelationManager] getAggregatedBlurredValue is deprecated; use getAggregatedIntervalValue instead.'); - } - return this.getAggregatedIntervalValue(srcId, relation, aggregator); - } - /** * Compare values between two relations using interval arithmetic * @param {Object} leftRelation - Left relation object or { srcId, relation, dstId } @@ -747,7 +709,6 @@ export class RelationManager { _clearAllCaches() { this._caches.clearAll(); - this._relationCsr.clear(); this._relationGraph.clear(); } diff --git a/src/core/ValueManager.js b/src/core/ValueManager.js index 4ff9708..b601fd1 100644 --- a/src/core/ValueManager.js +++ b/src/core/ValueManager.js @@ -1169,17 +1169,6 @@ export class ValueManager { }; } - /** - * @deprecated Use aggregateCrispValues instead. Removal after Stage 2. - */ - aggregateBlurredValues(blurredValues, aggregator = 'max') { - if (!this._warnedAggregateBlurredValues) { - this._warnedAggregateBlurredValues = true; - console.warn('[ValueManager] aggregateBlurredValues is deprecated; use aggregateCrispValues instead.'); - } - return this.aggregateCrispValues(blurredValues, aggregator); - } - /** * Compare two intervals using a comparator * @param {Object} leftInterval - { min, max } diff --git a/src/core/relation/RelationCSR.js b/src/core/relation/RelationCSR.js deleted file mode 100644 index 1f4790b..0000000 --- a/src/core/relation/RelationCSR.js +++ /dev/null @@ -1,154 +0,0 @@ -export class RelationCSR { - constructor(manager) { - this.manager = manager; - const options = manager.arbiter?.options || {}; - this.enabled = !!options.useRelationCsrIndex; - this.deltaThreshold = Number.isFinite(options.relationCsrDeltaThreshold) - ? options.relationCsrDeltaThreshold - : 1000; - this.minDegree = Number.isFinite(options.relationCsrMinDegree) - ? options.relationCsrMinDegree - : 200; - this.byName = new Map(); - } - - buildIndex(relation) { - const relSet = this.manager.arbiter.indices?.relationsByRel?.get(relation); - const relations = relSet ? Array.from(relSet) : []; - const bySrcMap = new Map(); - const byDstMap = new Map(); - - for (const rel of relations) { - let srcList = bySrcMap.get(rel.src); - if (!srcList) { - srcList = []; - bySrcMap.set(rel.src, srcList); - } - srcList.push(rel); - - let dstList = byDstMap.get(rel.dst); - if (!dstList) { - dstList = []; - byDstMap.set(rel.dst, dstList); - } - dstList.push(rel); - } - - const bySrcEntries = []; - const bySrcOffsets = new Map(); - for (const [srcId, list] of bySrcMap.entries()) { - const start = bySrcEntries.length; - for (const rel of list) bySrcEntries.push(rel); - bySrcOffsets.set(srcId, { start, end: bySrcEntries.length }); - } - - const byDstEntries = []; - const byDstOffsets = new Map(); - for (const [dstId, list] of byDstMap.entries()) { - const start = byDstEntries.length; - for (const rel of list) byDstEntries.push(rel); - byDstOffsets.set(dstId, { start, end: byDstEntries.length }); - } - - return { - relation, - bySrcEntries, - bySrcOffsets, - byDstEntries, - byDstOffsets, - addDeltaBySrc: new Map(), - addDeltaByDst: new Map(), - removeDelta: new Set(), - deltaCount: 0 - }; - } - - getIndex(relation) { - if (!this.enabled) return null; - let csr = this.byName.get(relation); - if (!csr || csr.deltaCount > this.deltaThreshold) { - csr = this.buildIndex(relation); - this.byName.set(relation, csr); - } - return csr; - } - - recordAdd(relationObj) { - if (!this.enabled) return; - const csr = this.byName.get(relationObj.rel); - if (!csr) return; - const key = this.manager._makeRelationKey(relationObj.src, relationObj.rel, relationObj.dst); - if (csr.removeDelta.has(key)) { - csr.removeDelta.delete(key); - } - - let srcList = csr.addDeltaBySrc.get(relationObj.src); - if (!srcList) { - srcList = []; - csr.addDeltaBySrc.set(relationObj.src, srcList); - } - srcList.push(relationObj); - - let dstList = csr.addDeltaByDst.get(relationObj.dst); - if (!dstList) { - dstList = []; - csr.addDeltaByDst.set(relationObj.dst, dstList); - } - dstList.push(relationObj); - - csr.deltaCount++; - } - - recordRemove(srcId, relation, dstId) { - if (!this.enabled) return; - const csr = this.byName.get(relation); - if (!csr) return; - const key = this.manager._makeRelationKey(srcId, relation, dstId); - csr.removeDelta.add(key); - csr.deltaCount++; - } - - getRelationsFromCsr(csr, nodeId, reverse = false) { - const entries = reverse ? csr.byDstEntries : csr.bySrcEntries; - const offsets = reverse ? csr.byDstOffsets : csr.bySrcOffsets; - const deltaMap = reverse ? csr.addDeltaByDst : csr.addDeltaBySrc; - const range = offsets.get(nodeId); - const removeDelta = csr.removeDelta; - - const result = []; - if (range) { - for (let i = range.start; i < range.end; i++) { - const rel = entries[i]; - const key = this.manager._makeRelationKey(rel.src, rel.rel, rel.dst); - if (!removeDelta.has(key)) { - result.push(rel); - } - } - } - - const delta = deltaMap.get(nodeId); - if (delta && delta.length) { - for (const rel of delta) { - const key = this.manager._makeRelationKey(rel.src, rel.rel, rel.dst); - if (!removeDelta.has(key)) { - result.push(rel); - } - } - } - - return result; - } - - getRelationsForNode(nodeId, relation, reverse = false) { - if (!this.enabled) return null; - const degree = this.manager._getRelationDegreeFromIndices(nodeId, relation, reverse); - if (degree < this.minDegree) return null; - const csr = this.getIndex(relation); - if (!csr) return null; - return this.getRelationsFromCsr(csr, nodeId, reverse); - } - - clear() { - this.byName.clear(); - } -} diff --git a/src/core/relation/RelationLookup.js b/src/core/relation/RelationLookup.js index 4b528b5..b570db4 100644 --- a/src/core/relation/RelationLookup.js +++ b/src/core/relation/RelationLookup.js @@ -47,10 +47,6 @@ export class RelationLookup { const persistent = this.manager.arbiter.indices.getRelationsFromSrc(srcId, relation); return this.manager._mergeRelationLists(persistent, partial); } - const csrResult = this.manager._relationCsr.getRelationsForNode(srcId, relation, false); - if (csrResult !== null) { - return csrResult; - } // Try cache first for frequently accessed patterns - use numeric key const cacheKey = this.manager._makeSrcRelCacheKey(srcId, relation); const cached = this.manager._caches.relationLookupCache.get(cacheKey); @@ -84,10 +80,6 @@ export class RelationLookup { const persistent = this.manager.arbiter.indices.getRelationsToDst(dstId, relation); return this.manager._mergeRelationLists(persistent, partial); } - const csrResult = this.manager._relationCsr.getRelationsForNode(dstId, relation, true); - if (csrResult !== null) { - return csrResult; - } // Try cache first - use numeric key const cacheKey = this.manager._makeDstRelCacheKey(dstId, relation); const cached = this.manager._caches.relationLookupCache.get(cacheKey); diff --git a/src/core/relation/RelationUpdates.js b/src/core/relation/RelationUpdates.js index 2aa7ca5..d278f23 100644 --- a/src/core/relation/RelationUpdates.js +++ b/src/core/relation/RelationUpdates.js @@ -71,7 +71,6 @@ export class RelationUpdates { this.manager.arbiter.indicesBuilt = true; this.manager._addRelationToGraph(srcId, relation, dstId); - this.manager._recordRelationCsrAdd(relationObj); // Update PLTC indices incrementally (if initialized and not in batch mode) if (!this.manager.arbiter.batchUpdateInProgress) { @@ -124,7 +123,6 @@ export class RelationUpdates { this.manager._invalidateValueRelationCaches(srcId, dstId, relationName); this.manager._removeRelationFromGraph(srcId, relationName, dstId); - this.manager._recordRelationCsrRemove(srcId, relationName, dstId); // Notify ValueManager about the removed relation's last state if (relationObjectToRemove.value !== undefined && relationObjectToRemove.stateId) { @@ -368,7 +366,6 @@ export class RelationUpdates { this.manager.arbiter.indicesBuilt = true; this.manager._addRelationToGraph(srcId, relation, dstId); - this.manager._recordRelationCsrAdd(relationObj); // Update PLTC indices incrementally (if initialized and not in batch mode) // For updates, only update if it's a new relation (not an existing one being modified)