generate-dataset.test.ts•14.7 kB
import { describe, it, expect } from 'vitest';
import type { DatasetSchema } from '../../src/types/schema.js';
import { EntityType, RelationshipType } from '../../src/types/schema.js';
describe('generate-dataset contract tests', () => {
describe('input schema validation', () => {
it('should accept valid dataset schema with single entity', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
};
// This test will validate against the Zod schema once implemented
expect(schema).toBeDefined();
expect(schema.entities['users']?.count).toBe(10);
expect(schema.entities['users']?.type).toBe(EntityType.PERSON);
});
it('should accept valid dataset schema with multiple entities', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
companies: {
count: 5,
type: EntityType.COMPANY,
},
},
};
expect(schema).toBeDefined();
expect(Object.keys(schema.entities)).toHaveLength(2);
});
it('should accept schema with relationships', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
orders: {
count: 50,
type: EntityType.CUSTOM,
fields: ['id', 'amount', 'date', 'userId'],
relationships: {
userId: {
references: 'users',
type: RelationshipType.ONE_TO_MANY,
},
},
},
},
};
expect(schema).toBeDefined();
expect(schema.entities['orders']?.relationships).toBeDefined();
expect(schema.entities['orders']?.relationships?.['userId']?.references).toBe('users');
});
it('should accept schema with optional fields', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
fields: ['id', 'name', 'email'],
},
},
};
expect(schema).toBeDefined();
expect(schema.entities['users']?.fields).toEqual(['id', 'name', 'email']);
});
it('should accept schema with nullable relationships', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
orders: {
count: 50,
type: EntityType.CUSTOM,
fields: ['id', 'userId'],
relationships: {
userId: {
references: 'users',
type: RelationshipType.ONE_TO_MANY,
nullable: true,
},
},
},
},
};
expect(schema.entities['orders']?.relationships?.['userId']?.nullable).toBe(true);
});
it('should reject schema with circular dependencies', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
relationships: {
profileId: {
references: 'profiles',
type: RelationshipType.ONE_TO_MANY,
},
},
},
profiles: {
count: 10,
type: EntityType.CUSTOM,
fields: ['id', 'userId'],
relationships: {
userId: {
references: 'users',
type: RelationshipType.ONE_TO_MANY,
},
},
},
},
};
// Will be tested once validation is implemented
expect(schema).toBeDefined();
});
it('should reject schema with non-existent entity references', () => {
const schema: DatasetSchema = {
entities: {
orders: {
count: 50,
type: EntityType.CUSTOM,
fields: ['id', 'userId'],
relationships: {
userId: {
references: 'users', // users entity doesn't exist
type: RelationshipType.ONE_TO_MANY,
},
},
},
},
};
// Will be tested once validation is implemented
expect(schema).toBeDefined();
});
it('should accept schema with count up to 10000', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10000,
type: EntityType.PERSON,
},
},
};
expect(schema.entities['users']?.count).toBe(10000);
});
it('should reject schema with count exceeding 10000', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10001,
type: EntityType.PERSON,
},
},
};
// Will be tested once validation is implemented
expect(schema).toBeDefined();
});
it('should accept schema with seed for reproducibility', () => {
const params = {
schema: {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
},
seed: 12345,
};
expect(params.seed).toBe(12345);
});
it('should accept schema with locale parameter', () => {
const params = {
schema: {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
},
locale: 'fr',
};
expect(params.locale).toBe('fr');
});
});
describe('output format validation', () => {
it('should return dataset with all requested entities', () => {
// Expected output structure
const expectedOutput = {
dataset: {
users: [
{
id: 'user_1',
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@example.com',
},
],
companies: [
{
id: 'company_1',
name: 'Acme Corp',
industry: 'Technology',
},
],
},
metadata: {
entityCounts: {
users: 1,
companies: 1,
},
totalRecords: 2,
seed: expect.any(Number) as number,
},
};
// Structure validation
expect(expectedOutput.dataset).toBeDefined();
expect(expectedOutput.metadata).toBeDefined();
expect(expectedOutput.metadata.entityCounts).toBeDefined();
expect(expectedOutput.metadata.totalRecords).toBe(2);
});
it('should return entities in correct dependency order', () => {
// Parent entities should appear before children
const expectedOutput = {
dataset: {
users: [], // Parent
orders: [], // Child (references users)
},
};
const keys = Object.keys(expectedOutput.dataset);
expect(keys[0]).toBe('users');
expect(keys[1]).toBe('orders');
});
it('should include valid foreign key references', () => {
// Expected order structure with FK
const expectedOrder = {
id: 'order_1',
amount: 100.5,
userId: 'user_1', // Must reference existing user
};
expect(expectedOrder.userId).toMatch(/^user_\d+$/);
});
it('should include metadata with entity counts', () => {
const expectedMetadata = {
entityCounts: {
users: 10,
orders: 50,
},
totalRecords: 60,
seed: 12345,
};
expect(expectedMetadata.entityCounts).toBeDefined();
expect(expectedMetadata.totalRecords).toBe(60);
expect(expectedMetadata.seed).toBe(12345);
});
it('should support nullable foreign keys', () => {
const expectedOrder = {
id: 'order_1',
amount: 100.5,
userId: null, // nullable FK
};
expect(expectedOrder.userId).toBeNull();
});
});
describe('referential integrity validation', () => {
it('should ensure all foreign keys reference existing entities', () => {
// Simulated dataset
const dataset = {
users: [
{ id: 'user_1', name: 'Alice' },
{ id: 'user_2', name: 'Bob' },
],
orders: [
{ id: 'order_1', userId: 'user_1' },
{ id: 'order_2', userId: 'user_2' },
{ id: 'order_3', userId: 'user_1' },
],
};
const userIds = dataset.users.map((u) => u.id);
dataset.orders.forEach((order) => {
expect(userIds).toContain(order.userId);
});
});
it('should handle many-to-many relationships correctly', () => {
// Multiple orders can reference same user
const dataset = {
users: [{ id: 'user_1', name: 'Alice' }],
orders: [
{ id: 'order_1', userId: 'user_1' },
{ id: 'order_2', userId: 'user_1' },
{ id: 'order_3', userId: 'user_1' },
],
};
const userIds = new Set(dataset.orders.map((o) => o.userId));
expect(userIds.size).toBe(1); // All orders reference same user
expect(userIds.has('user_1')).toBe(true);
});
it('should handle many-to-many relationships correctly', () => {
// Many-to-many junction table
const dataset = {
users: [
{ id: 'user_1', name: 'Alice' },
{ id: 'user_2', name: 'Bob' },
],
products: [
{ id: 'product_1', name: 'Widget' },
{ id: 'product_2', name: 'Gadget' },
],
userProducts: [
{ userId: 'user_1', productId: 'product_1' },
{ userId: 'user_1', productId: 'product_2' },
{ userId: 'user_2', productId: 'product_1' },
],
};
const userIds = dataset.users.map((u) => u.id);
const productIds = dataset.products.map((p) => p.id);
dataset.userProducts.forEach((up) => {
expect(userIds).toContain(up.userId);
expect(productIds).toContain(up.productId);
});
});
it('should handle nullable relationships with null values', () => {
const dataset = {
users: [{ id: 'user_1', name: 'Alice' }],
orders: [
{ id: 'order_1', userId: 'user_1' },
{ id: 'order_2', userId: null },
],
};
const userIds = dataset.users.map((u) => u.id);
dataset.orders.forEach((order) => {
if (order.userId !== null) {
expect(userIds).toContain(order.userId);
}
});
});
it('should maintain referential integrity across complex schemas', () => {
const dataset = {
companies: [{ id: 'company_1', name: 'Acme' }],
users: [
{ id: 'user_1', companyId: 'company_1' },
{ id: 'user_2', companyId: 'company_1' },
],
orders: [
{ id: 'order_1', userId: 'user_1' },
{ id: 'order_2', userId: 'user_2' },
],
};
// Validate company references
const companyIds = dataset.companies.map((c) => c.id);
dataset.users.forEach((user) => {
expect(companyIds).toContain(user.companyId);
});
// Validate user references
const userIds = dataset.users.map((u) => u.id);
dataset.orders.forEach((order) => {
expect(userIds).toContain(order.userId);
});
});
});
describe('seed reproducibility', () => {
it('should generate identical datasets with same seed', () => {
// This will be tested once generator is implemented
const seed = 12345;
// First generation
const params1 = {
schema: {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
},
seed,
};
// Second generation with same seed
const params2 = {
schema: {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
},
seed,
};
expect(params1.seed).toBe(params2.seed);
});
it('should generate different datasets with different seeds', () => {
const params1 = {
schema: {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
},
seed: 12345,
};
const params2 = {
schema: {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
},
},
seed: 67890,
};
expect(params1.seed).not.toBe(params2.seed);
});
});
describe('multi-entity support', () => {
it('should generate multiple entity types in single dataset', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 10,
type: EntityType.PERSON,
},
companies: {
count: 5,
type: EntityType.COMPANY,
},
orders: {
count: 50,
type: EntityType.CUSTOM,
fields: ['id', 'amount', 'userId'],
},
},
};
expect(Object.keys(schema.entities)).toHaveLength(3);
expect(schema.entities['users']?.type).toBe(EntityType.PERSON);
expect(schema.entities['companies']?.type).toBe(EntityType.COMPANY);
expect(schema.entities['orders']?.type).toBe(EntityType.CUSTOM);
});
it('should respect entity count limits per entity', () => {
const schema: DatasetSchema = {
entities: {
users: {
count: 100,
type: EntityType.PERSON,
},
orders: {
count: 1000,
type: EntityType.CUSTOM,
fields: ['id', 'userId'],
},
},
};
expect(schema.entities['users']?.count).toBe(100);
expect(schema.entities['orders']?.count).toBe(1000);
});
it('should handle custom entity types with custom fields', () => {
const schema: DatasetSchema = {
entities: {
products: {
count: 20,
type: EntityType.CUSTOM,
fields: ['id', 'name', 'price', 'sku', 'category'],
},
},
};
expect(schema.entities['products']?.type).toBe(EntityType.CUSTOM);
expect(schema.entities['products']?.fields).toHaveLength(5);
expect(schema.entities['products']?.fields).toContain('sku');
});
});
});