refactor: remove augmentation system and semantic type matching

Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.

What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)

What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers

What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export

Build passes, 1176 tests pass, 0 failures.
This commit is contained in:
David Snelling 2026-02-01 10:48:56 -08:00
parent ac7a1f772c
commit d1db3510be
97 changed files with 349 additions and 19705 deletions

View file

@ -1,535 +0,0 @@
import { describe, it, expect, beforeEach } from 'vitest'
import { Brainy } from '../../../src/brainy'
import { createAddParams } from '../../helpers/test-factory'
import { NounType, VerbType } from '../../../src/types/graphTypes'
/**
* Comprehensive test suite for Brainy's built-in augmentation system
* Tests the actual augmentation functionality that's available in production
*/
describe('Brainy Built-in Augmentations', () => {
let brain: Brainy<any>
beforeEach(async () => {
brain = new Brainy({
storage: { type: 'memory' },
augmentations: {
cache: { enabled: true, maxSize: 1000 },
display: { enabled: true },
metrics: { enabled: true }
}
})
await brain.init()
})
describe('1. Augmentation Registry', () => {
it('should list all registered augmentations', async () => {
const augmentations = brain.augmentations.list()
expect(Array.isArray(augmentations)).toBe(true)
expect(augmentations.length).toBeGreaterThan(0)
})
it('should have default augmentations', async () => {
const augmentations = brain.augmentations.list()
expect(augmentations).toContain('cache')
expect(augmentations).toContain('display')
expect(augmentations).toContain('metrics')
})
it('should get augmentation by name', async () => {
const cacheAug = brain.augmentations.get('cache')
expect(cacheAug).toBeDefined()
expect(cacheAug?.name).toBe('cache')
const displayAug = brain.augmentations.get('display')
expect(displayAug).toBeDefined()
expect(displayAug?.name).toBe('display')
const metricsAug = brain.augmentations.get('metrics')
expect(metricsAug).toBeDefined()
expect(metricsAug?.name).toBe('metrics')
})
it('should check if augmentation exists', async () => {
expect(brain.augmentations.has('cache')).toBe(true)
expect(brain.augmentations.has('display')).toBe(true)
expect(brain.augmentations.has('metrics')).toBe(true)
expect(brain.augmentations.has('non-existent')).toBe(false)
})
it('should return undefined for non-existent augmentation', async () => {
const nonExistent = brain.augmentations.get('does-not-exist')
expect(nonExistent).toBeUndefined()
})
})
describe('2. Cache Augmentation', () => {
it('should cache get operations', async () => {
const id = await brain.add(createAddParams({
data: 'cached entity',
metadata: { cached: true }
}))
// First get - should load from storage
const start1 = Date.now()
const entity1 = await brain.get(id)
const duration1 = Date.now() - start1
// Second get - should be cached (faster)
const start2 = Date.now()
const entity2 = await brain.get(id)
const duration2 = Date.now() - start2
// Compare key properties instead of full object equality
expect(entity1?.id).toBe(entity2?.id)
expect(entity1?.data).toBe(entity2?.data)
expect(entity1?.data).toBe('cached entity')
expect(entity1?.metadata?.cached).toBe(true)
// Cache should make second call faster (though this might not be reliable)
// expect(duration2).toBeLessThanOrEqual(duration1)
})
it('should handle cache misses gracefully', async () => {
// Try to get non-existent entity (v5.1.0: use valid UUID format)
const nonExistent = await brain.get('00000000-0000-0000-0000-000000000099')
expect(nonExistent).toBeNull()
})
it('should work with find operations', async () => {
await brain.add(createAddParams({ data: 'findable content 1' }))
await brain.add(createAddParams({ data: 'findable content 2' }))
// First search
const results1 = await brain.find({ query: 'findable' })
// Second search (may be cached)
const results2 = await brain.find({ query: 'findable' })
expect(results1.length).toBe(results2.length)
expect(results1.length).toBeGreaterThanOrEqual(2)
})
})
describe('3. Display Augmentation', () => {
it('should provide display functionality for entities', async () => {
const id = await brain.add(createAddParams({
data: 'Entity with display capabilities',
type: NounType.Document,
metadata: {
title: 'Test Document',
author: 'Test Author',
category: 'test'
}
}))
const entity = await brain.get(id)
expect(entity).toBeDefined()
// Check if getDisplay method is available
if (entity && typeof entity.getDisplay === 'function') {
const display = entity.getDisplay()
expect(display).toBeDefined()
expect(typeof display).toBe('object')
}
})
it('should work with different entity types', async () => {
const personId = await brain.add(createAddParams({
data: 'John Doe',
type: NounType.Person,
metadata: { role: 'developer', age: 30 }
}))
const locationId = await brain.add(createAddParams({
data: 'San Francisco',
type: NounType.Location,
metadata: { country: 'USA', population: 900000 }
}))
const person = await brain.get(personId)
const location = await brain.get(locationId)
expect(person).toBeDefined()
expect(location).toBeDefined()
// Display should work for all types
if (person && typeof person.getDisplay === 'function') {
const personDisplay = person.getDisplay()
expect(personDisplay).toBeDefined()
}
if (location && typeof location.getDisplay === 'function') {
const locationDisplay = location.getDisplay()
expect(locationDisplay).toBeDefined()
}
})
it('should handle entities without metadata', async () => {
const id = await brain.add(createAddParams({
data: 'Simple entity without metadata'
}))
const entity = await brain.get(id)
expect(entity).toBeDefined()
if (entity && typeof entity.getDisplay === 'function') {
const display = entity.getDisplay()
expect(display).toBeDefined()
}
})
it('should provide schema information', async () => {
const id = await brain.add(createAddParams({
data: 'Entity with schema',
metadata: {
stringField: 'text',
numberField: 42,
booleanField: true,
arrayField: [1, 2, 3]
}
}))
const entity = await brain.get(id)
expect(entity).toBeDefined()
if (entity && typeof entity.getSchema === 'function') {
const schema = entity.getSchema()
expect(schema).toBeDefined()
expect(typeof schema).toBe('object')
}
})
})
describe('4. Metrics Augmentation', () => {
it('should track operations without interfering', async () => {
// Perform various operations
const id1 = await brain.add(createAddParams({ data: 'metrics test 1' }))
const id2 = await brain.add(createAddParams({ data: 'metrics test 2' }))
const id3 = await brain.add(createAddParams({ data: 'metrics test 3' }))
// Read operations
await brain.get(id1)
await brain.get(id2)
await brain.find({ query: 'metrics' })
// Write operations
await brain.update({ id: id1, data: 'updated metrics test 1' })
await brain.delete(id3)
// Relationship operations
await brain.relate({
from: id1,
to: id2,
type: VerbType.RelatedTo
})
// All operations should complete successfully
const entity1 = await brain.get(id1)
const entity2 = await brain.get(id2)
const entity3 = await brain.get(id3)
expect(entity1).toBeDefined()
expect(entity1?.data).toBe('updated metrics test 1')
expect(entity2).toBeDefined()
expect(entity3).toBeNull() // Deleted
// Check relationships (may be empty if relationship storage isn't implemented)
const relations = await brain.getRelations(id1)
expect(Array.isArray(relations)).toBe(true)
})
it('should handle high-frequency operations', async () => {
// Create many entities rapidly
const promises = Array.from({ length: 50 }, (_, i) =>
brain.add(createAddParams({
data: `High frequency test ${i}`,
metadata: { index: i }
}))
)
const ids = await Promise.all(promises)
expect(ids.length).toBe(50)
// Perform many reads
const readPromises = ids.map(id => brain.get(id))
const entities = await Promise.all(readPromises)
expect(entities.length).toBe(50)
expect(entities.every(e => e !== null)).toBe(true)
})
it('should handle error scenarios gracefully', async () => {
// v5.1.0: Invalid UUID formats throw errors
await expect(brain.get('invalid-id')).rejects.toThrow('Invalid UUID format')
await expect(brain.delete('invalid-id')).rejects.toThrow('Invalid UUID format')
// Try invalid find parameters
await expect(brain.find({
query: 'test',
limit: -1
} as any)).rejects.toThrow()
await expect(brain.find({
query: 'test',
offset: -1
} as any)).rejects.toThrow()
})
})
describe('5. Augmentation Integration', () => {
it('should apply all augmentations to add operations', async () => {
const id = await brain.add(createAddParams({
data: 'Full integration test',
type: NounType.Document,
metadata: {
title: 'Integration Test',
priority: 'high',
tags: ['test', 'integration']
}
}))
expect(id).toBeDefined()
expect(typeof id).toBe('string')
// Verify entity was created correctly
const entity = await brain.get(id)
expect(entity).toBeDefined()
expect(entity?.data).toBe('Full integration test')
expect(entity?.type).toBe(NounType.Document)
expect(entity?.metadata?.title).toBe('Integration Test')
})
it('should apply all augmentations to find operations', async () => {
// Add test data
const id1 = await brain.add(createAddParams({
data: 'Integration search test 1',
metadata: { category: 'integration' }
}))
const id2 = await brain.add(createAddParams({
data: 'Integration search test 2',
metadata: { category: 'integration' }
}))
await brain.add(createAddParams({
data: 'Different content',
metadata: { category: 'other' }
}))
// Test text search
const textResults = await brain.find({ query: 'Integration search' })
expect(textResults.length).toBeGreaterThanOrEqual(2)
// Test metadata filtering
const categoryResults = await brain.find({
query: '',
where: { category: 'integration' }
})
expect(categoryResults.length).toBe(2)
// Verify entities have display capabilities
const firstResult = textResults[0]
if (firstResult?.entity && typeof firstResult.entity.getDisplay === 'function') {
const display = firstResult.entity.getDisplay()
expect(display).toBeDefined()
}
})
it('should apply augmentations to update operations', async () => {
const id = await brain.add(createAddParams({
data: 'Original data',
metadata: { version: 1 }
}))
// Update should work with all augmentations
await brain.update({
id,
data: 'Updated data',
metadata: { version: 2, updated: true }
})
const updatedEntity = await brain.get(id)
expect(updatedEntity?.data).toBe('Updated data')
expect(updatedEntity?.metadata?.version).toBe(2)
expect(updatedEntity?.metadata?.updated).toBe(true)
})
it('should apply augmentations to relationship operations', async () => {
const id1 = await brain.add(createAddParams({ data: 'Entity 1' }))
const id2 = await brain.add(createAddParams({ data: 'Entity 2' }))
// Create relationship
await brain.relate({
from: id1,
to: id2,
type: VerbType.RelatedTo,
metadata: { strength: 0.8 }
})
// Verify relationship exists (may be empty depending on storage implementation)
const relations = await brain.getRelations(id1)
expect(Array.isArray(relations)).toBe(true)
// If relationships are stored, verify the properties
if (relations.length > 0) {
const relation = relations.find(r => r.to === id2)
if (relation) {
expect(relation.type).toBe(VerbType.RelatedTo)
expect(relation.metadata?.strength).toBe(0.8)
}
}
})
})
describe('6. Performance with Augmentations', () => {
it('should perform well with many entities', async () => {
const start = Date.now()
// Create 100 entities
const createPromises = Array.from({ length: 100 }, (_, i) =>
brain.add(createAddParams({
data: `Performance test entity ${i}`,
metadata: { index: i, batch: 'performance' }
}))
)
const ids = await Promise.all(createPromises)
const createDuration = Date.now() - start
expect(ids.length).toBe(100)
expect(createDuration).toBeLessThan(5000) // Should complete in under 5 seconds
// Search should be fast
const searchStart = Date.now()
const searchResults = await brain.find({
query: 'Performance test',
limit: 50
})
const searchDuration = Date.now() - searchStart
expect(searchResults.length).toBeGreaterThan(0)
expect(searchResults.length).toBeLessThanOrEqual(50) // May return fewer due to relevance
expect(searchDuration).toBeLessThan(1000) // Should complete in under 1 second
})
it('should handle concurrent operations efficiently', async () => {
const start = Date.now()
// Perform 50 concurrent operations
const operations = Array.from({ length: 50 }, (_, i) => {
if (i % 4 === 0) {
return brain.add(createAddParams({ data: `Concurrent add ${i}` }))
} else if (i % 4 === 1) {
return brain.find({ query: 'concurrent', limit: 5 })
} else if (i % 4 === 2) {
return brain.add(createAddParams({ data: `Another add ${i}` }))
} else {
return brain.find({ query: 'test', limit: 3 })
}
})
const results = await Promise.all(operations)
const duration = Date.now() - start
expect(results.length).toBe(50)
expect(duration).toBeLessThan(3000) // Should handle concurrency well
// Verify some results
const addResults = results.filter(r => typeof r === 'string')
const findResults = results.filter(r => Array.isArray(r))
expect(addResults.length).toBeGreaterThan(0)
expect(findResults.length).toBeGreaterThan(0)
})
})
describe('7. Error Handling with Augmentations', () => {
it('should handle errors gracefully without breaking augmentations', async () => {
// v5.1.0: Invalid UUID formats throw errors (these should not crash the system)
await expect(brain.get('')).rejects.toThrow('UUID is required')
await expect(brain.update({
id: 'non-existent',
data: 'new data'
})).rejects.toThrow('Invalid UUID format')
// Normal operations should still work
const id = await brain.add(createAddParams({ data: 'After error test' }))
const entity = await brain.get(id)
expect(entity?.data).toBe('After error test')
})
it('should handle edge case data gracefully', async () => {
// Add entity with minimal but valid data
const id = await brain.add(createAddParams({
data: 'minimal', // Valid minimal data
metadata: { test: true }
}))
expect(id).toBeDefined()
const entity = await brain.get(id)
expect(entity).toBeDefined()
expect(entity?.data).toBe('minimal')
})
})
describe('8. Configuration and Customization', () => {
it('should respect augmentation configuration', async () => {
// Test that augmentations can be configured
const configuredBrain = new Brainy({
storage: { type: 'memory' },
augmentations: {
cache: {
enabled: true,
maxSize: 50,
ttl: 60000
},
display: {
enabled: true,
lazyComputation: true
},
metrics: {
enabled: true
}
}
})
await configuredBrain.init()
// Should work with custom configuration
const id = await configuredBrain.add(createAddParams({
data: 'Configured test'
}))
const entity = await configuredBrain.get(id)
expect(entity?.data).toBe('Configured test')
await configuredBrain.close()
})
it('should work with disabled augmentations', async () => {
const minimalBrain = new Brainy({
storage: { type: 'memory' },
augmentations: {
cache: { enabled: false },
display: { enabled: false },
metrics: { enabled: false }
}
})
await minimalBrain.init()
// Should still work with augmentations disabled
const id = await minimalBrain.add(createAddParams({
data: 'Minimal test'
}))
const entity = await minimalBrain.get(id)
expect(entity?.data).toBe('Minimal test')
await minimalBrain.close()
})
})
})

