ib-ruby 0.7.4 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/HISTORY +8 -0
- data/README.md +2 -2
- data/Rakefile +15 -0
- data/TODO +7 -2
- data/VERSION +1 -1
- data/bin/account_info +1 -1
- data/bin/cancel_orders +1 -1
- data/bin/contract_details +1 -1
- data/bin/depth_of_market +1 -1
- data/bin/fa_accounts +1 -1
- data/bin/fundamental_data +42 -0
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +1 -1
- data/bin/list_orders +1 -2
- data/bin/market_data +1 -1
- data/bin/option_data +1 -1
- data/bin/place_combo_order +1 -1
- data/bin/place_order +1 -1
- data/bin/template +1 -4
- data/bin/tick_data +2 -2
- data/bin/time_and_sales +1 -1
- data/lib/ib-ruby.rb +4 -0
- data/lib/ib-ruby/connection.rb +50 -34
- data/lib/ib-ruby/constants.rb +232 -37
- data/lib/ib-ruby/db.rb +25 -0
- data/lib/ib-ruby/extensions.rb +51 -1
- data/lib/ib-ruby/messages/abstract_message.rb +0 -8
- data/lib/ib-ruby/messages/incoming.rb +18 -493
- data/lib/ib-ruby/messages/incoming/abstract_message.rb +100 -0
- data/lib/ib-ruby/messages/incoming/alert.rb +34 -0
- data/lib/ib-ruby/messages/incoming/contract_data.rb +82 -0
- data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +20 -0
- data/lib/ib-ruby/messages/incoming/execution_data.rb +59 -0
- data/lib/ib-ruby/messages/incoming/historical_data.rb +55 -0
- data/lib/ib-ruby/messages/incoming/market_depths.rb +44 -0
- data/lib/ib-ruby/messages/incoming/open_order.rb +32 -16
- data/lib/ib-ruby/messages/incoming/order_status.rb +67 -0
- data/lib/ib-ruby/messages/incoming/portfolio_value.rb +39 -0
- data/lib/ib-ruby/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib-ruby/messages/incoming/scanner_data.rb +49 -0
- data/lib/ib-ruby/messages/outgoing.rb +25 -223
- data/lib/ib-ruby/messages/outgoing/abstract_message.rb +61 -0
- data/lib/ib-ruby/messages/outgoing/bar_requests.rb +149 -0
- data/lib/ib-ruby/messages/outgoing/place_order.rb +24 -0
- data/lib/ib-ruby/models.rb +4 -0
- data/lib/ib-ruby/models/bar.rb +31 -14
- data/lib/ib-ruby/models/combo_leg.rb +48 -23
- data/lib/ib-ruby/models/contracts.rb +2 -2
- data/lib/ib-ruby/models/contracts/bag.rb +11 -7
- data/lib/ib-ruby/models/contracts/contract.rb +90 -66
- data/lib/ib-ruby/models/contracts/option.rb +16 -7
- data/lib/ib-ruby/models/execution.rb +34 -18
- data/lib/ib-ruby/models/model.rb +15 -7
- data/lib/ib-ruby/models/model_properties.rb +101 -44
- data/lib/ib-ruby/models/order.rb +176 -187
- data/lib/ib-ruby/models/order_state.rb +99 -0
- data/lib/ib-ruby/symbols/forex.rb +10 -10
- data/lib/ib-ruby/symbols/futures.rb +6 -6
- data/lib/ib-ruby/symbols/stocks.rb +3 -3
- data/spec/account_helper.rb +4 -5
- data/spec/combo_helper.rb +4 -4
- data/spec/db.rb +18 -0
- data/spec/ib-ruby/messages/{incoming_spec.rb → incoming/alert_spec.rb} +1 -0
- data/spec/ib-ruby/messages/incoming/open_order_spec.rb +100 -0
- data/spec/ib-ruby/messages/incoming/order_status_spec.rb +74 -0
- data/spec/ib-ruby/messages/{outgoing_spec.rb → outgoing/account_data_spec.rb} +0 -0
- data/spec/ib-ruby/messages/outgoing/market_data_type_spec.rb +44 -0
- data/spec/ib-ruby/models/bag_spec.rb +97 -0
- data/spec/ib-ruby/models/bar_spec.rb +45 -0
- data/spec/ib-ruby/models/combo_leg_spec.rb +56 -40
- data/spec/ib-ruby/models/contract_spec.rb +134 -170
- data/spec/ib-ruby/models/execution_spec.rb +35 -50
- data/spec/ib-ruby/models/option_spec.rb +127 -0
- data/spec/ib-ruby/models/order_spec.rb +89 -68
- data/spec/ib-ruby/models/order_state_spec.rb +55 -0
- data/spec/integration/contract_info_spec.rb +4 -6
- data/spec/integration/fundamental_data_spec.rb +41 -0
- data/spec/integration/historic_data_spec.rb +4 -4
- data/spec/integration/market_data_spec.rb +1 -3
- data/spec/integration/orders/attached_spec.rb +8 -10
- data/spec/integration/orders/combo_spec.rb +2 -2
- data/spec/integration/orders/execution_spec.rb +0 -1
- data/spec/integration/orders/placement_spec.rb +1 -3
- data/spec/integration/orders/valid_ids_spec.rb +1 -2
- data/spec/message_helper.rb +1 -1
- data/spec/model_helper.rb +211 -0
- data/spec/order_helper.rb +44 -37
- data/spec/spec_helper.rb +36 -23
- data/spec/v.rb +7 -0
- data/tasks/doc.rake +1 -1
- metadata +116 -12
- data/spec/integration/orders/open_order +0 -98
@@ -13,8 +13,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
13
13
|
context "Request Stock data" do
|
14
14
|
|
15
15
|
before(:all) do
|
16
|
-
@contract = IB::Contract.new :symbol => 'AAPL',
|
17
|
-
:sec_type => IB::SECURITY_TYPES[:stock]
|
16
|
+
@contract = IB::Contract.new :symbol => 'AAPL', :sec_type => :stock
|
18
17
|
@ib.send_message :RequestContractData, :id => 111, :contract => @contract
|
19
18
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
20
19
|
end
|
@@ -52,8 +51,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
52
51
|
contract.order_types.should be_a String
|
53
52
|
contract.price_magnifier.should == 1
|
54
53
|
contract.min_tick.should be <= 0.01
|
55
|
-
|
56
|
-
contract.expiry.should be_nil
|
54
|
+
contract.expiry.should == ''
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end # Stock
|
@@ -108,7 +106,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
108
106
|
@contract = IB::Contract.new :symbol => 'EUR', # EURUSD pair
|
109
107
|
:currency => "USD",
|
110
108
|
:exchange => "IDEALPRO",
|
111
|
-
:sec_type =>
|
109
|
+
:sec_type => :forex
|
112
110
|
@ib.send_message :RequestContractData, :id => 135, :contract => @contract
|
113
111
|
@ib.wait_for :ContractDataEnd, 3 # sec
|
114
112
|
end
|
@@ -136,7 +134,7 @@ describe "Request Contract Info", :connected => true, :integration => true do
|
|
136
134
|
contract.industry.should == ''
|
137
135
|
contract.category.should == ''
|
138
136
|
contract.subcategory.should == ''
|
139
|
-
contract.expiry.should
|
137
|
+
contract.expiry.should == ''
|
140
138
|
contract.exchange.should == 'IDEALPRO'
|
141
139
|
contract.con_id.should be_an Integer
|
142
140
|
contract.trading_hours.should =~ /\d{8}:\d{4}-\d{4}/
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'integration_helper'
|
2
|
+
|
3
|
+
describe 'Request Fundamental Data',
|
4
|
+
:connected => true, :integration => true, :reuters => true do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
verify_account
|
8
|
+
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
9
|
+
|
10
|
+
@contract = IB::Contract.new :symbol => 'IBM',
|
11
|
+
:exchange => 'NYSE',
|
12
|
+
:currency => 'USD',
|
13
|
+
:sec_type => 'STK'
|
14
|
+
|
15
|
+
@ib.send_message :RequestFundamentalData,
|
16
|
+
:id => 456,
|
17
|
+
:contract => @contract,
|
18
|
+
:report_type => 'snapshot' # 'estimates', 'finstat'
|
19
|
+
|
20
|
+
@ib.wait_for :FundamentalData, 6 # sec
|
21
|
+
end
|
22
|
+
|
23
|
+
after(:all) do
|
24
|
+
close_connection
|
25
|
+
end
|
26
|
+
|
27
|
+
subject { @ib.received[:FundamentalData].first }
|
28
|
+
|
29
|
+
it { @ib.received[:FundamentalData].should have_at_least(1).data_message }
|
30
|
+
|
31
|
+
it { should be_an IB::Messages::Incoming::FundamentalData }
|
32
|
+
its(:request_id) { should == 456 }
|
33
|
+
its(:data) { should be_a String }
|
34
|
+
|
35
|
+
it 'responds with XML with relevand data' do
|
36
|
+
require 'xmlsimple'
|
37
|
+
data_xml = XmlSimple.xml_in(subject.data, 'ForceArray' => false) #, 'ContentKey' => 'content')
|
38
|
+
name = data_xml["CoIDs"]["CoID"].find {|tag| tag['Type'] == 'CompanyName'}['content']
|
39
|
+
name.should =~ /International Business Machines/
|
40
|
+
end
|
41
|
+
end
|
@@ -7,7 +7,7 @@ describe 'Request Historic Data', :connected => true, :integration => true do
|
|
7
7
|
:end_date_time => Time.now.to_ib,
|
8
8
|
:duration => '1 D',
|
9
9
|
:bar_size => '15 mins',
|
10
|
-
:
|
10
|
+
:data_type => :trades,
|
11
11
|
:format_date => 1}
|
12
12
|
before(:all) do
|
13
13
|
verify_account
|
@@ -26,10 +26,10 @@ describe 'Request Historic Data', :connected => true, :integration => true do
|
|
26
26
|
end.to raise_error /bar_size must be one of/
|
27
27
|
end
|
28
28
|
|
29
|
-
it 'raises if incorrect
|
29
|
+
it 'raises if incorrect data_type' do
|
30
30
|
expect do
|
31
|
-
@ib.send_message :RequestHistoricalData, CORRECT_OPTS.merge(:
|
32
|
-
end.to raise_error /:
|
31
|
+
@ib.send_message :RequestHistoricalData, CORRECT_OPTS.merge(:data_type => :nonsense)
|
32
|
+
end.to raise_error /:data_type must be one of/
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'integration_helper'
|
2
|
-
#!/usr/bin/env ruby
|
3
2
|
|
4
3
|
require 'ib-ruby'
|
5
4
|
|
6
|
-
#OPTS[:silent] = false
|
7
5
|
describe 'Request Market Data', :connected => true, :integration => true do
|
8
6
|
|
9
7
|
require 'ib-ruby'
|
@@ -15,7 +13,7 @@ describe 'Request Market Data', :connected => true, :integration => true do
|
|
15
13
|
@contract = IB::Contract.new(:symbol => 'AAPL',
|
16
14
|
:exchange => "Smart",
|
17
15
|
:currency => "USD",
|
18
|
-
:sec_type =>
|
16
|
+
:sec_type => :stock,
|
19
17
|
:description => "Apple"
|
20
18
|
)
|
21
19
|
@ib.send_message :RequestMarketData, :id => 456, :contract => @contract
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
require 'combo_helper'
|
3
3
|
|
4
|
-
#OPTS[:silent] = false
|
5
|
-
|
6
4
|
def define_contracts
|
7
5
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
8
6
|
@contracts = {
|
@@ -21,12 +19,12 @@ describe 'Attached Orders', :connected => true, :integration => true do
|
|
21
19
|
|
22
20
|
# Testing different combinations of Parent + Attached Orders:
|
23
21
|
[
|
24
|
-
|
25
|
-
[:stock, 100, 'DAY', 'STP', 9.13, 0.0, 8.0], # Parent + stoploss
|
26
|
-
[:stock, 100, 'GTC', 'LMT', 9.13, 20.0], # GTC Parent + target
|
22
|
+
[:stock, 100, 'DAY', 'LMT', 9.13, 20.0], # Parent + takeprofit target
|
23
|
+
#[:stock, 100, 'DAY', 'STP', 9.13, 0.0, 8.0], # Parent + stoploss
|
24
|
+
#[:stock, 100, 'GTC', 'LMT', 9.13, 20.0], # GTC Parent + target
|
27
25
|
[:butterfly, 10, 'DAY', 'LMT', 0.05, 1.0], # Combo Parent + target
|
28
|
-
|
29
|
-
|
26
|
+
#[:butterfly, 10, 'GTC', 'LMT', 0.05, 1.0], # GTC Combo Parent + target
|
27
|
+
#[:butterfly, 100, 'GTC', 'STPLMT', 0.05, 0.05, 1.0], # GTC Combo Parent + stoplimit target
|
30
28
|
|
31
29
|
].each do |(contract, qty, tif, attach_type, limit_price, attach_price, aux_price)|
|
32
30
|
context "#{tif} BUY (#{contract}) limit order with attached #{attach_type} SELL" do
|
@@ -57,10 +55,10 @@ describe 'Attached Orders', :connected => true, :integration => true do
|
|
57
55
|
|
58
56
|
context "Attaching #{attach_type} order" do
|
59
57
|
before(:all) do
|
60
|
-
@attached_order = IB::Order.new :
|
61
|
-
:limit_price => attach_price,
|
58
|
+
@attached_order = IB::Order.new :limit_price => attach_price,
|
62
59
|
:aux_price => aux_price || 0,
|
63
|
-
:
|
60
|
+
:total_quantity => qty,
|
61
|
+
:side => :sell,
|
64
62
|
:tif => tif,
|
65
63
|
:order_type => attach_type,
|
66
64
|
:parent_id => @order_id_placed
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
require 'combo_helper'
|
3
3
|
|
4
|
-
#OPTS[:silent] = false
|
5
|
-
|
6
4
|
describe "Combo Order", :connected => true, :integration => true, :slow => true do
|
7
5
|
|
8
6
|
let(:contract_type) { :butterfly }
|
@@ -17,6 +15,7 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
|
|
17
15
|
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
18
16
|
|
19
17
|
place_order @contract,
|
18
|
+
:order_ref => 'What_if',
|
20
19
|
:limit_price => 0.01,
|
21
20
|
:total_quantity => 10,
|
22
21
|
:what_if => true
|
@@ -70,6 +69,7 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
|
|
70
69
|
@contract = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
|
71
70
|
|
72
71
|
place_order @contract,
|
72
|
+
:order_ref => 'Original',
|
73
73
|
:limit_price => 0.01,
|
74
74
|
:total_quantity => 10
|
75
75
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
|
3
|
-
#OPTS[:silent] = false
|
4
|
-
|
5
3
|
describe 'Orders', :connected => true, :integration => true do
|
6
4
|
let(:contract_type) { :stock }
|
7
5
|
|
@@ -89,7 +87,7 @@ describe 'Orders', :connected => true, :integration => true do
|
|
89
87
|
@ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
|
90
88
|
@ib.wait_for :NextValidId
|
91
89
|
place_order IB::Symbols::Stocks[:wfc], :limit_price => 9.13 # Acceptable price
|
92
|
-
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2],
|
90
|
+
@ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2], 6
|
93
91
|
end
|
94
92
|
|
95
93
|
after(:all) { close_connection }
|
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'order_helper'
|
2
2
|
|
3
|
-
#OPTS[:silent] = false
|
4
3
|
shared_examples_for 'Received single id' do
|
5
4
|
subject { @ib.received[:NextValidId].first }
|
6
5
|
|
@@ -52,7 +51,7 @@ describe 'Ids valid for Order placement', :connected => true, :integration => tr
|
|
52
51
|
|
53
52
|
it_behaves_like 'Received single id'
|
54
53
|
|
55
|
-
it 'receives also :OpenOrderEnd message', :pending => 'not in GW 924.
|
54
|
+
it 'receives also :OpenOrderEnd message', :pending => 'not in GW 924.3a' do
|
56
55
|
@ib.received[:OpenOrderEnd].should have_exactly(1).message
|
57
56
|
@ib.received[:OpenOrderEnd].first.should be_an IB::Messages::Incoming::OpenOrderEnd
|
58
57
|
end
|
data/spec/message_helper.rb
CHANGED
@@ -35,7 +35,7 @@ end
|
|
35
35
|
|
36
36
|
# Clear logs and message collector. Output may be silenced.
|
37
37
|
def clean_connection
|
38
|
-
|
38
|
+
if OPTS[:verbose]
|
39
39
|
#puts @received.map { |type, msg| [" #{type}:", msg.map(&:to_human)] } if @received
|
40
40
|
puts @ib.received.map { |type, msg| [" #{type}:", msg.map(&:to_human)] }
|
41
41
|
puts " Logs:", log_entries if @stdout
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
def codes_and_values_for property
|
4
|
+
Hash[IB::VALUES[property].map { |code, value| [[code, value], value] }]
|
5
|
+
end
|
6
|
+
|
7
|
+
shared_examples_for 'Model' do
|
8
|
+
context 'instantiation without properties' do
|
9
|
+
subject { described_class.new }
|
10
|
+
|
11
|
+
it_behaves_like 'Model instantiated empty'
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'instantiation with properties' do
|
15
|
+
subject { described_class.new props }
|
16
|
+
|
17
|
+
it_behaves_like 'Model instantiated with properties'
|
18
|
+
|
19
|
+
|
20
|
+
it 'has correct human-readeable format' do
|
21
|
+
subject.to_human.should == human
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
shared_examples_for 'Self-equal Model' do
|
27
|
+
subject { described_class.new(props) }
|
28
|
+
|
29
|
+
it 'is self-equal ' do
|
30
|
+
should == subject
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'is equal to Model with the same properties' do
|
34
|
+
should == described_class.new(props)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
shared_examples_for 'Model instantiated empty' do
|
39
|
+
it { should_not be_nil }
|
40
|
+
|
41
|
+
it 'sets all properties to defaults' do
|
42
|
+
defined?(defaults) && defaults.each do |name, value|
|
43
|
+
case value
|
44
|
+
when Module, Class
|
45
|
+
subject.send(name).should be_a value
|
46
|
+
else
|
47
|
+
subject.send(name).should == value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it_behaves_like 'Model properties'
|
53
|
+
it_behaves_like 'Invalid Model'
|
54
|
+
end
|
55
|
+
|
56
|
+
shared_examples_for 'Model instantiated with properties' do
|
57
|
+
it 'auto-assigns all properties given to initializer' do
|
58
|
+
props.each do |name, value|
|
59
|
+
subject.send(name).should == value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it_behaves_like 'Model properties'
|
64
|
+
it_behaves_like 'Valid Model'
|
65
|
+
end
|
66
|
+
|
67
|
+
shared_examples_for 'Model properties' do
|
68
|
+
context 'essential properties are still set, even if not given explicitely' do
|
69
|
+
its(:created_at) { should be_a Time }
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'allows setting properties' do
|
73
|
+
expect {
|
74
|
+
props.each do |name, value|
|
75
|
+
subject.send("#{name}=", value)
|
76
|
+
subject.send(name).should == value
|
77
|
+
end
|
78
|
+
}.to_not raise_error
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'sets values to properties as directed by its setters' do
|
82
|
+
defined?(assigns) && assigns.each do |props, cases|
|
83
|
+
#p props, cases
|
84
|
+
|
85
|
+
# For each given property ...
|
86
|
+
[props].flatten.each do |prop|
|
87
|
+
|
88
|
+
# For all test cases given as an Array [res1, res2] or Hash {val => res} ...
|
89
|
+
(cases.is_a?(Array) ? cases.map { |e| [e, e] } : cases).each do |values, result|
|
90
|
+
|
91
|
+
# For all values in this test case ...
|
92
|
+
[values].flatten.each do |value|
|
93
|
+
|
94
|
+
# Assigning this value to property results in ...
|
95
|
+
case result
|
96
|
+
when Exception # ... Exception
|
97
|
+
expect { subject.send "#{prop}=", value }.
|
98
|
+
to raise_error result
|
99
|
+
|
100
|
+
when Regexp # ... Non-exceptional error, making model invalid
|
101
|
+
expect { subject.send "#{prop}=", value }.to_not raise_error
|
102
|
+
subject.should be_invalid
|
103
|
+
|
104
|
+
#pp subject.errors.messages
|
105
|
+
#p value, result
|
106
|
+
|
107
|
+
subject.errors.messages[prop].should_not be_nil
|
108
|
+
msg = subject.errors.messages[prop].find { |msg| msg =~ result }
|
109
|
+
msg.should =~ result
|
110
|
+
|
111
|
+
else # ... correct uniform assignment to result
|
112
|
+
|
113
|
+
was_valid = subject.valid?
|
114
|
+
expect { subject.send "#{prop}=", value }.to_not raise_error
|
115
|
+
subject.send("#{prop}").should == result
|
116
|
+
|
117
|
+
was_valid && (subject.should be_valid) # assignment keeps validity
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
shared_examples_for 'Valid Model' do
|
128
|
+
it 'validates' do
|
129
|
+
#subject.valid?
|
130
|
+
#pp subject.errors.messages
|
131
|
+
subject.should be_valid
|
132
|
+
subject.errors.should be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'with DB backend', :db => true do
|
136
|
+
after(:all) do
|
137
|
+
#DatabaseCleaner.clean
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'is saved' do
|
141
|
+
subject.save.should be_true
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'is loaded just right' do
|
145
|
+
models = described_class.find(:all)
|
146
|
+
model = models.first
|
147
|
+
#pp model
|
148
|
+
models.should have_exactly(1).model
|
149
|
+
model.should == subject
|
150
|
+
model.should be_valid
|
151
|
+
props.each do |name, value|
|
152
|
+
model.send(name).should == value
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end # DB
|
156
|
+
end
|
157
|
+
|
158
|
+
shared_examples_for 'Invalid Model' do
|
159
|
+
it 'does not validate' do
|
160
|
+
subject.should_not be_valid
|
161
|
+
subject.should be_invalid
|
162
|
+
subject.errors.should_not be_empty
|
163
|
+
subject.errors.messages.should == errors if defined? errors
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'with DB backend', :db => true do
|
167
|
+
after(:all) do
|
168
|
+
#DatabaseCleaner.clean
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'is not saved' do
|
172
|
+
subject.save.should be_false
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'is not loaded' do
|
176
|
+
models = described_class.find(:all)
|
177
|
+
models.should have_exactly(0).model
|
178
|
+
end
|
179
|
+
end # DB
|
180
|
+
end
|
181
|
+
|
182
|
+
shared_examples_for 'Contract' do
|
183
|
+
it 'summary points to itself (ContractDetails artifact' do
|
184
|
+
subject.summary.should == subject
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'becomes invalid if assigned wrong :sec_type property' do
|
188
|
+
subject.sec_type = 'FOO'
|
189
|
+
subject.should be_invalid
|
190
|
+
subject.errors.messages[:sec_type].should include "should be valid security type"
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'becomes invalid if assigned wrong :right property' do
|
194
|
+
subject.right = 'BAR'
|
195
|
+
subject.should be_invalid
|
196
|
+
subject.errors.messages[:right].should include "should be put, call or none"
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'becomes invalid if assigned wrong :expiry property' do
|
200
|
+
subject.expiry = 'BAR'
|
201
|
+
subject.should be_invalid
|
202
|
+
subject.errors.messages[:expiry].should include "should be YYYYMM or YYYYMMDD"
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'becomes invalid if primary_exchange is set to SMART' do
|
206
|
+
subject.primary_exchange = 'SMART'
|
207
|
+
subject.should be_invalid
|
208
|
+
subject.errors.messages[:primary_exchange].should include "should not be SMART"
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|