import { describe, it, expect } from 'vitest' import * as fc from 'fast-check' import { isParameterCoveredByInventory, suggestInventoryPath, } from '../../app/utils/inventory_coverage.js' /** * **Validates: Requirements 5.5** * * Property 9: Desired parameters require inventory coverage * Verifies subtree prefix matching logic using random TR-069-like paths. */ // Arbitrary: generates a single TR-069 path segment (alphanumeric, 1-10 chars) const segmentArb = fc.array( fc.constantFrom(...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('')), { minLength: 1, maxLength: 10 } ).map((chars) => chars.join('')) // Arbitrary: generates a TR-069-like dot-separated path with 2-5 segments (e.g. "Device.Info.Param") const tr069PathArb = fc.array(segmentArb, { minLength: 2, maxLength: 5 }).map((segments) => segments.join('.')) // Arbitrary: generates a subtree path (ends with dot) from a TR-069 path by removing the last segment const subtreePathFromParamArb = tr069PathArb.map((paramPath) => { const parts = paramPath.split('.') parts.pop() return { paramPath, subtreePath: parts.join('.') + '.' } }) describe('Property 9: Inventory coverage validation', () => { it('a parameter is always covered by its own subtree path', () => { fc.assert( fc.property(subtreePathFromParamArb, ({ paramPath, subtreePath }) => { const result = isParameterCoveredByInventory(paramPath, [{ path: subtreePath }]) expect(result).toBe(true) }), { numRuns: 200 } ) }) it('suggestInventoryPath always produces a path that covers the original parameter', () => { fc.assert( fc.property(tr069PathArb, (paramPath) => { const suggested = suggestInventoryPath(paramPath) const result = isParameterCoveredByInventory(paramPath, [{ path: suggested }]) expect(result).toBe(true) }), { numRuns: 200 } ) }) it('a subtree path covers all parameters that start with it', () => { fc.assert( fc.property( fc.array(segmentArb, { minLength: 1, maxLength: 3 }), fc.array(segmentArb, { minLength: 1, maxLength: 3 }), (prefixSegments, suffixSegments) => { const subtreePath = prefixSegments.join('.') + '.' const paramPath = prefixSegments.join('.') + '.' + suffixSegments.join('.') const result = isParameterCoveredByInventory(paramPath, [{ path: subtreePath }]) expect(result).toBe(true) } ), { numRuns: 200 } ) }) it('a subtree path does NOT cover parameters that do not start with it', () => { fc.assert( fc.property( fc.array(segmentArb, { minLength: 1, maxLength: 3 }), fc.array(segmentArb, { minLength: 1, maxLength: 3 }), segmentArb, (prefixSegments, suffixSegments, differentFirst) => { const subtreePath = prefixSegments.join('.') + '.' // Build a param that does NOT start with the subtree path // by using a different first segment const altFirst = differentFirst + 'X' // ensure it differs const paramPath = altFirst + '.' + suffixSegments.join('.') // Only assert when the param truly doesn't start with the subtree fc.pre(!paramPath.startsWith(subtreePath)) const result = isParameterCoveredByInventory(paramPath, [{ path: subtreePath }]) expect(result).toBe(false) } ), { numRuns: 200 } ) }) it('an exact path (no trailing dot) only matches the exact same string', () => { fc.assert( fc.property(tr069PathArb, tr069PathArb, (exactPath, otherPath) => { // exactPath has no trailing dot, so it's an exact match inventory path fc.pre(!exactPath.endsWith('.')) const result = isParameterCoveredByInventory(otherPath, [{ path: exactPath }]) if (otherPath === exactPath) { expect(result).toBe(true) } else { expect(result).toBe(false) } }), { numRuns: 200 } ) }) it('empty inventory paths array means never covered', () => { fc.assert( fc.property(tr069PathArb, (paramPath) => { const result = isParameterCoveredByInventory(paramPath, []) expect(result).toBe(false) }), { numRuns: 200 } ) }) })