battman 0.0.1
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.
- 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
|