fix(brainfs): bound the read in ReadRegularMax; honest test names (#157)
CI / Lint / Test / Vet (pull_request) Successful in 41s
CI / Mirror to GitHub (pull_request) Skipped

Review round 1 on PR #165:

- ReadRegularMax checked the size on the opened handle, then read with an
  unbounded io.ReadAll, so a file growing after the check returned past the
  limit. The read now goes through io.LimitReader(max+1). A test seam grows
  the file between the check and the read and counts bytes consumed.
- New: ReadScoped returns ErrTooLarge for a note over maxNoteBytes; red if
  readContained drops the limit.
- notes.Target carries the brain root instead of deriving it by TrimSuffix.
- Rule 9: reader tests renamed to <Reader>RefusesSymlinksAndSurvivesSwapRaces;
  ReadNote test has a positive control; brainfstest comment states what the
  harness observes and what it does not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-04 00:33:36 +02:00
co-authored by Claude Opus 5.5
parent b6f7dac46e
commit 02cecb25b1
8 changed files with 84 additions and 14 deletions
@@ -2,6 +2,7 @@ package brainfs
import (
"errors"
"io"
"os"
"path/filepath"
"syscall"
@@ -103,3 +104,38 @@ func TestReadRegularMaxRefusesAFileOverTheLimit(t *testing.T) {
require.NoError(t, err)
assert.Len(t, got, 100)
}
func TestReadRegularMaxRefusesAndStopsReadingAFileThatGrowsPastTheLimit(t *testing.T) {
dir := t.TempDir()
p := filepath.Join(dir, "grow.md")
require.NoError(t, os.WriteFile(p, make([]byte, 10), 0o644))
consumed := &countingReader{}
wrapAfterStat = func(r io.Reader) io.Reader {
f, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND, 0)
require.NoError(t, err)
_, err = f.Write(make([]byte, 1000))
require.NoError(t, err)
require.NoError(t, f.Close())
consumed.r = r
return consumed
}
t.Cleanup(func() { wrapAfterStat = nil })
b, err := Open(dir)
require.NoError(t, err)
defer func() { _ = b.Close() }()
got, err := b.ReadRegularMax("grow.md", 100)
assert.True(t, errors.Is(err, ErrTooLarge), "got %v", err)
assert.Nil(t, got)
assert.LessOrEqual(t, consumed.n, 101, "read past max+1 bytes")
}
type countingReader struct {
r io.Reader
n int
}
func (c *countingReader) Read(p []byte) (int, error) {
n, err := c.r.Read(p)
c.n += n
return n, err
}