Files
qwen-code/packages/core/src/utils/editHelper.test.ts

154 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { describe, expect, it } from 'vitest';
import {
countOccurrences,
maybeAugmentOldStringForDeletion,
normalizeEditStrings,
} from './editHelper.js';
describe('normalizeEditStrings', () => {
const file = `const one = 1;
const two = 2;
`;
it('returns literal matches unchanged and trims new_string trailing whitespace', () => {
const result = normalizeEditStrings(
file,
'const two = 2;',
' const two = 42; ',
);
expect(result).toEqual({
oldString: 'const two = 2;',
newString: ' const two = 42;',
});
});
it('normalizes smart quotes to match on-disk text', () => {
const result = normalizeEditStrings(
"const greeting = 'Don't';\n",
'const greeting = Dont;',
'const greeting = “Hello”; ',
);
expect(result).toEqual({
oldString: "const greeting = 'Don't';",
newString: 'const greeting = “Hello”;',
});
});
it('falls back to original strings when no match is found', () => {
const result = normalizeEditStrings(file, 'missing text', 'replacement');
expect(result).toEqual({
oldString: 'missing text',
newString: 'replacement',
});
});
it('still trims new_string when editing a brand-new file', () => {
const result = normalizeEditStrings(null, '', 'new file contents ');
expect(result).toEqual({
oldString: '',
newString: 'new file contents',
});
});
it('matches unicode dash variants', () => {
const result = normalizeEditStrings(
'const range = "1-2";\n',
'const range = "1\u20132";',
'const range = "3\u20135"; ',
);
expect(result).toEqual({
oldString: 'const range = "1-2";',
newString: 'const range = "3\u20135";',
});
});
it('matches when trailing whitespace differs only at line ends', () => {
const result = normalizeEditStrings(
'value = 1;\n',
'value = 1; \n',
'value = 2; \n',
);
expect(result).toEqual({
oldString: 'value = 1;\n',
newString: 'value = 2;\n',
});
});
it('treats non-breaking spaces as regular spaces', () => {
const result = normalizeEditStrings(
'const label = "hello world";\n',
'const label = "hello\u00a0world";',
'const label = "hi\u00a0world";',
);
expect(result).toEqual({
oldString: 'const label = "hello world";',
newString: 'const label = "hi\u00a0world";',
});
});
it('drops trailing newline from new content when the file lacks it', () => {
const result = normalizeEditStrings(
'console.log("hi")',
'console.log("hi")\n',
'console.log("bye")\n',
);
expect(result).toEqual({
oldString: 'console.log("hi")',
newString: 'console.log("bye")',
});
});
});
describe('countOccurrences', () => {
it('returns zero when substring empty or missing', () => {
expect(countOccurrences('abc', '')).toBe(0);
expect(countOccurrences('abc', 'z')).toBe(0);
});
it('counts non-overlapping occurrences', () => {
expect(countOccurrences('aaaa', 'aa')).toBe(2);
});
});
describe('maybeAugmentOldStringForDeletion', () => {
const file = 'console.log("hi")\nconsole.log("bye")\n';
it('appends newline when deleting text followed by newline', () => {
expect(
maybeAugmentOldStringForDeletion(file, 'console.log("hi")', ''),
).toBe('console.log("hi")\n');
});
it('leaves strings untouched when not deleting', () => {
expect(
maybeAugmentOldStringForDeletion(
file,
'console.log("hi")',
'replacement',
),
).toBe('console.log("hi")');
});
it('does not append newline when file lacks the variant', () => {
expect(
maybeAugmentOldStringForDeletion(
'console.log("hi")',
'console.log("hi")',
'',
),
).toBe('console.log("hi")');
});
it('no-ops when the old string already ends with a newline', () => {
expect(
maybeAugmentOldStringForDeletion(file, 'console.log("bye")\n', ''),
).toBe('console.log("bye")\n');
});
});