shrewd 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/README.md +416 -0
- data/Rakefile +0 -0
- data/lib/shrewd.rb +1 -0
- data/lib/shrewd/entities/event.rb +56 -0
- data/lib/shrewd/entities/process.rb +83 -0
- data/lib/shrewd/entities/variable.rb +58 -0
- data/lib/shrewd/simulation.rb +166 -0
- data/shrewd.gemspec +14 -0
- data/spec/integration/simple_spec.rb +145 -0
- data/spec/models/event_spec.rb +50 -0
- data/spec/models/process_spec.rb +51 -0
- data/spec/models/simulation_spec.rb +180 -0
- data/spec/models/variable_spec.rb +195 -0
- data/spec/spec_helper.rb +15 -0
- metadata +61 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# EventSpec
|
2
|
+
#
|
3
|
+
# Tests for the Shrewd::EventSpec class
|
4
|
+
|
5
|
+
require 'shrewd/simulation'
|
6
|
+
require 'shrewd/entities/event'
|
7
|
+
require 'shrewd/entities/process'
|
8
|
+
|
9
|
+
describe Shrewd::Event do
|
10
|
+
|
11
|
+
# Shared variables
|
12
|
+
let(:name) { 'Initial' }
|
13
|
+
let(:description) { 'Description' }
|
14
|
+
let(:processes) { [ Shrewd::Process.new('Process1'),
|
15
|
+
Shrewd::Process.new('Process2') ] }
|
16
|
+
|
17
|
+
describe "initialization" do
|
18
|
+
|
19
|
+
context "with name only" do
|
20
|
+
before :each do
|
21
|
+
@event = Shrewd::Event.new(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be valid" do
|
25
|
+
expect(@event).to be_an_instance_of Shrewd::Event
|
26
|
+
expect(@event.name).to eql name
|
27
|
+
expect(@event.description).to be_empty
|
28
|
+
expect(@event.processes).to eql Array.new
|
29
|
+
expect(@event.action).to be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with all parameters" do
|
35
|
+
let(:action) { Proc.new { |variables| } }
|
36
|
+
|
37
|
+
before :each do
|
38
|
+
@event = Shrewd::Event.new(name, description, processes, action)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should be valid" do
|
42
|
+
expect(@event).to be_an_instance_of Shrewd::Event
|
43
|
+
expect(@event.name).to eql name
|
44
|
+
expect(@event.description).to eql description
|
45
|
+
expect(@event.processes).to eql processes
|
46
|
+
expect(@event.action).to eql action
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# ProcessSpec
|
2
|
+
#
|
3
|
+
# Tests for Shrewd::ProcessSpec class
|
4
|
+
|
5
|
+
module Shrewd
|
6
|
+
require 'shrewd/entities/process'
|
7
|
+
require 'shrewd/entities/event'
|
8
|
+
end
|
9
|
+
|
10
|
+
describe Shrewd::Process do
|
11
|
+
|
12
|
+
describe "initialization" do
|
13
|
+
let(:name) { 'Service Event' }
|
14
|
+
let(:description) { 'Servicing a customer.' }
|
15
|
+
let(:event) { Shrewd::Event.new('Event') }
|
16
|
+
let(:conditions) { Proc.new { |variables| true } }
|
17
|
+
let(:delay) { Proc.new { |variables| 15 } }
|
18
|
+
|
19
|
+
context "with only name" do
|
20
|
+
before :each do
|
21
|
+
@process = Shrewd::Process.new(name)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be valid" do
|
25
|
+
expect(@process).to be_an_instance_of Shrewd::Process
|
26
|
+
expect(@process.name).to eql name
|
27
|
+
expect(@process.description).to be_empty
|
28
|
+
expect(@process.event).to be_nil
|
29
|
+
expect(@process.conditions).to be_nil
|
30
|
+
expect(@process.delay).to be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with all parameters" do
|
35
|
+
before :each do
|
36
|
+
@process = Shrewd::Process.new(name, description,
|
37
|
+
event, conditions, delay)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should be valid" do
|
41
|
+
expect(@process).to be_an_instance_of Shrewd::Process
|
42
|
+
expect(@process.name).to eql name
|
43
|
+
expect(@process.description).to eql description
|
44
|
+
expect(@process.event).to eql event
|
45
|
+
expect(@process.conditions).to eql conditions
|
46
|
+
expect(@process.delay).to eql delay
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# SimulationSpec
|
2
|
+
#
|
3
|
+
# Tests for the Shrewd::Simulation class
|
4
|
+
|
5
|
+
require 'shrewd/simulation'
|
6
|
+
|
7
|
+
describe Shrewd::Simulation do
|
8
|
+
|
9
|
+
# Shared variables
|
10
|
+
let(:state_variables) { [ Shrewd::Variable.new('Queue'),
|
11
|
+
Shrewd::Variable.new('Employees', '', 5)] }
|
12
|
+
let(:process_length) { 20 }
|
13
|
+
let(:simulation_length) { 1000 }
|
14
|
+
let(:initial_processes) do
|
15
|
+
process = Shrewd::Process.new('Process1')
|
16
|
+
process.delay = Proc.new { process_length }
|
17
|
+
|
18
|
+
event = Shrewd::Event.new('Arrival')
|
19
|
+
event.processes << process
|
20
|
+
process.event = event
|
21
|
+
|
22
|
+
[ process ]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create a simulation instance before each test
|
26
|
+
before :each do
|
27
|
+
@simulation = Shrewd::Simulation.new(state_variables, initial_processes)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Validate new simulation instance
|
31
|
+
describe "#new" do
|
32
|
+
it "should be a simulation" do
|
33
|
+
expect(@simulation).to be_an_instance_of Shrewd::Simulation
|
34
|
+
end
|
35
|
+
|
36
|
+
it "instantiates variables correctly" do
|
37
|
+
variables = @simulation.instance_variable_get(:@variables)
|
38
|
+
expect(variables).to be_an_instance_of Hash
|
39
|
+
|
40
|
+
variables.values.each do |variable|
|
41
|
+
expect(variable).to be_an_instance_of Shrewd::Variable
|
42
|
+
end
|
43
|
+
|
44
|
+
variables.each do |key, value|
|
45
|
+
expect(key).to eql value.name.downcase.gsub(/\s+/,"_").to_sym
|
46
|
+
end
|
47
|
+
|
48
|
+
expect(@simulation.initial_processes).to be_an_instance_of Array
|
49
|
+
expect(@simulation.initial_processes).to eql initial_processes
|
50
|
+
|
51
|
+
@simulation.initial_processes.each do |process|
|
52
|
+
expect(process).to be_an_instance_of Shrewd::Process
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#start" do
|
58
|
+
before :each do
|
59
|
+
@simulation.start(simulation_length)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "generates a start event" do
|
63
|
+
expect(@simulation.print_log.size).to eql (simulation_length/process_length) + 1
|
64
|
+
expect(@simulation.print_log.first[:event].name).to eql 'Start'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#print_log" do
|
69
|
+
it "generates a log" do
|
70
|
+
expect(@simulation.print_log).to be_an_instance_of Array
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#create_initial_event" do
|
75
|
+
before :each do
|
76
|
+
@simulation.send(:create_initial_event)
|
77
|
+
@queue = @simulation.instance_variable_get(:@queue)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "adds initial event to the queue" do
|
81
|
+
expect(@queue.size).to eql 1
|
82
|
+
end
|
83
|
+
|
84
|
+
it "creates initial event" do
|
85
|
+
initial_event = @queue.first[:event]
|
86
|
+
expect(initial_event).to be_an_instance_of Shrewd::Event
|
87
|
+
expect(initial_event.name).to eql 'Start'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "adds initial processes to initial event" do
|
91
|
+
initial_event = @queue.first[:event]
|
92
|
+
expect(initial_event.processes.size).to be > 0
|
93
|
+
expect(initial_event.processes).to eql initial_processes
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#add_to_queue" do
|
98
|
+
let(:first_name) { 'First' }
|
99
|
+
let(:first_time) { 5 }
|
100
|
+
let(:second_name) { 'Second' }
|
101
|
+
let(:second_time) { 10 }
|
102
|
+
let(:third_name) { 'Third' }
|
103
|
+
let(:third_time) { 7 }
|
104
|
+
let(:fourth_name) { 'Fourth' }
|
105
|
+
let(:fourth_time) { 3 }
|
106
|
+
|
107
|
+
before :each do
|
108
|
+
@initial_event = Shrewd::Event.new(first_name)
|
109
|
+
@simulation.send(:add_to_queue, { time: first_time, event: @initial_event })
|
110
|
+
@queue = @simulation.instance_variable_get(:@queue)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "adds an event to the queue" do
|
114
|
+
expect(@queue).to be_an_instance_of Array
|
115
|
+
expect(@queue).to_not be_empty
|
116
|
+
expect(@queue.first[:event].name).to eql first_name
|
117
|
+
expect(@queue.first[:time]).to eql first_time
|
118
|
+
end
|
119
|
+
|
120
|
+
# Test base binary search
|
121
|
+
context "multiples events" do
|
122
|
+
before :each do
|
123
|
+
@second_event = Shrewd::Event.new(second_name)
|
124
|
+
@simulation.send(:add_to_queue, { time: second_time,
|
125
|
+
event: @second_event })
|
126
|
+
end
|
127
|
+
|
128
|
+
it "adds second event to the queue" do
|
129
|
+
expect(@queue.size).to eql 2
|
130
|
+
expect(@queue[1][:event].name).to eql second_name
|
131
|
+
expect(@queue[1][:time]).to eql second_time
|
132
|
+
end
|
133
|
+
|
134
|
+
context "with third and fourth event" do
|
135
|
+
before :each do
|
136
|
+
@third_event = Shrewd::Event.new(third_name)
|
137
|
+
@fourth_event = Shrewd::Event.new(fourth_name)
|
138
|
+
|
139
|
+
@simulation.send(:add_to_queue, { time: third_time,
|
140
|
+
event: @third_event })
|
141
|
+
@simulation.send(:add_to_queue, { time: fourth_time,
|
142
|
+
event: @fourth_event })
|
143
|
+
end
|
144
|
+
|
145
|
+
it "adds third and fourth events to the queue" do
|
146
|
+
expect(@queue.size).to eql 4
|
147
|
+
end
|
148
|
+
|
149
|
+
it "places events in order" do
|
150
|
+
time = 0
|
151
|
+
@queue.each do |item|
|
152
|
+
expect(item[:time]).to be > time
|
153
|
+
time = item[:time]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "#reset" do
|
161
|
+
before :each do
|
162
|
+
@simulation.start(1000)
|
163
|
+
@simulation.reset
|
164
|
+
end
|
165
|
+
|
166
|
+
it "resets system state" do
|
167
|
+
log = @simulation.print_log
|
168
|
+
queue = @simulation.instance_variable_get(:@queue)
|
169
|
+
clock = @simulation.instance_variable_get(:@clock)
|
170
|
+
variables = @simulation.instance_variable_get(:@variables)
|
171
|
+
initial = @simulation.instance_variable_get(:@initial_state)
|
172
|
+
|
173
|
+
expect(log).to be_empty
|
174
|
+
expect(queue).to be_empty
|
175
|
+
expect(clock).to eql 0
|
176
|
+
expect(variables).to eql initial
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# VariableSpec
|
2
|
+
#
|
3
|
+
# Tests for the Shrewd::Variable class
|
4
|
+
|
5
|
+
require 'shrewd/entities/variable'
|
6
|
+
|
7
|
+
describe Shrewd::Variable do
|
8
|
+
|
9
|
+
# Shared variables
|
10
|
+
let(:name) { 'Queue' }
|
11
|
+
let(:description) { 'Number of people in line.' }
|
12
|
+
let(:initial_value) { 5 }
|
13
|
+
|
14
|
+
describe "initialization" do
|
15
|
+
|
16
|
+
# Common examples for validating a variable
|
17
|
+
shared_examples "valid variable" do
|
18
|
+
|
19
|
+
it "should be a variable" do
|
20
|
+
expect(@variable).to be_an_instance_of Shrewd::Variable
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should have the correct properties" do
|
24
|
+
expect(@variable.name).to eql name
|
25
|
+
expect(@variable.description).to eql description
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when default value provided" do
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
@variable = Shrewd::Variable.new(name, description, initial_value)
|
34
|
+
end
|
35
|
+
|
36
|
+
include_examples "valid variable"
|
37
|
+
|
38
|
+
it "should have the provided default value" do
|
39
|
+
expect(@variable.value).to eql initial_value
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when no default value provided" do
|
45
|
+
|
46
|
+
before :each do
|
47
|
+
@variable = Shrewd::Variable.new(name, description)
|
48
|
+
end
|
49
|
+
|
50
|
+
include_examples "valid variable"
|
51
|
+
|
52
|
+
it "should have a default of 0" do
|
53
|
+
expect(@variable.value).to eql 0
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "increment" do
|
61
|
+
|
62
|
+
let(:positive_amount) { 4 }
|
63
|
+
let(:negative_amount) { -2 }
|
64
|
+
|
65
|
+
before :each do
|
66
|
+
@variable = Shrewd::Variable.new(name, description, initial_value)
|
67
|
+
end
|
68
|
+
|
69
|
+
context "by default amount" do
|
70
|
+
|
71
|
+
before :each do
|
72
|
+
@variable.increment
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should add one to initial value" do
|
76
|
+
expected_value = initial_value + 1
|
77
|
+
expect(@variable.value).to eql expected_value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "by positive amount" do
|
82
|
+
|
83
|
+
before :each do
|
84
|
+
@variable.increment positive_amount
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should add positive amount to initial value" do
|
88
|
+
expected_value = initial_value + positive_amount
|
89
|
+
expect(@variable.value).to eql expected_value
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
context "by negative amount" do
|
95
|
+
|
96
|
+
before :each do
|
97
|
+
@variable.increment negative_amount
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should subtract negative amount from initial value" do
|
101
|
+
expected_value = initial_value + negative_amount
|
102
|
+
expect(@variable.value).to eql expected_value
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "decrement" do
|
109
|
+
|
110
|
+
let(:positive_amount) { 2 }
|
111
|
+
let(:negative_amount) { -2 }
|
112
|
+
|
113
|
+
before :each do
|
114
|
+
@variable = Shrewd::Variable.new(name, description, initial_value)
|
115
|
+
end
|
116
|
+
|
117
|
+
context "by default amount" do
|
118
|
+
|
119
|
+
before :each do
|
120
|
+
@variable.decrement
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should subtract one from initial value" do
|
124
|
+
expected_value = initial_value - 1
|
125
|
+
expect(@variable.value).to eql expected_value
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context "by provided positive amount" do
|
130
|
+
|
131
|
+
before :each do
|
132
|
+
@variable.decrement positive_amount
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should subtract positive amount from initial value" do
|
136
|
+
expected_value = initial_value - positive_amount
|
137
|
+
expect(@variable.value).to eql expected_value
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
context "by provided negative amount" do
|
143
|
+
|
144
|
+
before :each do
|
145
|
+
@variable.decrement negative_amount
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should add negative amount to initial value" do
|
149
|
+
expected_value = initial_value - negative_amount
|
150
|
+
expect(@variable.value).to eql expected_value
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "compare" do
|
157
|
+
|
158
|
+
context "with self" do
|
159
|
+
before :each do
|
160
|
+
@variable1 = Shrewd::Variable.new(name, description, initial_value)
|
161
|
+
@variable2 = @variable1
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should be equal" do
|
165
|
+
expect(@variable1 == @variable2.value).to be true
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "with variable with same value" do
|
170
|
+
before :each do
|
171
|
+
@variable1 = Shrewd::Variable.new(name, description, initial_value)
|
172
|
+
@variable2 = Shrewd::Variable.new(name, description, initial_value)
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should be equal" do
|
176
|
+
expect(@variable1 == @variable2.value).to be true
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "with a variable with different value" do
|
181
|
+
let(:different_value) { initial_value + 3 }
|
182
|
+
|
183
|
+
before :each do
|
184
|
+
@variable1 = Shrewd::Variable.new(name, description, initial_value)
|
185
|
+
@variable2 = Shrewd::Variable.new(name, description, different_value)
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should not be equal" do
|
189
|
+
expect(@variable1 == @variable2.value).to be false
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|