randdata

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2020 License: MIT Imports: 11 Imported by: 0

README

go-randdata

GitHub GoDoc Go Report Card codecov

go-randdata is a Go package providing a mechanism for unit testing to generate and verify reproducible pseudo-random byte sequences.

Reader is the pseudo-random byte sequence generator. It implements the io.Reader interface and can be Read the generated byte sequence. Verifier is the Reader companion object that implements the io.Writer interface. It verifies that the data written is exactly the same as the byte sequence generated by the Reader.

import (
	"fmt"
	"github.com/tunabay/go-randdata"
)

func main() {
        // 5 MB pseudo-random byte sequence, using random seed 123
        r := randdata.New(randdata.Binary, 123, 5000000)

        // paired verifier
        v := r.NewVerifier()

        // read and veriry data
        buf := make([]byte, 256)
        for {
                n, err := r.Read(buf)
                if 0 < n {
                        if _, err := v.Write(buf[:n]); err != nil {
                                fmt.Println(err)
                                break
                        }
                }
                if err != nil {
                        if err != io.EOF {
                                fmt.Println(err)
                        }
                        break
                }
        }

        // verify that written data is enough
        if err := v.Close(); err != nil {
                fmt.Println(err)
        }

        fmt.Println("Read:", r.TotalRead())
}

Run in Go Playground

The Reader also generates "jitter" to reading operation. In the above example, calling Read method with the 256 bytes buffer returns randomly shorter written length. While the Read method of the io.Reader interface can return shorter length than passed buffer, program should be able to handle that.

Documentation

See also

License

go-randdata is available under the MIT license. See the LICENSE file for more information.

Documentation

Overview

Package randdata provides a mechanism for unit testing to generate and verify reproducible pseudo-random byte sequences.

Reader is the pseudo-random byte sequence generator. It implements the io.Reader interface and can be Read the generated byte sequence. Verifier is the Reader companion object that implements the io.Writer interface. It verifies that the data written is exactly the same as the byte sequence generated by the Reader.

It is designed for unit testing of programs that process data from files or networks and is used to verify that the processed data is not corrupted.

// 5 MB pseudo-random byte sequence, using random seed 123
r := randdata.New(randdata.Binary, 123, 5000000)

// paired verifier
v := r.NewVerifier()

// read and veriry data
buf := make([]byte, 256)
for {
	n, err := r.Read(buf)
	if 0 < n {
		if _, err := v.Write(buf[:n]); err != nil {
			fmt.Println(err)
			break
		}
	}
	if err != nil {
		if err != io.EOF {
			fmt.Println(err)
		}
		break
	}
}

// verify that written data is enough
if err := v.Close(); err != nil {
	fmt.Println(err)
}

fmt.Println("Read:", r.TotalRead())

The Reader also generates "jitter" to reading operation. In the above example, calling Read method with the 256 bytes buffer returns randomly shorter written length. While the Read method of the io.Reader interface can return shorter length than passed buffer, program should be able to handle that. If the program can not handle this behavior, it should use bufio.Reader, io.ReadFull, or ioutil.ReadAll.

Example
// 5 MB pseudo-random byte sequence, using random seed 123
r := randdata.New(randdata.Binary, 123, 5000000)

// paired verifier
v := r.NewVerifier()

// read and veriry data
buf := make([]byte, 256)
for {
	n, err := r.Read(buf)
	if 0 < n {
		if _, err := v.Write(buf[:n]); err != nil {
			fmt.Println(err)
			break
		}
	}
	if err != nil {
		if err != io.EOF {
			fmt.Println(err)
		}
		break
	}
}

// verify that written data is enough
if err := v.Close(); err != nil {
	fmt.Println(err)
}

fmt.Println("Read:", r.TotalRead())
Output:

Read: 5.0 MB
Example (ShortData)
// 3 MB pseudo-random byte sequence, using random seed 777
r := randdata.New(randdata.Binary, 777, 3000000)

// verifier expecting 10 bytes extra
v := randdata.NewVerifier(randdata.Binary, 777, 3000000+10)