View file

@ -1,437 +0,0 @@
/**
* FormatHandlerRegistry Tests (v5.2.0)
*
* Tests for MIME-based format handler registration and routing
*/
import { describe, it, expect, beforeEach } from 'vitest'
import { FormatHandlerRegistry } from '../../../src/augmentations/intelligentImport/FormatHandlerRegistry.js'
import type { FormatHandler, ProcessedData } from '../../../src/augmentations/intelligentImport/types.js'
describe('FormatHandlerRegistry (v5.2.0)', () => {
let registry: FormatHandlerRegistry
// Mock handlers for testing
const createMockHandler = (format: string): FormatHandler => ({
format,
async process(): Promise<ProcessedData> {
return {
format,
data: [],
metadata: {
rowCount: 0,
fields: [],
processingTime: 0
}
}
},
canHandle(): boolean {
return true
}
})
beforeEach(() => {
registry = new FormatHandlerRegistry()
})
describe('Handler Registration', () => {
it('should register handler with MIME types and extensions', () => {
const csvHandler = createMockHandler('csv')
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv', 'application/csv'],
extensions: ['.csv', '.tsv'],
loader: async () => csvHandler
})
expect(registry.hasHandler('csv')).toBe(true)
expect(registry.getRegisteredHandlers()).toContain('csv')
})
it('should register multiple handlers', () => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
registry.registerHandler({
name: 'excel',
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
extensions: ['.xlsx'],
loader: async () => createMockHandler('excel')
})
const handlers = registry.getRegisteredHandlers()
expect(handlers).toContain('csv')
expect(handlers).toContain('excel')
expect(handlers).toHaveLength(2)
})
it('should normalize extensions (remove leading dots)', () => {
registry.registerHandler({
name: 'test',
mimeTypes: [],
extensions: ['.txt', 'md'], // Mixed with/without dots
loader: async () => createMockHandler('test')
})
expect(registry.hasHandler('test')).toBe(true)
})
})
describe('MIME Type Routing', () => {
beforeEach(() => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv', 'application/csv'],
extensions: ['.csv', '.tsv'],
loader: async () => createMockHandler('csv')
})
registry.registerHandler({
name: 'excel',
mimeTypes: [
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel'
],
extensions: ['.xlsx', '.xls'],
loader: async () => createMockHandler('excel')
})
registry.registerHandler({
name: 'pdf',
mimeTypes: ['application/pdf'],
extensions: ['.pdf'],
loader: async () => createMockHandler('pdf')
})
})
it('should get handler by MIME type', async () => {
const handler = await registry.getHandlerByMimeType('text/csv')
expect(handler).toBeDefined()
expect(handler?.format).toBe('csv')
})
it('should get handler by Excel MIME type', async () => {
const handler = await registry.getHandlerByMimeType(
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
expect(handler).toBeDefined()
expect(handler?.format).toBe('excel')
})
it('should get handler by legacy Excel MIME type', async () => {
const handler = await registry.getHandlerByMimeType('application/vnd.ms-excel')
expect(handler).toBeDefined()
expect(handler?.format).toBe('excel')
})
it('should return null for unknown MIME type', async () => {
const handler = await registry.getHandlerByMimeType('application/unknown')
expect(handler).toBeNull()
})
it('should list handlers for a MIME type', () => {
const handlers = registry.getHandlersForMimeType('text/csv')
expect(handlers).toContain('csv')
})
})
describe('Extension Routing', () => {
beforeEach(() => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv', '.tsv'],
loader: async () => createMockHandler('csv')
})
registry.registerHandler({
name: 'excel',
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
extensions: ['.xlsx', '.xls'],
loader: async () => createMockHandler('excel')
})
})
it('should get handler by extension (with dot)', async () => {
const handler = await registry.getHandlerByExtension('.csv')
expect(handler).toBeDefined()
expect(handler?.format).toBe('csv')
})
it('should get handler by extension (without dot)', async () => {
const handler = await registry.getHandlerByExtension('csv')
expect(handler).toBeDefined()
expect(handler?.format).toBe('csv')
})
it('should handle case-insensitive extensions', async () => {
const handler = await registry.getHandlerByExtension('.XLSX')
expect(handler).toBeDefined()
expect(handler?.format).toBe('excel')
})
it('should return null for unknown extension', async () => {
const handler = await registry.getHandlerByExtension('.xyz')
expect(handler).toBeNull()
})
})
describe('Filename-Based Handler Selection', () => {
beforeEach(() => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
registry.registerHandler({
name: 'excel',
mimeTypes: ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
extensions: ['.xlsx'],
loader: async () => createMockHandler('excel')
})
})
it('should get handler by filename (MIME detection)', async () => {
const handler = await registry.getHandler('data.xlsx')
expect(handler).toBeDefined()
expect(handler?.format).toBe('excel')
})
it('should get handler by filename (extension fallback)', async () => {
const handler = await registry.getHandler('report.csv')
expect(handler).toBeDefined()
expect(handler?.format).toBe('csv')
})
it('should handle full paths', async () => {
const handler = await registry.getHandler('/path/to/file.xlsx')
expect(handler).toBeDefined()
expect(handler?.format).toBe('excel')
})
it('should return null for unsupported filename', async () => {
const handler = await registry.getHandler('document.txt')
expect(handler).toBeNull()
})
})
describe('Lazy Loading', () => {
it('should lazy-load handlers on first access', async () => {
let loadCount = 0
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => {
loadCount++
return createMockHandler('csv')
}
})
expect(loadCount).toBe(0)
const handler1 = await registry.getHandlerByName('csv')
expect(loadCount).toBe(1)
expect(handler1?.format).toBe('csv')
// Second access should use cached instance
const handler2 = await registry.getHandlerByName('csv')
expect(loadCount).toBe(1) // Still 1, not 2
expect(handler2).toBe(handler1) // Same instance
})
it('should cache handler instances', async () => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
const handler1 = await registry.getHandlerByExtension('.csv')
const handler2 = await registry.getHandlerByMimeType('text/csv')
expect(handler2).toBe(handler1) // Same cached instance
})
it('should handle loader errors gracefully', async () => {
registry.registerHandler({
name: 'failing',
mimeTypes: ['application/x-failing'],
extensions: ['.fail'],
loader: async () => {
throw new Error('Handler failed to load')
}
})
const handler = await registry.getHandlerByExtension('.fail')
expect(handler).toBeNull()
})
})
describe('Interface Compatibility', () => {
it('should implement HandlerRegistry interface', () => {
// Check required properties exist
expect(registry.handlers).toBeDefined()
expect(registry.loaded).toBeDefined()
expect(typeof registry.register).toBe('function')
expect(typeof registry.getHandler).toBe('function')
})
it('should support register() method for backward compatibility', async () => {
const csvHandler = createMockHandler('csv')
registry.register(['.csv', '.tsv'], async () => csvHandler)
const handler = await registry.getHandler('.csv')
expect(handler).toBe(csvHandler)
})
it('should populate handlers Map for backward compatibility', () => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
expect(registry.handlers.has('csv')).toBe(true)
expect(typeof registry.handlers.get('csv')).toBe('function')
})
it('should populate loaded Map after loading', async () => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
expect(registry.loaded.has('csv')).toBe(false)
await registry.getHandlerByName('csv')
expect(registry.loaded.has('csv')).toBe(true)
})
})
describe('Multiple Handlers Per MIME Type', () => {
it('should support multiple handlers for same MIME type', () => {
registry.registerHandler({
name: 'csv-basic',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv-basic')
})
registry.registerHandler({
name: 'csv-advanced',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv-advanced')
})
const handlers = registry.getHandlersForMimeType('text/csv')
expect(handlers).toHaveLength(2)
expect(handlers).toContain('csv-basic')
expect(handlers).toContain('csv-advanced')
})
it('should return first matching handler', async () => {
registry.registerHandler({
name: 'csv-basic',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv-basic')
})
registry.registerHandler({
name: 'csv-advanced',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv-advanced')
})
// Should return first registered handler
const handler = await registry.getHandlerByMimeType('text/csv')
expect(handler?.format).toBe('csv-basic')
})
})
describe('Registry Management', () => {
it('should clear all handlers', () => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
expect(registry.hasHandler('csv')).toBe(true)
registry.clear()
expect(registry.hasHandler('csv')).toBe(false)
expect(registry.getRegisteredHandlers()).toHaveLength(0)
})
it('should check if handler is registered', () => {
expect(registry.hasHandler('csv')).toBe(false)
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
expect(registry.hasHandler('csv')).toBe(true)
expect(registry.hasHandler('excel')).toBe(false)
})
})
describe('Edge Cases', () => {
it('should handle files without extensions', async () => {
registry.registerHandler({
name: 'csv',
mimeTypes: ['text/csv'],
extensions: ['.csv'],
loader: async () => createMockHandler('csv')
})
const handler = await registry.getHandler('data')
expect(handler).toBeNull()
})
it('should handle empty extension list', () => {
registry.registerHandler({
name: 'special',
mimeTypes: ['application/x-special'],
extensions: [],
loader: async () => createMockHandler('special')
})
expect(registry.hasHandler('special')).toBe(true)
})
it('should handle empty MIME type list', async () => {
registry.registerHandler({
name: 'extension-only',
mimeTypes: [],
extensions: ['.xyz'],
loader: async () => createMockHandler('extension-only')
})
const handler = await registry.getHandlerByExtension('.xyz')
expect(handler?.format).toBe('extension-only')
})
})
})

