brainy/tests/helpers/test-factory.ts
David Snelling ce2bc76648 feat: Brainy 3.0 - Triple Intelligence Release
BREAKING CHANGE: New unified API for vector, graph, and document search

Major Changes:
- NEW: brain.add() replaces brain.addNoun()
- NEW: brain.find() replaces brain.search()
- NEW: brain.relate() replaces brain.addVerb()
- NEW: brain.update() replaces brain.updateNoun()
- NEW: brain.delete() replaces brain.deleteNoun()

Features:
- Triple Intelligence™ engine (vector + graph + document)
- 31 NounTypes × 40 VerbTypes for universal knowledge modeling
- Zero-config parameter validation
- Enhanced augmentation system (cache, display, metrics)
- <10ms search performance with HNSW indexing
- Full TypeScript type safety

Infrastructure:
- Comprehensive test suites for find() and neural APIs
- Fixed neural API internal calls (getNoun → get)
- Updated README with accurate 3.0 examples
- ESLint v9 configuration
- Structured logging framework

🧠 Generated with Brainy 3.0

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-15 11:06:16 -07:00

486 lines
No EOL
12 KiB
TypeScript

/**
* Test Factory - Comprehensive test data generation and utilities
* Provides consistent, realistic test data for all Brainy tests
*/
import { v4 as uuidv4 } from '../../src/universal/uuid'
import type { NounType, VerbType } from '../../src/types/graphTypes'
import type {
Entity,
Relation,
Result,
AddParams,
UpdateParams,
RelateParams,
FindParams,
BrainyConfig,
} from '../../src/types/brainy.types'
import type { Vector } from '../../src/coreTypes'
/**
* Test Data Generators
*/
// Generate a unique test ID
export function generateTestId(prefix = 'test'): string {
return `${prefix}_${uuidv4().slice(0, 8)}_${Date.now()}`
}
// Generate test vector (384-dimensional vector matching all-MiniLM-L6-v2)
export function generateTestVector(dimension = 384): Vector {
// Generate a deterministic but varied embedding
const vector = new Array(dimension)
for (let i = 0; i < dimension; i++) {
// Create varied but deterministic values
vector[i] = Math.sin(i * 0.1) * 0.5 + Math.cos(i * 0.05) * 0.3
}
// Normalize to unit vector
const magnitude = Math.sqrt(vector.reduce((sum, val) => sum + val * val, 0))
return vector.map(val => val / magnitude)
}
// Generate realistic metadata
export function generateTestMetadata(overrides: any = {}): any {
return {
name: `Test Item ${generateTestId()}`,
description: 'Test description',
tags: ['test', 'automated'],
createdAt: Date.now(),
updatedAt: Date.now(),
version: 1,
source: 'test-factory',
confidence: 0.95,
...overrides,
}
}
// Generate a test entity
export function createTestEntity(overrides: Partial<Entity> = {}): Entity {
const id = overrides.id || generateTestId('entity')
const now = Date.now()
return {
id,
type: 'person' as NounType,
vector: generateTestVector(),
metadata: generateTestMetadata(),
service: 'test',
createdAt: now,
updatedAt: now,
...overrides,
}
}
// Generate multiple test entities
export function createTestEntities(count: number, baseOverrides: Partial<Entity> = {}): Entity[] {
return Array.from({ length: count }, (_, i) =>
createTestEntity({
...baseOverrides,
metadata: {
...generateTestMetadata(),
name: `Test Entity ${i + 1}`,
index: i,
},
})
)
}
// Generate a test relation
export function createTestRelation(overrides: Partial<Relation> = {}): Relation {
const id = overrides.id || generateTestId('relation')
const now = Date.now()
return {
id,
from: overrides.from || generateTestId('from'),
to: overrides.to || generateTestId('to'),
type: (overrides.type || 'RelatedTo') as VerbType,
weight: 1.0,
metadata: generateTestMetadata(),
service: 'test',
createdAt: now,
updatedAt: now,
...overrides,
}
}
// Generate multiple test relations
export function createTestRelations(count: number, baseOverrides: Partial<Relation> = {}): Relation[] {
return Array.from({ length: count }, (_, i) =>
createTestRelation({
...baseOverrides,
metadata: {
...generateTestMetadata(),
index: i,
},
})
)
}
// Generate a test result (entity with score)
export function createTestResult(
score: number = 0.95,
entityOverrides: Partial<Entity> = {}
): Result {
return {
id: entityOverrides.id || generateTestId('result'),
score,
entity: createTestEntity(entityOverrides),
}
}
// Generate add parameters
export function createAddParams(overrides: Partial<AddParams> = {}): AddParams {
return {
data: 'Test content for embedding',
type: 'thing' as NounType,
metadata: generateTestMetadata(),
service: 'test',
...overrides,
}
}
// Generate update parameters
export function createUpdateParams(id: string, overrides: Partial<UpdateParams> = {}): UpdateParams {
return {
id,
metadata: { updated: true },
merge: true,
...overrides,
}
}
// Generate relate parameters
export function createRelateParams(from: string, to: string, overrides: Partial<RelateParams> = {}): RelateParams {
return {
from,
to,
type: 'RelatedTo' as VerbType,
weight: 1.0,
metadata: generateTestMetadata(),
service: 'test',
...overrides,
}
}
// Generate find parameters
export function createFindParams(overrides: Partial<FindParams> = {}): FindParams {
return {
query: 'test query',
limit: 10,
offset: 0,
explain: false,
includeRelations: false,
service: 'test',
...overrides,
}
}
// Generate test configuration
export function createTestConfig(overrides: Partial<BrainyConfig> = {}): BrainyConfig {
return {
storage: { type: 'memory' },
model: { type: 'fast' },
index: {
m: 16,
efConstruction: 200,
efSearch: 50,
},
cache: { maxSize: 1000, ttl: 3600 },
...overrides,
}
}
/**
* Test Data Sets - Pre-built realistic scenarios
*/
// Create a social network graph
export function createSocialNetworkTestData() {
const alice = createTestEntity({
id: 'alice',
type: 'person' as NounType,
metadata: { name: 'Alice', age: 30 }
})
const bob = createTestEntity({
id: 'bob',
type: 'person' as NounType,
metadata: { name: 'Bob', age: 25 }
})
const charlie = createTestEntity({
id: 'charlie',
type: 'person' as NounType,
metadata: { name: 'Charlie', age: 35 }
})
const diana = createTestEntity({
id: 'diana',
type: 'person' as NounType,
metadata: { name: 'Diana', age: 28 }
})
const entities = [alice, bob, charlie, diana]
const relations = [
createTestRelation({ from: 'alice', to: 'bob', type: 'friendOf' as VerbType }),
createTestRelation({ from: 'alice', to: 'charlie', type: 'friendOf' as VerbType }),
createTestRelation({ from: 'bob', to: 'charlie', type: 'worksWith' as VerbType }),
createTestRelation({ from: 'charlie', to: 'diana', type: 'mentors' as VerbType }),
createTestRelation({ from: 'alice', to: 'diana', type: 'likes' as VerbType }),
]
return { entities, relations }
}
// Create a knowledge graph
export function createKnowledgeGraphTestData() {
const entities = [
createTestEntity({
id: 'earth',
type: 'location' as NounType,
metadata: { name: 'Earth', type: 'planet' }
}),
createTestEntity({
id: 'sun',
type: 'thing' as NounType,
metadata: { name: 'Sun', type: 'star' }
}),
createTestEntity({
id: 'moon',
type: 'thing' as NounType,
metadata: { name: 'Moon', type: 'satellite' }
}),
createTestEntity({
id: 'mars',
type: 'location' as NounType,
metadata: { name: 'Mars', type: 'planet' }
}),
]
const relations = [
createTestRelation({ from: 'earth', to: 'sun', type: 'DependsOn' as VerbType }),
createTestRelation({ from: 'moon', to: 'earth', type: 'DependsOn' as VerbType }),
createTestRelation({ from: 'mars', to: 'sun', type: 'DependsOn' as VerbType }),
createTestRelation({ from: 'earth', to: 'moon', type: 'Contains' as VerbType }),
]
return { entities, relations }
}
// Create large dataset for performance testing
export function createLargeTestDataset(entityCount = 1000, relationCount = 5000) {
const entities = createTestEntities(entityCount)
const relations: Relation[] = []
const verbTypes = ['relatedTo', 'friendOf', 'worksWith', 'creates', 'owns'] as VerbType[]
// Create random relations between entities
for (let i = 0; i < relationCount; i++) {
const fromIdx = Math.floor(Math.random() * entityCount)
const toIdx = Math.floor(Math.random() * entityCount)
if (fromIdx !== toIdx) {
relations.push(
createTestRelation({
from: entities[fromIdx].id,
to: entities[toIdx].id,
type: verbTypes[Math.floor(Math.random() * verbTypes.length)],
})
)
}
}
return { entities, relations }
}
/**
* Test Assertion Helpers
*/
export function assertEntity(entity: any): asserts entity is Entity {
if (!entity || typeof entity !== 'object') {
throw new Error('Entity must be an object')
}
if (!entity.id || typeof entity.id !== 'string') {
throw new Error('Entity must have a string id')
}
if (!entity.type || typeof entity.type !== 'string') {
throw new Error('Entity must have a string type')
}
if (!entity.vector || !Array.isArray(entity.vector)) {
throw new Error('Entity must have an array vector')
}
if (typeof entity.createdAt !== 'number') {
throw new Error('Entity must have a numeric createdAt timestamp')
}
}
export function assertRelation(relation: any): asserts relation is Relation {
if (!relation || typeof relation !== 'object') {
throw new Error('Relation must be an object')
}
if (!relation.id || typeof relation.id !== 'string') {
throw new Error('Relation must have a string id')
}
if (!relation.from || typeof relation.from !== 'string') {
throw new Error('Relation must have a string from')
}
if (!relation.to || typeof relation.to !== 'string') {
throw new Error('Relation must have a string to')
}
if (!relation.type || typeof relation.type !== 'string') {
throw new Error('Relation must have a string type')
}
if (typeof relation.createdAt !== 'number') {
throw new Error('Relation must have a numeric createdAt timestamp')
}
}
export function assertResult(result: any): asserts result is Result {
if (!result || typeof result !== 'object') {
throw new Error('Result must be an object')
}
if (!result.id || typeof result.id !== 'string') {
throw new Error('Result must have a string id')
}
if (typeof result.score !== 'number') {
throw new Error('Result must have a numeric score')
}
assertEntity(result.entity)
}
/**
* Test Cleanup Helpers
*/
export class TestCleanup {
private cleanupFunctions: Array<() => Promise<void>> = []
register(fn: () => Promise<void>) {
this.cleanupFunctions.push(fn)
}
async cleanup() {
for (const fn of this.cleanupFunctions.reverse()) {
try {
await fn()
} catch (error) {
console.error('Cleanup error:', error)
}
}
this.cleanupFunctions = []
}
}
/**
* Test Timing Helpers
*/
export async function measureExecutionTime<T>(
fn: () => Promise<T>,
label?: string
): Promise<{ result: T; duration: number }> {
const start = performance.now()
const result = await fn()
const duration = performance.now() - start
if (label) {
console.log(`${label}: ${duration.toFixed(2)}ms`)
}
return { result, duration }
}
/**
* Test Delay Helper
*/
export function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
/**
* Mock Storage Helper
*/
export function createMockStorage() {
const store = new Map<string, any>()
return {
get: async (key: string) => store.get(key),
set: async (key: string, value: any) => { store.set(key, value); return true },
delete: async (key: string) => store.delete(key),
has: async (key: string) => store.has(key),
clear: async () => store.clear(),
size: () => store.size,
entries: () => Array.from(store.entries()),
}
}
/**
* Test Error Generators
*/
export function createTestError(message = 'Test error', code = 'TEST_ERROR') {
const error = new Error(message) as any
error.code = code
return error
}
export function createNetworkError() {
return createTestError('Network request failed', 'NETWORK_ERROR')
}
export function createTimeoutError() {
return createTestError('Operation timed out', 'TIMEOUT_ERROR')
}
export function createValidationError(field: string) {
return createTestError(`Validation failed for field: ${field}`, 'VALIDATION_ERROR')
}
// Export everything as a namespace for convenience
export const TestFactory = {
// IDs
generateTestId,
// Core data
generateTestVector,
generateTestMetadata,
createTestEntity,
createTestEntities,
createTestRelation,
createTestRelations,
createTestResult,
// Parameters
createAddParams,
createUpdateParams,
createRelateParams,
createFindParams,
// Config
createTestConfig,
// Datasets
createSocialNetworkTestData,
createKnowledgeGraphTestData,
createLargeTestDataset,
// Assertions
assertEntity,
assertRelation,
assertResult,
// Utilities
TestCleanup,
measureExecutionTime,
delay,
createMockStorage,
// Errors
createTestError,
createNetworkError,
createTimeoutError,
createValidationError,
}
export default TestFactory