|
@@ -2,7 +2,6 @@ import {
|
|
|
SseMessageSchema,
|
|
SseMessageSchema,
|
|
|
SseDetectedDiffSchema,
|
|
SseDetectedDiffSchema,
|
|
|
SseFinalizedSchema,
|
|
SseFinalizedSchema,
|
|
|
- hasApplicationResult,
|
|
|
|
|
type SseMessage,
|
|
type SseMessage,
|
|
|
type SseDetectedDiff,
|
|
type SseDetectedDiff,
|
|
|
type SseFinalized,
|
|
type SseFinalized,
|
|
@@ -192,343 +191,29 @@ describe('sse-schemas', () => {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
describe('SseFinalizedSchema', () => {
|
|
describe('SseFinalizedSchema', () => {
|
|
|
- test('should validate minimal finalized response', () => {
|
|
|
|
|
|
|
+ test('should validate finalized response with success true', () => {
|
|
|
const validFinalized = {
|
|
const validFinalized = {
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Changes have been applied successfully.',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ success: true,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.success).toBe(true);
|
|
|
if (result.success) {
|
|
if (result.success) {
|
|
|
- expect(result.data.finalized.message).toBe(validFinalized.finalized.message);
|
|
|
|
|
- expect(result.data.finalized.replacements).toEqual([]);
|
|
|
|
|
- expect(result.data.finalized.applicationResult).toBeUndefined();
|
|
|
|
|
|
|
+ expect(result.data.success).toBe(true);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- test('should validate finalized response with replacements', () => {
|
|
|
|
|
|
|
+ test('should validate finalized response with success false', () => {
|
|
|
const validFinalized = {
|
|
const validFinalized = {
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Successfully applied 2 changes.',
|
|
|
|
|
- replacements: [
|
|
|
|
|
- {
|
|
|
|
|
- search: 'old code 1',
|
|
|
|
|
- replace: 'new code 1',
|
|
|
|
|
- startLine: 5,
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- search: 'old code 2',
|
|
|
|
|
- replace: 'new code 2',
|
|
|
|
|
- startLine: 10,
|
|
|
|
|
- endLine: 12,
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ success: false,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.success).toBe(true);
|
|
|
if (result.success) {
|
|
if (result.success) {
|
|
|
- expect(result.data.finalized.replacements).toHaveLength(2);
|
|
|
|
|
- expect(result.data.finalized.replacements[0].search).toBe('old code 1');
|
|
|
|
|
- expect(result.data.finalized.replacements[1].endLine).toBe(12);
|
|
|
|
|
|
|
+ expect(result.data.success).toBe(false);
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
- test('should validate finalized response with successful application result', () => {
|
|
|
|
|
- const validFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'All changes applied successfully.',
|
|
|
|
|
- replacements: [
|
|
|
|
|
- {
|
|
|
|
|
- search: 'test code',
|
|
|
|
|
- replace: 'updated code',
|
|
|
|
|
- startLine: 1,
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: true,
|
|
|
|
|
- appliedCount: 1,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
|
|
|
- expect(result.success).toBe(true);
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.success).toBe(true);
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.appliedCount).toBe(1);
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.totalCount).toBe(1);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should validate finalized response with failed application result', () => {
|
|
|
|
|
- const validFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Some changes failed to apply.',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: 0,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- failedParts: [
|
|
|
|
|
- {
|
|
|
|
|
- type: 'SEARCH_NOT_FOUND',
|
|
|
|
|
- message: 'Could not find the specified search content',
|
|
|
|
|
- line: 10,
|
|
|
|
|
- details: {
|
|
|
|
|
- searchContent: 'missing code',
|
|
|
|
|
- bestMatch: 'similar code',
|
|
|
|
|
- similarity: 0.7,
|
|
|
|
|
- suggestions: ['Check line numbers', 'Verify content'],
|
|
|
|
|
- correctFormat: 'function example() {}',
|
|
|
|
|
- lineRange: '8-12',
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
|
|
|
- expect(result.success).toBe(true);
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.success).toBe(false);
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.failedParts).toHaveLength(1);
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.failedParts?.[0].type).toBe('SEARCH_NOT_FOUND');
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.failedParts?.[0].details.similarity).toBe(0.7);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should validate all error types in failedParts', () => {
|
|
|
|
|
- const errorTypes = [
|
|
|
|
|
- 'SEARCH_NOT_FOUND',
|
|
|
|
|
- 'SIMILARITY_TOO_LOW',
|
|
|
|
|
- 'MULTIPLE_MATCHES',
|
|
|
|
|
- 'EMPTY_SEARCH',
|
|
|
|
|
- 'MARKER_SEQUENCE_ERROR',
|
|
|
|
|
- 'CONTENT_ERROR',
|
|
|
|
|
- ];
|
|
|
|
|
-
|
|
|
|
|
- for (const errorType of errorTypes) {
|
|
|
|
|
- const validFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: `Error type: ${errorType}`,
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: 0,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- failedParts: [
|
|
|
|
|
- {
|
|
|
|
|
- type: errorType,
|
|
|
|
|
- message: `Test message for ${errorType}`,
|
|
|
|
|
- details: {
|
|
|
|
|
- searchContent: 'test',
|
|
|
|
|
- suggestions: [],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
|
|
|
- expect(result.success).toBe(true);
|
|
|
|
|
- if (result.success) {
|
|
|
|
|
- expect(result.data.finalized.applicationResult?.failedParts?.[0].type).toBe(errorType);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when finalized field is missing', () => {
|
|
|
|
|
- const invalidFinalized = {};
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- if (!result.success) {
|
|
|
|
|
- expect(result.error.issues[0].code).toBe('invalid_type');
|
|
|
|
|
- expect(result.error.issues[0].path).toEqual(['finalized']);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when message is missing', () => {
|
|
|
|
|
- const invalidFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- if (!result.success) {
|
|
|
|
|
- const messageError = result.error.issues.find(issue => issue.path.includes('message'));
|
|
|
|
|
- expect(messageError).toBeDefined();
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when replacements is missing', () => {
|
|
|
|
|
- const invalidFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test message',
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- if (!result.success) {
|
|
|
|
|
- const replacementsError = result.error.issues.find(issue => issue.path.includes('replacements'));
|
|
|
|
|
- expect(replacementsError).toBeDefined();
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when appliedCount is negative', () => {
|
|
|
|
|
- const invalidFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: -1,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when totalCount is negative', () => {
|
|
|
|
|
- const invalidFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: 0,
|
|
|
|
|
- totalCount: -1,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when similarity is out of range', () => {
|
|
|
|
|
- const invalidFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: 0,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- failedParts: [
|
|
|
|
|
- {
|
|
|
|
|
- type: 'SIMILARITY_TOO_LOW',
|
|
|
|
|
- message: 'Low similarity',
|
|
|
|
|
- details: {
|
|
|
|
|
- searchContent: 'test',
|
|
|
|
|
- similarity: 1.5, // Invalid: > 1.0
|
|
|
|
|
- suggestions: [],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should fail when line number is not positive', () => {
|
|
|
|
|
- const invalidFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: 0,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- failedParts: [
|
|
|
|
|
- {
|
|
|
|
|
- type: 'SEARCH_NOT_FOUND',
|
|
|
|
|
- message: 'Not found',
|
|
|
|
|
- line: 0, // Invalid: must be positive
|
|
|
|
|
- details: {
|
|
|
|
|
- searchContent: 'test',
|
|
|
|
|
- suggestions: [],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(invalidFinalized);
|
|
|
|
|
- expect(result.success).toBe(false);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should allow extra fields in finalized', () => {
|
|
|
|
|
- const validFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- },
|
|
|
|
|
- extraField: 'ignored',
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(validFinalized);
|
|
|
|
|
- expect(result.success).toBe(true);
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- describe('hasApplicationResult helper', () => {
|
|
|
|
|
- test('should return true when applicationResult is present', () => {
|
|
|
|
|
- const finalized: SseFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: true,
|
|
|
|
|
- appliedCount: 1,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- expect(hasApplicationResult(finalized)).toBe(true);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should return false when applicationResult is undefined', () => {
|
|
|
|
|
- const finalized: SseFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- expect(hasApplicationResult(finalized)).toBe(false);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should return false when applicationResult is undefined (explicit)', () => {
|
|
|
|
|
- const finalized: SseFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Test',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: undefined,
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- expect(hasApplicationResult(finalized)).toBe(false);
|
|
|
|
|
- });
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
describe('Type inference', () => {
|
|
describe('Type inference', () => {
|
|
@@ -556,77 +241,11 @@ describe('sse-schemas', () => {
|
|
|
|
|
|
|
|
test('SseFinalized type should match schema', () => {
|
|
test('SseFinalized type should match schema', () => {
|
|
|
const finalized: SseFinalized = {
|
|
const finalized: SseFinalized = {
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Done',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ success: true,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const result = SseFinalizedSchema.safeParse(finalized);
|
|
const result = SseFinalizedSchema.safeParse(finalized);
|
|
|
expect(result.success).toBe(true);
|
|
expect(result.success).toBe(true);
|
|
|
});
|
|
});
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
- describe('Real-world scenarios', () => {
|
|
|
|
|
- test('should validate complete SSE flow', () => {
|
|
|
|
|
- const realWorldFinalized = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Successfully refactored the authentication function and added error handling.',
|
|
|
|
|
- replacements: [
|
|
|
|
|
- {
|
|
|
|
|
- search: 'function authenticate(token) {\n return validateToken(token);\n}',
|
|
|
|
|
- // eslint-disable-next-line max-len
|
|
|
|
|
- replace: 'async function authenticate(token) {\n try {\n if (!token) {\n throw new Error("Token is required");\n }\n return await validateToken(token);\n } catch (error) {\n console.error("Authentication failed:", error);\n throw error;\n }\n}',
|
|
|
|
|
- startLine: 25,
|
|
|
|
|
- endLine: 27,
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: true,
|
|
|
|
|
- appliedCount: 1,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(realWorldFinalized);
|
|
|
|
|
- expect(result.success).toBe(true);
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- test('should validate error scenario with detailed feedback', () => {
|
|
|
|
|
- const errorScenario = {
|
|
|
|
|
- finalized: {
|
|
|
|
|
- message: 'Failed to apply changes. The specified code was not found.',
|
|
|
|
|
- replacements: [],
|
|
|
|
|
- applicationResult: {
|
|
|
|
|
- success: false,
|
|
|
|
|
- appliedCount: 0,
|
|
|
|
|
- totalCount: 1,
|
|
|
|
|
- failedParts: [
|
|
|
|
|
- {
|
|
|
|
|
- type: 'SEARCH_NOT_FOUND',
|
|
|
|
|
- message: 'Could not find exact match for the specified code',
|
|
|
|
|
- line: 25,
|
|
|
|
|
- details: {
|
|
|
|
|
- searchContent: 'function authenticate(token) {',
|
|
|
|
|
- bestMatch: 'function authenticateUser(userToken) {',
|
|
|
|
|
- similarity: 0.85,
|
|
|
|
|
- suggestions: [
|
|
|
|
|
- 'Check if the function name has changed',
|
|
|
|
|
- 'Verify the parameter name is correct',
|
|
|
|
|
- 'Ensure the code structure matches exactly',
|
|
|
|
|
- ],
|
|
|
|
|
- correctFormat: 'function authenticateUser(userToken) {',
|
|
|
|
|
- lineRange: '20-30',
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const result = SseFinalizedSchema.safeParse(errorScenario);
|
|
|
|
|
- expect(result.success).toBe(true);
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
});
|
|
});
|