import { describe, it, expect } from 'vitest';
import { generateDNA } from '../../src/tools/generateDNA';
describe('generateDNA Tool', () => {
describe('Basic functionality', () => {
it('should generate DNA sequence of specified length', async () => {
const result = await generateDNA.handler({
length: 100
});
expect(result.content).toHaveLength(1);
expect(result.content[0].type).toBe('text');
const data = JSON.parse(result.content[0].text);
expect(data.statistics.totalSequences).toBe(1);
expect(data.statistics.averageLength).toBe(100);
});
it('should respect GC content parameter', async () => {
const result = await generateDNA.handler({
length: 1000,
gcContent: 0.7,
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.averageGC).toBeCloseTo(70, 0); // Within 10% tolerance
});
it('should generate multiple sequences', async () => {
const result = await generateDNA.handler({
length: 50,
count: 5
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.totalSequences).toBe(5);
});
it('should use seed for reproducible results', async () => {
const seed = 54321;
const result1 = await generateDNA.handler({
length: 100,
seed
});
const result2 = await generateDNA.handler({
length: 100,
seed
});
expect(result1.content[0].text).toBe(result2.content[0].text);
});
});
describe('Output formats', () => {
it('should output FASTA format by default', async () => {
const result = await generateDNA.handler({
length: 50,
outputFormat: 'fasta'
});
const data = JSON.parse(result.content[0].text);
expect(typeof data.sequences).toBe('string');
expect(data.sequences).toMatch(/^>sim_dna_1/);
expect(data.sequences).toMatch(/\n[ATGC]+$/);
});
it('should output plain format when requested', async () => {
const result = await generateDNA.handler({
length: 50,
outputFormat: 'plain'
});
const data = JSON.parse(result.content[0].text);
expect(data.rawOutput).toMatch(/^[ATGC]+$/);
});
});
describe('Generation models', () => {
it('should support random model', async () => {
const result = await generateDNA.handler({
length: 100,
model: 'random',
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.model).toBe('random');
});
it('should support markov model', async () => {
const result = await generateDNA.handler({
length: 100,
model: 'markov',
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.model).toBe('markov');
});
it('should support codon-biased model', async () => {
const result = await generateDNA.handler({
length: 99, // Multiple of 3 for codons
model: 'codon-biased',
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.model).toBe('codon-biased');
});
});
describe('Input validation', () => {
it('should handle minimum length', async () => {
const result = await generateDNA.handler({
length: 1
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.averageLength).toBe(1);
});
it('should handle GC content boundaries', async () => {
const testCases = [
{ gcContent: 0.0 },
{ gcContent: 1.0 }
];
for (const testCase of testCases) {
const result = await generateDNA.handler({
length: 100,
...testCase,
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.averageGC).toBeGreaterThanOrEqual(0);
expect(data.statistics.averageGC).toBeLessThanOrEqual(100);
}
});
it('should handle large sequences', async () => {
const result = await generateDNA.handler({
length: 10000,
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.averageLength).toBe(10000);
});
});
describe('Statistics accuracy', () => {
it('should calculate GC content correctly', async () => {
const result = await generateDNA.handler({
length: 1000,
gcContent: 0.5,
seed: 12345
});
const data = JSON.parse(result.content[0].text);
// Extract the actual sequence to verify calculation
if (data.sequences && typeof data.sequences === 'string') {
const sequenceMatch = data.sequences.match(/\n([ATGC]+)/);
if (sequenceMatch) {
const sequence = sequenceMatch[1];
const gcCount = (sequence.match(/[GC]/g) || []).length;
const expectedGC = Math.round((gcCount / sequence.length) * 10000) / 100;
expect(data.statistics.averageGC).toBe(expectedGC);
}
}
});
it('should track sequence count correctly', async () => {
const counts = [1, 3, 10];
for (const count of counts) {
const result = await generateDNA.handler({
length: 50,
count,
seed: 12345
});
const data = JSON.parse(result.content[0].text);
expect(data.statistics.totalSequences).toBe(count);
}
});
});
describe('Tool definition', () => {
it('should have correct tool definition structure', () => {
expect(generateDNA.definition.name).toBe('generate_dna_sequence');
expect(generateDNA.definition.description).toContain('Generate random DNA sequences');
expect(generateDNA.definition.inputSchema.type).toBe('object');
expect(generateDNA.definition.inputSchema.required).toContain('length');
});
it('should have proper parameter definitions', () => {
const props = generateDNA.definition.inputSchema.properties;
expect(props.length.type).toBe('number');
expect(props.gcContent.minimum).toBe(0);
expect(props.gcContent.maximum).toBe(1);
expect(props.count.minimum).toBe(1);
expect(props.model.enum).toEqual(['random', 'markov', 'codon-biased']);
expect(props.outputFormat.enum).toEqual(['fasta', 'plain']);
});
});
});