bitcoin 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/.rvmrc +1 -1
  2. data/Gemfile.lock +56 -4
  3. data/Guardfile +38 -0
  4. data/README.markdown +21 -2
  5. data/bin/rbcoin +8 -1
  6. data/bitcoin.gemspec +17 -5
  7. data/config/cucumber.yml +3 -3
  8. data/config/darcs.boring +121 -0
  9. data/doc/DEFINITION_OF_DONE.markdown +12 -0
  10. data/doc/HISTORY.markdown +19 -0
  11. data/{LICENCE.markdown → doc/LICENCE.markdown} +1 -1
  12. data/doc/TODO.markdown +31 -0
  13. data/doc/UBIQUITOUS_LANGUAGE.markdown +15 -0
  14. data/features/descriptions/command_help.feature +31 -0
  15. data/features/descriptions/satoshi_wallet/add_address.feature +49 -0
  16. data/features/descriptions/satoshi_wallet/show_addresses.feature +18 -0
  17. data/features/descriptions/satoshi_wallet/show_version.feature +17 -0
  18. data/features/descriptions/satoshi_wallet/subcommand_help.feature +20 -0
  19. data/features/fixtures/ABOUT_FIXTURES.markdown +6 -0
  20. data/features/fixtures/addressbook_wallet.dat +0 -0
  21. data/features/fixtures/new_wallet.dat +0 -0
  22. data/features/step_definitions/command_steps.rb +3 -0
  23. data/features/step_definitions/wallet_steps.rb +11 -0
  24. data/features/support/env.rb +8 -1
  25. data/lib/bitcoin/cli.rb +35 -0
  26. data/lib/bitcoin/commands.rb +3 -0
  27. data/lib/bitcoin/commands/help_command.rb +32 -0
  28. data/lib/bitcoin/commands/satoshi_wallet.rb +11 -0
  29. data/lib/bitcoin/commands/satoshi_wallet/add_address_command.rb +61 -0
  30. data/lib/bitcoin/commands/satoshi_wallet/show_addresses_command.rb +16 -0
  31. data/lib/bitcoin/commands/satoshi_wallet/show_version_command.rb +15 -0
  32. data/lib/bitcoin/commands/satoshi_wallet_command.rb +37 -0
  33. data/lib/bitcoin/commands/satoshi_wallet_command_environment.rb +28 -0
  34. data/lib/bitcoin/console/capturing_stream_bundle.rb +42 -0
  35. data/lib/bitcoin/console/stream_bundle.rb +21 -0
  36. data/lib/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository.rb +155 -0
  37. data/lib/bitcoin/data_access/satoshi/satoshi_version.rb +58 -0
  38. data/lib/bitcoin/data_access/satoshi/satoshi_wallet.rb +39 -0
  39. data/lib/bitcoin/domain/address_book.rb +19 -0
  40. data/lib/bitcoin/domain/bitcoin_address.rb +33 -0
  41. data/lib/bitcoin/filesystem/empty_temp_dir.rb +74 -0
  42. data/lib/bitcoin/rspec/argument_matchers.rb +1 -0
  43. data/lib/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher.rb +23 -0
  44. data/lib/bitcoin/rspec/directory_helpers.rb +22 -0
  45. data/lib/bitcoin/version.rb +1 -1
  46. data/spec/bitcoin/cli_spec.rb +128 -0
  47. data/spec/bitcoin/commands/help_command_spec.rb +53 -0
  48. data/spec/bitcoin/commands/satoshi_wallet/add_address_command_spec.rb +149 -0
  49. data/spec/bitcoin/commands/satoshi_wallet/show_addresses_command_spec.rb +26 -0
  50. data/spec/bitcoin/commands/satoshi_wallet/show_version_command_spec.rb +26 -0
  51. data/spec/bitcoin/commands/satoshi_wallet_command_environment_spec.rb +76 -0
  52. data/spec/bitcoin/commands/satoshi_wallet_command_spec.rb +73 -0
  53. data/spec/bitcoin/console/_contracts/stream_bundle_contract.rb +29 -0
  54. data/spec/bitcoin/console/capturing_stream_bundle_spec.rb +74 -0
  55. data/spec/bitcoin/console/stream_bundle_spec.rb +13 -0
  56. data/spec/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository_spec.rb +78 -0
  57. data/spec/bitcoin/data_access/satoshi/satoshi_version_spec.rb +112 -0
  58. data/spec/bitcoin/data_access/satoshi/satoshi_wallet_spec.rb +102 -0
  59. data/spec/bitcoin/domain/address_book_spec.rb +63 -0
  60. data/spec/bitcoin/domain/bitcoin_address_spec.rb +52 -0
  61. data/spec/bitcoin/filesystem/empty_temp_dir_spec.rb +170 -0
  62. data/spec/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher_spec.rb +36 -0
  63. data/spec/spec_helper.rb +29 -1
  64. metadata +221 -18
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ require 'bitcoin/commands/satoshi_wallet_command'
4
+
5
+ # Dependencies only used in the spec
6
+ require 'bitcoin/domain/address_book'
7
+ require 'bitcoin/console/capturing_stream_bundle'
8
+ require 'bitcoin/commands/satoshi_wallet_command_environment'
9
+
10
+ module Bitcoin
11
+ module Commands
12
+ describe SatoshiWalletCommand do
13
+ let(:stream_bundle) { Console::CapturingStreamBundle.test_bundle }
14
+ let(:command_environment) { mock(SatoshiWalletCommandEnvironment, run_command: nil) }
15
+
16
+ subject { SatoshiWalletCommand.new(stream_bundle, command_environment) }
17
+
18
+ describe "#run" do
19
+ shared_examples_for "SatoshiWalletCommand#run" do |options|
20
+ let(:command) { mock(options[:command_class]) }
21
+
22
+ before(:each) do
23
+ options[:command_class].stub(new: command)
24
+ end
25
+
26
+ it "makes a command" do
27
+ options[:command_class].should_receive(:new).with(stream_bundle)
28
+ subject.run([ options[:command_name], "wallet.dat", "foo", "bar" ])
29
+ end
30
+
31
+ it "runs the command" do
32
+ command_environment.should_receive(:run_command).with(command, %w[ wallet.dat foo bar ])
33
+ subject.run([ options[:command_name], "wallet.dat", "foo", "bar" ])
34
+ end
35
+ end
36
+
37
+ context "show-version" do
38
+ it_behaves_like "SatoshiWalletCommand#run",
39
+ command_name: "show-version",
40
+ command_class: Commands::SatoshiWallet::ShowVersionCommand
41
+ end
42
+
43
+ context "show-addresses" do
44
+ it_behaves_like "SatoshiWalletCommand#run",
45
+ command_name: "show-addresses",
46
+ command_class: Commands::SatoshiWallet::ShowAddressesCommand
47
+ end
48
+
49
+ context "add-address" do
50
+ it_behaves_like "SatoshiWalletCommand#run",
51
+ command_name: "add-address",
52
+ command_class: Commands::SatoshiWallet::AddAddressCommand
53
+ end
54
+
55
+ context "<unknown subcommand>" do
56
+ it "prints an error" do
57
+ expect {
58
+ subject.run(%w[ unknown-subcommand wallet.dat foo bar ])
59
+ }.to raise_error
60
+
61
+ stream_bundle.captured_error.should eq %'Unknown satoshi-wallet subcommand: "unknown-subcommand"\n'
62
+ end
63
+
64
+ it "raises an error" do
65
+ expect {
66
+ subject.run(%w[ unknown-subcommand wallet.dat foo bar ])
67
+ }.to raise_error(CLI::CommandError)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,29 @@
1
+ contract "StreamBundle" do
2
+ let(:input) { StringIO.new }
3
+ let(:output) { StringIO.new }
4
+ let(:error) { StringIO.new }
5
+
6
+ let(:subject) { described_class.new(input, output, error) }
7
+
8
+ describe "#puts_output" do
9
+ it "writes a line to the output" do
10
+ subject.puts_output("foo")
11
+ subject.puts_output("bar")
12
+ subject.puts_output("baz")
13
+
14
+ output.rewind
15
+ output.read.should eq "foo\nbar\nbaz\n"
16
+ end
17
+ end
18
+
19
+ describe "#puts_error" do
20
+ it "writes a line to the output" do
21
+ subject.puts_error("foo")
22
+ subject.puts_error("bar")
23
+ subject.puts_error("baz")
24
+
25
+ error.rewind
26
+ error.read.should eq "foo\nbar\nbaz\n"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ require 'bitcoin/console/capturing_stream_bundle'
4
+
5
+ require_relative '_contracts/stream_bundle_contract'
6
+
7
+ module Bitcoin
8
+ module Console
9
+ describe CapturingStreamBundle do
10
+ it_satisfies_contract "StreamBundle"
11
+
12
+ let(:input) { StringIO.new }
13
+ let(:output) { StringIO.new }
14
+ let(:error) { StringIO.new }
15
+
16
+ let(:subject) { CapturingStreamBundle.new(input, output, error) }
17
+
18
+ describe ".test_bundle" do
19
+ it "creates a CapturingStreamBundle with three StringIO streams", because: "we only care about captured output" do
20
+ # Really should be a separate factory object, but not for the sake of one method
21
+ CapturingStreamBundle.should_receive(:new).with(
22
+ an_instance_of(StringIO), an_instance_of(StringIO), an_instance_of(StringIO)
23
+ ).and_return(:stream_bundle)
24
+ CapturingStreamBundle.test_bundle.should eq :stream_bundle
25
+ end
26
+ end
27
+
28
+ # The output and error streams are effectively the same with different names,
29
+ # but the duplication is only textual and I don't see a neat way to remove it yet
30
+
31
+ describe "#captured_output" do
32
+ before(:each) do
33
+ subject.puts_output("foo")
34
+ subject.puts_output("bar")
35
+ subject.puts_output("baz")
36
+ end
37
+
38
+ its(:captured_output) { should eq "foo\nbar\nbaz\n" }
39
+
40
+ it "doesn't manipulate the output stream" do
41
+ output.stub(:rewind).and_raise(RuntimeError.new)
42
+ expect { subject.captured_output }.to_not raise_error
43
+ end
44
+
45
+ it "accumulates output across reads" do
46
+ subject.captured_output
47
+ subject.puts_output("quux")
48
+ subject.captured_output.should eq "foo\nbar\nbaz\nquux\n"
49
+ end
50
+ end
51
+
52
+ describe "#captured_error" do
53
+ before(:each) do
54
+ subject.puts_error("foo")
55
+ subject.puts_error("bar")
56
+ subject.puts_error("baz")
57
+ end
58
+
59
+ its(:captured_error) { should eq "foo\nbar\nbaz\n" }
60
+
61
+ it "doesn't manipulate the error stream" do
62
+ error.stub(:rewind).and_raise(RuntimeError.new)
63
+ expect { subject.captured_error }.to_not raise_error
64
+ end
65
+
66
+ it "accumulates output across reads" do
67
+ subject.captured_error
68
+ subject.puts_error("quux")
69
+ subject.captured_error.should eq "foo\nbar\nbaz\nquux\n"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ require 'bitcoin/console/stream_bundle'
4
+
5
+ require_relative '_contracts/stream_bundle_contract'
6
+
7
+ module Bitcoin
8
+ module Console
9
+ describe StreamBundle do
10
+ it_satisfies_contract "StreamBundle"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ require 'bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository'
4
+ require 'bitcoin/rspec/directory_helpers'
5
+
6
+ module Bitcoin
7
+ module DataAccess
8
+ module Satoshi
9
+ describe BDBSatoshiWalletRepository, adapter: :slow do
10
+ include Bitcoin::RSpec::DirectoryHelpers
11
+
12
+ TEMP_DB_DIR = File.join(PROJECT_ROOT, "tmp", "db").freeze
13
+ ensure_empty_test_dir(TEMP_DB_DIR)
14
+
15
+ # Temporary means to get a copy of the fixture file
16
+ before(:each) do
17
+ FileUtils.cp(File.join(PROJECT_ROOT, "features", "fixtures", wallet_fixture_filename), TEMP_DB_DIR)
18
+ end
19
+
20
+ def wallet_filename
21
+ File.join(PROJECT_ROOT, "tmp", "db", wallet_fixture_filename)
22
+ end
23
+
24
+ let(:wallet_fixture_filename) { "addressbook_wallet.dat" }
25
+
26
+ subject { BDBSatoshiWalletRepository.new(wallet_filename, db_dirname: TEMP_DB_DIR) }
27
+
28
+ it "has a less naive write_compact_size"
29
+
30
+ describe "4-byte unsigned little endian integers stored immediately (no compact length in the value)" do
31
+ specify {
32
+ subject.get_value_immediate_uint32le("version").should eq 32400
33
+ }
34
+
35
+ specify {
36
+ expect {
37
+ subject.set_value_immediate_uint32le("version", 32500)
38
+ }.to change {
39
+ subject.get_value_immediate_uint32le("version")
40
+ }.from(32400).to(32500)
41
+ }
42
+ end
43
+
44
+ describe "string key data, string value data" do
45
+ it "lets you read all values" do
46
+ subject.get_key_and_value_data_string_utf8("name").should eq [
47
+ [ "13f2t2WKnCZh1rZbDhdUKB6fY1rZNWZVzd", "Receiving address 2" ],
48
+ [ "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz", "Bitcoin Monitor" ],
49
+ [ "16kzGRdP8LToECecna3EynghiApUM9duLw", "Receiving address 1" ],
50
+ [ "1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw", "Bitcoincharts" ]
51
+ ]
52
+ end
53
+
54
+ it "lets you read individual values" do
55
+ subject.get_value_with_key_data_string_utf8("name", "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz").should eq "Bitcoin Monitor"
56
+ end
57
+
58
+ it "lets you create" do
59
+ expect {
60
+ subject.set_value_with_key_data_string_utf8("name", "1ThisIsAMadeUpKeyKudFr63EwHqQT2njz", "New Value")
61
+ }.to change {
62
+ subject.get_value_with_key_data_string_utf8("name", "1ThisIsAMadeUpKeyKudFr63EwHqQT2njz")
63
+ }.from(nil).to("New Value")
64
+ end
65
+
66
+ it "lets you update" do
67
+ expect {
68
+ subject.set_value_with_key_data_string_utf8("name", "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz", "Really is Bitcoin Monitor")
69
+ }.to change {
70
+ subject.get_value_with_key_data_string_utf8("name", "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz")
71
+ }.from("Bitcoin Monitor").to("Really is Bitcoin Monitor")
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ require 'bitcoin/data_access/satoshi/satoshi_version'
4
+
5
+ module Bitcoin
6
+ module DataAccess
7
+ module Satoshi
8
+ describe SatoshiVersion do
9
+ describe ".from_wallet_bytes" do
10
+ it "supports the data format as extracted from the BDB database" do
11
+ SatoshiVersion.from_wallet_bytes([144, 126, 0, 0]).should eq SatoshiVersion.new(0, 3, 24)
12
+ end
13
+ end
14
+
15
+ describe ".from_wallet_int" do
16
+ it "supports the data format as extracted from the BDB database" do
17
+ SatoshiVersion.from_wallet_int(32400).should eq SatoshiVersion.new(0, 3, 24)
18
+ end
19
+ end
20
+
21
+ describe "three-part form" do
22
+ it "compares equality" do
23
+ SatoshiVersion.new(0, 3, 24).should eq SatoshiVersion.new(0, 3, 24)
24
+
25
+ SatoshiVersion.new(0, 3, 24).should_not eq SatoshiVersion.new(0, 3, 25)
26
+ SatoshiVersion.new(0, 3, 24).should_not eq SatoshiVersion.new(0, 4, 24)
27
+ SatoshiVersion.new(0, 3, 24).should_not eq SatoshiVersion.new(1, 3, 24)
28
+ end
29
+
30
+ it "has a total ordering" do
31
+ SatoshiVersion.new(0, 3, 24).should be < SatoshiVersion.new(0, 3, 25)
32
+ SatoshiVersion.new(0, 3, 24).should be > SatoshiVersion.new(0, 3, 23)
33
+
34
+ SatoshiVersion.new(0, 3, 24).should be < SatoshiVersion.new(0, 4, 23)
35
+ SatoshiVersion.new(0, 3, 24).should be > SatoshiVersion.new(0, 2, 25)
36
+
37
+ SatoshiVersion.new(1, 3, 24).should be < SatoshiVersion.new(2, 2, 23)
38
+ SatoshiVersion.new(1, 3, 24).should be > SatoshiVersion.new(0, 4, 25)
39
+ end
40
+ end
41
+
42
+ describe "four-part form" do
43
+ # We cheat slightly here and make assumptions about the implementation
44
+ # (by not re-specifying every conceivable possibility)
45
+
46
+ it "compares equality" do
47
+ SatoshiVersion.new(0, 3, 24, 0).should eq SatoshiVersion.new(0, 3, 24, 0)
48
+ SatoshiVersion.new(0, 3, 24, 0).should_not eq SatoshiVersion.new(0, 3, 24, 1)
49
+ end
50
+
51
+ it "has a total ordering" do
52
+ SatoshiVersion.new(0, 3, 24, 1).should be < SatoshiVersion.new(0, 3, 25, 2)
53
+ SatoshiVersion.new(0, 3, 24, 1).should be > SatoshiVersion.new(0, 3, 23, 0)
54
+
55
+ SatoshiVersion.new(0, 3, 24, 1).should be < SatoshiVersion.new(0, 3, 25, 0)
56
+ SatoshiVersion.new(0, 3, 24, 1).should be > SatoshiVersion.new(0, 3, 23, 2)
57
+
58
+ # etc, for the rest of the components...
59
+ end
60
+ end
61
+
62
+ describe "-beta version suffixes" do
63
+ it "are not supported", because: "this is hardcoded into the Satoshi client" do
64
+ # As of 0.3.24, the "beta" status is determined in the C++ code with this value:
65
+ # static const bool VERSION_IS_BETA = true;
66
+ false.should be_false
67
+ end
68
+ end
69
+
70
+ describe "comparing three- and four-part forms" do
71
+ # This is not explicit in the Satoshi code, but seems a reasonable assumption for now,
72
+ # until it breaks...
73
+ it "assumes an implicit 0 at the end of the three-part form" do
74
+ SatoshiVersion.new(0, 3, 24).should eq SatoshiVersion.new(0, 3, 24, 0)
75
+ SatoshiVersion.new(0, 3, 24, 0).should eq SatoshiVersion.new(0, 3, 24)
76
+ # it seems safe to assume the rest of the comparisons work by induction
77
+ end
78
+ end
79
+
80
+ describe "conversion" do
81
+ describe "to strings" do
82
+ it "supports #to_s", because: "we need to be usable with IO#<<" do
83
+ SatoshiVersion.new(0, 3, 24).to_s.should eq "0.3.24"
84
+ SatoshiVersion.new(0, 3, 24, 1).to_s.should eq "0.3.24.1"
85
+ end
86
+
87
+ it "truncates a fourth zero", because: "the standard client does this (semantic versioning?)" do
88
+ SatoshiVersion.new(0, 3, 24, 0).to_s.should eq "0.3.24"
89
+ end
90
+
91
+ it "does not truncate a third version", because: "the standard client does this (semantic versioning?)" do
92
+ SatoshiVersion.new(0, 4, 0).to_s.should eq "0.4.0"
93
+ end
94
+
95
+ it "supports #to_str as an alias of :to_s" do
96
+ version = SatoshiVersion.new(0, 3, 24)
97
+ to_s_method = version.method(:to_s)
98
+ to_str_method = version.method(:to_str)
99
+ to_str_method.should eq to_s_method
100
+ end
101
+ end
102
+
103
+ describe "to Satoshi-format wallet bytes" do
104
+ it "creates the same bytes as came from the BDB database" do
105
+ SatoshiVersion.new(0, 3, 24).to_wallet_bytes.should eq [144, 126, 0, 0]
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ require 'bitcoin/data_access/satoshi/satoshi_wallet'
4
+
5
+ module Bitcoin
6
+ module DataAccess
7
+ module Satoshi
8
+ describe SatoshiWallet do
9
+ describe ".open" do
10
+ let(:satoshi_wallet_repository) { mock(BDBSatoshiWalletRepository) }
11
+ let(:satoshi_wallet) { mock(SatoshiWallet) }
12
+
13
+ before(:each) do
14
+ BDBSatoshiWalletRepository.stub(new: satoshi_wallet_repository)
15
+ SatoshiWallet.stub(new: satoshi_wallet)
16
+ end
17
+
18
+ it "makes a BDBSatoshiWalletRepository" do
19
+ BDBSatoshiWalletRepository.should_receive(:new).with("wallet.dat", db_dirname: "/db/dir")
20
+ SatoshiWallet.open(wallet_filename: "wallet.dat", db_dirname: "/db/dir", & ->(wallet) { :noop })
21
+ end
22
+
23
+ it "makes a SatoshiWallet with the BDBSatoshiWalletRepository" do
24
+ SatoshiWallet.should_receive(:new).with(satoshi_wallet_repository)
25
+ SatoshiWallet.open(wallet_filename: "wallet.dat", db_dirname: "/db/dir", & ->(wallet) { :noop })
26
+ end
27
+
28
+ it "yields the wallet" do
29
+ SatoshiWallet.open(wallet_filename: "wallet.dat", db_dirname: "/db/dir") do |wallet|
30
+ wallet.should eq satoshi_wallet
31
+ end
32
+ end
33
+
34
+ it "returns the value of the block" do
35
+ SatoshiWallet.open(wallet_filename: "wallet.dat", db_dirname: "/db/dir") { |wallet|
36
+ :block_value
37
+ }.should eq :block_value
38
+ end
39
+
40
+ it "raises an error if no block is given", because: "we use blocks to manage the opening and closing of the BDB database" do
41
+ expect {
42
+ SatoshiWallet.open(wallet_filename: "wallet.dat", db_dirname: "/db/dir")
43
+ }.to raise_error(ArgumentError) { |error|
44
+ error.message.should =~ /you must provide a block to SatoshiWallet\.new/i
45
+ }
46
+ end
47
+ end
48
+
49
+ describe "instance methods" do
50
+ let(:satoshi_wallet_repository) { mock(BDBSatoshiWalletRepository) }
51
+
52
+ before(:each) do
53
+ BDBSatoshiWalletRepository.stub(new: satoshi_wallet_repository)
54
+ end
55
+
56
+ subject { SatoshiWallet.new(satoshi_wallet_repository) }
57
+
58
+ describe "#version" do
59
+ it "returns the version from the wallet" do
60
+ satoshi_wallet_repository.should_receive(:get_value_immediate_uint32le).with("version").and_return(32400)
61
+ subject.version.should eq SatoshiVersion.new(0, 3, 24)
62
+ end
63
+ end
64
+
65
+ describe "#addresses" do
66
+ before(:each) do
67
+ satoshi_wallet_repository.stub(
68
+ get_key_and_value_data_string_utf8: [
69
+ [ "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz", "Bitcoin Monitor" ],
70
+ [ "1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw", "Bitcoincharts" ]
71
+ ]
72
+ )
73
+ end
74
+
75
+ it "fetches the data" do
76
+ satoshi_wallet_repository.should_receive(:get_key_and_value_data_string_utf8).with("name")
77
+ subject.addresses
78
+ end
79
+
80
+ it "returns an AddressBook with the wallet addresses" do
81
+ subject.addresses.should be_a Domain::AddressBook
82
+ expected_addresses = Domain::AddressBook.new([
83
+ { address: Domain::BitcoinAddress.new("14Z1mazY4HfysZyMaKudFr63EwHqQT2njz"), name: "Bitcoin Monitor" },
84
+ { address: Domain::BitcoinAddress.new("1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw"), name: "Bitcoincharts" }
85
+ ]).to_a
86
+ subject.addresses.to_a.should =~ expected_addresses
87
+ end
88
+ end
89
+
90
+ describe "#add_address" do
91
+ it "adds the BitcoinAddress to the Wallet" do
92
+ satoshi_wallet_repository.should_receive(:set_value_with_key_data_string_utf8).with(
93
+ "name", "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz", "Bitcoin Monitor"
94
+ )
95
+ subject.add_address(Domain::BitcoinAddress.new("14Z1mazY4HfysZyMaKudFr63EwHqQT2njz"), name: "Bitcoin Monitor")
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end