battman 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +17 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/battman.gemspec +31 -0
- data/battman_example.rb +57 -0
- data/lib/battman/acpi_battery.rb +64 -0
- data/lib/battman/battery.rb +101 -0
- data/lib/battman/dsl/every_block.rb +31 -0
- data/lib/battman/dsl/watch_block.rb +20 -0
- data/lib/battman/dsl.rb +48 -0
- data/lib/battman/errors.rb +12 -0
- data/lib/battman/smapi_battery.rb +59 -0
- data/lib/battman/version.rb +3 -0
- data/lib/battman.rb +8 -0
- data/spec/lib/battman/acpi_battery_spec.rb +232 -0
- data/spec/lib/battman/battery_spec.rb +111 -0
- data/spec/lib/battman/dsl/every_block_spec.rb +62 -0
- data/spec/lib/battman/dsl/watch_block_spec.rb +27 -0
- data/spec/lib/battman/dsl_spec.rb +137 -0
- data/spec/lib/battman/smapi_battery_spec.rb +173 -0
- data/spec/spec_helper.rb +83 -0
- metadata +204 -0
@@ -0,0 +1,232 @@
|
|
1
|
+
require 'battman/acpi_battery'
|
2
|
+
|
3
|
+
module Battman
|
4
|
+
|
5
|
+
describe AcpiBattery do
|
6
|
+
it 'is a subclass of Battery' do
|
7
|
+
expect(AcpiBattery.new).to be_a Battery
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '.new' do
|
11
|
+
it 'accepts an precision option and sets the corresponding instance variable' do
|
12
|
+
battery = AcpiBattery.new(0, precision: 100)
|
13
|
+
|
14
|
+
expect(battery.instance_variable_get(:@precision)).to eq 100
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'sets precision to 1000 by default' do
|
18
|
+
expect(AcpiBattery.new.instance_variable_get(:@precision)).to eq 1000
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#path' do
|
23
|
+
|
24
|
+
let(:path_prefix) { '/sys/class/power_supply' }
|
25
|
+
|
26
|
+
it 'builds the path for a smapi battery with the correct index' do
|
27
|
+
battery = AcpiBattery.new
|
28
|
+
|
29
|
+
expect(battery.path).to eq File.join(path_prefix, 'BAT0')
|
30
|
+
|
31
|
+
battery = AcpiBattery.new(1)
|
32
|
+
|
33
|
+
expect(battery.path).to eq File.join(path_prefix, 'BAT1')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'sets the corresponding instance variable' do
|
37
|
+
battery = AcpiBattery.new
|
38
|
+
path = battery.path
|
39
|
+
|
40
|
+
expect(battery.instance_variable_get(:@path)).to eq path
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:battery) { AcpiBattery.new }
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
allow(File).to receive(:join).and_call_original
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#remaining_percent' do
|
51
|
+
|
52
|
+
let(:energy_full_file) { File.join(battery.path, 'energy_full') }
|
53
|
+
let(:energy_now_file) { File.join(battery.path, 'energy_now') }
|
54
|
+
|
55
|
+
before(:each) do
|
56
|
+
allow(File).to receive(:read).with(energy_full_file).and_return("1000\n")
|
57
|
+
allow(File).to receive(:read).with(energy_now_file).and_return("100\n")
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'reads the value from the correct files' do
|
61
|
+
battery.remaining_percent
|
62
|
+
|
63
|
+
expect(File).to have_received(:read).with(energy_full_file)
|
64
|
+
expect(File).to have_received(:read).with(energy_now_file)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'calculates the percentage from the read file contents' do
|
68
|
+
expect(battery.remaining_percent).to eq 10
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#power' do
|
74
|
+
|
75
|
+
let(:power_file) { File.join(battery.path, 'power_now') }
|
76
|
+
|
77
|
+
it 'reads the value from the correct file' do
|
78
|
+
allow(File).to receive(:read).with(power_file).and_return("1000000\n")
|
79
|
+
allow(battery).to receive(:state).and_return(:charging)
|
80
|
+
battery.power
|
81
|
+
|
82
|
+
expect(File).to have_received(:read).with(power_file)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'returns the power used in watt' do
|
86
|
+
allow(File).to receive(:read).with(power_file).and_return("1000000\n")
|
87
|
+
allow(battery).to receive(:state).and_return(:charging)
|
88
|
+
|
89
|
+
expect(battery.power).to eq(1.0)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns a negative value if state is :discharging' do
|
93
|
+
allow(File).to receive(:read).with(power_file).and_return("1000000\n")
|
94
|
+
allow(battery).to receive(:state).and_return(:discharging)
|
95
|
+
|
96
|
+
expect(battery.power).to be < 0
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'returns a positive value if state is either :charging or :idle' do
|
100
|
+
allow(File).to receive(:read).with(power_file).and_return("1000000\n")
|
101
|
+
allow(battery).to receive(:state).and_return(:charging)
|
102
|
+
|
103
|
+
expect(battery.power).to be >= 0
|
104
|
+
|
105
|
+
allow(battery).to receive(:state).and_return(:idle)
|
106
|
+
|
107
|
+
expect(battery.power).to be >= 0
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#state" do
|
113
|
+
let(:state_file) { File.join(battery.path, 'status') }
|
114
|
+
|
115
|
+
it 'reads the state from the correct file' do
|
116
|
+
allow(File).to receive(:read).with(state_file).and_return("Discharging\n")
|
117
|
+
battery.state
|
118
|
+
|
119
|
+
expect(File).to have_received(:read).with(state_file)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns the correct state as a symbol' do
|
123
|
+
allow(File).to receive(:read).with(state_file).and_return("Discharging\n")
|
124
|
+
|
125
|
+
expect(battery.state).to eq :discharging
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'returns :idle if state read from file is Unknown' do
|
129
|
+
allow(File).to receive(:read).with(state_file).and_return("Unknown\n")
|
130
|
+
|
131
|
+
expect(battery.state).to eq :idle
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe "#remaining_energy" do
|
136
|
+
let(:energy_file) { File.join(battery.path, 'energy_now') }
|
137
|
+
|
138
|
+
it 'reads the value from the correct file' do
|
139
|
+
allow(File).to receive(:read).with(energy_file).and_return("100000000\n")
|
140
|
+
battery.remaining_energy
|
141
|
+
|
142
|
+
expect(File).to have_received(:read).with(energy_file)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'returns the remaining energy in Wh' do
|
146
|
+
allow(File).to receive(:read).with(energy_file).and_return("100000000\n")
|
147
|
+
|
148
|
+
expect(battery.remaining_energy).to eq 100.0
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe '#remaining_running_time' do
|
153
|
+
it 'calculates the value from the current power and remaining energy' do
|
154
|
+
allow(battery).to receive(:state).and_return(:discharging)
|
155
|
+
allow(battery).to receive(:power).and_return(10.0)
|
156
|
+
allow(battery).to receive(:remaining_energy).and_return(100.0)
|
157
|
+
battery.remaining_running_time
|
158
|
+
|
159
|
+
expect(battery).to have_received(:power)
|
160
|
+
expect(battery).to have_received(:remaining_energy)
|
161
|
+
|
162
|
+
expect(battery.remaining_running_time).to eq 600
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'raises a WrongStateError if the battery is not discharging' do
|
166
|
+
allow(battery).to receive(:power).and_return(10.0)
|
167
|
+
allow(battery).to receive(:remaining_energy).and_return(100.0)
|
168
|
+
|
169
|
+
allow(battery).to receive(:state).and_return(:discharging)
|
170
|
+
battery.remaining_running_time
|
171
|
+
|
172
|
+
allow(battery).to receive(:state).and_return(:idle)
|
173
|
+
|
174
|
+
expect { battery.remaining_running_time }.to raise_error(WrongStateError)
|
175
|
+
|
176
|
+
allow(battery).to receive(:state).and_return(:charging)
|
177
|
+
|
178
|
+
expect { battery.remaining_running_time }.to raise_error(WrongStateError)
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "#full_energy" do
|
184
|
+
let(:energy_file) { File.join(battery.path, 'energy_full') }
|
185
|
+
|
186
|
+
it 'reads the value from the correct file' do
|
187
|
+
allow(File).to receive(:read).with(energy_file).and_return("100000000\n")
|
188
|
+
battery.full_energy
|
189
|
+
|
190
|
+
expect(File).to have_received(:read).with(energy_file)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'returns the remaining energy in Wh' do
|
194
|
+
allow(File).to receive(:read).with(energy_file).and_return("100000000\n")
|
195
|
+
|
196
|
+
expect(battery.full_energy).to eq 100.0
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '#remaining_charging_time' do
|
201
|
+
it 'calculates the value from the current power and remaining energy' do
|
202
|
+
allow(battery).to receive(:state).and_return(:charging)
|
203
|
+
allow(battery).to receive(:power).and_return(10.0)
|
204
|
+
allow(battery).to receive(:remaining_energy).and_return(90.0)
|
205
|
+
allow(battery).to receive(:full_energy).and_return(100.0)
|
206
|
+
battery.remaining_charging_time
|
207
|
+
|
208
|
+
expect(battery).to have_received(:power)
|
209
|
+
expect(battery).to have_received(:remaining_energy)
|
210
|
+
|
211
|
+
expect(battery.remaining_charging_time).to eq 60.0
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'raises a WrongStateError if the battery is not charging' do
|
215
|
+
allow(battery).to receive(:remaining_energy).and_return(90.0)
|
216
|
+
allow(battery).to receive(:power).and_return(10.0)
|
217
|
+
allow(battery).to receive(:full_energy).and_return(100.0)
|
218
|
+
|
219
|
+
allow(battery).to receive(:state).and_return(:charging)
|
220
|
+
battery.remaining_charging_time
|
221
|
+
|
222
|
+
allow(battery).to receive(:state).and_return(:discharging)
|
223
|
+
|
224
|
+
expect { battery.remaining_charging_time }.to raise_error(WrongStateError)
|
225
|
+
|
226
|
+
allow(battery).to receive(:state).and_return(:idle)
|
227
|
+
|
228
|
+
expect { battery.remaining_charging_time }.to raise_error(WrongStateError)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'battman/battery'
|
2
|
+
module Battman
|
3
|
+
describe Battery do
|
4
|
+
|
5
|
+
describe '.new' do
|
6
|
+
|
7
|
+
it 'throws an AbstractError if directly instantiated' do
|
8
|
+
expect { Battery.new }.to raise_error AbstractError
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:subclass) { Class.new(Battery) }
|
12
|
+
|
13
|
+
it 'allows instantiation of subclasses' do
|
14
|
+
subclass.new
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'accepts an index and sets the corresponding instance variable' do
|
18
|
+
battery = subclass.new(1)
|
19
|
+
|
20
|
+
expect(battery.instance_variable_get(:@index)).to eq 1
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'sets index to 0 by default' do
|
24
|
+
battery = subclass.new
|
25
|
+
|
26
|
+
expect(battery.instance_variable_get(:@index)).to eq 0
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:battery) { Class.new(Battery).new }
|
32
|
+
|
33
|
+
[:remaining_percent, :power, :remaining_running_time,
|
34
|
+
:remaining_charging_time, :state, :remaining_energy,
|
35
|
+
:full_energy].each do |method|
|
36
|
+
|
37
|
+
describe "##{method}" do
|
38
|
+
|
39
|
+
it 'throws an NotImplementedError' do
|
40
|
+
expect { battery.send(method) }.to raise_error NotImplementedError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
describe '#power_in' do
|
47
|
+
it 'requires a unit argument' do
|
48
|
+
expect { battery.power_in }.to raise_error(ArgumentError)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'only accepts units from CONVERSIONS[:power]' do
|
52
|
+
expect { battery.power_in(:unsupported_unit) }.to raise_error(UnsupportedUnitError)
|
53
|
+
|
54
|
+
allow(battery).to receive(:power).and_return(10.0)
|
55
|
+
battery.power_in(Battery::CONVERSIONS[:power].keys.sample)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'converts the power from watts to the given unit' do
|
59
|
+
allow(battery).to receive(:power).and_return(10.0)
|
60
|
+
|
61
|
+
expect(battery.power_in(:watts)).to eq 10.0
|
62
|
+
expect(battery.power_in(:milliwatts)).to eq 10_000.0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
[:remaining_running_time, :remaining_charging_time].each do |method|
|
67
|
+
describe "#{method}_in" do
|
68
|
+
it 'requires a unit argument' do
|
69
|
+
expect { battery.send(:"#{method}_in") }.to raise_error(ArgumentError)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'only accepts units from CONVERSIONS[:time]' do
|
73
|
+
expect { battery.send(:"#{method}_in", :unsupported_unit) }.to raise_error(UnsupportedUnitError)
|
74
|
+
|
75
|
+
allow(battery).to receive(method).and_return(10.0)
|
76
|
+
battery.send(:"#{method}_in", Battery::CONVERSIONS[:time].keys.sample)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'converts the time from seconds to the given unit' do
|
80
|
+
allow(battery).to receive(method).and_return(3600.0)
|
81
|
+
|
82
|
+
expect(battery.send(:"#{method}_in", :seconds)).to eq 3600.0
|
83
|
+
expect(battery.send(:"#{method}_in", :minutes)).to eq 60.0
|
84
|
+
expect(battery.send(:"#{method}_in", :hours)).to eq 1.0
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
[:remaining_energy, :full_energy].each do |method|
|
90
|
+
describe "#{method}_in" do
|
91
|
+
it 'requires a unit argument' do
|
92
|
+
expect { battery.send(:"#{method}_in") }.to raise_error(ArgumentError)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'only accepts units from CONVERSIONS[:energy]' do
|
96
|
+
expect { battery.send(:"#{method}_in", :unsupported_unit) }.to raise_error(UnsupportedUnitError)
|
97
|
+
|
98
|
+
allow(battery).to receive(method).and_return(10.0)
|
99
|
+
battery.send(:"#{method}_in", Battery::CONVERSIONS[:energy].keys.sample)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'converts the time from watt hours to the given unit' do
|
103
|
+
allow(battery).to receive(method).and_return(10.0)
|
104
|
+
|
105
|
+
expect(battery.send(:"#{method}_in", :watt_hours)).to eq 10.0
|
106
|
+
expect(battery.send(:"#{method}_in", :milliwatt_hours)).to eq 10_000.0
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'battman/dsl/every_block'
|
2
|
+
|
3
|
+
module Battman
|
4
|
+
module DSL
|
5
|
+
describe EveryBlock do
|
6
|
+
|
7
|
+
describe '#check' do
|
8
|
+
|
9
|
+
let(:dsl) { double('DSL') }
|
10
|
+
let(:battery) { double('Battery') }
|
11
|
+
let(:state) { EveryBlock.new(dsl, battery, 10) }
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
allow(battery).to receive(:power_in).with(:milliwatts)
|
15
|
+
allow(battery).to receive(:remaining_percent)
|
16
|
+
allow(dsl).to receive(:register)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'expects a battery attribute and a block' do
|
20
|
+
expect { state.check }.to raise_error(ArgumentError)
|
21
|
+
expect { state.check(:remaining_percent) }.to raise_error(ArgumentError)
|
22
|
+
state.check(:remaining_percent) {}
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'allows additional arguments to pass methods' do
|
26
|
+
state.check(:power_in, :milliwatts) {}
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'correctly registers a block on the dsl instance' do
|
30
|
+
task_was_called = false
|
31
|
+
value_passed = nil
|
32
|
+
last_value_passed = nil
|
33
|
+
task = Proc.new do |value, last_value|
|
34
|
+
task_was_called = true
|
35
|
+
value_passed = value
|
36
|
+
last_value_passed = last_value
|
37
|
+
end
|
38
|
+
|
39
|
+
expect(dsl).to receive(:register) do |interval, block|
|
40
|
+
expect(interval).to eq 10
|
41
|
+
|
42
|
+
expect(battery).to receive(:power_in).with(:milliwatts).and_return(10_000.0)
|
43
|
+
block.call
|
44
|
+
|
45
|
+
expect(task_was_called)
|
46
|
+
expect(value_passed).to eq 10_000.0
|
47
|
+
expect(last_value_passed).to be nil
|
48
|
+
|
49
|
+
expect(battery).to receive(:power_in).with(:milliwatts).and_return(9_000.0)
|
50
|
+
block.call
|
51
|
+
|
52
|
+
expect(value_passed).to eq 9_000.0
|
53
|
+
expect(last_value_passed).to eq 10_000.0
|
54
|
+
end
|
55
|
+
|
56
|
+
state.check(:power_in, :milliwatts, &task)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'battman/dsl/watch_block'
|
2
|
+
|
3
|
+
module Battman
|
4
|
+
module DSL
|
5
|
+
describe WatchBlock do
|
6
|
+
let(:dsl) { double('DSL') }
|
7
|
+
let(:battery) { double('Battery') }
|
8
|
+
let(:watcher) { WatchBlock.new(dsl, battery) }
|
9
|
+
|
10
|
+
describe '#every' do
|
11
|
+
it 'expects an interval in seconds and a block' do
|
12
|
+
expect { watcher.every }.to raise_error(ArgumentError)
|
13
|
+
expect { watcher.every(10) }.to raise_error(ArgumentError)
|
14
|
+
|
15
|
+
watcher.every(10) {}
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'yields an object that responds to check' do
|
19
|
+
expect {|b| watcher.every(10, &b) }.to yield_with_args do |arg|
|
20
|
+
expect(arg).to respond_to(:check)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'battman/dsl'
|
2
|
+
require 'battman/smapi_battery'
|
3
|
+
require 'active_support/core_ext/numeric/time'
|
4
|
+
|
5
|
+
module Battman
|
6
|
+
describe DSL do
|
7
|
+
|
8
|
+
let(:dsl) { Class.new { include DSL }.new }
|
9
|
+
|
10
|
+
describe '.new' do
|
11
|
+
it 'initializes @blocks correctly' do
|
12
|
+
blocks = dsl.instance_variable_get(:@blocks)
|
13
|
+
expect(blocks).not_to be nil
|
14
|
+
expect(blocks[2]).to eq []
|
15
|
+
|
16
|
+
blocks[4] << :foo
|
17
|
+
blocks[4] << :bar
|
18
|
+
expect(blocks[4]).to eq [:foo, :bar]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'initializes @intervals_due correctly' do
|
22
|
+
intervals_due = dsl.instance_variable_get(:@intervals_due)
|
23
|
+
|
24
|
+
expect(intervals_due[1]).to eq 0
|
25
|
+
expect(intervals_due[:anything]).to eq 0
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'yields self if given a block' do
|
29
|
+
expect {|b| Class.new { include DSL }.new(&b) }.to yield_with_args(DSL)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#watch' do
|
34
|
+
|
35
|
+
it 'instantiates a battery of given type' do
|
36
|
+
expect(SmapiBattery).to receive(:new)
|
37
|
+
|
38
|
+
dsl.watch(:smapi) {}
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'expects a valid type and a block' do
|
42
|
+
expect { dsl.watch }.to raise_error(ArgumentError)
|
43
|
+
expect { dsl.watch(:type) }.to raise_error(ArgumentError)
|
44
|
+
expect { dsl.watch(:invalid_type) {} }.to raise_error(LoadError)
|
45
|
+
|
46
|
+
dsl.watch(:smapi) {}
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'yields a WatchBlock' do
|
50
|
+
expect {|b| dsl.watch(:smapi, &b) }.to yield_with_args(DSL::WatchBlock)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#register' do
|
56
|
+
|
57
|
+
it 'adds a given block to the blocks hash' do
|
58
|
+
first_block = Proc.new {}
|
59
|
+
second_block = Proc.new {}
|
60
|
+
dsl.register(1, first_block)
|
61
|
+
dsl.register(1, second_block)
|
62
|
+
|
63
|
+
expect(dsl.instance_variable_get(:@blocks)[1]).to eq [first_block, second_block]
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'sets the greatest common interval correctly' do
|
67
|
+
dsl.register(4, Proc.new {})
|
68
|
+
expect(dsl.instance_variable_get(:@greatest_common_interval)).to eq 4
|
69
|
+
|
70
|
+
dsl.register(8, Proc.new {})
|
71
|
+
expect(dsl.instance_variable_get(:@greatest_common_interval)).to eq 4
|
72
|
+
|
73
|
+
dsl.register(10, Proc.new {})
|
74
|
+
expect(dsl.instance_variable_get(:@greatest_common_interval)).to eq 2
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#run_once' do
|
80
|
+
let(:blocks) do
|
81
|
+
blocks = Hash.new {|hash, key| hash[key] = []}
|
82
|
+
3.times do |i|
|
83
|
+
block = double('proc')
|
84
|
+
allow(block).to receive(:call)
|
85
|
+
blocks[2**(i+1)] << block
|
86
|
+
end
|
87
|
+
|
88
|
+
blocks
|
89
|
+
end
|
90
|
+
|
91
|
+
let(:greatest_common_interval) { blocks.keys.inject(:gcd) }
|
92
|
+
|
93
|
+
before(:each) do
|
94
|
+
dsl.instance_variable_set(:@blocks, blocks)
|
95
|
+
dsl.instance_variable_set(:@greatest_common_interval, greatest_common_interval)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'calls all registered blocks on the first run' do
|
99
|
+
blocks.values.inject(&:+).each do |block|
|
100
|
+
expect(block).to receive(:call).once
|
101
|
+
end
|
102
|
+
|
103
|
+
dsl.run_once
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'sets the correct schedules for blocks in @intervals_due' do
|
107
|
+
expected_schedule = {}
|
108
|
+
blocks.keys.each do |interval|
|
109
|
+
expected_schedule[interval] = interval
|
110
|
+
end
|
111
|
+
|
112
|
+
dsl.run_once
|
113
|
+
expect(dsl.instance_variable_get(:@intervals_due)).to eq expected_schedule
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'calls only scheduled blocks on consecutive runs' do
|
117
|
+
dsl.run_once
|
118
|
+
dsl.run_once
|
119
|
+
|
120
|
+
blocks[greatest_common_interval].each do |block|
|
121
|
+
expect(block).to have_received(:call).twice
|
122
|
+
end
|
123
|
+
|
124
|
+
dsl.run_once
|
125
|
+
|
126
|
+
blocks[greatest_common_interval].each do |block|
|
127
|
+
expect(block).to have_received(:call).exactly(3).times
|
128
|
+
end
|
129
|
+
|
130
|
+
blocks[greatest_common_interval * 2].each do |block|
|
131
|
+
expect(block).to have_received(:call).twice
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|