- Implements intelligent display fields with AI-generated titles and descriptions - Leverages existing IntelligentTypeMatcher for semantic type detection - Adds lazy computation with LRU caching for zero performance impact - Enhances CLI with clean, minimal formatting (no visual clutter) - Provides method-based API (getDisplay()) to avoid namespace conflicts - Maintains 100% backward compatibility with existing code - Enables by default with complete isolation architecture - Includes comprehensive tests and documentation The augmentation transforms search results and data display with smart, contextual information while maintaining Soulcraft's clean aesthetic.
448 lines
No EOL
15 KiB
TypeScript
448 lines
No EOL
15 KiB
TypeScript
/**
|
|
* Universal Display Augmentation Tests
|
|
*
|
|
* Comprehensive test suite for the display augmentation system
|
|
* including AI-powered field computation, caching, and CLI integration
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
|
|
import { BrainyData } from '../src/brainyData.js'
|
|
import { UniversalDisplayAugmentation } from '../src/augmentations/universalDisplayAugmentation.js'
|
|
import { DisplayCache } from '../src/augmentations/display/cache.js'
|
|
import { IntelligentComputationEngine } from '../src/augmentations/display/intelligentComputation.js'
|
|
|
|
describe('Universal Display Augmentation', () => {
|
|
let brainy: BrainyData
|
|
let displayAugmentation: UniversalDisplayAugmentation
|
|
|
|
beforeEach(async () => {
|
|
// Use in-memory storage for tests
|
|
brainy = new BrainyData({
|
|
storage: { forceMemoryStorage: true },
|
|
verbose: false
|
|
})
|
|
|
|
await brainy.init()
|
|
|
|
// Get display augmentation (should be enabled by default)
|
|
const augmentations = (brainy as any).augmentations
|
|
displayAugmentation = augmentations?.get('display')
|
|
})
|
|
|
|
afterEach(async () => {
|
|
if (brainy) {
|
|
await brainy.clearAll({ force: true })
|
|
}
|
|
})
|
|
|
|
describe('Augmentation Setup', () => {
|
|
it('should be enabled by default', () => {
|
|
expect(displayAugmentation).toBeDefined()
|
|
expect(displayAugmentation.name).toBe('display')
|
|
expect(displayAugmentation.version).toBe('1.0.0')
|
|
})
|
|
|
|
it('should have correct metadata access configuration', () => {
|
|
expect(displayAugmentation.metadata).toEqual({
|
|
reads: '*',
|
|
writes: ['_display']
|
|
})
|
|
})
|
|
|
|
it('should declare computed fields', () => {
|
|
expect(displayAugmentation.computedFields).toBeDefined()
|
|
expect(displayAugmentation.computedFields.display).toBeDefined()
|
|
expect(displayAugmentation.computedFields.display.title).toEqual({
|
|
type: 'string',
|
|
description: 'Primary display name (AI-computed)'
|
|
})
|
|
})
|
|
|
|
it('should have correct operation targeting', () => {
|
|
expect(displayAugmentation.operations).toContain('get')
|
|
expect(displayAugmentation.operations).toContain('search')
|
|
expect(displayAugmentation.operations).toContain('findSimilar')
|
|
})
|
|
})
|
|
|
|
describe('Display Field Computation', () => {
|
|
it('should enhance noun results with display fields', async () => {
|
|
// Add test data
|
|
const id = await brainy.addNoun('John Doe', {
|
|
type: 'Person',
|
|
role: 'CEO',
|
|
company: 'Acme Corp'
|
|
})
|
|
|
|
// Get the enhanced result
|
|
const result = await brainy.getNoun(id)
|
|
|
|
// Should have display capabilities
|
|
expect(result.getDisplay).toBeDefined()
|
|
expect(typeof result.getDisplay).toBe('function')
|
|
|
|
// Test display fields
|
|
const displayFields = await result.getDisplay()
|
|
expect(displayFields).toBeDefined()
|
|
expect(displayFields.title).toBeDefined()
|
|
expect(displayFields.type).toBeDefined()
|
|
expect(displayFields.icon).toBeDefined()
|
|
expect(displayFields.description).toBeDefined()
|
|
expect(displayFields.confidence).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('should provide type-appropriate icons', async () => {
|
|
const testCases = [
|
|
{ data: 'Apple Inc', metadata: { type: 'Organization' }, expectedIcon: '🏢' },
|
|
{ data: 'Jane Smith', metadata: { type: 'Person' }, expectedIcon: '👤' },
|
|
{ data: 'San Francisco', metadata: { type: 'Location' }, expectedIcon: '📍' },
|
|
{ data: 'Machine Learning', metadata: { type: 'Concept' }, expectedIcon: '💭' }
|
|
]
|
|
|
|
for (const testCase of testCases) {
|
|
const id = await brainy.addNoun(testCase.data, testCase.metadata)
|
|
const result = await brainy.getNoun(id)
|
|
const displayFields = await result.getDisplay()
|
|
|
|
expect(displayFields.icon).toBe(testCase.expectedIcon)
|
|
expect(displayFields.type).toBeDefined()
|
|
}
|
|
})
|
|
|
|
it('should handle missing or minimal metadata gracefully', async () => {
|
|
// Add data with minimal metadata
|
|
const id = await brainy.addNoun('Some random text')
|
|
const result = await brainy.getNoun(id)
|
|
|
|
const displayFields = await result.getDisplay()
|
|
expect(displayFields.title).toBeDefined()
|
|
expect(displayFields.type).toBeDefined()
|
|
expect(displayFields.icon).toBeDefined()
|
|
expect(displayFields.confidence).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('should compute enhanced descriptions', async () => {
|
|
const id = await brainy.addNoun('Tesla Model 3', {
|
|
type: 'Product',
|
|
category: 'Electric Vehicle',
|
|
manufacturer: 'Tesla'
|
|
})
|
|
|
|
const result = await brainy.getNoun(id)
|
|
const displayFields = await result.getDisplay()
|
|
|
|
expect(displayFields.description).toBeDefined()
|
|
expect(displayFields.description.length).toBeGreaterThan(displayFields.title.length)
|
|
})
|
|
})
|
|
|
|
describe('Search Result Enhancement', () => {
|
|
beforeEach(async () => {
|
|
// Add test data for search
|
|
await brainy.addNoun('John Doe', { type: 'Person', role: 'CEO' })
|
|
await brainy.addNoun('Apple Inc', { type: 'Organization', industry: 'Technology' })
|
|
await brainy.addNoun('MacBook Pro', { type: 'Product', brand: 'Apple' })
|
|
})
|
|
|
|
it('should enhance search results', async () => {
|
|
const results = await brainy.search('CEO', { limit: 5 })
|
|
expect(results.length).toBeGreaterThan(0)
|
|
|
|
// Check that results are enhanced
|
|
const firstResult = results[0]
|
|
expect(firstResult.getDisplay).toBeDefined()
|
|
|
|
const displayFields = await firstResult.getDisplay()
|
|
expect(displayFields.title).toBeDefined()
|
|
expect(displayFields.icon).toBeDefined()
|
|
})
|
|
|
|
it('should maintain search scores while adding display fields', async () => {
|
|
const results = await brainy.search('Apple', { limit: 5 })
|
|
expect(results.length).toBeGreaterThan(0)
|
|
|
|
const firstResult = results[0]
|
|
expect(firstResult.score).toBeDefined()
|
|
expect(firstResult.getDisplay).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('Verb Display Enhancement', () => {
|
|
it('should enhance verb relationships with display fields', async () => {
|
|
// Add entities and relationship
|
|
const johnId = await brainy.addNoun('John Doe', { type: 'Person' })
|
|
const appleId = await brainy.addNoun('Apple Inc', { type: 'Organization' })
|
|
const verbId = await brainy.addVerb(johnId, appleId, 'WorksFor')
|
|
|
|
// Get the enhanced verb
|
|
const verb = await brainy.getVerb(verbId)
|
|
expect(verb.getDisplay).toBeDefined()
|
|
|
|
const displayFields = await verb.getDisplay()
|
|
expect(displayFields.relationship).toBeDefined()
|
|
expect(displayFields.icon).toBeDefined()
|
|
expect(displayFields.type).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('Caching System', () => {
|
|
it('should cache computed display fields', async () => {
|
|
const id = await brainy.addNoun('Test Entity', { type: 'Concept' })
|
|
const result = await brainy.getNoun(id)
|
|
|
|
// First computation
|
|
const displayFields1 = await result.getDisplay()
|
|
|
|
// Second computation should be cached
|
|
const displayFields2 = await result.getDisplay()
|
|
|
|
// Should be identical (cached)
|
|
expect(displayFields1).toEqual(displayFields2)
|
|
|
|
// Check cache statistics
|
|
const stats = displayAugmentation.getStats()
|
|
expect(stats.totalComputations).toBeGreaterThan(0)
|
|
})
|
|
|
|
it('should provide cache statistics', () => {
|
|
const stats = displayAugmentation.getStats()
|
|
expect(stats).toBeDefined()
|
|
expect(stats.totalComputations).toBeDefined()
|
|
expect(stats.cacheHitRatio).toBeDefined()
|
|
expect(stats.averageComputationTime).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('Helper Methods', () => {
|
|
it('should provide getAvailableFields method', async () => {
|
|
const id = await brainy.addNoun('Test Entity')
|
|
const result = await brainy.getNoun(id)
|
|
|
|
expect(result.getAvailableFields).toBeDefined()
|
|
const fields = result.getAvailableFields('display')
|
|
expect(Array.isArray(fields)).toBe(true)
|
|
expect(fields).toContain('title')
|
|
expect(fields).toContain('description')
|
|
expect(fields).toContain('type')
|
|
expect(fields).toContain('icon')
|
|
})
|
|
|
|
it('should provide getAvailableAugmentations method', async () => {
|
|
const id = await brainy.addNoun('Test Entity')
|
|
const result = await brainy.getNoun(id)
|
|
|
|
expect(result.getAvailableAugmentations).toBeDefined()
|
|
const augs = result.getAvailableAugmentations()
|
|
expect(Array.isArray(augs)).toBe(true)
|
|
expect(augs).toContain('display')
|
|
})
|
|
|
|
it('should provide explore method for debugging', async () => {
|
|
const id = await brainy.addNoun('Test Entity', { type: 'Concept', description: 'Test' })
|
|
const result = await brainy.getNoun(id)
|
|
|
|
expect(result.explore).toBeDefined()
|
|
|
|
// Should not throw when called
|
|
await expect(result.explore()).resolves.toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('Configuration', () => {
|
|
it('should support runtime configuration', () => {
|
|
const newConfig = {
|
|
enabled: false,
|
|
cacheSize: 500
|
|
}
|
|
|
|
displayAugmentation.configure(newConfig)
|
|
|
|
// Configuration should be applied
|
|
expect((displayAugmentation as any).config.enabled).toBe(false)
|
|
expect((displayAugmentation as any).config.cacheSize).toBe(500)
|
|
})
|
|
|
|
it('should clear cache when disabled', () => {
|
|
displayAugmentation.configure({ enabled: false })
|
|
|
|
// Cache should be cleared
|
|
const stats = displayAugmentation.getStats()
|
|
expect(stats.totalComputations).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('Error Handling', () => {
|
|
it('should handle computation errors gracefully', async () => {
|
|
// Add data that might cause computation issues
|
|
const id = await brainy.addNoun('') // Empty string
|
|
const result = await brainy.getNoun(id)
|
|
|
|
// Should still provide display fields, even if basic
|
|
const displayFields = await result.getDisplay()
|
|
expect(displayFields).toBeDefined()
|
|
expect(displayFields.title).toBeDefined()
|
|
expect(displayFields.icon).toBeDefined()
|
|
})
|
|
|
|
it('should work without AI components', async () => {
|
|
// Test fallback to heuristic-based computation
|
|
const id = await brainy.addNoun('Test Without AI', { type: 'Thing' })
|
|
const result = await brainy.getNoun(id)
|
|
|
|
// Should still work with heuristic fallback
|
|
const displayFields = await result.getDisplay()
|
|
expect(displayFields).toBeDefined()
|
|
expect(displayFields.title).toBeDefined()
|
|
expect(displayFields.type).toBeDefined()
|
|
})
|
|
})
|
|
|
|
describe('Performance', () => {
|
|
it('should have reasonable computation times', async () => {
|
|
const startTime = Date.now()
|
|
|
|
const id = await brainy.addNoun('Performance Test Entity', {
|
|
type: 'Concept',
|
|
description: 'Testing performance characteristics'
|
|
})
|
|
|
|
const result = await brainy.getNoun(id)
|
|
await result.getDisplay()
|
|
|
|
const endTime = Date.now()
|
|
const duration = endTime - startTime
|
|
|
|
// Should complete within reasonable time (adjust based on system capabilities)
|
|
expect(duration).toBeLessThan(5000) // 5 seconds max
|
|
})
|
|
|
|
it('should handle batch operations efficiently', async () => {
|
|
const startTime = Date.now()
|
|
const ids: string[] = []
|
|
|
|
// Add multiple entities
|
|
for (let i = 0; i < 10; i++) {
|
|
const id = await brainy.addNoun(`Test Entity ${i}`, { type: 'Concept' })
|
|
ids.push(id)
|
|
}
|
|
|
|
// Get display fields for all
|
|
const displayPromises = ids.map(async id => {
|
|
const result = await brainy.getNoun(id)
|
|
return result.getDisplay()
|
|
})
|
|
|
|
await Promise.all(displayPromises)
|
|
|
|
const endTime = Date.now()
|
|
const duration = endTime - startTime
|
|
|
|
// Batch should be reasonably fast
|
|
expect(duration).toBeLessThan(10000) // 10 seconds max for 10 items
|
|
})
|
|
})
|
|
|
|
describe('Shutdown and Cleanup', () => {
|
|
it('should shutdown gracefully', async () => {
|
|
// Should not throw
|
|
await expect(displayAugmentation.shutdown()).resolves.toBeUndefined()
|
|
})
|
|
|
|
it('should clear cache on shutdown', async () => {
|
|
displayAugmentation.clearCache()
|
|
|
|
const stats = displayAugmentation.getStats()
|
|
expect(stats.totalComputations).toBe(0)
|
|
expect(stats.cacheHitRatio).toBe(0)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('Display Cache', () => {
|
|
let cache: DisplayCache
|
|
|
|
beforeEach(() => {
|
|
cache = new DisplayCache(100)
|
|
})
|
|
|
|
it('should store and retrieve display fields', () => {
|
|
const testFields = {
|
|
title: 'Test Title',
|
|
description: 'Test Description',
|
|
type: 'Test Type',
|
|
icon: '📝',
|
|
tags: ['test'],
|
|
confidence: 0.9,
|
|
computedAt: Date.now(),
|
|
version: '1.0.0'
|
|
}
|
|
|
|
const key = cache.generateKey('test-id', { name: 'test' }, 'noun')
|
|
cache.set(key, testFields)
|
|
|
|
const retrieved = cache.get(key)
|
|
expect(retrieved).toEqual(testFields)
|
|
})
|
|
|
|
it('should implement LRU eviction', () => {
|
|
const smallCache = new DisplayCache(2)
|
|
|
|
const fields = {
|
|
title: 'Test',
|
|
description: 'Test',
|
|
type: 'Test',
|
|
icon: '📝',
|
|
tags: [],
|
|
confidence: 0.9,
|
|
computedAt: Date.now(),
|
|
version: '1.0.0'
|
|
}
|
|
|
|
// Fill cache to capacity
|
|
smallCache.set('key1', fields)
|
|
smallCache.set('key2', fields)
|
|
|
|
// Add one more (should evict oldest)
|
|
smallCache.set('key3', fields)
|
|
|
|
// key1 should be evicted
|
|
expect(smallCache.get('key1')).toBeNull()
|
|
expect(smallCache.get('key2')).toBeDefined()
|
|
expect(smallCache.get('key3')).toBeDefined()
|
|
})
|
|
|
|
it('should generate consistent cache keys', () => {
|
|
const data = { name: 'test', type: 'Person' }
|
|
|
|
const key1 = cache.generateKey('id-123', data, 'noun')
|
|
const key2 = cache.generateKey('id-123', data, 'noun')
|
|
|
|
expect(key1).toBe(key2)
|
|
|
|
// Different entity type should produce different key
|
|
const key3 = cache.generateKey('id-123', data, 'verb')
|
|
expect(key1).not.toBe(key3)
|
|
})
|
|
|
|
it('should provide cache statistics', () => {
|
|
const fields = {
|
|
title: 'Test',
|
|
description: 'Test',
|
|
type: 'Test',
|
|
icon: '📝',
|
|
tags: [],
|
|
confidence: 0.9,
|
|
computedAt: Date.now(),
|
|
version: '1.0.0'
|
|
}
|
|
|
|
cache.set('test-key', fields, 100) // 100ms computation time
|
|
cache.get('test-key') // Hit
|
|
cache.get('nonexistent') // Miss
|
|
|
|
const stats = cache.getStats()
|
|
expect(stats.totalComputations).toBe(1)
|
|
expect(stats.cacheHitRatio).toBe(0.5) // 1 hit, 1 miss
|
|
expect(stats.averageComputationTime).toBe(100)
|
|
})
|
|
}) |