// read and veriry data
buf := make([]byte, 256)
for {
	n, err := r.Read(buf)
	if 0 < n {
		if _, err := v.Write(buf[:n]); err != nil {
			fmt.Println(err)
			break
		}
	}
	if err != nil {
		if err != io.EOF {
			fmt.Println(err)
		}
		break
	}
}

// verify that written data is enough
if err := v.Close(); err != nil {
	fmt.Println(err)
}

fmt.Println("Read:", r.TotalRead())
Output:

not enough bytes: 10 B short
Read: 3.0 MB

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Generator

type Generator interface {
	Gen(r *rand.Rand, pos, rem infounit.ByteCount) ([]byte, error)
}

Generator is the interface implemented by mechanisms that generate various random data. Gen() returns a pseudo-random byte sequence of arbitrary length using the passed pseudo-random generator r. The parameters pos and rem represent the position from the beginning of the data and the number of bytes remaining up to the end of the data, respectively. Gen() must return the same byte sequence for the same parameters to generate reproducible data. Generator must not hold any state. The byte sequence returned by Gen() should not depend on anything other than parameters.

type NotEnoughBytesError

type NotEnoughBytesError struct {
	ExpectedLen infounit.ByteCount
	WrittenLen  infounit.ByteCount
}

NotEnoughBytesError is the error thrown when the Verifier is closed before the expected size of data is written.

func (NotEnoughBytesError) Error

func (err NotEnoughBytesError) Error() string

Error returns the string representation of NotEnoughBytesError.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader is a reproducible and verifiable pseudo-random byte sequence generator. Reader with the same parameters, type, seed, and size, always produces the same byte sequence. The byte sequence read from Reader is verified by writing it to Verifier. Reader implements io.Reader, io.ByteReader, and io.WriterTo interfaces.

func New

func New(dType Type, seed int64, size infounit.ByteCount) *Reader

New creates and returns a new Reader instance with the specified data type, random seed, and size.

func NewWithGenerator

func NewWithGenerator(gen Generator, seed int64, size infounit.ByteCount) *Reader

NewWithGenerator creates a new Reader instance with a custom Generator.

func (*Reader) IsEOF

func (r *Reader) IsEOF() bool

IsEOF returns true if the end of the pseudo-random byte sequence is reached.

func (*Reader) NewVerifier

func (r *Reader) NewVerifier() *Verifier

NewVerifier creates a Verifier that can be used to verify byte sequence generated from this Reader.

func (*Reader) Read

func (r *Reader) Read(p []byte) (int, error)

Read reads up to len(p) bytes of generated pseudo-random byte sequence into p. It returns (0, io.EOF) at end of the byte sequence. According to the io.Reader interface specification, Read may return only a length less than len(p). To test this behavior, this Read is implemented to intentionally return short data using pseudo-random. Programs that do not handle this behavior properly should wrap Reader with bufio.Reader.

func (*Reader) ReadByte

func (r *Reader) ReadByte() (byte, error)

ReadByte reads and returns the next byte from the generated pseudo-random byte sequence. This implements the ByteReader interface in the package io.

func (*Reader) TotalRead

func (r *Reader) TotalRead() infounit.ByteCount

TotalRead returns the total number of bytes already read.

func (*Reader) WriteTo

func (r *Reader) WriteTo(w io.Writer) (int64, error)

WriteTo writes generated pseudo-random byte sequence to w. This implements the WriterTo interface in the package io.

type TrailingExtraBytesError

type TrailingExtraBytesError struct {
	ExpectedLen   infounit.ByteCount
	WrittenLen    infounit.ByteCount
	AcceptedBytes []byte
	ExtraBytes    []byte
}

TrailingExtraBytesError is the error thrown when extra bytes are written to the Verifier beyond the expected data end.

func (TrailingExtraBytesError) Error

func (err TrailingExtraBytesError) Error() string

Error returns the string representation of TrailingExtraBytesError.

type Type

type Type uint8

Type represents the type of the random data to be generated.

const (
	Zero     Type = iota          // zero filled data (not random)
	Binary                        // binary data
	Text                          // text data
	UTF8Text                      // unicode text data (not implemented yet)
	Custom   Type = math.MaxUint8 // custon generator
)

