bitcoin 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -1
- data/Gemfile.lock +56 -4
- data/Guardfile +38 -0
- data/README.markdown +21 -2
- data/bin/rbcoin +8 -1
- data/bitcoin.gemspec +17 -5
- data/config/cucumber.yml +3 -3
- data/config/darcs.boring +121 -0
- data/doc/DEFINITION_OF_DONE.markdown +12 -0
- data/doc/HISTORY.markdown +19 -0
- data/{LICENCE.markdown → doc/LICENCE.markdown} +1 -1
- data/doc/TODO.markdown +31 -0
- data/doc/UBIQUITOUS_LANGUAGE.markdown +15 -0
- data/features/descriptions/command_help.feature +31 -0
- data/features/descriptions/satoshi_wallet/add_address.feature +49 -0
- data/features/descriptions/satoshi_wallet/show_addresses.feature +18 -0
- data/features/descriptions/satoshi_wallet/show_version.feature +17 -0
- data/features/descriptions/satoshi_wallet/subcommand_help.feature +20 -0
- data/features/fixtures/ABOUT_FIXTURES.markdown +6 -0
- data/features/fixtures/addressbook_wallet.dat +0 -0
- data/features/fixtures/new_wallet.dat +0 -0
- data/features/step_definitions/command_steps.rb +3 -0
- data/features/step_definitions/wallet_steps.rb +11 -0
- data/features/support/env.rb +8 -1
- data/lib/bitcoin/cli.rb +35 -0
- data/lib/bitcoin/commands.rb +3 -0
- data/lib/bitcoin/commands/help_command.rb +32 -0
- data/lib/bitcoin/commands/satoshi_wallet.rb +11 -0
- data/lib/bitcoin/commands/satoshi_wallet/add_address_command.rb +61 -0
- data/lib/bitcoin/commands/satoshi_wallet/show_addresses_command.rb +16 -0
- data/lib/bitcoin/commands/satoshi_wallet/show_version_command.rb +15 -0
- data/lib/bitcoin/commands/satoshi_wallet_command.rb +37 -0
- data/lib/bitcoin/commands/satoshi_wallet_command_environment.rb +28 -0
- data/lib/bitcoin/console/capturing_stream_bundle.rb +42 -0
- data/lib/bitcoin/console/stream_bundle.rb +21 -0
- data/lib/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository.rb +155 -0
- data/lib/bitcoin/data_access/satoshi/satoshi_version.rb +58 -0
- data/lib/bitcoin/data_access/satoshi/satoshi_wallet.rb +39 -0
- data/lib/bitcoin/domain/address_book.rb +19 -0
- data/lib/bitcoin/domain/bitcoin_address.rb +33 -0
- data/lib/bitcoin/filesystem/empty_temp_dir.rb +74 -0
- data/lib/bitcoin/rspec/argument_matchers.rb +1 -0
- data/lib/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher.rb +23 -0
- data/lib/bitcoin/rspec/directory_helpers.rb +22 -0
- data/lib/bitcoin/version.rb +1 -1
- data/spec/bitcoin/cli_spec.rb +128 -0
- data/spec/bitcoin/commands/help_command_spec.rb +53 -0
- data/spec/bitcoin/commands/satoshi_wallet/add_address_command_spec.rb +149 -0
- data/spec/bitcoin/commands/satoshi_wallet/show_addresses_command_spec.rb +26 -0
- data/spec/bitcoin/commands/satoshi_wallet/show_version_command_spec.rb +26 -0
- data/spec/bitcoin/commands/satoshi_wallet_command_environment_spec.rb +76 -0
- data/spec/bitcoin/commands/satoshi_wallet_command_spec.rb +73 -0
- data/spec/bitcoin/console/_contracts/stream_bundle_contract.rb +29 -0
- data/spec/bitcoin/console/capturing_stream_bundle_spec.rb +74 -0
- data/spec/bitcoin/console/stream_bundle_spec.rb +13 -0
- data/spec/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository_spec.rb +78 -0
- data/spec/bitcoin/data_access/satoshi/satoshi_version_spec.rb +112 -0
- data/spec/bitcoin/data_access/satoshi/satoshi_wallet_spec.rb +102 -0
- data/spec/bitcoin/domain/address_book_spec.rb +63 -0
- data/spec/bitcoin/domain/bitcoin_address_spec.rb +52 -0
- data/spec/bitcoin/filesystem/empty_temp_dir_spec.rb +170 -0
- data/spec/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher_spec.rb +36 -0
- data/spec/spec_helper.rb +29 -1
- 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,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
|