package keys import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" cmn "github.com/tendermint/tmlibs/common" ) func TestLengthCalc(t *testing.T) { assert := assert.New(t) cases := []struct { bytes, words int flexible bool }{ {1, 1, false}, {2, 2, false}, // bytes pairs with same word count {3, 3, true}, {4, 3, true}, {5, 4, false}, // bytes pairs with same word count {10, 8, true}, {11, 8, true}, {12, 9, false}, {13, 10, false}, {20, 15, false}, // bytes pairs with same word count {21, 16, true}, {32, 24, true}, } for _, tc := range cases { wl := wordlenFromBytes(tc.bytes) assert.Equal(tc.words, wl, "%d", tc.bytes) bl, flex := bytelenFromWords(tc.words) assert.Equal(tc.flexible, flex, "%d", tc.words) if !flex { assert.Equal(tc.bytes, bl, "%d", tc.words) } else { // check if it is either tc.bytes or tc.bytes +1 choices := []int{tc.bytes, tc.bytes + 1} assert.Contains(choices, bl, "%d", tc.words) } } } func TestEncodeDecode(t *testing.T) { assert, require := assert.New(t), require.New(t) codec, err := LoadCodec("english") require.Nil(err, "%+v", err) cases := [][]byte{ {7, 8, 9}, // TODO: 3 words -> 3 or 4 bytes {12, 54, 99, 11}, // TODO: 3 words -> 3 or 4 bytes {0, 54, 99, 11}, // TODO: 3 words -> 3 or 4 bytes, detect leading 0 {1, 2, 3, 4, 5}, // normal {0, 0, 0, 0, 122, 23, 82, 195}, // leading 0s (8 chars, unclear) {0, 0, 0, 0, 5, 22, 123, 55, 22}, // leading 0s (9 chars, clear) {22, 44, 55, 1, 13, 0, 0, 0, 0}, // trailing 0s (9 chars, clear) {0, 5, 253, 2, 0}, // leading and trailing zeros {255, 196, 172, 234, 192, 255}, // big numbers {255, 196, 172, 1, 234, 192, 255}, // big numbers, two length choices // others? } for i, tc := range cases { w, err := codec.BytesToWords(tc) if assert.Nil(err, "%d: %v", i, err) { b, err := codec.WordsToBytes(w) if assert.Nil(err, "%d: %v", i, err) { assert.Equal(len(tc), len(b)) assert.Equal(tc, b) } } } } func TestCheckInvalidLists(t *testing.T) { assert := assert.New(t) trivial := []string{"abc", "def"} short := make([]string, 1234) long := make([]string, BankSize+1) right := make([]string, BankSize) dups := make([]string, BankSize) for _, list := range [][]string{short, long, right, dups} { for i := range list { list[i] = cmn.RandStr(8) } } // create one single duplicate dups[192] = dups[782] cases := []struct { words []string loadable bool valid bool }{ {trivial, false, false}, {short, false, false}, {long, false, false}, {dups, true, false}, // we only check dups on first use... {right, true, true}, } for i, tc := range cases { codec, err := NewCodec(tc.words) if !tc.loadable { assert.NotNil(err, "%d", i) } else if assert.Nil(err, "%d: %+v", i, err) { data := cmn.RandBytes(32) w, err := codec.BytesToWords(data) if tc.valid { assert.Nil(err, "%d: %+v", i, err) b, err := codec.WordsToBytes(w) assert.Nil(err, "%d: %+v", i, err) assert.Equal(data, b) } else { assert.NotNil(err, "%d", i) } } } } func getRandWord(c *WordCodec) string { idx := cmn.RandInt() % BankSize return c.words[idx] } func getDiffWord(c *WordCodec, not string) string { w := getRandWord(c) if w == not { w = getRandWord(c) } return w } func TestCheckTypoDetection(t *testing.T) { assert, require := assert.New(t), require.New(t) banks := []string{"english", "spanish", "japanese", "chinese_simplified"} for _, bank := range banks { codec, err := LoadCodec(bank) require.Nil(err, "%s: %+v", bank, err) for i := 0; i < 1000; i++ { numBytes := cmn.RandInt()%60 + 1 data := cmn.RandBytes(numBytes) words, err := codec.BytesToWords(data) assert.Nil(err, "%s: %+v", bank, err) good, err := codec.WordsToBytes(words) assert.Nil(err, "%s: %+v", bank, err) assert.Equal(data, good, bank) // now try some tweaks... cut := words[1:] _, err = codec.WordsToBytes(cut) assert.NotNil(err, "%s: %s", bank, words) // swap a word within the bank, should fails words[3] = getDiffWord(codec, words[3]) _, err = codec.WordsToBytes(words) assert.NotNil(err, "%s: %s", bank, words) // put a random word here, must fail words[3] = cmn.RandStr(10) _, err = codec.WordsToBytes(words) assert.NotNil(err, "%s: %s", bank, words) } } }