stego / permute / permute_test.go

package permute

import (
	"bytes"
	"fmt"
	"math/big"
	"sort"
	"testing"
)

func makeRange(length int) sort.Interface {
	r := make([]int, length)
	for i := range r {
		r[i] = i
	}
	return sort.IntSlice(r)
}

func intRoundTrip(t *testing.T, n *big.Int) {
	size := MinSizeForBits(n.BitLen())
	seq := makeRange(size)
	p := NewHider(seq)

	start := big.NewInt(0)
	start.Set(n)

	err := p.encodeInt(start)
	if err != nil {
		t.Errorf("%v", err)
	}
	state := fmt.Sprint(seq)
	end := p.decodeInt()
	if n.Cmp(end) != 0 {
		t.Errorf("started with %d, got %d\nencoded state: %s", n, end, state)
	}
	if !sort.IsSorted(seq) {
		t.Errorf("sequence didn't end up sorted: %v", seq)
	}
}

func TestIntRoundTrip(t *testing.T) {
	intRoundTrip(t, big.NewInt(0))
	intRoundTrip(t, big.NewInt(1))
	intRoundTrip(t, big.NewInt(12))
	intRoundTrip(t, big.NewInt(1234567891))
	intRoundTrip(t, big.NewInt(9223372036854775783))
}

func factorial(n int) *big.Int {
	fact := big.NewInt(1)
	num := big.NewInt(0)
	for i := 2; i <= n; i++ {
		num.SetInt64(int64(i))
		fact.Mul(fact, num)
	}
	return fact
}

func TestIntOverflow(t *testing.T) {
	const size = 13
	seq := makeRange(size)
	p := NewHider(seq)
	n := big.NewInt(0)

	// Negative is bad
	n.SetInt64(-1)
	err := p.encodeInt(n)
	if err == nil {
		t.Errorf("Expected error on negative integer input.")
	}

	// The enumeration of all permutations starts at 0, so the last valid one is n!-1
	n.Set(factorial(size))
	err = p.encodeInt(n)
	if err == nil {
		t.Errorf("Expected encoding error for size %d and integer %d", seq.Len(), n)
	}

	// This should be the last valid permutation.
	n.Set(factorial(size))
	n.Sub(n, big.NewInt(1))
	err = p.encodeInt(n)
	if err != nil {
		t.Errorf("Spurious error when that totally should have fit.\n%s", err)
	}
}

func permuteRoundTrip(t *testing.T, st string) {
	in := []byte(st)
	size := MinSizeForBytes(len(in))
	seq := makeRange(size)
	p := NewHider(seq)

	err := p.Embed(in)
	if err != nil {
		t.Errorf("Error: %v", err)
	}
	end, err := p.Reveal()
	if err != nil {
		t.Errorf("Error: %v", err)
	}

	if !bytes.HasPrefix(end, in) {
		t.Errorf("started with %q, got %q", in, end)
	}
	if !sort.IsSorted(seq) {
		t.Errorf("sequence didn't end up sorted: %v", seq)
	}
}

func TestPermuteRoundTrip(t *testing.T) {
	permuteRoundTrip(t, "")
	permuteRoundTrip(t, "short")
	permuteRoundTrip(t, "this one is considered a bit longer than the last")
}

func TestDups(t *testing.T) {
	p := NewHider(sort.IntSlice([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 3}))
	err := p.Embed([]byte{'a'})
	if err == nil {
		t.Errorf("Duplicates in input string should fail.")
	}
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.