View file

@ -1,311 +0,0 @@
/**
* ImageHandler Tests (v5.8.0 - Pure JavaScript)
*
* Tests for image processing with EXIF extraction and metadata extraction
* Using probe-image-size + exifr (no native dependencies)
*/
import { describe, it, expect, beforeEach } from 'vitest'
import { ImageHandler } from '../../../src/augmentations/intelligentImport/handlers/imageHandler.js'
import { readFileSync } from 'fs'
import { join } from 'path'
describe('ImageHandler (v5.8.0 - Pure JS)', () => {
let handler: ImageHandler
// Simple test image generators (minimal PNG/JPEG headers)
const createMinimalJPEG = (width: number = 100, height: number = 100): Buffer => {
// Minimal JPEG: SOI + SOF0 + EOI
// This is a valid but minimal JPEG structure
const soi = Buffer.from([0xFF, 0xD8]) // Start of Image
const sof0 = Buffer.from([
0xFF, 0xC0, // SOF0 marker
0x00, 0x11, // Length: 17 bytes
0x08, // Precision: 8 bits
(height >> 8) & 0xFF, height & 0xFF, // Height
(width >> 8) & 0xFF, width & 0xFF, // Width
0x03, // Components: 3 (YCbCr)
0x01, 0x22, 0x00, // Y component
0x02, 0x11, 0x01, // Cb component
0x03, 0x11, 0x01 // Cr component
])
const eoi = Buffer.from([0xFF, 0xD9]) // End of Image
return Buffer.concat([soi, sof0, eoi])
}
const createMinimalPNG = (width: number = 100, height: number = 100): Buffer => {
// PNG signature
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])
// IHDR chunk
const ihdr = Buffer.alloc(25)
ihdr.writeUInt32BE(13, 0) // Length
ihdr.write('IHDR', 4)
ihdr.writeUInt32BE(width, 8)
ihdr.writeUInt32BE(height, 12)
ihdr.writeUInt8(8, 16) // Bit depth
ihdr.writeUInt8(2, 17) // Color type (RGB)
ihdr.writeUInt8(0, 18) // Compression
ihdr.writeUInt8(0, 19) // Filter
ihdr.writeUInt8(0, 20) // Interlace
ihdr.writeUInt32BE(0, 21) // CRC (simplified)
// IEND chunk
const iend = Buffer.from([0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130])
return Buffer.concat([signature, ihdr, iend])
}
beforeEach(() => {
handler = new ImageHandler()
})
describe('Handler Detection', () => {
it('should identify as image format handler', () => {
expect(handler.format).toBe('image')
})
it('should handle JPEG files by filename', () => {
expect(handler.canHandle({ filename: 'photo.jpg' })).toBe(true)
expect(handler.canHandle({ filename: 'photo.jpeg' })).toBe(true)
})
it('should handle PNG files by filename', () => {
expect(handler.canHandle({ filename: 'logo.png' })).toBe(true)
})
it('should handle WebP files by filename', () => {
expect(handler.canHandle({ filename: 'image.webp' })).toBe(true)
})
it('should handle other image formats', () => {
expect(handler.canHandle({ filename: 'photo.gif' })).toBe(true)
expect(handler.canHandle({ filename: 'photo.tiff' })).toBe(true)
expect(handler.canHandle({ filename: 'photo.bmp' })).toBe(true)
expect(handler.canHandle({ filename: 'icon.svg' })).toBe(true)
})
it('should handle images by extension', () => {
expect(handler.canHandle({ ext: '.jpg' })).toBe(true)
expect(handler.canHandle({ ext: 'png' })).toBe(true)
})
it('should reject non-image files', () => {
expect(handler.canHandle({ filename: 'document.pdf' })).toBe(false)
expect(handler.canHandle({ filename: 'data.csv' })).toBe(false)
expect(handler.canHandle({ filename: 'text.txt' })).toBe(false)
})
it('should detect JPEG by magic bytes', () => {
const jpegBuffer = createMinimalJPEG(100, 100)
expect(handler.canHandle(jpegBuffer)).toBe(true)
})
it('should detect PNG by magic bytes', () => {
const pngBuffer = createMinimalPNG(100, 100)
expect(handler.canHandle(pngBuffer)).toBe(true)
})
})
describe('Image Metadata Extraction', () => {
it('should extract JPEG metadata', async () => {
const imageBuffer = createMinimalJPEG(800, 600)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
expect(result.format).toBe('image')
expect(result.data).toHaveLength(1)
const imageData = result.data[0]
expect(imageData.type).toBe('media')
expect(imageData.metadata).toBeDefined()
expect(imageData.metadata.subtype).toBe('image')
expect(imageData.metadata.width).toBe(800)
expect(imageData.metadata.height).toBe(600)
expect(imageData.metadata.format).toBe('jpg') // probe-image-size uses 'jpg' not 'jpeg'
})
it('should extract PNG metadata', async () => {
const imageBuffer = createMinimalPNG(400, 300)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
const imageData = result.data[0]
expect(imageData.metadata.width).toBe(400)
expect(imageData.metadata.height).toBe(300)
expect(imageData.metadata.format).toBe('png')
})
it('should include image size in bytes', async () => {
const imageBuffer = createMinimalJPEG(200, 200)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
const imageData = result.data[0]
expect(imageData.metadata.size).toBe(imageBuffer.length)
expect(imageData.metadata.size).toBeGreaterThan(0)
})
it('should include MIME type when available', async () => {
const imageBuffer = createMinimalJPEG(100, 100)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
const imageData = result.data[0]
expect(imageData.metadata.mimeType).toBeDefined()
expect(imageData.metadata.mimeType).toContain('image/')
})
it('should include processing time in metadata', async () => {
const imageBuffer = createMinimalJPEG(800, 600)
const result = await handler.process(imageBuffer)
expect(result.metadata.processingTime).toBeGreaterThanOrEqual(0)
expect(result.metadata.processingTime).toBeLessThan(5000)
})
it('should include image metadata in result metadata', async () => {
const imageBuffer = createMinimalJPEG(800, 600)
const result = await handler.process(imageBuffer)
expect(result.metadata.imageMetadata).toBeDefined()
expect(result.metadata.imageMetadata.width).toBe(800)
expect(result.metadata.imageMetadata.height).toBe(600)
})
})
describe('EXIF Data Extraction', () => {
it('should handle images without EXIF data', async () => {
const imageBuffer = createMinimalJPEG(800, 600)
const result = await handler.process(imageBuffer, {
extractEXIF: true
})
const imageData = result.data[0]
// Should not crash, EXIF will be undefined
expect(imageData.metadata.exif).toBeUndefined()
})
it('should extract EXIF by default', async () => {
const imageBuffer = createMinimalJPEG(800, 600)
// Default: EXIF extraction enabled
const result = await handler.process(imageBuffer)
// Will be undefined for test images, but should not crash
expect(result.metadata.exifData).toBeUndefined()
})
it('should allow disabling EXIF extraction', async () => {
const imageBuffer = createMinimalJPEG(800, 600)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
const imageData = result.data[0]
expect(imageData.metadata.exif).toBeUndefined()
})
})
describe('Error Handling', () => {
it('should handle invalid image data gracefully', async () => {
const invalidBuffer = Buffer.from('not an image', 'utf-8')
// Should still process but with fallback values
const result = await handler.process(invalidBuffer, { extractEXIF: false })
// Fallback detection should provide basic info
expect(result.data[0].metadata.format).toBeDefined()
expect(result.data[0].metadata.size).toBe(invalidBuffer.length)
})
it('should handle empty buffer', async () => {
const emptyBuffer = Buffer.alloc(0)
// Should not crash, but will have unknown format
const result = await handler.process(emptyBuffer, { extractEXIF: false })
expect(result.data[0].metadata.format).toBe('unknown')
})
})
describe('Format Support', () => {
it('should process JPEG images', async () => {
const imageBuffer = createMinimalJPEG(200, 200)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
expect(result.data[0].metadata.format).toBe('jpg') // probe-image-size uses 'jpg' not 'jpeg'
})
it('should process PNG images', async () => {
const imageBuffer = createMinimalPNG(200, 200)
const result = await handler.process(imageBuffer, {
extractEXIF: false
})
expect(result.data[0].metadata.format).toBe('png')
})
it('should handle various image dimensions', async () => {
const sizes = [
[100, 100],
[1920, 1080],
[400, 300],
[1000, 500]
]
for (const [width, height] of sizes) {
const imageBuffer = createMinimalJPEG(width, height)
const result = await handler.process(imageBuffer, { extractEXIF: false })
expect(result.data[0].metadata.width).toBe(width)
expect(result.data[0].metadata.height).toBe(height)
}
})
})
describe('Integration with BaseFormatHandler', () => {
it('should inherit MIME type detection from BaseFormatHandler', () => {
// getMimeType is protected, but we can verify behavior
expect(handler.canHandle({ filename: 'test.jpg' })).toBe(true)
expect(handler.canHandle({ filename: 'test.png' })).toBe(true)
})
it('should provide structured ProcessedData', async () => {
const imageBuffer = createMinimalJPEG(200, 200)
const result = await handler.process(imageBuffer, {
filename: 'test-image.jpg',
extractEXIF: false
})
// Verify ProcessedData structure
expect(result.format).toBe('image')
expect(result.data).toBeInstanceOf(Array)
expect(result.metadata).toBeDefined()
expect(result.filename).toBe('test-image.jpg')
// Verify data structure
const entity = result.data[0]
expect(entity.name).toBe('test-image')
expect(entity.type).toBe('media')
expect(entity.metadata).toBeDefined()
})
})
})

