blob: 58e191e0aa1ed5861d7aa32d5889fa7e00abd96f [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package testlib a test library for testing implementations of the
// block.Device interface.
package blocktest
import (
"bytes"
"math/rand"
"testing"
"thinfs/block"
)
const (
numIterations = 100
)
// ReadAt tests the block.Device.ReadAt implementation. buf must be a []byte
// with the same contents as dev.
func ReadAt(t *testing.T, dev block.Device, r *rand.Rand, buf []byte) {
blockSize := dev.BlockSize()
numBlocks := dev.Size() / blockSize
if int64(len(buf)) != dev.Size() {
t.Fatalf("len(buf) = %v; want %v\n", len(buf), dev.Size())
}
// Read a random number of blocks from a random offset.
for i := int64(0); i < numIterations; i++ {
block := r.Int63n(numBlocks)
off := block * dev.BlockSize()
count := r.Int63n(numBlocks-block) * dev.BlockSize()
if count == 0 {
count = dev.BlockSize()
}
expected := buf[off : off+count]
actual := make([]byte, count)
if _, err := dev.ReadAt(actual, off); err != nil {
t.Errorf("Error reading %v bytes from offset %v: %v\n", count, off, err)
continue
}
if !bytes.Equal(actual, expected) {
t.Errorf("Mismatched byte slices for %v byte read from offset %v\n", count, off)
}
}
}
// WriteAt tests the block.Device.WriteAt implementation. buf must be a []byte
// with the same contents as dev.
func WriteAt(t *testing.T, dev block.Device, r *rand.Rand, buf []byte) {
blockSize := dev.BlockSize()
numBlocks := dev.Size() / blockSize
if int64(len(buf)) != dev.Size() {
t.Fatalf("len(buf) = %v; want %v\n", len(buf), dev.Size())
}
// Write a random number of blocks to a random offset.
for i := int64(0); i < numIterations; i++ {
block := r.Int63n(numBlocks)
off := block * blockSize
count := r.Int63n(numBlocks-block) * blockSize
if count == 0 {
count = blockSize
}
expected := make([]byte, count)
r.Read(expected)
if _, err := dev.WriteAt(expected, off); err != nil {
t.Errorf("Error writing %v bytes from offset %v: %v\n", count, off, err)
continue
}
copy(buf[off:], expected)
}
actual := make([]byte, dev.Size())
if _, err := dev.ReadAt(actual, 0); err != nil {
t.Error("Error reading contents of device: ", err)
}
if !bytes.Equal(actual, buf) {
t.Error("Device contents differ from expected contents")
}
}
// ErrorPaths tests that block.Device implementations return errors when clients
// attempt to perform any operations with invalid arguments.
func ErrorPaths(t *testing.T, dev block.Device) {
blockSize := dev.BlockSize()
// Write a random number of blocks to a random offset.
// Offset is not aligned.
off := blockSize + 1
if _, err := dev.ReadAt([]byte{}, off); err == nil {
t.Error("dev.ReadAt returned a nil error for an unaligned offset")
}
if _, err := dev.WriteAt([]byte{}, off); err == nil {
t.Error("dev.WriteAt returned a nil error for an unaligned offset")
}
// len(p) is not aligned.
p := make([]byte, blockSize-1)
off = blockSize
if _, err := dev.ReadAt(p, off); err == nil {
t.Error("dev.ReadAt returned a nil error for an unaligned len(p)")
}
if _, err := dev.WriteAt(p, off); err == nil {
t.Error("dev.WriteAt returned a nil error for an unaligned len(p)")
}
// Range is out of bounds.
off = dev.Size() - blockSize
p = make([]byte, 2*blockSize)
if _, err := dev.ReadAt(p, off); err == nil {
t.Error("dev.ReadAt returned a nil error for an out of bounds range")
}
if _, err := dev.WriteAt(p, off); err == nil {
t.Error("dev.WriteAt returned a nil error for an out of bounds range")
}
}