LineReaderTest.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. namespace Bcremer\LineReaderTests;
  3. use Bcremer\LineReader\LineReader;
  4. use PHPUnit\Framework\TestCase;
  5. class LineReaderTest extends TestCase
  6. {
  7. private static $maxLines;
  8. private static $testFile;
  9. public static function setUpBeforeClass(): void
  10. {
  11. self::$maxLines = (int)getenv('TEST_MAX_LINES') ?: 10000;
  12. self::$testFile = __DIR__.'/testfile_'.self::$maxLines.'.txt';
  13. if (is_file(self::$testFile)) {
  14. return;
  15. }
  16. $fh = fopen(self::$testFile, 'w');
  17. for ($i = 1; $i <= self::$maxLines; $i++) {
  18. fwrite($fh, "Line $i\n");
  19. }
  20. fclose($fh);
  21. }
  22. public function testReadLinesThrowsException(): void
  23. {
  24. $this->expectException(\InvalidArgumentException::class);
  25. $this->expectExceptionMessage('Cannot open file for reading: /tmp/invalid-file.txt');
  26. LineReader::readLines('/tmp/invalid-file.txt');
  27. }
  28. public function testReadLinesBackwardsThrowsException(): void
  29. {
  30. $this->expectException(\InvalidArgumentException::class);
  31. $this->expectExceptionMessage('Cannot open file for reading: /tmp/invalid-file.txt');
  32. LineReader::readLinesBackwards('/tmp/invalid-file.txt');
  33. }
  34. public function testReadsAllLines(): void
  35. {
  36. $result = LineReader::readLines(self::$testFile);
  37. self::assertInstanceOf(\Traversable::class, $result);
  38. $firstLine = 1;
  39. $lastLine = self::$maxLines;
  40. $lineCount = self::$maxLines;
  41. $this->assertLines($result, $firstLine, $lastLine, $lineCount);
  42. }
  43. public function testReadsLinesByStartline(): void
  44. {
  45. $lineGenerator = LineReader::readLines(self::$testFile);
  46. $lineGenerator = new \LimitIterator($lineGenerator, 50);
  47. $firstLine = 51;
  48. $lastLine = self::$maxLines;
  49. $lineCount = self::$maxLines-50;
  50. $this->assertLines($lineGenerator, $firstLine, $lastLine, $lineCount);
  51. }
  52. public function testReadsLinesByLimit(): void
  53. {
  54. $lineGenerator = LineReader::readLines(self::$testFile);
  55. $lineGenerator = new \LimitIterator($lineGenerator, 50, 100);
  56. $firstLine = 51;
  57. $lastLine = 150;
  58. $lineCount = 100;
  59. $this->assertLines($lineGenerator, $firstLine, $lastLine, $lineCount);
  60. }
  61. public function testReadsLinesBackwards(): void
  62. {
  63. $lineGenerator = LineReader::readLinesBackwards(self::$testFile);
  64. $firstLine = self::$maxLines;
  65. $lastLine = 1;
  66. $lineCount = self::$maxLines;
  67. $this->assertLines($lineGenerator, $firstLine, $lastLine, $lineCount);
  68. }
  69. public function testReadsLinesBackwardsWithOffsetAndLimit(): void
  70. {
  71. $lineGenerator = LineReader::readLinesBackwards(self::$testFile);
  72. $lineGenerator = new \LimitIterator($lineGenerator, 10, 50);
  73. $firstLine = self::$maxLines-10;
  74. $lastLine = self::$maxLines-59;
  75. $lineCount = 50;
  76. $this->assertLines($lineGenerator, $firstLine, $lastLine, $lineCount);
  77. }
  78. public function testEmptyFile(): void
  79. {
  80. $testFile = __DIR__.'/testfile_empty.txt';
  81. $content = '';
  82. file_put_contents($testFile, $content);
  83. $lineGenerator = LineReader::readLines($testFile);
  84. self::assertSame([], iterator_to_array($lineGenerator));
  85. $lineGenerator = LineReader::readLinesBackwards($testFile);
  86. self::assertSame([], iterator_to_array($lineGenerator));
  87. }
  88. public function testFileWithLeadingAndTrailingNewlines(): void
  89. {
  90. $testFile = __DIR__.'/testfile_space.txt';
  91. $content = <<<CONTENT
  92. Line 1
  93. Line 4
  94. Line 5
  95. CONTENT;
  96. file_put_contents($testFile, $content);
  97. self::assertSame(
  98. [
  99. '',
  100. '',
  101. 'Line 1',
  102. '',
  103. '',
  104. 'Line 4',
  105. 'Line 5',
  106. '',
  107. ],
  108. iterator_to_array(LineReader::readLines($testFile))
  109. );
  110. self::assertSame(
  111. [
  112. '',
  113. 'Line 5',
  114. 'Line 4',
  115. '',
  116. '',
  117. 'Line 1',
  118. '',
  119. '',
  120. ],
  121. iterator_to_array(LineReader::readLinesBackwards($testFile))
  122. );
  123. }
  124. /**
  125. * Runs the generator and asserts on first, last and the total line count
  126. *
  127. * @param \Traversable $generator
  128. */
  129. private function assertLines(\Traversable $generator, string $firstLine, int $lastLine, int $lineCount): void
  130. {
  131. $count = 0;
  132. $line = '';
  133. foreach ($generator as $line) {
  134. if ($count === 0) {
  135. self::assertSame("Line $firstLine", $line, 'Expect first line');
  136. }
  137. $count++;
  138. }
  139. self::assertSame("Line $lastLine", $line, 'Expect last line');
  140. self::assertSame($lineCount, $count, 'Expect total line count');
  141. }
  142. }