mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 14:22:02 +00:00
- Introduced a new method in ProviderFactory to check if a model supports vision/image input. - Updated AgentService and AutoModeService to validate vision support before processing images, throwing an error if the model does not support it. - Enhanced error messages to guide users on switching models or removing images if necessary. These changes improve the robustness of image processing by ensuring compatibility with the selected models.
307 lines
9.4 KiB
TypeScript
307 lines
9.4 KiB
TypeScript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
import {
|
|
writeValidation,
|
|
readValidation,
|
|
getAllValidations,
|
|
deleteValidation,
|
|
isValidationStale,
|
|
getValidationWithFreshness,
|
|
markValidationViewed,
|
|
getUnviewedValidationsCount,
|
|
type StoredValidation,
|
|
} from '@/lib/validation-storage.js';
|
|
import fs from 'fs/promises';
|
|
import path from 'path';
|
|
import os from 'os';
|
|
|
|
describe('validation-storage.ts', () => {
|
|
let testProjectPath: string;
|
|
|
|
beforeEach(async () => {
|
|
testProjectPath = path.join(os.tmpdir(), `validation-storage-test-${Date.now()}`);
|
|
await fs.mkdir(testProjectPath, { recursive: true });
|
|
});
|
|
|
|
afterEach(async () => {
|
|
try {
|
|
await fs.rm(testProjectPath, { recursive: true, force: true });
|
|
} catch {
|
|
// Ignore cleanup errors
|
|
}
|
|
});
|
|
|
|
const createMockValidation = (overrides: Partial<StoredValidation> = {}): StoredValidation => ({
|
|
issueNumber: 123,
|
|
issueTitle: 'Test Issue',
|
|
validatedAt: new Date().toISOString(),
|
|
model: 'haiku',
|
|
result: {
|
|
verdict: 'valid',
|
|
confidence: 'high',
|
|
reasoning: 'Test reasoning',
|
|
},
|
|
...overrides,
|
|
});
|
|
|
|
describe('writeValidation', () => {
|
|
it('should write validation to storage', async () => {
|
|
const validation = createMockValidation();
|
|
|
|
await writeValidation(testProjectPath, 123, validation);
|
|
|
|
// Verify file was created
|
|
const validationPath = path.join(
|
|
testProjectPath,
|
|
'.automaker',
|
|
'validations',
|
|
'123',
|
|
'validation.json'
|
|
);
|
|
const content = await fs.readFile(validationPath, 'utf-8');
|
|
expect(JSON.parse(content)).toEqual(validation);
|
|
});
|
|
|
|
it('should create nested directories if they do not exist', async () => {
|
|
const validation = createMockValidation({ issueNumber: 456 });
|
|
|
|
await writeValidation(testProjectPath, 456, validation);
|
|
|
|
const validationPath = path.join(
|
|
testProjectPath,
|
|
'.automaker',
|
|
'validations',
|
|
'456',
|
|
'validation.json'
|
|
);
|
|
const content = await fs.readFile(validationPath, 'utf-8');
|
|
expect(JSON.parse(content)).toEqual(validation);
|
|
});
|
|
});
|
|
|
|
describe('readValidation', () => {
|
|
it('should read validation from storage', async () => {
|
|
const validation = createMockValidation();
|
|
await writeValidation(testProjectPath, 123, validation);
|
|
|
|
const result = await readValidation(testProjectPath, 123);
|
|
|
|
expect(result).toEqual(validation);
|
|
});
|
|
|
|
it('should return null when validation does not exist', async () => {
|
|
const result = await readValidation(testProjectPath, 999);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('getAllValidations', () => {
|
|
it('should return all validations for a project', async () => {
|
|
const validation1 = createMockValidation({ issueNumber: 1, issueTitle: 'Issue 1' });
|
|
const validation2 = createMockValidation({ issueNumber: 2, issueTitle: 'Issue 2' });
|
|
const validation3 = createMockValidation({ issueNumber: 3, issueTitle: 'Issue 3' });
|
|
|
|
await writeValidation(testProjectPath, 1, validation1);
|
|
await writeValidation(testProjectPath, 2, validation2);
|
|
await writeValidation(testProjectPath, 3, validation3);
|
|
|
|
const result = await getAllValidations(testProjectPath);
|
|
|
|
expect(result).toHaveLength(3);
|
|
expect(result[0]).toEqual(validation1);
|
|
expect(result[1]).toEqual(validation2);
|
|
expect(result[2]).toEqual(validation3);
|
|
});
|
|
|
|
it('should return empty array when no validations exist', async () => {
|
|
const result = await getAllValidations(testProjectPath);
|
|
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
it('should skip non-numeric directories', async () => {
|
|
const validation = createMockValidation({ issueNumber: 1 });
|
|
await writeValidation(testProjectPath, 1, validation);
|
|
|
|
// Create a non-numeric directory
|
|
const invalidDir = path.join(testProjectPath, '.automaker', 'validations', 'invalid');
|
|
await fs.mkdir(invalidDir, { recursive: true });
|
|
|
|
const result = await getAllValidations(testProjectPath);
|
|
|
|
expect(result).toHaveLength(1);
|
|
expect(result[0]).toEqual(validation);
|
|
});
|
|
});
|
|
|
|
describe('deleteValidation', () => {
|
|
it('should delete validation from storage', async () => {
|
|
const validation = createMockValidation();
|
|
await writeValidation(testProjectPath, 123, validation);
|
|
|
|
const result = await deleteValidation(testProjectPath, 123);
|
|
|
|
expect(result).toBe(true);
|
|
|
|
const readResult = await readValidation(testProjectPath, 123);
|
|
expect(readResult).toBeNull();
|
|
});
|
|
|
|
it('should return true even when validation does not exist', async () => {
|
|
const result = await deleteValidation(testProjectPath, 999);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('isValidationStale', () => {
|
|
it('should return false for recent validation', () => {
|
|
const validation = createMockValidation({
|
|
validatedAt: new Date().toISOString(),
|
|
});
|
|
|
|
const result = isValidationStale(validation);
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should return true for validation older than 24 hours', () => {
|
|
const oldDate = new Date();
|
|
oldDate.setHours(oldDate.getHours() - 25); // 25 hours ago
|
|
|
|
const validation = createMockValidation({
|
|
validatedAt: oldDate.toISOString(),
|
|
});
|
|
|
|
const result = isValidationStale(validation);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for validation exactly at 24 hours', () => {
|
|
const exactDate = new Date(Date.now() - 24 * 60 * 60 * 1000 + 100);
|
|
|
|
const validation = createMockValidation({
|
|
validatedAt: exactDate.toISOString(),
|
|
});
|
|
|
|
const result = isValidationStale(validation);
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getValidationWithFreshness', () => {
|
|
it('should return validation with isStale false for recent validation', async () => {
|
|
const validation = createMockValidation({
|
|
validatedAt: new Date().toISOString(),
|
|
});
|
|
await writeValidation(testProjectPath, 123, validation);
|
|
|
|
const result = await getValidationWithFreshness(testProjectPath, 123);
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result!.validation).toEqual(validation);
|
|
expect(result!.isStale).toBe(false);
|
|
});
|
|
|
|
it('should return validation with isStale true for old validation', async () => {
|
|
const oldDate = new Date();
|
|
oldDate.setHours(oldDate.getHours() - 25);
|
|
|
|
const validation = createMockValidation({
|
|
validatedAt: oldDate.toISOString(),
|
|
});
|
|
await writeValidation(testProjectPath, 123, validation);
|
|
|
|
const result = await getValidationWithFreshness(testProjectPath, 123);
|
|
|
|
expect(result).not.toBeNull();
|
|
expect(result!.isStale).toBe(true);
|
|
});
|
|
|
|
it('should return null when validation does not exist', async () => {
|
|
const result = await getValidationWithFreshness(testProjectPath, 999);
|
|
|
|
expect(result).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('markValidationViewed', () => {
|
|
it('should mark validation as viewed', async () => {
|
|
const validation = createMockValidation();
|
|
await writeValidation(testProjectPath, 123, validation);
|
|
|
|
const result = await markValidationViewed(testProjectPath, 123);
|
|
|
|
expect(result).toBe(true);
|
|
|
|
const updated = await readValidation(testProjectPath, 123);
|
|
expect(updated).not.toBeNull();
|
|
expect(updated!.viewedAt).toBeDefined();
|
|
});
|
|
|
|
it('should return false when validation does not exist', async () => {
|
|
const result = await markValidationViewed(testProjectPath, 999);
|
|
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('getUnviewedValidationsCount', () => {
|
|
it('should return count of unviewed non-stale validations', async () => {
|
|
const validation1 = createMockValidation({ issueNumber: 1 });
|
|
const validation2 = createMockValidation({ issueNumber: 2 });
|
|
const validation3 = createMockValidation({
|
|
issueNumber: 3,
|
|
viewedAt: new Date().toISOString(),
|
|
});
|
|
|
|
await writeValidation(testProjectPath, 1, validation1);
|
|
await writeValidation(testProjectPath, 2, validation2);
|
|
await writeValidation(testProjectPath, 3, validation3);
|
|
|
|
const result = await getUnviewedValidationsCount(testProjectPath);
|
|
|
|
expect(result).toBe(2);
|
|
});
|
|
|
|
it('should not count stale validations', async () => {
|
|
const oldDate = new Date();
|
|
oldDate.setHours(oldDate.getHours() - 25);
|
|
|
|
const validation1 = createMockValidation({ issueNumber: 1 });
|
|
const validation2 = createMockValidation({
|
|
issueNumber: 2,
|
|
validatedAt: oldDate.toISOString(),
|
|
});
|
|
|
|
await writeValidation(testProjectPath, 1, validation1);
|
|
await writeValidation(testProjectPath, 2, validation2);
|
|
|
|
const result = await getUnviewedValidationsCount(testProjectPath);
|
|
|
|
expect(result).toBe(1);
|
|
});
|
|
|
|
it('should return 0 when no validations exist', async () => {
|
|
const result = await getUnviewedValidationsCount(testProjectPath);
|
|
|
|
expect(result).toBe(0);
|
|
});
|
|
|
|
it('should return 0 when all validations are viewed', async () => {
|
|
const validation = createMockValidation({
|
|
issueNumber: 1,
|
|
viewedAt: new Date().toISOString(),
|
|
});
|
|
|
|
await writeValidation(testProjectPath, 1, validation);
|
|
|
|
const result = await getUnviewedValidationsCount(testProjectPath);
|
|
|
|
expect(result).toBe(0);
|
|
});
|
|
});
|
|
});
|