summaryrefslogtreecommitdiffstats
path: root/internal/entropy/entropy_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/entropy/entropy_test.go')
-rw-r--r--internal/entropy/entropy_test.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/internal/entropy/entropy_test.go b/internal/entropy/entropy_test.go
new file mode 100644
index 0000000..4ee1a6b
--- /dev/null
+++ b/internal/entropy/entropy_test.go
@@ -0,0 +1,93 @@
+package entropy
+
+import (
+ "bytes"
+ "io"
+ "strings"
+ "testing"
+)
+
+func TestHybridReaderMixesBaseAndExternal(t *testing.T) {
+ base := strings.NewReader(strings.Repeat("a", 4096))
+ external := strings.NewReader(strings.Repeat("b", 4096))
+ reader, err := NewHybridReader(base, external, HybridOptions{})
+ if err != nil {
+ t.Fatalf("NewHybridReader returned error: %v", err)
+ }
+
+ out := make([]byte, 128)
+ if _, err := io.ReadFull(reader, out); err != nil {
+ t.Fatalf("Read returned error: %v", err)
+ }
+
+ if bytes.Equal(out, bytes.Repeat([]byte("a"), len(out))) {
+ t.Fatalf("hybrid output matched raw base reader")
+ }
+ if reader.Degraded() {
+ t.Fatalf("hybrid reader degraded with enough external bytes")
+ }
+}
+
+func TestHybridReaderDegradesToBaseWhenExternalFails(t *testing.T) {
+ base := strings.NewReader(strings.Repeat("x", 4096))
+ external := strings.NewReader("")
+ reader, err := NewHybridReader(base, external, HybridOptions{})
+ if err != nil {
+ t.Fatalf("NewHybridReader returned error: %v", err)
+ }
+
+ out := make([]byte, 32)
+ if _, err := io.ReadFull(reader, out); err != nil {
+ t.Fatalf("Read returned error: %v", err)
+ }
+
+ if !bytes.Equal(out, bytes.Repeat([]byte("x"), len(out))) {
+ t.Fatalf("degraded output should come from base reader")
+ }
+ if !reader.Degraded() {
+ t.Fatalf("hybrid reader should report degraded state")
+ }
+ if reader.DegradeError() == nil {
+ t.Fatalf("hybrid reader should keep the external source error")
+ }
+}
+
+func TestHybridReaderBuffersSmallReads(t *testing.T) {
+ base := strings.NewReader(strings.Repeat("a", blockSize))
+ external := strings.NewReader(strings.Repeat("b", blockSize))
+ reader, err := NewHybridReader(base, external, HybridOptions{})
+ if err != nil {
+ t.Fatalf("NewHybridReader returned error: %v", err)
+ }
+
+ var one [1]byte
+ for i := 0; i < blockSize; i++ {
+ if _, err := io.ReadFull(reader, one[:]); err != nil {
+ t.Fatalf("Read %d returned error: %v", i, err)
+ }
+ }
+
+ if reader.Degraded() {
+ t.Fatalf("small reads should reuse one mixed block before reading external again")
+ }
+}
+
+func TestHybridReaderRequiresExternalWhenConfigured(t *testing.T) {
+ base := strings.NewReader(strings.Repeat("x", 4096))
+ external := strings.NewReader("")
+ reader, err := NewHybridReader(base, external, HybridOptions{RequireExternal: true})
+ if err != nil {
+ t.Fatalf("NewHybridReader returned error: %v", err)
+ }
+
+ out := make([]byte, 1)
+ if _, err := io.ReadFull(reader, out); err == nil {
+ t.Fatalf("Read returned nil error with required external entropy")
+ }
+}
+
+func TestNewHybridReaderRejectsMissingExternalSource(t *testing.T) {
+ if _, err := NewHybridReader(strings.NewReader("base"), nil, HybridOptions{}); err != ErrExternalEntropyRequired {
+ t.Fatalf("NewHybridReader error = %v, want %v", err, ErrExternalEntropyRequired)
+ }
+}