Files
hse-2026/homework/03-http-server/tests/compare.go
T
2026-09-24 21:30:37 +03:00

125 lines
3.6 KiB
Go

package hw3test
import (
"bytes"
"fmt"
"github.com/stretchr/testify/require"
"io"
"math/rand"
"os"
"path"
)
// RequireFileContent requires that the contents of the file match the contents of the reader.
func RequireFileContent(t *TC, workdir, p string, f *EnvFile) {
fullpath := path.Join(workdir, p)
file, err := os.Open(fullpath)
require.NoError(t, err, "failed to open file %s, expected it exists on disk", p)
defer file.Close()
stat, err := file.Stat()
require.NoError(t, err, "failed to stat file %s", p)
require.Equal(t, f.Size, stat.Size(), "file %s has wrong size", p)
require.NoError(t, CompareFileContent(t, file, f), "file %s has wrong content", p)
}
// CompareFileContent compares first f.Size bytes of the reader with generated content.
func CompareFileContent(t *TC, r io.Reader, f *EnvFile) error {
actual := make([]byte, 64*1024)
expected := make([]byte, len(actual))
var generator io.Reader
if f.TextOnly {
generator = f.Open()
} else {
generator = newComparisonReader(f.GenSeed)
}
for offset := int64(0); offset < f.Size; {
count := int64(len(actual))
if remaining := f.Size - offset; remaining < count {
count = remaining
}
if _, err := io.ReadFull(r, actual[:count]); err != nil {
return fmt.Errorf("unexpected file error at position %d: %w", offset, err)
}
if _, err := io.ReadFull(generator, expected[:count]); err != nil {
return fmt.Errorf("unexpected generator error at position %d: %w", offset, err)
}
if !bytes.Equal(actual[:count], expected[:count]) {
for i := int64(0); i < count; i++ {
if actual[i] != expected[i] {
return fmt.Errorf("position %d, expected byte %d, got %d", offset+i, expected[i], actual[i])
}
}
}
offset += count
}
return nil
}
// comparisonReader emits the same bytes as rand.New(source).Read, seven bytes
// from each Int63 value. It fills complete seven-byte groups without the
// per-byte branch in math/rand.Read. Request bodies still use EnvFile.Open.
type comparisonReader struct {
source rand.Source
value uint64
remaining uint8
}
func newComparisonReader(seed int64) *comparisonReader {
return &comparisonReader{source: rand.NewSource(seed)}
}
func (r *comparisonReader) Read(p []byte) (int, error) {
n := len(p)
for len(p) > 0 && r.remaining > 0 {
p[0] = byte(r.value)
r.value >>= 8
r.remaining--
p = p[1:]
}
for len(p) >= 7 {
value := uint64(r.source.Int63())
p[0] = byte(value)
p[1] = byte(value >> 8)
p[2] = byte(value >> 16)
p[3] = byte(value >> 24)
p[4] = byte(value >> 32)
p[5] = byte(value >> 40)
p[6] = byte(value >> 48)
p = p[7:]
}
if len(p) > 0 {
r.value = uint64(r.source.Int63())
r.remaining = 7
for i := range p {
p[i] = byte(r.value)
r.value >>= 8
r.remaining--
}
}
return n, nil
}
// RequireDir ensures that the directory exists on disk.
func RequireDir(t *TC, workdir string, p string, dir *EnvDir) {
fullpath := path.Join(workdir, p)
stat, err := os.Stat(fullpath)
require.NoError(t, err, "failed to stat directory %s, expected it exists on disk", p)
require.True(t, stat.IsDir(), "expected %s to be a directory", p)
}
// RequireNotExists ensures that the file/directory does not exist on disk.
func RequireNotExists(t *TC, workdir string, p string) {
fullpath := path.Join(workdir, p)
_, err := os.Stat(fullpath)
require.True(t, os.IsNotExist(err), "expected %s to not exist on disk", p)
}
// RequireExists ensures that the file/directory exists on disk.
func RequireExists(t *TC, workdir string, p string) {
fullpath := path.Join(workdir, p)
_, err := os.Stat(fullpath)
require.NoError(t, err, "failed to stat %s, expected it exists on disk", p)
}