View file

@ -15,13 +15,7 @@ describe('Brainy 3.0 Core (Unit Tests)', () => {
beforeEach(async () => {
// Create instance with real embeddings for production-ready tests
brain = new Brainy({
storage: { type: 'memory' },
augmentations: {
cache: false,
metrics: false,
display: false,
monitoring: false
}
storage: { type: 'memory' }
})
await brain.init()
@ -196,7 +190,7 @@ describe('Brainy 3.0 Core (Unit Tests)', () => {
})
describe('Statistics and Metadata', () => {
it('should track statistics through augmentations', async () => {
it('should track statistics', async () => {
await brain.add({
data: { name: 'Test1' },
type: NounType.Concept

View file

@ -482,24 +482,6 @@ describe('Brainy.add()', () => {
})
})
describe('augmentations', () => {
it('should apply augmentations during add', async () => {
// This would test augmentation pipeline if configured
// For now, just verify the entity is added correctly
const params = createAddParams({
data: 'Augmentation test',
type: 'thing',
metadata: { augment: true }
})
const id = await brain.add(params)
const entity = await brain.get(id)
expect(entity).not.toBeNull()
expect(entity!.metadata.augment).toBe(true)
})
})
describe('caching behavior', () => {
it('should retrieve consistent entities', async () => {
// Arrange (v5.1.0: use valid UUID format)

View file

@ -18,13 +18,7 @@ describe('add() Performance Regression Tests', () => {
beforeEach(async () => {
brain = new Brainy({
storage: { type: 'memory' },
silent: true,
augmentations: {
cache: false,
metrics: false,
display: false,
monitoring: false
}
silent: true
})
await brain.init()
})

View file

@ -214,7 +214,6 @@ describe('Brainy plugin integration', () => {
const brain = new Brainy({
storage: { type: 'memory' },
silent: true,
augmentations: { cache: false, metrics: false, display: false, monitoring: false }
})
brain.use(mockPlugin)
await brain.init()
@ -244,7 +243,6 @@ describe('Brainy plugin integration', () => {
const brain = new Brainy({
storage: { type: 'memory' },
silent: true,
augmentations: { cache: false, metrics: false, display: false, monitoring: false }
})
brain.use(mockPlugin)
await brain.init()
@ -263,7 +261,6 @@ describe('Brainy plugin integration', () => {
const brain = new Brainy({
storage: { type: 'memory' },
silent: true,
augmentations: { cache: false, metrics: false, display: false, monitoring: false }
})
brain.use(mockPlugin)
await brain.init()
@ -293,7 +290,6 @@ describe('Brainy plugin integration', () => {
const brain = new Brainy({
storage: { type: 'memory' },
silent: true,
augmentations: { cache: false, metrics: false, display: false, monitoring: false }
})
brain.use(mockPlugin)

View file

@ -1,219 +0,0 @@
/**
* Tests for Intelligent Type Matching with embeddings
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import { IntelligentTypeMatcher } from '../../src/augmentations/typeMatching/intelligentTypeMatcher.js'
import { NounType, VerbType } from '../../src/types/graphTypes.js'
describe('Intelligent Type Matching', () => {
let matcher: IntelligentTypeMatcher
beforeAll(async () => {
matcher = new IntelligentTypeMatcher()
await matcher.init()
})
afterAll(async () => {
await matcher.dispose()
})
describe('Noun Type Detection', () => {
it('should detect Person type from user data', async () => {
const result = await matcher.matchNounType({
name: 'John Doe',
email: 'john@example.com',
age: 30
})
expect(result.type).toBeDefined()
expect(result.confidence).toBeGreaterThan(0)
expect(result.alternatives).toBeDefined()
expect(result.alternatives.length).toBeGreaterThanOrEqual(0)
})
it('should detect Organization type from company data', async () => {
const result = await matcher.matchNounType({
companyName: 'Acme Corp',
employees: 500,
industry: 'Technology'
})
// With real type embeddings (v3.33.0+), type detection uses actual semantic similarity
// Results depend on the embedding quality and field patterns
expect(result.type).toBeDefined()
expect(result.confidence).toBeGreaterThan(0.1)
})
it('should detect Location type from geographic data', async () => {
const result = await matcher.matchNounType({
latitude: 37.7749,
longitude: -122.4194,
city: 'San Francisco'
})
// With real type embeddings (v3.33.0+), geographic data detection is semantic
expect(result.type).toBeDefined()
expect(result.confidence).toBeGreaterThan(0.1)
})
it('should detect Document type from text content', async () => {
const result = await matcher.matchNounType({
title: 'Research Paper',
content: 'Abstract: This paper discusses...',
author: 'Dr. Smith',
pages: 20
})
// With real type embeddings (v3.33.0+), could match various types based on semantic similarity
expect(result.type).toBeDefined()
expect(result.confidence).toBeGreaterThan(0.0)
})
it('should detect Product type from commercial data', async () => {
const result = await matcher.matchNounType({
price: 99.99,
sku: 'PROD-123',
inventory: 50,
productId: 'abc-123'
})
// With real type embeddings (v3.33.0+), commercial data uses semantic matching
expect(result.type).toBeDefined()
expect(result.confidence).toBeGreaterThan(0.1)
})
it('should detect Event type from temporal data', async () => {
const result = await matcher.matchNounType({
startTime: '2024-01-01',
endTime: '2024-01-02',
attendees: 100,
eventType: 'conference'
})
// With real type embeddings (v3.33.0+), temporal data uses semantic matching
expect(result.type).toBeDefined()
expect(result.confidence).toBeGreaterThan(0.1)
})
it('should handle ambiguous data with alternatives', async () => {
const result = await matcher.matchNounType({
value: 100,
type: 'unknown',
data: 'mixed'
})
expect(result.type).toBeDefined()
expect(result.alternatives).toBeDefined()
expect(result.alternatives.length).toBeGreaterThan(0)
})
})
describe('Verb Type Detection', () => {
it('should detect MemberOf relationship', async () => {
const result = await matcher.matchVerbType(
{ id: 'user1', type: 'person' },
{ id: 'org1', type: 'organization' },
'memberOf'
)
// With mocked embeddings, type detection is non-deterministic
expect(result.type).toBeDefined()
expect(Object.values(VerbType)).toContain(result.type)
expect(result.confidence).toBeGreaterThan(0)
})
it('should detect CreatedBy relationship', async () => {
const result = await matcher.matchVerbType(
{ id: 'doc1', type: 'document' },
{ id: 'author1', type: 'person' },
'created by'
)
// With mocked embeddings, type detection is non-deterministic
expect(result.type).toBeDefined()
expect(Object.values(VerbType)).toContain(result.type)
expect(result.confidence).toBeGreaterThan(0)
})
it('should detect Contains relationship', async () => {
const result = await matcher.matchVerbType(
{ id: 'folder1', type: 'collection' },
{ id: 'file1', type: 'file' },
'contains'
)
// With mocked embeddings, type detection is non-deterministic
expect(result.type).toBeDefined()
expect(Object.values(VerbType)).toContain(result.type)
expect(result.confidence).toBeGreaterThan(0)
})
it('should handle unknown relationships with defaults', async () => {
const result = await matcher.matchVerbType(
{ id: 'a' },
{ id: 'b' },
'somehow connected'
)
expect(result.type).toBeDefined()
expect(Object.values(VerbType)).toContain(result.type)
})
})
describe('Type Coverage', () => {
it('should have embeddings for all 42 noun types', async () => {
const nounTypes = Object.values(NounType)
expect(nounTypes.length).toBe(42)
// Test that each type can be matched
for (const nounType of nounTypes) {
const result = await matcher.matchNounType({
type: nounType,
test: 'coverage check'
})
expect(result.type).toBeDefined()
}
})
it('should have embeddings for all 127 verb types', async () => {
const verbTypes = Object.values(VerbType)
expect(verbTypes.length).toBe(127)
// Test that each type can be matched
for (const verbType of verbTypes) {
const result = await matcher.matchVerbType(
{ id: 'source' },
{ id: 'target' },
verbType
)
expect(result.type).toBeDefined()
}
})
})
describe('Cache Performance', () => {
it('should cache repeated type matches', async () => {
const testData = { name: 'Cache Test', value: 123 }
const result1 = await matcher.matchNounType(testData)
const result2 = await matcher.matchNounType(testData)
expect(result1.type).toBe(result2.type)
expect(result1.confidence).toBe(result2.confidence)
// Cache should return consistent results
expect(result2.type).toBeDefined()
})
it('should clear cache when requested', async () => {
const testData = { name: 'Clear Cache Test' }
await matcher.matchNounType(testData) // Populate cache
matcher.clearCache()
// Should still work after cache clear
const result = await matcher.matchNounType(testData)
expect(result.type).toBeDefined()
})
})
})