Skip to content

Commit ed8e210

Browse files
committed
Add test case for #1559
1 parent 87b163c commit ed8e210

File tree

1 file changed

+254
-0
lines changed

1 file changed

+254
-0
lines changed

src/core/diff/strategies/__tests__/multi-search-replace.test.ts

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,260 @@ function five() {
780780
}`)
781781
}
782782
})
783+
784+
it("should handle multiple search/replace blocks with proper indentation #1559", async () => {
785+
// This test verifies the fix for GitHub issue #1559
786+
// where applying a diff with multiple search/replace blocks previously resulted in incorrect indentation
787+
788+
// Test case 1: Simple scenario with two search/replace blocks
789+
{
790+
const originalContent = `function test() {
791+
const a = 1;
792+
const b = 2;
793+
794+
// Some comment
795+
return a + b;
796+
}`
797+
798+
const diffContent = `\<<<<<<< SEARCH
799+
:start_line:2
800+
:end_line:3
801+
-------
802+
const a = 1;
803+
const b = 2;
804+
=======
805+
const x = 10;
806+
const y = 20;
807+
>>>>>>> REPLACE
808+
809+
<<<<<<< SEARCH
810+
:start_line:6
811+
-------
812+
return a + b;
813+
=======
814+
return x + y;
815+
>>>>>>> REPLACE`
816+
817+
const expectedContent = `function test() {
818+
const x = 10;
819+
const y = 20;
820+
821+
// Some comment
822+
return x + y;
823+
}`
824+
825+
const result = await strategy.applyDiff(originalContent, diffContent)
826+
827+
// Verify that the operation succeeds
828+
expect(result.success).toBe(true)
829+
830+
// Verify the content matches what we expect
831+
if (result.success) {
832+
expect(result.content).toBe(expectedContent)
833+
}
834+
}
835+
836+
// Test case 2: Complex scenario that resembles the original bug report
837+
{
838+
const complexOriginalContent = ` const BUTTON_HEIGHT=100
839+
const scrollRect = scrollContainer.getBoundingClientRect()
840+
const isPartiallyVisible = rectCodeBlock.top < (scrollRect.bottom - BUTTON_HEIGHT) && rectCodeBlock.bottom >= (scrollRect.top + BUTTON_HEIGHT)
841+
842+
// Calculate margin from existing padding in the component
843+
const computedStyle = window.getComputedStyle(codeBlock)
844+
const paddingValue = parseInt(computedStyle.getPropertyValue("padding") || "0", 10)
845+
const margin =
846+
paddingValue > 0 ? paddingValue : parseInt(computedStyle.getPropertyValue("padding-top") || "0", 10)
847+
848+
// Get wrapper height dynamically
849+
let wrapperHeight
850+
if (copyWrapper) {
851+
const copyRect = copyWrapper.getBoundingClientRect()
852+
// If height is 0 due to styling, estimate from children
853+
if (copyRect.height > 0) {
854+
wrapperHeight = copyRect.height
855+
} else if (copyWrapper.children.length > 0) {
856+
// Try to get height from the button inside
857+
const buttonRect = copyWrapper.children[0].getBoundingClientRect()
858+
const buttonStyle = window.getComputedStyle(copyWrapper.children[0] as Element)
859+
const buttonPadding =
860+
parseInt(buttonStyle.getPropertyValue("padding-top") || "0", 10) +
861+
parseInt(buttonStyle.getPropertyValue("padding-bottom") || "0", 10)
862+
wrapperHeight = buttonRect.height + buttonPadding
863+
}
864+
}
865+
866+
// If we still don't have a height, calculate from font size
867+
if (!wrapperHeight) {
868+
const fontSize = parseInt(window.getComputedStyle(document.body).getPropertyValue("font-size"), 10)
869+
wrapperHeight = fontSize * 2.5 // Approximate button height based on font size
870+
}`
871+
872+
const complexDiffContent = `\<<<<<<< SEARCH
873+
:start_line:1
874+
:end_line:3
875+
-------
876+
const BUTTON_HEIGHT=100
877+
const scrollRect = scrollContainer.getBoundingClientRect()
878+
const isPartiallyVisible = rectCodeBlock.top < (scrollRect.bottom - BUTTON_HEIGHT) && rectCodeBlock.bottom >= (scrollRect.top + BUTTON_HEIGHT)
879+
880+
=======
881+
const scrollRect = scrollContainer.getBoundingClientRect()
882+
883+
// Get wrapper height dynamically
884+
let wrapperHeight
885+
if (copyWrapper) {
886+
const copyRect = copyWrapper.getBoundingClientRect()
887+
// If height is 0 due to styling, estimate from children
888+
if (copyRect.height > 0) {
889+
wrapperHeight = copyRect.height
890+
} else if (copyWrapper.children.length > 0) {
891+
// Try to get height from the button inside
892+
const buttonRect = copyWrapper.children[0].getBoundingClientRect()
893+
const buttonStyle = window.getComputedStyle(copyWrapper.children[0] as Element)
894+
const buttonPadding =
895+
parseInt(buttonStyle.getPropertyValue("padding-top") || "0", 10) +
896+
parseInt(buttonStyle.getPropertyValue("padding-bottom") || "0", 10)
897+
wrapperHeight = buttonRect.height + buttonPadding
898+
}
899+
}
900+
901+
// If we still don't have a height, calculate from font size
902+
if (!wrapperHeight) {
903+
const fontSize = parseInt(window.getComputedStyle(document.body).getPropertyValue("font-size"), 10)
904+
wrapperHeight = fontSize * 2.5 // Approximate button height based on font size
905+
}
906+
907+
const isPartiallyVisible = rectCodeBlock.top < (scrollRect.bottom - wrapperHeight) && rectCodeBlock.bottom >= (scrollRect.top + wrapperHeight)
908+
909+
>>>>>>> REPLACE
910+
911+
<<<<<<< SEARCH
912+
:start_line:11
913+
:end_line:30
914+
-------
915+
// Get wrapper height dynamically
916+
let wrapperHeight
917+
if (copyWrapper) {
918+
const copyRect = copyWrapper.getBoundingClientRect()
919+
// If height is 0 due to styling, estimate from children
920+
if (copyRect.height > 0) {
921+
wrapperHeight = copyRect.height
922+
} else if (copyWrapper.children.length > 0) {
923+
// Try to get height from the button inside
924+
const buttonRect = copyWrapper.children[0].getBoundingClientRect()
925+
const buttonStyle = window.getComputedStyle(copyWrapper.children[0] as Element)
926+
const buttonPadding =
927+
parseInt(buttonStyle.getPropertyValue("padding-top") || "0", 10) +
928+
parseInt(buttonStyle.getPropertyValue("padding-bottom") || "0", 10)
929+
wrapperHeight = buttonRect.height + buttonPadding
930+
}
931+
}
932+
933+
// If we still don't have a height, calculate from font size
934+
if (!wrapperHeight) {
935+
const fontSize = parseInt(window.getComputedStyle(document.body).getPropertyValue("font-size"), 10)
936+
wrapperHeight = fontSize * 2.5 // Approximate button height based on font size
937+
}
938+
939+
=======
940+
>>>>>>> REPLACE`
941+
942+
// Execute the diff application
943+
const complexResult = await strategy.applyDiff(complexOriginalContent, complexDiffContent)
944+
945+
// Log the actual result for debugging
946+
console.log(
947+
"Complex test actual result:",
948+
complexResult.success ? complexResult.content : complexResult.error,
949+
)
950+
951+
// Verify that the operation succeeds
952+
expect(complexResult.success).toBe(true)
953+
954+
// Instead of comparing exact content, we'll verify key aspects of the result
955+
if (complexResult.success) {
956+
const content = complexResult.content
957+
958+
// Check that the content starts with the expected scrollRect line
959+
expect(content.startsWith(" const scrollRect = scrollContainer.getBoundingClientRect()")).toBe(
960+
true,
961+
)
962+
963+
// Check that the content contains the wrapperHeight variable declaration
964+
expect(content.includes(" let wrapperHeight")).toBe(true)
965+
966+
// Check that the content contains the isPartiallyVisible line with wrapperHeight
967+
expect(
968+
content.includes(
969+
" const isPartiallyVisible = rectCodeBlock.top < (scrollRect.bottom - wrapperHeight) && rectCodeBlock.bottom >= (scrollRect.top + wrapperHeight)",
970+
),
971+
).toBe(true)
972+
973+
// Check that the content contains the margin calculation
974+
expect(content.includes(" const margin =")).toBe(true)
975+
expect(
976+
content.includes(
977+
' paddingValue > 0 ? paddingValue : parseInt(computedStyle.getPropertyValue("padding-top") || "0", 10)',
978+
),
979+
).toBe(true)
980+
}
981+
}
982+
// This test verifies the fix for GitHub issue #1559
983+
// where applying a diff with multiple search/replace blocks previously resulted in incorrect indentation
984+
985+
// Create a very simple test case with minimal content
986+
const originalContent = `function test() {
987+
const a = 1;
988+
const b = 2;
989+
990+
// Some comment
991+
return a + b;
992+
}`
993+
994+
// Create a diff with two search/replace blocks
995+
const diffContent = `\<<<<<<< SEARCH
996+
:start_line:2
997+
:end_line:3
998+
-------
999+
const a = 1;
1000+
const b = 2;
1001+
=======
1002+
const x = 10;
1003+
const y = 20;
1004+
>>>>>>> REPLACE
1005+
1006+
<<<<<<< SEARCH
1007+
:start_line:6
1008+
-------
1009+
return a + b;
1010+
=======
1011+
return x + y;
1012+
>>>>>>> REPLACE`
1013+
1014+
// The expected content after applying the diff
1015+
const expectedContent = `function test() {
1016+
const x = 10;
1017+
const y = 20;
1018+
1019+
// Some comment
1020+
return x + y;
1021+
}`
1022+
1023+
// Execute the diff application
1024+
const result = await strategy.applyDiff(originalContent, diffContent)
1025+
1026+
// Log the actual result for debugging
1027+
console.log("Actual result:", result.success ? result.content : result.error)
1028+
1029+
// Verify that the operation succeeds
1030+
expect(result.success).toBe(true)
1031+
1032+
// Verify the content matches what we expect
1033+
if (result.success) {
1034+
expect(result.content).toBe(expectedContent)
1035+
}
1036+
})
7831037
})
7841038

7851039
describe("line number stripping", () => {

0 commit comments

Comments
 (0)