shad-go/otp/cipher_test.go

161 lines
3.2 KiB
Go
Raw Normal View History

2020-02-28 17:26:29 +00:00
package otp
import (
"bytes"
2023-02-22 13:14:39 +00:00
"crypto/rand"
2020-02-28 17:26:29 +00:00
"io"
"testing"
"testing/iotest"
"github.com/stretchr/testify/require"
)
type zeroSometimesReader struct {
io.Reader
i int
}
func (r *zeroSometimesReader) Read(p []byte) (n int, err error) {
r.i++
if r.i&1 == 0 {
return 0, nil
}
return r.Reader.Read(p)
}
const testSize = 1234
var (
plaintext = make([]byte, testSize)
randomBytes = make([]byte, testSize)
ciphertext = make([]byte, testSize)
plaintextBackup = make([]byte, testSize)
)
func init() {
2023-02-22 13:14:39 +00:00
_, _ = rand.Read(plaintext)
_, _ = rand.Read(randomBytes)
2020-02-28 17:26:29 +00:00
copy(plaintextBackup, plaintext)
for i := range plaintext {
ciphertext[i] = plaintext[i] ^ randomBytes[i]
}
}
func TestReader(t *testing.T) {
for _, testCase := range []struct {
name string
r io.Reader
prng io.Reader
err error
result []byte
2023-03-19 16:16:58 +00:00
limit bool
2020-02-28 17:26:29 +00:00
}{
{
name: "simple",
r: bytes.NewBuffer(plaintext),
prng: bytes.NewBuffer(randomBytes),
result: ciphertext,
},
{
name: "eof",
r: iotest.DataErrReader(bytes.NewBuffer(plaintext)),
prng: bytes.NewBuffer(randomBytes),
result: ciphertext,
},
{
name: "halfreader",
r: iotest.HalfReader(bytes.NewBuffer(plaintext)),
prng: bytes.NewBuffer(randomBytes),
result: ciphertext,
},
{
name: "zerosometimes",
r: &zeroSometimesReader{Reader: iotest.HalfReader(iotest.HalfReader(bytes.NewBuffer(plaintext)))},
prng: bytes.NewBuffer(randomBytes),
result: ciphertext,
},
{
name: "timeout",
r: iotest.TimeoutReader(bytes.NewBuffer(plaintext)),
prng: bytes.NewBuffer(randomBytes),
2023-03-19 16:16:58 +00:00
result: ciphertext,
2020-02-28 17:26:29 +00:00
err: iotest.ErrTimeout,
2023-03-19 16:16:58 +00:00
limit: true,
2020-02-28 17:26:29 +00:00
},
} {
t.Run(testCase.name, func(t *testing.T) {
r := NewReader(testCase.r, testCase.prng)
buf, err := io.ReadAll(r)
require.ErrorIs(t, err, testCase.err)
2023-03-19 16:16:58 +00:00
if testCase.limit {
require.Equal(t, testCase.result[:len(buf)], buf)
} else {
require.Equal(t, testCase.result, buf)
}
2020-02-28 17:26:29 +00:00
})
}
}
func TestWriterSimple(t *testing.T) {
out := &bytes.Buffer{}
prng := bytes.NewBuffer(randomBytes)
w := NewWriter(out, prng)
n, err := w.Write(plaintext)
require.Equalf(t, plaintextBackup, plaintext, "Write must not modify the slice data, even temporarily.")
require.NoError(t, err)
require.Equal(t, len(plaintext), n)
require.Equal(t, out.Bytes(), ciphertext)
}
type errWriter struct {
buf bytes.Buffer
n int
}
func (w *errWriter) Write(p []byte) (n int, err error) {
if len(p) > w.n {
p = p[:w.n]
}
n = len(p)
2020-03-05 20:57:41 +00:00
w.n -= n
2020-02-28 17:26:29 +00:00
if w.n == 0 {
err = iotest.ErrTimeout
}
w.buf.Write(p)
return
}
func TestWriterError(t *testing.T) {
out := &errWriter{n: 512}
prng := bytes.NewBuffer(randomBytes)
w := NewWriter(out, prng)
n, err := w.Write(plaintext)
require.Equalf(t, plaintextBackup, plaintext, "Write must not modify the slice data, even temporarily.")
require.ErrorIs(t, err, iotest.ErrTimeout)
2020-02-28 17:26:29 +00:00
require.Equal(t, 512, n)
require.Equal(t, out.buf.Bytes(), ciphertext[:512])
}
type panicReader struct{}
func (panicReader) Read([]byte) (int, error) {
panic("read called")
}
func TestNewReaderNotReading(t *testing.T) {
_ = NewReader(panicReader{}, panicReader{})
}