@@ -2686,4 +2686,167 @@ function two() {
26862686 expect ( result . error ) . toContain ( ":start_line:5 <-- Invalid location" )
26872687 } )
26882688 } )
2689+
2690+ describe ( "Generalized line duplication heuristic" , ( ) => {
2691+ let strategy : MultiSearchReplaceDiffStrategy
2692+
2693+ beforeEach ( ( ) => {
2694+ strategy = new MultiSearchReplaceDiffStrategy ( )
2695+ } )
2696+
2697+ it ( "should correctly append content and avoid duplicating a closing brace" , async ( ) => {
2698+ const originalContent = `function test() {
2699+ console.log("original");
2700+ }`
2701+
2702+ const diffContent = `<<<<<<< SEARCH
2703+ :start_line:2
2704+ -------
2705+ console.log("original");
2706+ =======
2707+ console.log("original");
2708+ }
2709+ function newFunction() {
2710+ console.log("appended");
2711+ }
2712+ >>>>>>> REPLACE`
2713+
2714+ const result = await strategy . applyDiff ( originalContent , diffContent )
2715+
2716+ expect ( result . success ) . toBe ( true )
2717+ if ( result . success )
2718+ expect ( result . content ) . toBe ( `function test() {
2719+ console.log("original");
2720+ }
2721+ function newFunction() {
2722+ console.log("appended");
2723+ }` )
2724+ } )
2725+
2726+ it ( "should correctly append content and avoid duplicating a common line" , async ( ) => {
2727+ const originalContent = `Section A
2728+ Common Line to keep
2729+ Section B`
2730+
2731+ const diffContent = `<<<<<<< SEARCH
2732+ :start_line:1
2733+ -------
2734+ Section A
2735+ =======
2736+ Section A
2737+ Common Line to keep
2738+ New Appended Content
2739+ >>>>>>> REPLACE`
2740+
2741+ const result = await strategy . applyDiff ( originalContent , diffContent )
2742+
2743+ expect ( result . success ) . toBe ( true )
2744+ if ( result . success )
2745+ expect ( result . content ) . toBe ( `Section A
2746+ Common Line to keep
2747+ New Appended Content
2748+ Section B` )
2749+ } )
2750+
2751+ it ( "should not alter behavior when the line after search prefix in REPLACE differs from original line after SEARCH" , async ( ) => {
2752+ const originalContent = `Line 1
2753+ Line 2 (original next)
2754+ Line 3`
2755+
2756+ const diffContent = `<<<<<<< SEARCH
2757+ :start_line:1
2758+ -------
2759+ Line 1
2760+ =======
2761+ Line 1
2762+ Line X (different next in replace)
2763+ Appended Content
2764+ >>>>>>> REPLACE`
2765+
2766+ const result = await strategy . applyDiff ( originalContent , diffContent )
2767+
2768+ expect ( result . success ) . toBe ( true )
2769+ if ( result . success )
2770+ expect ( result . content ) . toBe ( `Line 1
2771+ Line X (different next in replace)
2772+ Appended Content
2773+ Line 2 (original next)
2774+ Line 3` )
2775+ } )
2776+
2777+ it ( "should not trigger heuristic if SEARCH content is not a prefix of REPLACE content" , async ( ) => {
2778+ const originalContent = `Alpha
2779+ Bravo
2780+ Charlie`
2781+
2782+ const diffContent = `<<<<<<< SEARCH
2783+ :start_line:1
2784+ -------
2785+ Alpha
2786+ =======
2787+ Completely New Content
2788+ Even More New Content
2789+ Bravo
2790+ >>>>>>> REPLACE`
2791+
2792+ const result = await strategy . applyDiff ( originalContent , diffContent )
2793+
2794+ expect ( result . success ) . toBe ( true )
2795+ if ( result . success )
2796+ expect ( result . content ) . toBe ( `Completely New Content
2797+ Even More New Content
2798+ Bravo
2799+ Bravo
2800+ Charlie` )
2801+ } )
2802+
2803+ it ( "should handle edge case where heuristic conditions are met but no line follows search in original" , async ( ) => {
2804+ const originalContent = `Last Line`
2805+
2806+ const diffContent = `<<<<<<< SEARCH
2807+ :start_line:1
2808+ -------
2809+ Last Line
2810+ =======
2811+ Last Line
2812+ New Line
2813+ Added Content
2814+ >>>>>>> REPLACE`
2815+
2816+ const result = await strategy . applyDiff ( originalContent , diffContent )
2817+
2818+ expect ( result . success ) . toBe ( true )
2819+ if ( result . success )
2820+ expect ( result . content ) . toBe ( `Last Line
2821+ New Line
2822+ Added Content` )
2823+ } )
2824+
2825+ it ( "should handle case where similarity threshold is not met" , async ( ) => {
2826+ const originalContent = `Original Content
2827+ Next Line
2828+ Final Line`
2829+
2830+ const diffContent = `<<<<<<< SEARCH
2831+ :start_line:1
2832+ -------
2833+ Original Content
2834+ =======
2835+ Completely Different Content
2836+ Next Line
2837+ Appended Content
2838+ >>>>>>> REPLACE`
2839+
2840+ const result = await strategy . applyDiff ( originalContent , diffContent )
2841+
2842+ expect ( result . success ) . toBe ( true )
2843+ // Should behave as normal replacement since similarity < 0.95
2844+ if ( result . success )
2845+ expect ( result . content ) . toBe ( `Completely Different Content
2846+ Next Line
2847+ Appended Content
2848+ Next Line
2849+ Final Line` )
2850+ } )
2851+ } )
26892852} )
0 commit comments