bitcoin 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. metadata +17 -288
  2. data/.rspec +0 -1
  3. data/.rvmrc +0 -1
  4. data/Gemfile +0 -4
  5. data/Gemfile.lock +0 -98
  6. data/Guardfile +0 -38
  7. data/README.markdown +0 -24
  8. data/Rakefile +0 -1
  9. data/bin/rbcoin +0 -8
  10. data/bitcoin.gemspec +0 -40
  11. data/config/cucumber.yml +0 -5
  12. data/config/darcs.boring +0 -121
  13. data/doc/DEFINITION_OF_DONE.markdown +0 -12
  14. data/doc/HISTORY.markdown +0 -19
  15. data/doc/LICENCE.markdown +0 -25
  16. data/doc/TODO.markdown +0 -31
  17. data/doc/UBIQUITOUS_LANGUAGE.markdown +0 -15
  18. data/features/descriptions/command_help.feature +0 -31
  19. data/features/descriptions/satoshi_wallet/add_address.feature +0 -49
  20. data/features/descriptions/satoshi_wallet/show_addresses.feature +0 -18
  21. data/features/descriptions/satoshi_wallet/show_version.feature +0 -17
  22. data/features/descriptions/satoshi_wallet/subcommand_help.feature +0 -20
  23. data/features/fixtures/ABOUT_FIXTURES.markdown +0 -6
  24. data/features/fixtures/addressbook_wallet.dat +0 -0
  25. data/features/fixtures/new_wallet.dat +0 -0
  26. data/features/step_definitions/command_steps.rb +0 -3
  27. data/features/step_definitions/wallet_steps.rb +0 -11
  28. data/features/support/env.rb +0 -9
  29. data/lib/bitcoin.rb +0 -5
  30. data/lib/bitcoin/cli.rb +0 -35
  31. data/lib/bitcoin/commands.rb +0 -3
  32. data/lib/bitcoin/commands/help_command.rb +0 -32
  33. data/lib/bitcoin/commands/satoshi_wallet.rb +0 -11
  34. data/lib/bitcoin/commands/satoshi_wallet/add_address_command.rb +0 -61
  35. data/lib/bitcoin/commands/satoshi_wallet/show_addresses_command.rb +0 -16
  36. data/lib/bitcoin/commands/satoshi_wallet/show_version_command.rb +0 -15
  37. data/lib/bitcoin/commands/satoshi_wallet_command.rb +0 -37
  38. data/lib/bitcoin/commands/satoshi_wallet_command_environment.rb +0 -28
  39. data/lib/bitcoin/console/capturing_stream_bundle.rb +0 -42
  40. data/lib/bitcoin/console/stream_bundle.rb +0 -21
  41. data/lib/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository.rb +0 -155
  42. data/lib/bitcoin/data_access/satoshi/satoshi_version.rb +0 -58
  43. data/lib/bitcoin/data_access/satoshi/satoshi_wallet.rb +0 -39
  44. data/lib/bitcoin/domain/address_book.rb +0 -19
  45. data/lib/bitcoin/domain/bitcoin_address.rb +0 -33
  46. data/lib/bitcoin/filesystem/empty_temp_dir.rb +0 -74
  47. data/lib/bitcoin/rspec/argument_matchers.rb +0 -1
  48. data/lib/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher.rb +0 -23
  49. data/lib/bitcoin/rspec/directory_helpers.rb +0 -22
  50. data/lib/bitcoin/version.rb +0 -3
  51. data/spec/bitcoin/cli_spec.rb +0 -128
  52. data/spec/bitcoin/commands/help_command_spec.rb +0 -53
  53. data/spec/bitcoin/commands/satoshi_wallet/add_address_command_spec.rb +0 -149
  54. data/spec/bitcoin/commands/satoshi_wallet/show_addresses_command_spec.rb +0 -26
  55. data/spec/bitcoin/commands/satoshi_wallet/show_version_command_spec.rb +0 -26
  56. data/spec/bitcoin/commands/satoshi_wallet_command_environment_spec.rb +0 -76
  57. data/spec/bitcoin/commands/satoshi_wallet_command_spec.rb +0 -73
  58. data/spec/bitcoin/console/_contracts/stream_bundle_contract.rb +0 -29
  59. data/spec/bitcoin/console/capturing_stream_bundle_spec.rb +0 -74
  60. data/spec/bitcoin/console/stream_bundle_spec.rb +0 -13
  61. data/spec/bitcoin/data_access/satoshi/bdb_satoshi_wallet_repository_spec.rb +0 -78
  62. data/spec/bitcoin/data_access/satoshi/satoshi_version_spec.rb +0 -112
  63. data/spec/bitcoin/data_access/satoshi/satoshi_wallet_spec.rb +0 -102
  64. data/spec/bitcoin/domain/address_book_spec.rb +0 -63
  65. data/spec/bitcoin/domain/bitcoin_address_spec.rb +0 -52
  66. data/spec/bitcoin/filesystem/empty_temp_dir_spec.rb +0 -170
  67. data/spec/bitcoin/rspec/argument_matchers/block_evaluating_to_matcher_spec.rb +0 -36
  68. data/spec/spec_helper.rb +0 -29
