Skip to content
This repository has been archived by the owner on Oct 1, 2023. It is now read-only.

Commit

Permalink
Fix readUntilAsync/genReadUntil across chunk boundaries (#167)
Browse files Browse the repository at this point in the history
Summary:
fixes #166

Pull Request resolved: #167

Test Plan:
- added unit test
- if I revert the code change, test fails
- if I revert the code chaange and replace the `- 1` in the test with
  `- 2`, it passes

Reviewed By: jjergus

Differential Revision: D25438423

Pulled By: fredemmott

fbshipit-source-id: 0c20c7b47c0bce00a1687a8b625165dc22707a43
  • Loading branch information
fredemmott authored and facebook-github-bot committed Dec 10, 2020
1 parent 3d940fb commit edda6a3
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
9 changes: 6 additions & 3 deletions src/io/BufferedReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace HH\Lib\IO;

use namespace HH\Lib\{IO, OS, Str};
use namespace HH\Lib\{IO, Math, OS, Str};
use namespace HH\Lib\_Private\_OS;

/** Wrapper for `ReadHandle`s, with buffered line-based byte-based accessors.
Expand Down Expand Up @@ -109,15 +109,18 @@ public function read(?int $max_bytes = null): string {
}

do {
// + 1 as it would have been matched in the previous iteration if it
// fully fit in the chunk
$offset = Math\maxva(0, Str\length($buf) - $suffix_len + 1);
$chunk = await $this->handle->readAsync();
if ($chunk === '') {
$this->buffer = $buf;
return null;
}
$buf .= $chunk;
} while (!Str\contains($chunk, $suffix));
$idx = Str\search($buf, $suffix, $offset);
} while ($idx === null);

$idx = Str\search($buf, $suffix);
invariant($idx !== null, 'Should not have exited loop without suffix');
$this->buffer = Str\slice($buf, $idx + $suffix_len);
return Str\slice($buf, 0, $idx);
Expand Down
25 changes: 24 additions & 1 deletion tests/io/BufferedReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
*
*/

use namespace HH\Lib\{IO, OS, Vec};
use namespace HH\Lib\{IO, OS, Str, Vec};
use namespace HH\Lib\_Private\_IO;

use function Facebook\FBExpect\expect; // @oss-enable
use type Facebook\HackTest\HackTest; // @oss-enable
Expand Down Expand Up @@ -107,6 +108,28 @@ final class BufferedReaderTest extends HackTest {
expect(await $r->readUntilAsync("FOO"))->toEqual("cd");
}

public async function testReadUntilBufferBoundary(): Awaitable<void> {
// Intent is to test the case when the separator starts in one chunk, and
// ends in another, i.e.:
// - Str\length($padding) < chunk size
// - Str\length($padding.$separator) > chunk size
$padding = Str\repeat('a', _IO\DEFAULT_READ_BUFFER_SIZE - 1);
$separator = 'bc';

list($r, $w) = IO\pipe();
concurrent {
await async {
await $w->writeAllAsync($padding.$separator.'junk');
$w->close();
};
await async {
$br = new IO\BufferedReader($r);
expect(await $br->readUntilAsync($separator))->toEqual($padding);
$r->close();
};
}
}

public async function testReadLineVsReadUntil(): Awaitable<void> {
$r = new IO\BufferedReader(new IO\MemoryHandle("ab\ncd"));
expect(await $r->readLineAsync())->toEqual('ab');
Expand Down

0 comments on commit edda6a3

Please sign in to comment.