From a3e8fb7f75aa0c2d41c87b5725405ab941baea0c Mon Sep 17 00:00:00 2001 From: "Vytautas M." Date: Thu, 14 Aug 2025 16:16:44 +0300 Subject: [PATCH 1/3] Ensure file content ends with a newline --- src/Install/GuidelineWriter.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Install/GuidelineWriter.php b/src/Install/GuidelineWriter.php index 13f828fb..bc6ad3d9 100644 --- a/src/Install/GuidelineWriter.php +++ b/src/Install/GuidelineWriter.php @@ -72,6 +72,11 @@ public function write(string $guidelines): int $newContent = $frontMatter.$existingContent.$separatingNewlines.$replacement; } + // Ensure file content ends with a newline + if (! str_ends_with($newContent, "\n")) { + $newContent .= "\n"; + } + if (ftruncate($handle, 0) === false || fseek($handle, 0) === -1) { throw new RuntimeException("Failed to reset file pointer: {$filePath}"); } From 93e9d8e932d32fa084debe8a80ec7821d6a5ce76 Mon Sep 17 00:00:00 2001 From: Vytautas Motuzas Date: Thu, 14 Aug 2025 16:42:00 +0300 Subject: [PATCH 2/3] Update GuidelineWriterTest --- tests/Unit/Install/GuidelineWriterTest.php | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/Unit/Install/GuidelineWriterTest.php b/tests/Unit/Install/GuidelineWriterTest.php index 25719945..3f60cdcb 100644 --- a/tests/Unit/Install/GuidelineWriterTest.php +++ b/tests/Unit/Install/GuidelineWriterTest.php @@ -60,7 +60,7 @@ $writer->write('test guidelines content'); $content = file_get_contents($tempFile); - expect($content)->toBe("\ntest guidelines content\n"); + expect($content)->toBe("\ntest guidelines content\n\n"); unlink($tempFile); }); @@ -77,7 +77,7 @@ $writer->write('new guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n"); + expect($content)->toBe("# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n\n"); unlink($tempFile); }); @@ -95,7 +95,7 @@ $writer->write('updated guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("# Header\n\n\nupdated guidelines\n\n\n# Footer"); + expect($content)->toBe("# Header\n\n\nupdated guidelines\n\n\n# Footer\n"); unlink($tempFile); }); @@ -114,7 +114,7 @@ $content = file_get_contents($tempFile); // Should replace in-place, preserving structure - expect($content)->toBe("Start\n\nsingle line\n\nEnd"); + expect($content)->toBe("Start\n\nsingle line\n\nEnd\n"); unlink($tempFile); }); @@ -133,7 +133,7 @@ $content = file_get_contents($tempFile); // Should replace first occurrence, second block remains untouched due to non-greedy matching - expect($content)->toBe("Start\n\nreplacement\n\nMiddle\n\nsecond\n\nEnd"); + expect($content)->toBe("Start\n\nreplacement\n\nMiddle\n\nsecond\n\nEnd\n"); unlink($tempFile); }); @@ -165,7 +165,7 @@ $writer->write('my guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("# Title\n\nParagraph 1\n\nParagraph 2\n\n===\n\n\nmy guidelines\n"); + expect($content)->toBe("# Title\n\nParagraph 1\n\nParagraph 2\n\n===\n\n\nmy guidelines\n\n"); unlink($tempFile); }); @@ -182,7 +182,7 @@ $writer->write('first guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("\nfirst guidelines\n"); + expect($content)->toBe("\nfirst guidelines\n\n"); unlink($tempFile); }); @@ -199,7 +199,7 @@ $writer->write('clean guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("\nclean guidelines\n"); + expect($content)->toBe("\nclean guidelines\n\n"); unlink($tempFile); }); @@ -218,7 +218,7 @@ expect($result)->toBe(GuidelineWriter::REPLACED); $content = file_get_contents($tempFile); - expect($content)->toBe("# Title\n\n\nShould not be touched\n\n\n\nnew guidelines\n\n\n\nAlso untouched\n"); + expect($content)->toBe("# Title\n\n\nShould not be touched\n\n\n\nnew guidelines\n\n\n\nAlso untouched\n\n"); unlink($tempFile); }); @@ -248,7 +248,7 @@ expect($content)->toContain('More content here.'); // Verify exact structure - expect($content)->toBe("# My Project\n\n\nupdated guidelines from boost\n\n\n# User Added Section\nThis content was added by the user after the guidelines.\n\n## Another user section\nMore content here."); + expect($content)->toBe("# My Project\n\n\nupdated guidelines from boost\n\n\n# User Added Section\nThis content was added by the user after the guidelines.\n\n## Another user section\nMore content here.\n"); unlink($tempFile); }); @@ -296,7 +296,7 @@ $writer->write('new guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("---\nalwaysApply: true\n---\n# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n"); + expect($content)->toBe("---\nalwaysApply: true\n---\n# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n\n"); unlink($tempFile); }); @@ -313,7 +313,7 @@ $writer->write('new guidelines'); $content = file_get_contents($tempFile); - expect($content)->toBe("---\ncustomOption: true\n---\n# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n"); + expect($content)->toBe("---\ncustomOption: true\n---\n# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n\n"); unlink($tempFile); }); @@ -331,7 +331,7 @@ expect($result)->toBe(GuidelineWriter::NEW); $content = file_get_contents($tempFile); - expect($content)->toBe("# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n"); + expect($content)->toBe("# Existing content\n\nSome text here.\n\n===\n\n\nnew guidelines\n\n"); unlink($tempFile); }); From 6522e476c97f3b2e1abd06cbc213ab45e0584506 Mon Sep 17 00:00:00 2001 From: Vytautas Motuzas Date: Thu, 14 Aug 2025 16:55:22 +0300 Subject: [PATCH 3/3] Test to avoid adding extra newline --- tests/Unit/Install/GuidelineWriterTest.php | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/Unit/Install/GuidelineWriterTest.php b/tests/Unit/Install/GuidelineWriterTest.php index 3f60cdcb..655e674b 100644 --- a/tests/Unit/Install/GuidelineWriterTest.php +++ b/tests/Unit/Install/GuidelineWriterTest.php @@ -100,6 +100,29 @@ unlink($tempFile); }); +test('it avoids adding extra newline if one already exists', function () { + $tempFile = tempnam(sys_get_temp_dir(), 'boost_test_'); + $initialContent = "# Header\n\n\nold guidelines\n\n\n# Footer\n"; + file_put_contents($tempFile, $initialContent); + + $agent = Mockery::mock(Agent::class); + $agent->shouldReceive('guidelinesPath')->andReturn($tempFile); + $agent->shouldReceive('frontmatter')->andReturn(false); + + $writer = new GuidelineWriter($agent); + $writer->write('updated guidelines'); + + $content = file_get_contents($tempFile); + expect($content)->toBe("# Header\n\n\nupdated guidelines\n\n\n# Footer\n"); + + // Assert no double newline at the end + expect(substr($content, -2))->not->toBe("\n\n"); + // Assert still ends with exactly one newline + expect(substr($content, -1))->toBe("\n"); + + unlink($tempFile); +}); + test('it handles multiline existing guidelines', function () { $tempFile = tempnam(sys_get_temp_dir(), 'boost_test_'); $initialContent = "Start\n\nline 1\nline 2\nline 3\n\nEnd";