package mnemonic_test import ( "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/require" "sneak.berlin/go/keyfunc/internal/mnemonic" ) // Two more mnemonics that pass the checksum, so a test can tell which // source an answer came from. const ( fromCommandVariable = "legal winner thank year wave sausage worth " + "useful legal winner thank yellow" fromVariable = "letter advice cage absurd amount doctor acoustic " + "avoid letter advice cage above" ) // example returns the mnemonic every BIP-39 document uses to show its // test vectors: eleven abandons and about. func example() string { return strings.Repeat("abandon ", 11) + "about" } // broken returns a mnemonic whose last word does not match the rest. func broken() string { return strings.TrimSpace(strings.Repeat("abandon ", 12)) } // prints builds a shell command that writes the given words padded // with spaces, so the test also shows that the padding is dropped. func prints(words string) string { return "printf ' %s \\n' '" + words + "'" } func TestTheCommandOnTheCommandLineWins(t *testing.T) { t.Setenv(mnemonic.CommandVariable, prints(fromCommandVariable)) t.Setenv(mnemonic.Variable, fromVariable) words, err := mnemonic.Read(t.Context(), prints(example())) require.NoError(t, err) require.Equal(t, example(), words) } func TestTheCommandInTheEnvironmentComesNext(t *testing.T) { t.Setenv(mnemonic.CommandVariable, prints(fromCommandVariable)) t.Setenv(mnemonic.Variable, fromVariable) words, err := mnemonic.Read(t.Context(), "") require.NoError(t, err) require.Equal(t, fromCommandVariable, words) } func TestTheMnemonicInTheEnvironmentComesLast(t *testing.T) { t.Setenv(mnemonic.CommandVariable, "") t.Setenv(mnemonic.Variable, " "+fromVariable+" ") words, err := mnemonic.Read(t.Context(), "") require.NoError(t, err) require.Equal(t, fromVariable, words) } func TestTheMnemonicIsNotHandedToTheCommand(t *testing.T) { const marker = "KEYFUNC_TEST_MARKER" t.Setenv(mnemonic.CommandVariable, prints(fromCommandVariable)) t.Setenv(mnemonic.Variable, fromVariable) t.Setenv(marker, "reaches the command") path := filepath.Join(t.TempDir(), "environment") words, err := mnemonic.Read( t.Context(), "env > '"+path+"'; "+prints(example()), ) require.NoError(t, err) require.Equal(t, example(), words) //nolint:gosec // the path is a temporary file of the test's own content, err := os.ReadFile(path) require.NoError(t, err) environment := string(content) require.NotContains(t, environment, mnemonic.Variable+"=") require.NotContains(t, environment, mnemonic.CommandVariable+"=") require.Contains(t, environment, marker+"=") } func TestAFailingCommandSaysWhatWentWrong(t *testing.T) { t.Setenv(mnemonic.CommandVariable, "") t.Setenv(mnemonic.Variable, "") _, err := mnemonic.Read(t.Context(), "echo nothing here >&2; exit 3") require.Error(t, err) require.Contains(t, err.Error(), "nothing here") } func TestABadChecksumIsRefused(t *testing.T) { t.Setenv(mnemonic.CommandVariable, "") t.Setenv(mnemonic.Variable, broken()) _, err := mnemonic.Read(t.Context(), "") require.ErrorIs(t, err, mnemonic.ErrChecksum) } func TestNothingToReadAndNobodyToAsk(t *testing.T) { t.Setenv(mnemonic.CommandVariable, "") t.Setenv(mnemonic.Variable, "") _, err := mnemonic.Read(t.Context(), "") require.ErrorIs(t, err, mnemonic.ErrMissing) }