func (Type) String

func (t Type) String() string

String returns the string representation of Type value.

type UnexpectedBytesError

type UnexpectedBytesError struct {
	Pos           infounit.ByteCount // the first byte is 0
	ExpectedBytes []byte
	WrittenBytes  []byte
}

UnexpectedBytesError is the error thrown when an unexpected wrong byte sequence is written to the Verifier.

func (UnexpectedBytesError) Error

func (err UnexpectedBytesError) Error() string

Error returns the string representation of UnexpectedBytesError.

type Verifier

type Verifier struct {
	// contains filtered or unexported fields
}

Verifier represents a verifier that verifies the byte sequence generated by Reader. Verification requires a Verifier with the same parameters, data type, random seed and size, as Reader that generates the target data. The byte sequence is verified by writing it to Verifier. If incorrect data is written, the writing will fail and an error will be returned. Verifier implements the Writer, StringWriter, ByteWriter, and ReaderFrom interfaces in the package io. There is also ReadFromFile method to verify data from a file. Whichever method is used, the same validation is performed. Note that wrong bytes and extra bytes than expected are verified on write, but shorter data length is not verified on write but on close. Therefore, after writing all the data to Verifier, be sure to call Close to verify that enough data was written.

func NewAsFile

func NewAsFile(dType Type, seed int64, size infounit.ByteCount, path string) (*Verifier, error)

NewAsFile generates a pseudo-random byte sequence into the specified file. The contents of the file can be verified by Verifier. For convenience, it returns the Verifier with identical parameters. It is the caller's responsibility to remove the file when no longer needed.

func NewAsTempFile

func NewAsTempFile(dType Type, seed int64, size infounit.ByteCount) (string, *Verifier, error)

NewAsTempFile generates a pseudo-random byte sequence into a temporary file, and returns the file name and the Verifier with identical parameters. The contents of the temporary file can be verified by Verifier. It is the caller's responsibility to remove the file when no longer needed.

func NewVerifier

func NewVerifier(dType Type, seed int64, size infounit.ByteCount) *Verifier

NewVerifier creates a Verifier with parameters. It is preferable to use Reader.Verifier(), which requires no parameters, if possible.

func NewVerifierWithGenerator

func NewVerifierWithGenerator(gen Generator, seed int64, size infounit.ByteCount) *Verifier

NewVerifierWithGenerator creates a new Verifier with a custom Generator. It is preferable to use Reader.Verifier() if possible.

func (*Verifier) Close

func (v *Verifier) Close() error

Close informs Verifier that writing of all data is complete. If the expected length of data has not been written, a NotEnoughBytesError will be returned.

func (*Verifier) ReadFrom

func (v *Verifier) ReadFrom(r io.Reader) (int64, error)

ReaderFrom reads and verifies data from r until io.EOF or error. It does not close Verifier automatically, so it is possible to combine it with other writing methods and/or to call it multiple times. To verify if the data is shorter than expected, Close should be called after writing all the data.

func (*Verifier) ReadFromFile

func (v *Verifier) ReadFromFile(path string) (int64, error)

ReadFromFile verifies the contents of the file specified by path. It does not close Verifier automatically, so it is possible to combine it with other writing methods and/or to call it multiple times. To verify if the data is shorter than expected, Close should be called after writing all the data.

func (*Verifier) Write

func (v *Verifier) Write(p []byte) (int, error)

Write writes the byte sequence to be verified to Verifier and returns the number of bytes written and the error. This implements the Writer interface in the package io. It returns an UnexpectedBytesError if incorrect data is written, and a TrailingExtraBytesError if the data is longer than expected. To verify if the data is shorter than expected, Close should be called after writing all the data.

func (*Verifier) WriteByte

func (v *Verifier) WriteByte(c byte) error

WriteByte verifies a single byte c. This implements the ByteWriter interface in the package io.

func (*Verifier) WriteString

func (v *Verifier) WriteString(s string) (int, error)

WriteString verifies the contents of the string s. This implements the StringWriter interface in the package io.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL