Add tests to the wallet.py module.
[electrum-nvc.git] / lib / tests / test_wallet.py
1 import shutil
2 import tempfile
3 import sys
4 import unittest
5 import os
6
7 from StringIO import StringIO
8 from lib.wallet import WalletStorage, NewWallet
9
10
11 class FakeConfig(object):
12     """A stub config file to be used in tests"""
13     def __init__(self, path):
14         self.path = path
15         self.store = {}
16
17     def set(self, key, value):
18         self.store[key] = value
19
20     def get(self, key, default=None):
21         return self.store.get(key, default)
22
23
24 class FakeSynchronizer(object):
25
26     def __init__(self):
27         self.store = []
28
29     def add(self, address):
30         self.store.append(address)
31
32
33 class WalletTestCase(unittest.TestCase):
34
35     def setUp(self):
36         super(WalletTestCase, self).setUp()
37         self.user_dir = tempfile.mkdtemp()
38
39         self.fake_config = FakeConfig(self.user_dir)
40
41         self._saved_stdout = sys.stdout
42         self._stdout_buffer = StringIO()
43         sys.stdout = self._stdout_buffer
44
45     def tearDown(self):
46         super(WalletTestCase, self).tearDown()
47         shutil.rmtree(self.user_dir)
48         # Restore the "real" stdout
49         sys.stdout = self._saved_stdout
50
51
52 class TestWalletStorage(WalletTestCase):
53
54     def test_init_wallet_default_path(self):
55         storage = WalletStorage(self.fake_config)
56         expected = os.path.join(self.user_dir, "wallets", "default_wallet")
57         self.assertEqual(expected, storage.path)
58
59     def test_init_wallet_explicit_path(self):
60         path = os.path.join(self.user_dir, "somewallet")
61         self.fake_config.set("wallet_path", path)
62
63         storage = WalletStorage(self.fake_config)
64         self.assertEqual(path, storage.path)
65
66     def test_init_wallet_default_wallet_path(self):
67         path = os.path.join(self.user_dir, "somewallet")
68         self.fake_config.set("default_wallet_path", path)
69
70         storage = WalletStorage(self.fake_config)
71         self.assertEqual(path, storage.path)
72
73     def test_read_dictionnary_from_file(self):
74         path = os.path.join(self.user_dir, "somewallet")
75         self.fake_config.set("wallet_path", path)
76
77         some_dict = {"a":"b", "c":"d"}
78         contents = repr(some_dict)
79         with open(path, "w") as f:
80             contents = f.write(contents)
81
82         storage = WalletStorage(self.fake_config)
83         self.assertEqual("b", storage.get("a"))
84         self.assertEqual("d", storage.get("c"))
85
86     def test_write_dictionnary_to_file(self):
87         path = os.path.join(self.user_dir, "somewallet")
88         self.fake_config.set("wallet_path", path)
89
90         storage = WalletStorage(self.fake_config)
91
92         some_dict = {"a":"b", "c":"d"}
93         storage.data = some_dict
94
95         storage.write()
96
97         contents = ""
98         with open(path, "r") as f:
99             contents = f.read()
100         self.assertEqual(repr(some_dict), contents)
101
102
103 class TestNewWallet(WalletTestCase):
104
105     seed_text = "The seed will sprout and grow up tall."
106     password = "secret"
107
108     master_xpub = "xpub661MyMwAqRbcGEop5Rnp68oX1ikeFNVMtx1utwXZGRKMmeXVxwBM5UzkwU9nGB1EofZekLDRfi1w5F9P7Vac3PEuWdWHr2gHLW8vp5YyKJ1"
109     master_xpriv = "xprv9s21ZrQH143K3kjLyQFoizrnTgv9qumWXj6K6Z7wi5nNtrCMRPs6XggH6Bbgz9CUgPJnZnV74yUdRSr8qWVELr9QQTgU5aNL33ViMyD9nhs"
110
111     first_account_name = "account1"
112     first_account_first_address = "1Jv9pLCJ4Sqr7aDYLGX5QhET4ps5qRcB9V"
113     first_account_second_address = "14n9EsZsgTTc4eC4TxeP1ccP8bXgwxPMmL"
114
115     import_private_key = "L52XzL2cMkHxqxBXRyEpnPQZGUs3uKiL3R11XbAdHigRzDozKZeW"
116     import_key_address = "15mKKb2eos1hWa6tisdPwwDC1a5J1y9nma"
117
118     def setUp(self):
119         super(TestNewWallet, self).setUp()
120         self.storage = WalletStorage(self.fake_config)
121         self.wallet = NewWallet(self.storage)
122         # This cannot be constructed by electrum at random, it should be safe
123         # from eventual collisions.
124         self.wallet.add_seed(self.seed_text, self.password)
125
126     def test_wallet_with_seed_is_not_watching_only(self):
127         self.assertFalse(self.wallet.is_watching_only())
128
129     def test_wallet_without_seed_is_watching_only(self):
130         # We need a new storage , since the default storage was already seeded
131         # in setUp()
132         new_dir = tempfile.mkdtemp()
133         config = FakeConfig(new_dir)
134         wallet = NewWallet(config)
135         self.assertTrue(wallet.is_watching_only())
136         shutil.rmtree(new_dir)  # Don't leave useless stuff in /tmp
137
138     def test_new_wallet_is_deterministic(self):
139         self.assertTrue(self.wallet.is_deterministic())
140
141     def test_get_seed_returns_correct_seed(self):
142         self.assertEqual(self.wallet.get_seed(self.password), self.seed_text)
143         self.assertEqual(0, len(self.wallet.addresses()))
144
145     def test_get_master_keys(self):
146         self.assertEqual(self.master_xpub, self.wallet.get_master_public_key())
147         self.assertEqual(self.master_xpriv, self.wallet.get_master_private_key("m/", self.password))
148
149     def test_add_account(self):
150         self.wallet.create_account(self.first_account_name, self.password)
151         self.assertEqual(1, len(self.wallet.addresses()))
152         self.assertIn(self.first_account_first_address,
153                          self.wallet.addresses())
154
155     def test_add_account_add_address(self):
156         self.wallet.create_account(self.first_account_name, self.password)
157         self.wallet.synchronizer = FakeSynchronizer()
158
159         self.wallet.create_new_address()
160         self.assertEqual(2, len(self.wallet.addresses()))
161         self.assertIn(self.first_account_first_address,
162                          self.wallet.addresses())
163         self.assertIn(self.first_account_second_address,
164                       self.wallet.addresses())
165
166     def test_key_import(self):
167         # Wallets have no imported keys by default.
168         self.wallet.create_account(self.first_account_name, self.password)
169         self.assertFalse(self.wallet.has_imported_keys())
170
171         # Importing a key works.
172         self.wallet.import_key(self.import_private_key, "")
173         self.assertEqual(2, len(self.wallet.addresses()))
174         self.assertIn(self.import_key_address, self.wallet.addresses())
175
176         self.assertTrue(self.wallet.has_imported_keys())
177
178         # Deleting the key works.
179         self.wallet.delete_imported_key(self.import_key_address)
180         self.assertFalse(self.wallet.has_imported_keys())
181         self.assertEqual(1, len(self.wallet.addresses()))
182         self.assertNotIn(self.import_key_address, self.wallet.addresses())
183
184     def test_update_password(self):
185         new_password = "secret2"
186         self.wallet.update_password(self.password, new_password)
187         self.wallet.create_account(self.first_account_name, new_password)
188         self.assertEqual(1, len(self.wallet.addresses()))