Skip to main content
Glama
system-runtime.test.ts15.2 kB
/** * Unit tests for System Runtime transformers */ import { describe, expect, test } from 'bun:test'; import { determineAttributeKind, entityToModel, entityToSchema, generateId, msonToSystemRuntimeBundle, } from '../../src/transformers/system-runtime'; import type { MsonAttribute, MsonEntity, MsonModel, MsonRelationship } from '../../src/types'; describe('System Runtime Transformers', () => { describe('generateId', () => { test('should generate unique IDs', () => { const id1 = generateId(); const id2 = generateId(); expect(id1).not.toBe(id2); }); test('should include prefix when provided', () => { const id = generateId('test'); expect(id).toStartWith('test'); }); test('should generate IDs without prefix', () => { const id = generateId(); expect(id.length).toBeGreaterThan(0); }); }); describe('determineAttributeKind', () => { test('should identify primitive types as properties', () => { const attr: MsonAttribute = { name: 'firstName', type: 'string', visibility: 'public', isStatic: false, isReadOnly: false, }; const kind = determineAttributeKind(attr, [], 'entity1'); expect(kind).toBe('property'); }); test('should identify number type as property', () => { const attr: MsonAttribute = { name: 'age', type: 'number', visibility: 'public', isStatic: false, isReadOnly: false, }; const kind = determineAttributeKind(attr, [], 'entity1'); expect(kind).toBe('property'); }); test('should identify boolean type as property', () => { const attr: MsonAttribute = { name: 'isActive', type: 'boolean', visibility: 'public', isStatic: false, isReadOnly: false, }; const kind = determineAttributeKind(attr, [], 'entity1'); expect(kind).toBe('property'); }); test('should identify entity reference as link when no relationship', () => { const attr: MsonAttribute = { name: 'manager', type: 'Person', visibility: 'public', isStatic: false, isReadOnly: false, }; const kind = determineAttributeKind(attr, [], 'entity1'); expect(kind).toBe('link'); }); test('should identify collection based on multiplicity', () => { const attr: MsonAttribute = { name: 'courses', type: 'Course', visibility: 'public', isStatic: false, isReadOnly: false, }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'entity1', to: 'course', type: 'association', multiplicity: { from: '1', to: '0..*' }, }, ]; const kind = determineAttributeKind(attr, relationships, 'entity1'); expect(kind).toBe('collection'); }); test('should identify link based on multiplicity', () => { const attr: MsonAttribute = { name: 'department', type: 'Department', visibility: 'public', isStatic: false, isReadOnly: false, }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'entity1', to: 'department', type: 'association', multiplicity: { from: '1', to: '1' }, }, ]; const kind = determineAttributeKind(attr, relationships, 'entity1'); expect(kind).toBe('link'); }); }); describe('entityToSchema', () => { test('should convert simple entity to schema', () => { const entity: MsonEntity = { id: 'person', name: 'Person', type: 'class', attributes: [ { name: 'firstName', type: 'string', visibility: 'public', isStatic: false, isReadOnly: false, }, { name: 'lastName', type: 'string', visibility: 'public', isStatic: false, isReadOnly: false, }, ], methods: [ { name: 'getFullName', parameters: [], returnType: 'string', visibility: 'public', isStatic: false, isAbstract: false, }, ], }; const schema = entityToSchema(entity, [], [entity]); expect(schema._name).toBe('Person'); expect(schema._inherit).toEqual(['_Component']); expect(schema.firstName).toBe('property'); expect(schema.lastName).toBe('property'); expect(schema.getFullName).toBe('method'); }); test('should handle inheritance relationships', () => { const baseEntity: MsonEntity = { id: 'animal', name: 'Animal', type: 'class', attributes: [], methods: [], }; const derivedEntity: MsonEntity = { id: 'dog', name: 'Dog', type: 'class', attributes: [], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'dog', to: 'animal', type: 'inheritance', }, ]; const schema = entityToSchema(derivedEntity, relationships, [baseEntity, derivedEntity]); expect(schema._inherit).toContain('Animal'); expect(schema._inherit).toContain('_Component'); }); }); describe('entityToModel', () => { test('should convert entity to model with correct types', () => { const entity: MsonEntity = { id: 'person', name: 'Person', type: 'class', attributes: [ { name: 'firstName', type: 'string', visibility: 'public', isStatic: false, isReadOnly: false, }, { name: 'age', type: 'number', visibility: 'public', isStatic: false, isReadOnly: false, }, ], methods: [ { name: 'greet', parameters: [{ name: 'message', type: 'string' }], returnType: 'void', visibility: 'public', isStatic: false, isAbstract: false, }, ], }; const model = entityToModel(entity, [], [entity]); expect(model._name).toBe('Person'); expect(model.firstName).toBe('string'); expect(model.age).toBe('number'); expect(model.greet).toEqual({ message: 'string', '=>': 'void', }); }); test('should handle link types', () => { const personEntity: MsonEntity = { id: 'person', name: 'Person', type: 'class', attributes: [], methods: [], }; const employeeEntity: MsonEntity = { id: 'employee', name: 'Employee', type: 'class', attributes: [ { name: 'manager', type: 'Person', visibility: 'public', isStatic: false, isReadOnly: false, }, ], methods: [], }; const model = entityToModel(employeeEntity, [], [personEntity, employeeEntity]); expect(model.manager).toBe('Person'); }); test('should handle collection types', () => { const courseEntity: MsonEntity = { id: 'course', name: 'Course', type: 'class', attributes: [], methods: [], }; const studentEntity: MsonEntity = { id: 'student', name: 'Student', type: 'class', attributes: [ { name: 'courses', type: 'Course', visibility: 'public', isStatic: false, isReadOnly: false, }, ], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'student', to: 'course', type: 'association', multiplicity: { from: '1', to: '0..*' }, }, ]; const model = entityToModel(studentEntity, relationships, [courseEntity, studentEntity]); expect(model.courses).toEqual(['Course']); }); }); describe('msonToSystemRuntimeBundle', () => { test('should convert complete MSON model to bundle', () => { const model: MsonModel = { id: 'test-model', name: 'Test System', type: 'class', description: 'A test system', entities: [ { id: 'person', name: 'Person', type: 'class', attributes: [ { name: 'name', type: 'string', visibility: 'public', isStatic: false, isReadOnly: false, }, ], methods: [], }, ], relationships: [], }; const bundle = msonToSystemRuntimeBundle(model); expect(bundle.name).toBe('Test System'); expect(bundle.description).toBe('A test system'); expect(bundle.version).toBe('0.0.1'); expect(bundle.master).toBe(true); expect(Object.keys(bundle.schemas).length).toBe(1); expect(Object.keys(bundle.models).length).toBe(1); expect(bundle.components.Person).toBeDefined(); }); test('should create empty sections for types, behaviors, and components', () => { const model: MsonModel = { id: 'test-model', name: 'Test System', type: 'class', entities: [], relationships: [], }; const bundle = msonToSystemRuntimeBundle(model); expect(bundle.types).toEqual({}); expect(bundle.behaviors).toEqual({}); expect(bundle.components).toEqual({}); }); }); describe('Edge Cases and Complex Scenarios', () => { test('should handle bidirectional relationships', () => { const personEntity: MsonEntity = { id: 'person', name: 'Person', type: 'class', attributes: [], methods: [], }; const companyEntity: MsonEntity = { id: 'company', name: 'Company', type: 'class', attributes: [], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'person', to: 'company', type: 'association', multiplicity: { from: '0..*', to: '1' }, name: 'employer', }, ]; const personSchema = entityToSchema(personEntity, relationships, [ personEntity, companyEntity, ]); const companySchema = entityToSchema(companyEntity, relationships, [ personEntity, companyEntity, ]); // Person should have employer link expect(personSchema.employer).toBe('link'); // Company should have persons collection (reverse relationship) expect(companySchema.persons).toBe('collection'); }); test('should handle multiple inheritance', () => { const interfaceA: MsonEntity = { id: 'interfaceA', name: 'InterfaceA', type: 'interface', attributes: [], methods: [], }; const interfaceB: MsonEntity = { id: 'interfaceB', name: 'InterfaceB', type: 'interface', attributes: [], methods: [], }; const implementingClass: MsonEntity = { id: 'impl', name: 'Implementation', type: 'class', attributes: [], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'impl', to: 'interfaceA', type: 'implementation', }, { id: 'rel2', from: 'impl', to: 'interfaceB', type: 'implementation', }, ]; const schema = entityToSchema(implementingClass, relationships, [ interfaceA, interfaceB, implementingClass, ]); expect(schema._inherit).toContain('_Component'); expect(schema._inherit).toContain('InterfaceA'); expect(schema._inherit).toContain('InterfaceB'); expect(schema._inherit.length).toBe(3); }); test('should handle self-referential relationships', () => { const treeNode: MsonEntity = { id: 'treenode', name: 'TreeNode', type: 'class', attributes: [], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'treenode', to: 'treenode', type: 'association', multiplicity: { from: '1', to: '0..*' }, name: 'children', }, ]; const schema = entityToSchema(treeNode, relationships, [treeNode]); const model = entityToModel(treeNode, relationships, [treeNode]); expect(schema.children).toBe('collection'); expect(model.children).toEqual(['TreeNode']); }); test('should avoid duplicate relationship properties', () => { const entity: MsonEntity = { id: 'entity1', name: 'Entity1', type: 'class', attributes: [ { name: 'relatedEntity', type: 'Entity2', visibility: 'public', isStatic: false, isReadOnly: false, }, ], methods: [], }; const entity2: MsonEntity = { id: 'entity2', name: 'Entity2', type: 'class', attributes: [], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'entity1', to: 'entity2', type: 'association', name: 'relatedEntity', }, ]; const schema = entityToSchema(entity, relationships, [entity, entity2]); // Should only have one 'relatedEntity' property (from attribute, not duplicated from relationship) const relatedEntityCount = Object.keys(schema).filter((k) => k === 'relatedEntity').length; expect(relatedEntityCount).toBe(1); }); test('should handle aggregation and composition relationships', () => { const part: MsonEntity = { id: 'part', name: 'Part', type: 'class', attributes: [], methods: [], }; const whole: MsonEntity = { id: 'whole', name: 'Whole', type: 'class', attributes: [], methods: [], }; const relationships: MsonRelationship[] = [ { id: 'rel1', from: 'whole', to: 'part', type: 'composition', multiplicity: { from: '1', to: '1..*' }, }, ]; const wholeSchema = entityToSchema(whole, relationships, [part, whole]); const wholeModel = entityToModel(whole, relationships, [part, whole]); expect(wholeSchema.parts).toBe('collection'); expect(wholeModel.parts).toEqual(['Part']); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/chevyfsa/system-designer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server