diff --git a/src/Highlighter.php b/src/Highlighter.php
index f284bbb..5b6e527 100644
--- a/src/Highlighter.php
+++ b/src/Highlighter.php
@@ -103,7 +103,13 @@ public function getCodeSnippet($source, $lineNumber, $linesBefore = 2, $linesAft
$offset = $lineNumber - $linesBefore - 1;
$offset = max($offset, 0);
- $length = $linesAfter + $linesBefore + 1;
+
+ if ($lineNumber <= $linesBefore) {
+ $length = $lineNumber + $linesAfter;
+ } else {
+ $length = $linesAfter + $linesBefore + 1;
+ }
+
$tokenLines = array_slice($tokenLines, $offset, $length, $preserveKeys = true);
$lines = $this->colorLines($tokenLines);
@@ -309,6 +315,6 @@ private function lineNumbers(array $lines, $markLine = null)
$snippet .= $line . PHP_EOL;
}
- return $snippet;
+ return rtrim($snippet, PHP_EOL);
}
}
diff --git a/tests/GetCodeSnippetTest.php b/tests/GetCodeSnippetTest.php
new file mode 100644
index 0000000..989a6ed
--- /dev/null
+++ b/tests/GetCodeSnippetTest.php
@@ -0,0 +1,138 @@
+
+EOL;
+
+ /**
+ * Test retrieving a code snippet from a larger context.
+ *
+ * @dataProvider dataGetCodeSnippet
+ *
+ * @param string $expected Expected function output.
+ * @param int $lineNo Line number to get the code snippet for.
+ * @param int $linesBeforeAfter Number of lines of code context to retrieve.
+ */
+ public function testGetCodeSnippet($expected, $lineNo, $linesBeforeAfter = 2)
+ {
+ $highlighter = new Highlighter($this->getConsoleColorMock());
+ $output = $highlighter->getCodeSnippet($this->input, $lineNo, $linesBeforeAfter, $linesBeforeAfter);
+
+ // Allow unit tests to succeed on non-*nix systems.
+ $output = str_replace(array("\r\n", "\r"), "\n", $output);
+
+ $this->assertSame($expected, $output);
+ }
+
+ /**
+ * Data provider.
+ *
+ * Includes test cases to verify that the line number padding is handled correctly
+ * depending on the "widest" line number.
+ *
+ * @return array
+ */
+ public function dataGetCodeSnippet()
+ {
+ return array(
+ 'Snippet at start of code - line 1' => array(
+ 'expected' => <<<'EOL'
+ > 1|
+ 2|
+ 3| namespace FooBar;
+EOL
+ ,
+ 'lineNo' => 1,
+ ),
+ 'Snippet at start of code - line 2' => array(
+ 'expected' => <<<'EOL'
+ 1|
+ > 2|
+ 3| namespace FooBar;
+ 4|
+EOL
+ ,
+ 'lineNo' => 2,
+ ),
+ 'Snippet middle of code' => array(
+ 'expected' => <<<'EOL'
+ 7| * @param type $param Description.
+ 8| */
+ > 9| public function bar($param) {
+ 10| // Do something.
+ 11| }
+EOL
+ ,
+ 'lineNo' => 9,
+ ),
+ 'Snippet at end of code - line before last' => array(
+ 'expected' => <<<'EOL'
+ 10| // Do something.
+ 11| }
+ > 12| }
+ 13| ?>
+EOL
+ ,
+ 'lineNo' => 12,
+ ),
+ 'Snippet at end of code - last line' => array(
+ 'expected' => <<<'EOL'
+ 11| }
+ 12| }
+ > 13| ?>
+EOL
+ ,
+ 'lineNo' => 13,
+ ),
+ 'Snippet middle of code, 1 line context' => array(
+ 'expected' => <<<'EOL'
+ 8| */
+ > 9| public function bar($param) {
+ 10| // Do something.
+EOL
+ ,
+ 'lineNo' => 9,
+ 'linesBeforeAfter' => 1,
+ ),
+ 'Snippet middle of code, 3 line context' => array(
+ 'expected' => <<<'EOL'
+ 6| /**
+ 7| * @param type $param Description.
+ 8| */
+ > 9| public function bar($param) {
+ 10| // Do something.
+ 11| }
+ 12| }
+EOL
+ ,
+ 'lineNo' => 9,
+ 'linesBeforeAfter' => 3,
+ ),
+ );
+ }
+}
diff --git a/tests/HighlighterTestCase.php b/tests/HighlighterTestCase.php
new file mode 100644
index 0000000..ebedff5
--- /dev/null
+++ b/tests/HighlighterTestCase.php
@@ -0,0 +1,39 @@
+createMock('\PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor')
+ : $this->getMock('\PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor');
+
+ $mock->expects($this->any())
+ ->method('apply')
+ ->will($this->returnCallback(function ($style, $text) use ($withTheme) {
+ if ($withTheme) {
+ return "<$style>$text$style>";
+ } else {
+ return $text;
+ }
+ }));
+
+ $mock->expects($this->any())
+ ->method('hasTheme')
+ ->will($this->returnValue($withTheme));
+
+ return $mock;
+ }
+}
diff --git a/tests/TokenizeTest.php b/tests/TokenizeTest.php
index 0170bc8..11e36f7 100644
--- a/tests/TokenizeTest.php
+++ b/tests/TokenizeTest.php
@@ -3,7 +3,6 @@
namespace PHP_Parallel_Lint\PhpConsoleHighlighter\Test;
use PHP_Parallel_Lint\PhpConsoleHighlighter\Highlighter;
-use PHPUnit\Framework\TestCase;
/**
* Test support for all token types.
@@ -11,7 +10,7 @@
* @covers PHP_Parallel_Lint\PhpConsoleHighlighter\Highlighter::tokenize
* @covers PHP_Parallel_Lint\PhpConsoleHighlighter\Highlighter::getTokenType
*/
-class TokenizeTest extends TestCase
+class TokenizeTest extends HighlighterTestCase
{
/** @var Highlighter */
private $uut;
@@ -24,30 +23,6 @@ protected function setUpHighlighter()
$this->uut = new Highlighter($this->getConsoleColorMock());
}
- /**
- * Helper method mocking the Console Color Class.
- *
- * @return \PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor
- */
- protected function getConsoleColorMock()
- {
- $mock = method_exists($this, 'createMock')
- ? $this->createMock('\PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor')
- : $this->getMock('\PHP_Parallel_Lint\PhpConsoleColor\ConsoleColor');
-
- $mock->expects($this->any())
- ->method('apply')
- ->will($this->returnCallback(function ($style, $text) {
- return "<$style>$text$style>";
- }));
-
- $mock->expects($this->any())
- ->method('hasTheme')
- ->will($this->returnValue(true));
-
- return $mock;
- }
-
/**
* Helper method executing the actual tests.
*