@@ -1,13 +0,0 @@
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
@@ -1,78 +0,0 @@
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
-
@@ -1,112 +0,0 @@
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
@@ -1,102 +0,0 @@
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
@@ -1,63 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'bitcoin/domain/address_book'
4
-
5
- module Bitcoin
6
- module Domain
7
- describe AddressBook do
8
- context "made with no addresses" do
9
- subject { AddressBook.new }
10
- its(:to_a) { should eq [ ] }
11
- end
12
-
13
- context "made with addresses" do
14
- let(:address_hashes) {
15
- [
16
- { address: "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz", name: "Bitcoin Monitor" },
17
- { address: "1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw", name: "Bitcoincharts" }
18
- ]
19
- }
20
-
21
- subject {
22
- AddressBook.new(address_hashes)
23
- }
24
-
25
- its(:to_a) {
26
- should =~ [
27
- { address: "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz", name: "Bitcoin Monitor" },
28
- { address: "1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw", name: "Bitcoincharts" }
29
- ]
30
- }
31
-
32
- # We're assuming the output comes out in the input order, so this example is
33
- # overly precise until we know how we'll handle presentation
34
- its(:to_s) {
35
- should eq(
36
- -%{
37
- 14Z1mazY4HfysZyMaKudFr63EwHqQT2njz Bitcoin Monitor
38
- 1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw Bitcoincharts
39
- }
40
- )
41
- }
42
-
43
- describe "argument cloning" do
44
- # Ensure this is created before we try changing the input arguments
45
- before(:each) { subject }
46
-
47
- it "does not mutate the args" do
48
- expect {
49
- address_hashes.delete_if { true }
50
- }.to_not change {
51
- subject.to_a.length
52
- }.from(2).to(0)
53
- end
54
-
55
- it "makes a deep copy" do
56
- address_hashes.first[:name] = "changed"
57
- subject.to_a.map { |hash| hash[:name] }.should_not include("changed")
58
- end
59
- end
60
- end
61
- end
62
- end
63
- end
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'bitcoin/domain/bitcoin_address'
4
-
5
- module Bitcoin
6
- module Domain
7
- describe BitcoinAddress do
8
- context "created with a valid real network address" do
9
- subject { BitcoinAddress.new("14Z1mazY4HfysZyMaKudFr63EwHqQT2njz") }
10
-
11
- its(:to_s) { should eq "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz" }
12
-
13
- describe "#==" do
14
- it "is equal to another BitcoinAddress with the same address" do
15
- subject.should eq BitcoinAddress.new("14Z1mazY4HfysZyMaKudFr63EwHqQT2njz")
16
- end
17
-
18
- it "is not equal to a BitcoinAddress with a different address" do
19
- subject.should_not eq BitcoinAddress.new("1Nqr3MqVyUp6k3o3QPePAdn4Yg4tzgB9kw")
20
- end
21
-
22
- it "is not equal to a String" do
23
- subject.should_not eq "14Z1mazY4HfysZyMaKudFr63EwHqQT2njz"
24
- end
25
- end
26
- end
27
-
28
- context "creating with an invalid address" do
29
- invalid_addresses = [
30
- # Not actually sure the reasons here are valid in general but it's just enough to
31
- # get us going (the point of the exercise is to put an error protocol in place)
32
- { address: "14Z1mazY4HfysZyMaKudFr63EwHqQT2nj", because: "this is too short" },
33
- { address: "14Z1mazY4HfysZyMaKudFr63EwHqQT2njzX", because: "this is too long" }
34
- # Hash doesn't match
35
- # Wrong version
36
- # ... etc ...
37
- # (When we know more about Bitcoin crypto we can come back and finish this off)
38
- ]
39
-
40
- invalid_addresses.each do |invalid_address|
41
- it "raises an error for address #{invalid_address[:address]} because #{invalid_address[:because]}" do
42
- expect {
43
- BitcoinAddress.new(invalid_address[:address])
44
- }.to raise_error(BitcoinAddress::InvalidBitcoinAddressError) { |error|
45
- error.message.should eq %'The address "#{invalid_address[:address]}" is not a valid Bitcoin address'
46
- }
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,170 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'bitcoin/filesystem/empty_temp_dir'
4
- require 'bitcoin/rspec/directory_helpers'
5
-
6
- module Bitcoin
7
- module FileSystem
8
- describe EmptyTempDir do
9
- include Bitcoin::RSpec::DirectoryHelpers
10
-
11
- TEMP_TEST_DIR = File.join(PROJECT_ROOT, "tmp", "test").freeze
12
-
13
- ensure_empty_test_dir(TEMP_TEST_DIR)
14
-
15
- describe ".open" do
16
- describe "integration" do # refactoring invariant
17
- it "lets you create a temporary file inside the temporary directory" do
18
- expected_temp_dir_name = File.join(TEMP_TEST_DIR, "temp_dir")
19
-
20
- EmptyTempDir.open(with_name: "temp_dir", parallel_to: File.join(TEMP_TEST_DIR, "wallet.dat")) do |temp_dir|
21
- File.open(File.join(temp_dir.absolute_path, "test_file"), "w") do |file|
22
- file << "some unimportant contents"
23
- end
24
- Dir.entries(temp_dir.absolute_path).should eq %w[ . .. test_file ]
25
- end
26
-
27
- File.exist?(expected_temp_dir_name).should be_false
28
- end
29
- end
30
-
31
- describe "interactions" do
32
- let(:block_runner) { mock(EmptyTempDir::BlockRunner, run: :block_runner_run_value) }
33
-
34
- before(:each) do
35
- EmptyTempDir::BlockRunner.stub(new: block_runner)
36
- end
37
-
38
- it "raises an error if no block is provided", because: "this would be a pointless thing to do" do
39
- expect {
40
- EmptyTempDir.open(with_name: "temp_dir", parallel_to: File.join(TEMP_TEST_DIR, "wallet.dat"))
41
- }.to raise_error(ArgumentError) { |error|
42
- error.message.should =~ /you must provide a block to EmptyTempDir\.open/i
43
- }
44
- end
45
-
46
- describe "creating the BlockRunner" do
47
- it "calculates a directory name parallel to the file" do
48
- EmptyTempDir::BlockRunner.should_receive(:new).with("/foo/bar/temp_dir")
49
- EmptyTempDir.open(with_name: "temp_dir", parallel_to: "/foo/bar/baz", & -> { :noop })
50
- end
51
-
52
- it "always passed absolute directories" do
53
- EmptyTempDir::BlockRunner.should_receive(:new).with(File.join(PROJECT_ROOT, "/foo/bar/anything"))
54
- EmptyTempDir.open(with_name: "anything", parallel_to: "foo/bar/baz", & -> { :noop })
55
- end
56
- end
57
-
58
- it "runs the block" do
59
- block = -> { :block_value }
60
- block_runner.should_receive(:run).with(block_evaluating_to(:block_value))
61
- EmptyTempDir.open(with_name: "anything", parallel_to: "/foo/bar/baz", &block)
62
- end
63
-
64
- it "returns the value of the block" do
65
- EmptyTempDir.open(with_name: "temp_dir", parallel_to: "/foo/bar/baz", & -> { :noop }).should eq :block_runner_run_value
66
- end
67
- end
68
- end
69
-
70
- describe EmptyTempDir::BlockRunner do
71
- describe ".new" do
72
- # Yes, I actually did this to myself.
73
- describe "raising an error on unsafe paths", because: "otherwise it could format your hard drive!" do
74
- [ "", "/", "//" ].each do |unacceptable_path|
75
- it "blocks #{unacceptable_path.inspect}" do
76
- expect {
77
- EmptyTempDir::BlockRunner.new(unacceptable_path)
78
- }.to raise_error(ArgumentError) { |error|
79
- error.message.should eq "Unacceptable directory name for EmptyTempDir"
80
- }
81
- end
82
- end
83
- end
84
- end
85
-
86
- describe "#run" do
87
- shared_examples "EmptyTempDir::BlockRunner#run" do
88
- let(:expected_temp_dir_name) { File.join(TEMP_TEST_DIR, "temp_dir") }
89
- subject { EmptyTempDir::BlockRunner.new(expected_temp_dir_name) }
90
-
91
- it "ensures the directory exists" do
92
- subject.run(
93
- ->(temp_dir) { File.directory?(expected_temp_dir_name) }
94
- ).should be_true
95
- end
96
-
97
- it "ensures the directory is empty" do
98
- subject.run(
99
- ->(temp_dir) { Dir.entries(expected_temp_dir_name) }
100
- ).should =~ %w[ . .. ]
101
- end
102
-
103
- it "removes the directory at the end (even if a file was created inside it)" do
104
- subject.run(
105
- ->(temp_dir) {
106
- File.open(File.join(temp_dir.absolute_path, "test_file"), "w") do |file|
107
- file << "unimportant contents"
108
- end
109
- Dir.entries(temp_dir.absolute_path).should eq %w[ . .. test_file ]
110
- }
111
- )
112
-
113
- File.exist?(expected_temp_dir_name).should be_false
114
- end
115
-
116
- it "removes the directory even if the block raises an error" do
117
- expect {
118
- subject.run(->(temp_dir) { raise RuntimeError.new("I'm trying to make the temp dir persist!") })
119
- }.to raise_error
120
-
121
- File.exist?(expected_temp_dir_name).should be_false
122
- end
123
-
124
- it "re-raises any error thrown in the block" do
125
- expected_error = RuntimeError.new("I'm trying to make the temp dir persist!")
126
-
127
- expect {
128
- subject.run(->(temp_dir) { raise expected_error })
129
- }.to raise_error { |actual_error|
130
- actual_error.should equal expected_error
131
- }
132
- end
133
-
134
- it "has the expected path name" do
135
- subject.run(->(temp_dir) { temp_dir.absolute_path.should eq expected_temp_dir_name })
136
- end
137
-
138
- it "returns the value of the block", because: "all the examples rely on this" do
139
- subject.run(->(temp_dir) {
140
- :block_value
141
- }).should eq :block_value
142
- end
143
- end
144
-
145
- context "where the target directory does not exist" do
146
- before(:each) do
147
- FileUtils.rm_rf(expected_temp_dir_name)
148
- end
149
-
150
- it_behaves_like "EmptyTempDir::BlockRunner#run"
151
- end
152
-
153
- context "where the target directory exists" do
154
- before(:each) do
155
- existing_file_name = File.join(expected_temp_dir_name, "intermediate_dir", "test_file")
156
-
157
- # Make the target directory and a file inside a nested folder inside it
158
- FileUtils.mkdir_p(File.dirname(existing_file_name))
159
- File.open(existing_file_name, "w") do |file|
160
- file << "some unimportant contents"
161
- end
162
- end
163
-
164
- it_behaves_like "EmptyTempDir::BlockRunner#run"
165
- end
166
- end
167
- end
168
- end
169
- end
170
- end