precedence 0.6.0
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/CHANGELOG +5 -0
- data/README +63 -0
- data/TODO +22 -0
- data/lib/precedence/activity.rb +251 -0
- data/lib/precedence/network.rb +187 -0
- data/lib/precedence.rb +2 -0
- data/tests/tc_activity.rb +343 -0
- data/tests/tc_network.rb +208 -0
- data/tests/ts_precedence.rb +14 -0
- metadata +50 -0
data/CHANGELOG
ADDED
data/README
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
= Precedence
|
2
|
+
|
3
|
+
Precedence is a library that allows for the creation, manipulation and analysis
|
4
|
+
of precedence networks.
|
5
|
+
|
6
|
+
== Download and Install
|
7
|
+
|
8
|
+
Available as a RubyGem from Rubyforge. To install
|
9
|
+
$ gem install precedence
|
10
|
+
will fetch the latest gem from Rubyforge and install it.
|
11
|
+
|
12
|
+
Source can also be downloaded from http://rubyforge.org/projects/precedence.
|
13
|
+
|
14
|
+
== Example Usage
|
15
|
+
require('precedence')
|
16
|
+
|
17
|
+
# Set up network
|
18
|
+
net = Precedence::Network.new('Begin','End')
|
19
|
+
net.new_activity('act-1-1',3,'System specification')
|
20
|
+
net.new_activity('act-1-2',2,'Review')
|
21
|
+
net.new_activity('act-1-3',2,'System re-specification')
|
22
|
+
net.new_activity('act-2-1',3,'Test tool design')
|
23
|
+
net.new_activity('act-2-2',5,'Test tool implementation')
|
24
|
+
net.new_activity('act-3-1',3,'System design')
|
25
|
+
net.new_activity('act-3-2',12,'System implementation')
|
26
|
+
net.new_activity('act-2-3',10,'System testing')
|
27
|
+
net.connect('act-1-1','act-1-2')
|
28
|
+
net.connect('act-1-2','act-1-3')
|
29
|
+
net.connect('act-1-3','act-3-1')
|
30
|
+
net.connect('act-1-2','act-2-1')
|
31
|
+
net.connect('act-2-1','act-2-2')
|
32
|
+
net.connect('act-2-2','act-3-2')
|
33
|
+
net.connect('act-3-1','act-3-2')
|
34
|
+
net.connect('act-3-2','act-2-3')
|
35
|
+
net.fix_connections!
|
36
|
+
|
37
|
+
# Generate a diagram
|
38
|
+
File.open('network.dot',File::CREAT|File::TRUNC|File::WRONLY) do|file|
|
39
|
+
file.puts(net.to_dot)
|
40
|
+
end
|
41
|
+
system("dot","-Tpng","-onetwork.png","network.dot")
|
42
|
+
|
43
|
+
# Perform some analysis of the activities
|
44
|
+
activity = net.activities['act-1-2']
|
45
|
+
activity.on_critical_path? # => true
|
46
|
+
activity.earliest_start # => 3.0
|
47
|
+
activity.latest_finish # => 5.0
|
48
|
+
activity.total_float # => 0 - activities on the critical path have no float
|
49
|
+
|
50
|
+
== Documentation
|
51
|
+
|
52
|
+
The Precedence API online documentation is available at
|
53
|
+
http://precedence.rubyforge.org.
|
54
|
+
|
55
|
+
Refer to the CHANGELOG and TODO files for past changes and upcoming plans.
|
56
|
+
|
57
|
+
== Credits
|
58
|
+
|
59
|
+
Farrel Lifson <farrel@lifson.info>
|
60
|
+
|
61
|
+
== License
|
62
|
+
|
63
|
+
This software is made available under the BSD license.
|
data/TODO
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
= To Do
|
2
|
+
|
3
|
+
I plan on adding the following leading up to a 1.0 release
|
4
|
+
|
5
|
+
== 0.7
|
6
|
+
|
7
|
+
* Adding resource usage (money, coffee, bulldozers) to each activity.
|
8
|
+
* Saving and loading precedence networks (probably using YAML).
|
9
|
+
|
10
|
+
== 0.8
|
11
|
+
|
12
|
+
* Adding an 'each_day' method to the network that will return the set of
|
13
|
+
activities used on that day.
|
14
|
+
* Calculating daily resource usage and generating some graphs from that.
|
15
|
+
|
16
|
+
== 0.9
|
17
|
+
|
18
|
+
* Generating Gantt charts
|
19
|
+
|
20
|
+
== 1.0 and further
|
21
|
+
|
22
|
+
* Some probability based reasoning using Beta/Normal distributions.
|
@@ -0,0 +1,251 @@
|
|
1
|
+
module Precedence
|
2
|
+
|
3
|
+
# A representation of an activity in a precedence network. Each activity
|
4
|
+
# has a user specified reference, description and duration. When activities
|
5
|
+
# are connected (via the add_post/pre_activities functions) then various
|
6
|
+
# other properties of the activity can be determined such as it's earliest
|
7
|
+
# finish time, float and so on.
|
8
|
+
#
|
9
|
+
|
10
|
+
class Activity
|
11
|
+
|
12
|
+
# A textual description of the activity.
|
13
|
+
attr_accessor :description
|
14
|
+
# The time the activity will take to complete.
|
15
|
+
attr_accessor :duration
|
16
|
+
# A unique reference for this activity.
|
17
|
+
attr_reader :reference
|
18
|
+
# The collection of activites that are dependent on the completion of
|
19
|
+
# this activity.
|
20
|
+
attr_reader :post_activities
|
21
|
+
# The collection of activities that this activity depends on before it
|
22
|
+
# can begin executing.
|
23
|
+
attr_reader :pre_activities
|
24
|
+
|
25
|
+
# Creates a new activity. The post_activities and pre_activities
|
26
|
+
# collections should contain the activities themselves and not their
|
27
|
+
# references.
|
28
|
+
#
|
29
|
+
# *Note*: When assigning a reference for an activity 'start' and
|
30
|
+
# 'finish' are reserved for internal usage.
|
31
|
+
def initialize(reference,duration=0,description="",post_activities=[],
|
32
|
+
pre_activities=[])
|
33
|
+
if (reference.to_s == 'start') || (reference.to_s == 'finish')
|
34
|
+
raise "The reference '#{reference.to_s}' is reserved"
|
35
|
+
end
|
36
|
+
@reference = reference.to_s
|
37
|
+
@description = description.to_s
|
38
|
+
@duration = duration.to_f
|
39
|
+
@post_activities = post_activities.to_a
|
40
|
+
@pre_activities = pre_activities.to_a
|
41
|
+
end
|
42
|
+
|
43
|
+
# Adds the activities in the parameter list to the post_activities
|
44
|
+
# collection of this activity and also adds this activity to the
|
45
|
+
# pre_activities collection of each of the activities.
|
46
|
+
def add_post_activities(*post_activities)
|
47
|
+
post_activities.each do |activity|
|
48
|
+
activity.register_pre_activity(self)
|
49
|
+
register_post_activity(activity)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Adds the activities in the parameter list to the pre_activities
|
54
|
+
# collection of this activity and also adds this activity to the
|
55
|
+
# post_activities collection of each of the activities.
|
56
|
+
def add_pre_activities(*pre_activities)
|
57
|
+
pre_activities.each do |activity|
|
58
|
+
activity.register_post_activity(self)
|
59
|
+
register_pre_activity(activity)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Removes the list of activities from the post_activities collection of
|
64
|
+
# the activity.
|
65
|
+
def remove_post_activities(*post_activities)
|
66
|
+
post_activities.each do |activity|
|
67
|
+
activity.deregister_pre_activity(self)
|
68
|
+
deregister_post_activity(activity)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Removes the list of activities from the pre_activities collection of
|
73
|
+
# the activity.
|
74
|
+
def remove_pre_activities(*post_activities)
|
75
|
+
post_activities.each do |activity|
|
76
|
+
activity.deregister_post_activity(self)
|
77
|
+
deregister_pre_activity(activity)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# The earliest possible time this activity can finish.
|
82
|
+
def earliest_finish
|
83
|
+
return @duration + earliest_start
|
84
|
+
end
|
85
|
+
|
86
|
+
# The earliest possible time this activity can start.
|
87
|
+
def earliest_start
|
88
|
+
unless @pre_activities.empty?
|
89
|
+
(@pre_activities.max do |a,b|
|
90
|
+
a.earliest_finish <=> b.earliest_finish
|
91
|
+
end).earliest_finish
|
92
|
+
else
|
93
|
+
0.0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# The latest possible time this activity can start so as not to delay
|
98
|
+
# any dependent activities.
|
99
|
+
def latest_start
|
100
|
+
return latest_finish - @duration
|
101
|
+
end
|
102
|
+
|
103
|
+
# The latest possible time this activity can finish so as not to delay
|
104
|
+
# any dependent activities.
|
105
|
+
def latest_finish
|
106
|
+
unless @post_activities.empty?
|
107
|
+
(@post_activities.min do |a,b|
|
108
|
+
a.latest_start <=> b.latest_start
|
109
|
+
end).latest_start
|
110
|
+
else
|
111
|
+
return earliest_finish
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# The maximum earliest finish of this activities pre-activities.
|
116
|
+
def pre_activities_max_earliest_finish
|
117
|
+
unless @pre_activities.empty?
|
118
|
+
(@pre_activities.max do |a,b|
|
119
|
+
a.earliest_finish <=> b.earliest_finish
|
120
|
+
end).earliest_finish
|
121
|
+
else
|
122
|
+
return 0
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# The minimum earliest start of this activities post-activities.
|
127
|
+
def post_activities_min_earliest_start
|
128
|
+
unless @post_activities.empty?
|
129
|
+
(@post_activities.min do |a,b|
|
130
|
+
a.earliest_start <=> b.earliest_start
|
131
|
+
end).earliest_start
|
132
|
+
else
|
133
|
+
return latest_finish
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# If the activity is on the critical path returns true, returns false
|
138
|
+
# otherwise.
|
139
|
+
def on_critical_path?
|
140
|
+
if earliest_finish == latest_finish
|
141
|
+
return true
|
142
|
+
else
|
143
|
+
return false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# The amount of float this activity has such that it does not delay
|
148
|
+
# the completion of the entire precedence network.
|
149
|
+
def total_float
|
150
|
+
return latest_finish - earliest_finish
|
151
|
+
end
|
152
|
+
|
153
|
+
# The amount of float this activity has if all preceding and succeeding
|
154
|
+
# activities start as early as possible.
|
155
|
+
#
|
156
|
+
# *Note*: In almost all practical cases this is the same as if all
|
157
|
+
# preceding and successing activities start as lates as possible and so
|
158
|
+
# no late_float method is defined.
|
159
|
+
def early_float
|
160
|
+
return post_activities_min_earliest_start -
|
161
|
+
pre_activities_max_earliest_finish - @duration
|
162
|
+
end
|
163
|
+
|
164
|
+
# Register this activity as a post-activity on the parameter.
|
165
|
+
def register_post_activity(activity) #:nodoc:
|
166
|
+
unless (@post_activities.detect do |post_activity|
|
167
|
+
activity.reference == post_activity.reference
|
168
|
+
end)
|
169
|
+
@post_activities << activity
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Register this activity as a pre-activity on the parameter.
|
174
|
+
def register_pre_activity(activity) #:nodoc:
|
175
|
+
unless (@pre_activities.detect do |pre_activity|
|
176
|
+
activity.reference == pre_activity.reference
|
177
|
+
end)
|
178
|
+
@pre_activities << activity
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Deregister this activity as a post-activity on the parameter.
|
183
|
+
def deregister_post_activity(activity) #:nodoc:
|
184
|
+
if (@post_activities.detect do |post_activity|
|
185
|
+
activity.reference == post_activity.reference
|
186
|
+
end)
|
187
|
+
@post_activities.delete(activity)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Deregister this activity as a pre-activity on the parameter.
|
192
|
+
def deregister_pre_activity(activity) #:nodoc:
|
193
|
+
if (@pre_activities.detect do |pre_activity|
|
194
|
+
activity.reference == pre_activity.reference
|
195
|
+
end)
|
196
|
+
@pre_activities.delete(activity)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Returns this activity in an Array object.
|
201
|
+
def to_a #:nodoc:
|
202
|
+
return [self]
|
203
|
+
end
|
204
|
+
|
205
|
+
# Redefines the inspect method.
|
206
|
+
def inspect #:nodoc:
|
207
|
+
"#{@reference}(#{@duration})"
|
208
|
+
end
|
209
|
+
|
210
|
+
# Redefines the to_s method
|
211
|
+
def to_s #:nodoc:
|
212
|
+
return "Reference: #{@reference}\n"+
|
213
|
+
"Description: #{@description}\n"+
|
214
|
+
"Duration: #{@duration}"+
|
215
|
+
("\nDepends on:\n " unless @pre_activities.empty?).to_s +
|
216
|
+
(@pre_activities.collect do |activity|
|
217
|
+
activity.reference
|
218
|
+
end).join(',')
|
219
|
+
end
|
220
|
+
|
221
|
+
# Priviliege settings
|
222
|
+
protected :register_post_activity, :register_pre_activity,
|
223
|
+
:deregister_post_activity, :deregister_pre_activity
|
224
|
+
|
225
|
+
private :pre_activities_max_earliest_finish,
|
226
|
+
:post_activities_min_earliest_start
|
227
|
+
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
# Represents the special case of a start or finish activity.
|
232
|
+
class StartFinishActivity < Precedence::Activity #:nodoc:
|
233
|
+
def initialize(reference,description=nil)
|
234
|
+
if (reference.to_s != 'start') and (reference.to_s != 'finish')
|
235
|
+
raise "StartFinishActivity reference may only be set to"+
|
236
|
+
"'start' or 'finish'. Given reference was '#{reference}'."
|
237
|
+
end
|
238
|
+
|
239
|
+
@reference = reference.to_s
|
240
|
+
if description
|
241
|
+
@description = description.to_s
|
242
|
+
else
|
243
|
+
@description = reference.to_s
|
244
|
+
end
|
245
|
+
@duration = duration.to_f
|
246
|
+
@post_activities = post_activities.to_a
|
247
|
+
@pre_activities = pre_activities.to_a
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require('erb')
|
2
|
+
|
3
|
+
module Precedence
|
4
|
+
|
5
|
+
# An overwritten Hash that has all keys as strings
|
6
|
+
class ActivityHash < Hash #:nodoc:
|
7
|
+
def[]=(ref,value)
|
8
|
+
super(ref.to_s, value)
|
9
|
+
end
|
10
|
+
|
11
|
+
def[](ref)
|
12
|
+
super(ref.to_s)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Represents an entire precedence network.
|
17
|
+
class Network
|
18
|
+
|
19
|
+
# A hashed collection of all the activities in the network. The index
|
20
|
+
# is the reference of the activity.
|
21
|
+
attr_reader :activities
|
22
|
+
|
23
|
+
# Initialises the precedence network. The descriptions for the start
|
24
|
+
# and finish activities can be set in the parameters. The start and
|
25
|
+
# finish activities of the network have as references 'start' and
|
26
|
+
# 'finish' respectively (and as such these references are reserved)
|
27
|
+
# and a duration of 0.
|
28
|
+
def initialize(startDescription='Start',
|
29
|
+
finishDescription='Finish')
|
30
|
+
@start = Precedence::StartFinishActivity.new('start',
|
31
|
+
startDescription)
|
32
|
+
@finish = Precedence::StartFinishActivity.new('finish',
|
33
|
+
finishDescription)
|
34
|
+
@activities = Precedence::ActivityHash.new
|
35
|
+
@activities[@start.reference] = @start
|
36
|
+
@activities[@finish.reference] = @finish
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates a new activity and adds it to the precedence network. The
|
40
|
+
# reference is the only mandatory parameter. The post_activities and
|
41
|
+
# pre_activities parameters should contain the references to activities
|
42
|
+
# already defined within the network and not the actual
|
43
|
+
# Precedence::Activity object.
|
44
|
+
#
|
45
|
+
# Exapmple usage:
|
46
|
+
# precNetwork.new_activity('a2',3,'Activity2',['a1'])
|
47
|
+
# will create a new activity in the network with referecne 'a2' and with
|
48
|
+
# activity 'a1' as a post-activity.
|
49
|
+
def new_activity(reference,duration=0,description="",
|
50
|
+
post_activities=[],pre_activities=[])
|
51
|
+
|
52
|
+
post_activities.each do |post_activity_ref|
|
53
|
+
unless @activities[post_activity_ref]
|
54
|
+
raise "Post-activity with reference #{post_activity_ref} "+
|
55
|
+
"was not found."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
pre_activities.each do |pre_activity_ref|
|
60
|
+
unless @activities[pre_activity_ref]
|
61
|
+
raise "Pre-activity with reference #{pre_activity_ref} "+
|
62
|
+
"was not found."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
activity =
|
67
|
+
Precedence::Activity.new(reference,duration,description)
|
68
|
+
|
69
|
+
post_activities.each do |post_activity_ref|
|
70
|
+
activity.add_post_activities(@activities[post_activity_ref])
|
71
|
+
end
|
72
|
+
|
73
|
+
pre_activities.each do |pre_activity_ref|
|
74
|
+
activity.add_pre_activities(@activities[pre_activity_ref])
|
75
|
+
end
|
76
|
+
|
77
|
+
@activities[reference]=activity
|
78
|
+
end
|
79
|
+
|
80
|
+
# Adds a Precedence::Activity object to the network. This should be a
|
81
|
+
# single activity (no pre- or post-activities should be referenced from
|
82
|
+
# it) and it's reference should not exist in the network.
|
83
|
+
#
|
84
|
+
# Example usage:
|
85
|
+
# activity = Precedence::Activity.new('a1',1,'Activity 1')
|
86
|
+
# precNetwork.add_activity(activity)
|
87
|
+
# will add the existing activity 'a1' to the network.
|
88
|
+
def add_activity(activity)
|
89
|
+
if @activities[activity.reference]
|
90
|
+
raise "Activity #{activity.reference} already exists in the "+
|
91
|
+
"network."
|
92
|
+
end
|
93
|
+
|
94
|
+
unless activity.post_activities == []
|
95
|
+
raise "Can not add an activity with post activities."
|
96
|
+
end
|
97
|
+
|
98
|
+
unless activity.pre_activities == []
|
99
|
+
raise "Can not add an activity with pre activities."
|
100
|
+
end
|
101
|
+
|
102
|
+
@activities[activity.reference] = activity
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# Connects two or more activities together. The pre_ref activity will
|
107
|
+
# become a pre-activity to all the activities referenced in the
|
108
|
+
# post_refs parameter.
|
109
|
+
#
|
110
|
+
# Example uysage:
|
111
|
+
# precNetwork.connect(:h1,:h2,:h3)
|
112
|
+
# will add activity 'h1' as a pre-activity to activities 'h2' and 'h3'.
|
113
|
+
def connect(pre_ref,*post_refs)
|
114
|
+
unless @activities[pre_ref]
|
115
|
+
raise "Pre-activity with reference #{pre_ref} "+
|
116
|
+
"was not found."
|
117
|
+
end
|
118
|
+
|
119
|
+
post_refs.each do |post_ref|
|
120
|
+
unless @activities[post_ref]
|
121
|
+
raise "Post-activity with reference #{post_ref} "+
|
122
|
+
"was not found."
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
post_refs.each do |post_ref|
|
127
|
+
@activities[pre_ref].add_post_activities(@activities[post_ref])
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Ensures that the network is properly connected by connecting any
|
132
|
+
# activity without pre-activities to the start node and to the finish
|
133
|
+
# node if it has no post-activities.
|
134
|
+
def fix_connections!
|
135
|
+
@activities.each do |ref,activity|
|
136
|
+
next if (ref == 'start' or ref == 'finish')
|
137
|
+
if activity.pre_activities.size == 0
|
138
|
+
connect(:start,ref)
|
139
|
+
end
|
140
|
+
|
141
|
+
if activity.post_activities.size == 0
|
142
|
+
connect(ref,:finish)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns the rdot (Ruby embedded in a dot file) template that is used
|
148
|
+
# by default when generating the precedence network diagrams.
|
149
|
+
def get_rdot_template
|
150
|
+
return <<EOS
|
151
|
+
/* Generated by Precedence on <%= Time.now.to_s %> */
|
152
|
+
digraph network {
|
153
|
+
rankdir=LR;
|
154
|
+
node [shape=record];
|
155
|
+
|
156
|
+
/* Activities */
|
157
|
+
<% @activities.each do |ref,activity| %>
|
158
|
+
<% case ref == 'start'
|
159
|
+
when 'start'%>
|
160
|
+
"<%= ref %>" [label="<%= activity.description %>"];
|
161
|
+
<% when 'finish' %>
|
162
|
+
"<%= ref %>" [label="{<%= activity.description%>|<%= activity.earliest_finish %>}"];
|
163
|
+
<% else %>
|
164
|
+
"<%= ref %>" [label="<%=ref%>|{{<%=activity.earliest_start%>|<%=activity.latest_start%>}|{<%=activity.description%>|{<%=activity.total_float%>|<%=activity.early_float%>}}|{<%=activity.earliest_finish%>|<%=activity.latest_finish%>}}|<%=activity.duration%>"];
|
165
|
+
<% end %>
|
166
|
+
<% end %>
|
167
|
+
|
168
|
+
/* Dependencies */
|
169
|
+
<% @activities.each do |ref,activity|%>
|
170
|
+
<% activity.post_activities.each do |post_activity| %>
|
171
|
+
"<%= activity.reference %>" -> "<%= post_activity.reference %>" <% if (activity.on_critical_path? and post_activity.on_critical_path?)%>[style=bold];<% else %>;<% end %>
|
172
|
+
<% end %>
|
173
|
+
<% end %>
|
174
|
+
}
|
175
|
+
EOS
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns a dot file capable of being rendered by the Dot graph renderer
|
179
|
+
# (available from GraphViz http://www.graphviz.org).
|
180
|
+
def to_dot(template=nil)
|
181
|
+
unless template
|
182
|
+
template = get_rdot_template
|
183
|
+
end
|
184
|
+
return ERB.new(template).result(binding)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
data/lib/precedence.rb
ADDED
@@ -0,0 +1,343 @@
|
|
1
|
+
require('lib/precedence/activity')
|
2
|
+
|
3
|
+
class TC_Activity < Test::Unit::TestCase #:nodoc:
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@activity1 = Precedence::Activity.new(:activity1,1,"Activity One")
|
7
|
+
@activity2 = Precedence::Activity.new(:activity2,2,"Activity Two")
|
8
|
+
@activity3 = Precedence::Activity.new(:activity3,3,"Activity Three")
|
9
|
+
@activity4 = Precedence::Activity.new(:activity4,4,"Activity Four")
|
10
|
+
@activity5 = Precedence::Activity.new(:activity5,5,"Activity Five")
|
11
|
+
@activity6 = Precedence::Activity.new(:activity6,6,"Activity Six")
|
12
|
+
@activity7 = Precedence::Activity.new(:activity7,7,"Activity Seven")
|
13
|
+
@activity8 = Precedence::Activity.new(:activity8,8,"Activity Eight")
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_initialize
|
17
|
+
|
18
|
+
assert_raises(RuntimeError) do
|
19
|
+
Precedence::Activity.new(:start)
|
20
|
+
end
|
21
|
+
assert_raises(RuntimeError) do
|
22
|
+
Precedence::Activity.new(:finish)
|
23
|
+
end
|
24
|
+
|
25
|
+
prec = nil
|
26
|
+
assert_nothing_raised do
|
27
|
+
prec = Precedence::Activity.new(:reference)
|
28
|
+
end
|
29
|
+
assert_equal(:reference.to_s, prec.reference)
|
30
|
+
assert_equal("",prec.description)
|
31
|
+
assert_equal(0,prec.duration)
|
32
|
+
assert_equal([],prec.post_activities)
|
33
|
+
assert_equal([],prec.pre_activities)
|
34
|
+
|
35
|
+
assert_nothing_raised do
|
36
|
+
prec = Precedence::Activity.new(:reference,1)
|
37
|
+
end
|
38
|
+
assert_equal(:reference.to_s, prec.reference)
|
39
|
+
assert_equal("", prec.description)
|
40
|
+
assert_equal(1,prec.duration)
|
41
|
+
assert_equal([],prec.post_activities)
|
42
|
+
assert_equal([],prec.pre_activities)
|
43
|
+
|
44
|
+
assert_nothing_raised do
|
45
|
+
prec = Precedence::Activity.new(:reference,1,"description")
|
46
|
+
end
|
47
|
+
assert_equal(:reference.to_s, prec.reference)
|
48
|
+
assert_equal("description", prec.description)
|
49
|
+
assert_equal(1,prec.duration)
|
50
|
+
assert_equal([],prec.post_activities)
|
51
|
+
assert_equal([],prec.pre_activities)
|
52
|
+
|
53
|
+
prec2 = nil
|
54
|
+
assert_nothing_raised do
|
55
|
+
prec2 = Precedence::Activity.new(:reference,1,"description",prec)
|
56
|
+
end
|
57
|
+
assert_equal(:reference.to_s, prec2.reference)
|
58
|
+
assert_equal("description", prec2.description)
|
59
|
+
assert_equal(1,prec2.duration)
|
60
|
+
assert_equal([prec],prec2.post_activities)
|
61
|
+
assert_equal([],prec.pre_activities)
|
62
|
+
|
63
|
+
prec3 = nil
|
64
|
+
assert_nothing_raised do
|
65
|
+
prec3 = Precedence::Activity.new(:reference,1,"description")
|
66
|
+
end
|
67
|
+
assert_nothing_raised do
|
68
|
+
prec2 = Precedence::Activity.new(:reference,1,"description",prec,
|
69
|
+
prec3)
|
70
|
+
end
|
71
|
+
assert_equal(:reference.to_s, prec2.reference)
|
72
|
+
assert_equal("description", prec2.description)
|
73
|
+
assert_equal(1,prec2.duration)
|
74
|
+
assert_equal([prec],prec2.post_activities)
|
75
|
+
assert_equal([prec3],prec2.pre_activities)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_to_a
|
79
|
+
assert_equal([@activity1],@activity1.to_a)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_add_post_activities
|
83
|
+
assert_nothing_raised do
|
84
|
+
@activity1.add_post_activities(@activity2)
|
85
|
+
end
|
86
|
+
assert_equal(@activity2.to_a,@activity1.post_activities)
|
87
|
+
assert_equal(@activity1.to_a,@activity2.pre_activities)
|
88
|
+
|
89
|
+
assert_nothing_raised do
|
90
|
+
@activity1.add_post_activities(@activity2)
|
91
|
+
end
|
92
|
+
assert_equal(1,@activity1.post_activities.size)
|
93
|
+
assert_equal(1,@activity2.pre_activities.size)
|
94
|
+
|
95
|
+
assert_nothing_raised do
|
96
|
+
@activity1.add_post_activities(@activity3,@activity4)
|
97
|
+
end
|
98
|
+
assert_equal([@activity2,@activity3,@activity4],
|
99
|
+
@activity1.post_activities)
|
100
|
+
assert_equal(@activity1.to_a,@activity3.pre_activities)
|
101
|
+
assert_equal(@activity1.to_a,@activity4.pre_activities)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_add_pre_activities
|
105
|
+
assert_nothing_raised do
|
106
|
+
@activity1.add_pre_activities(@activity2)
|
107
|
+
end
|
108
|
+
assert_equal(@activity2.to_a,@activity1.pre_activities)
|
109
|
+
assert_equal(@activity1.to_a,@activity2.post_activities)
|
110
|
+
|
111
|
+
assert_nothing_raised do
|
112
|
+
@activity1.add_pre_activities(@activity2)
|
113
|
+
end
|
114
|
+
assert_equal(1,@activity1.pre_activities.size)
|
115
|
+
assert_equal(1,@activity2.post_activities.size)
|
116
|
+
|
117
|
+
assert_nothing_raised do
|
118
|
+
@activity1.add_pre_activities(@activity3,@activity4)
|
119
|
+
end
|
120
|
+
assert_equal([@activity2,@activity3,@activity4],
|
121
|
+
@activity1.pre_activities)
|
122
|
+
assert_equal(@activity1.to_a,@activity3.post_activities)
|
123
|
+
assert_equal(@activity1.to_a,@activity4.post_activities)
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_remove_post_activities
|
127
|
+
@activity1.add_post_activities(@activity2)
|
128
|
+
assert_nothing_raised do
|
129
|
+
@activity1.remove_post_activities(@activity2)
|
130
|
+
end
|
131
|
+
assert_equal([],@activity1.post_activities)
|
132
|
+
assert_equal([],@activity2.pre_activities)
|
133
|
+
|
134
|
+
@activity1.add_post_activities(@activity2,@activity3)
|
135
|
+
assert_nothing_raised do
|
136
|
+
@activity1.remove_post_activities(@activity2,@activity3)
|
137
|
+
end
|
138
|
+
assert_equal([],@activity1.post_activities)
|
139
|
+
assert_equal([],@activity2.pre_activities)
|
140
|
+
assert_equal([],@activity3.pre_activities)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_remove_pre_activities
|
144
|
+
@activity1.add_pre_activities(@activity2)
|
145
|
+
assert_nothing_raised do
|
146
|
+
@activity1.remove_pre_activities(@activity2)
|
147
|
+
end
|
148
|
+
assert_equal([],@activity1.pre_activities)
|
149
|
+
assert_equal([],@activity2.post_activities)
|
150
|
+
|
151
|
+
@activity1.add_pre_activities(@activity2,@activity3)
|
152
|
+
assert_nothing_raised do
|
153
|
+
@activity1.remove_pre_activities(@activity2,@activity3)
|
154
|
+
end
|
155
|
+
assert_equal([],@activity1.pre_activities)
|
156
|
+
assert_equal([],@activity2.post_activities)
|
157
|
+
assert_equal([],@activity3.post_activities)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_earliest_finish
|
161
|
+
assert_equal(1,@activity1.earliest_finish)
|
162
|
+
|
163
|
+
# a1-a2
|
164
|
+
@activity1.add_post_activities(@activity2)
|
165
|
+
assert_equal(3,@activity2.earliest_finish)
|
166
|
+
|
167
|
+
# a1-a3-a4
|
168
|
+
# '-a2-'
|
169
|
+
@activity1.add_post_activities(@activity3)
|
170
|
+
@activity3.add_post_activities(@activity4)
|
171
|
+
@activity2.add_post_activities(@activity4)
|
172
|
+
assert_equal(8,@activity4.earliest_finish)
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_latest_finish
|
176
|
+
assert_equal(1,@activity1.latest_finish)
|
177
|
+
|
178
|
+
# a1-a2
|
179
|
+
@activity1.add_post_activities(@activity2)
|
180
|
+
assert_equal(3,@activity2.latest_finish)
|
181
|
+
|
182
|
+
# a1-a3-a4
|
183
|
+
# '-a2-'
|
184
|
+
@activity1.add_post_activities(@activity3)
|
185
|
+
@activity3.add_post_activities(@activity4)
|
186
|
+
@activity2.add_post_activities(@activity4)
|
187
|
+
assert_equal(2,@activity2.latest_start)
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_on_critical_path?
|
191
|
+
# a1-a2
|
192
|
+
@activity1.add_post_activities(@activity2)
|
193
|
+
assert_equal(true,@activity1.on_critical_path?)
|
194
|
+
assert_equal(true,@activity2.on_critical_path?)
|
195
|
+
|
196
|
+
# a1-a3-a4
|
197
|
+
# '-a2-'
|
198
|
+
@activity1.add_post_activities(@activity3)
|
199
|
+
@activity3.add_post_activities(@activity4)
|
200
|
+
@activity2.add_post_activities(@activity4)
|
201
|
+
assert_equal(true,@activity1.on_critical_path?)
|
202
|
+
assert_equal(false,@activity2.on_critical_path?)
|
203
|
+
assert_equal(true,@activity3.on_critical_path?)
|
204
|
+
assert_equal(true,@activity4.on_critical_path?)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_total_float
|
208
|
+
# a1-a3-a4
|
209
|
+
# '-a2-'
|
210
|
+
@activity1.add_post_activities(@activity2)
|
211
|
+
@activity1.add_post_activities(@activity3)
|
212
|
+
@activity3.add_post_activities(@activity4)
|
213
|
+
@activity2.add_post_activities(@activity4)
|
214
|
+
|
215
|
+
assert_equal(0,@activity1.total_float)
|
216
|
+
assert_equal(0,@activity3.total_float)
|
217
|
+
assert_equal(0,@activity4.total_float)
|
218
|
+
assert_equal(1,@activity2.total_float)
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_early_total_floats
|
222
|
+
# a1-a3---.
|
223
|
+
# a2-a4-a6-a7
|
224
|
+
# 'a5-a7'
|
225
|
+
@activity1.duration = 1
|
226
|
+
@activity2.duration = 3
|
227
|
+
@activity3.duration = 2
|
228
|
+
@activity4.duration = 4
|
229
|
+
@activity5.duration = 2
|
230
|
+
@activity6.duration = 1
|
231
|
+
@activity7.duration = 2
|
232
|
+
@activity8.duration = 4
|
233
|
+
|
234
|
+
@activity1.add_post_activities(@activity3)
|
235
|
+
@activity2.add_post_activities(@activity4,@activity5)
|
236
|
+
@activity3.add_post_activities(@activity8)
|
237
|
+
@activity4.add_post_activities(@activity6)
|
238
|
+
@activity5.add_post_activities(@activity7)
|
239
|
+
@activity6.add_post_activities(@activity8)
|
240
|
+
@activity7.add_post_activities(@activity8)
|
241
|
+
|
242
|
+
assert_equal(true,@activity2.on_critical_path?)
|
243
|
+
assert_equal(true,@activity4.on_critical_path?)
|
244
|
+
assert_equal(true,@activity6.on_critical_path?)
|
245
|
+
assert_equal(true,@activity8.on_critical_path?)
|
246
|
+
|
247
|
+
assert_equal(false,@activity1.on_critical_path?)
|
248
|
+
assert_equal(false,@activity3.on_critical_path?)
|
249
|
+
assert_equal(false,@activity5.on_critical_path?)
|
250
|
+
assert_equal(false,@activity7.on_critical_path?)
|
251
|
+
|
252
|
+
assert_equal(0,@activity1.earliest_start)
|
253
|
+
assert_equal(5,@activity1.latest_start)
|
254
|
+
assert_equal(1,@activity1.earliest_finish)
|
255
|
+
assert_equal(6,@activity1.latest_finish)
|
256
|
+
assert_equal(5,@activity1.total_float)
|
257
|
+
assert_equal(0,@activity1.early_float)
|
258
|
+
|
259
|
+
assert_equal(0,@activity2.earliest_start)
|
260
|
+
assert_equal(0,@activity2.latest_start)
|
261
|
+
assert_equal(3,@activity2.earliest_finish)
|
262
|
+
assert_equal(3,@activity2.latest_finish)
|
263
|
+
assert_equal(0,@activity2.total_float)
|
264
|
+
assert_equal(0,@activity2.early_float)
|
265
|
+
|
266
|
+
assert_equal(1,@activity3.earliest_start)
|
267
|
+
assert_equal(6,@activity3.latest_start)
|
268
|
+
assert_equal(3,@activity3.earliest_finish)
|
269
|
+
assert_equal(8,@activity3.latest_finish)
|
270
|
+
assert_equal(5,@activity3.total_float)
|
271
|
+
assert_equal(5,@activity3.early_float)
|
272
|
+
|
273
|
+
assert_equal(3,@activity4.earliest_start)
|
274
|
+
assert_equal(3,@activity4.latest_start)
|
275
|
+
assert_equal(7,@activity4.earliest_finish)
|
276
|
+
assert_equal(7,@activity4.latest_finish)
|
277
|
+
assert_equal(0,@activity4.total_float)
|
278
|
+
assert_equal(0,@activity4.early_float)
|
279
|
+
|
280
|
+
assert_equal(3,@activity5.earliest_start)
|
281
|
+
assert_equal(4,@activity5.latest_start)
|
282
|
+
assert_equal(5,@activity5.earliest_finish)
|
283
|
+
assert_equal(6,@activity5.latest_finish)
|
284
|
+
assert_equal(1,@activity5.total_float)
|
285
|
+
assert_equal(0,@activity5.early_float)
|
286
|
+
|
287
|
+
assert_equal(7,@activity6.earliest_start)
|
288
|
+
assert_equal(7,@activity6.latest_start)
|
289
|
+
assert_equal(8,@activity6.earliest_finish)
|
290
|
+
assert_equal(8,@activity6.latest_finish)
|
291
|
+
assert_equal(0,@activity6.total_float)
|
292
|
+
assert_equal(0,@activity6.early_float)
|
293
|
+
|
294
|
+
assert_equal(5,@activity7.earliest_start)
|
295
|
+
assert_equal(6,@activity7.latest_start)
|
296
|
+
assert_equal(7,@activity7.earliest_finish)
|
297
|
+
assert_equal(8,@activity7.latest_finish)
|
298
|
+
assert_equal(1,@activity7.total_float)
|
299
|
+
assert_equal(1,@activity7.early_float)
|
300
|
+
|
301
|
+
assert_equal(8,@activity8.earliest_start)
|
302
|
+
assert_equal(8,@activity8.latest_start)
|
303
|
+
assert_equal(12,@activity8.earliest_finish)
|
304
|
+
assert_equal(12,@activity8.latest_finish)
|
305
|
+
assert_equal(0,@activity8.total_float)
|
306
|
+
assert_equal(0,@activity8.early_float)
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_to_s
|
310
|
+
assert_equal("Reference: activity1\nDescription: Activity One\n"+
|
311
|
+
"Duration: 1.0",@activity1.to_s)
|
312
|
+
|
313
|
+
@activity1.add_pre_activities(@activity2,@activity3)
|
314
|
+
assert_equal("Reference: activity1\nDescription: Activity One\n"+
|
315
|
+
"Duration: 1.0\nDepends on:\n activity2,activity3",@activity1.to_s)
|
316
|
+
|
317
|
+
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
class TC_StartFinishActivity < Test::Unit::TestCase
|
322
|
+
def test_new
|
323
|
+
assert_raises(RuntimeError) do
|
324
|
+
Precedence::StartFinishActivity.new('bogus')
|
325
|
+
end
|
326
|
+
|
327
|
+
assert_nothing_raised do
|
328
|
+
Precedence::StartFinishActivity.new('start')
|
329
|
+
end
|
330
|
+
|
331
|
+
assert_nothing_raised do
|
332
|
+
Precedence::StartFinishActivity.new('finish')
|
333
|
+
end
|
334
|
+
|
335
|
+
assert_nothing_raised do
|
336
|
+
Precedence::StartFinishActivity.new(:finish)
|
337
|
+
end
|
338
|
+
|
339
|
+
assert_nothing_raised do
|
340
|
+
Precedence::StartFinishActivity.new(:start)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
data/tests/tc_network.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
require('lib/precedence/network')
|
2
|
+
|
3
|
+
class TC_ActivityHash < Test::Unit::TestCase
|
4
|
+
def test_all
|
5
|
+
activityHash = nil
|
6
|
+
assert_nothing_raised do
|
7
|
+
activityHash = Precedence::ActivityHash.new
|
8
|
+
end
|
9
|
+
|
10
|
+
assert_nothing_raised do
|
11
|
+
activityHash[:test] = "test"
|
12
|
+
end
|
13
|
+
assert_equal("test",activityHash[:test])
|
14
|
+
assert_equal("test",activityHash['test'])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class TC_Network < Test::Unit::TestCase
|
19
|
+
|
20
|
+
def setup
|
21
|
+
@network = Precedence::Network.new
|
22
|
+
@activity1 = Precedence::Activity.new('a1',1,'Activity1')
|
23
|
+
@activity2 = Precedence::Activity.new('a2',1,'Activity2')
|
24
|
+
@activity3 = Precedence::Activity.new('a3',1,'Activity3')
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_initialize
|
28
|
+
net = nil
|
29
|
+
assert_nothing_raised do
|
30
|
+
net = Precedence::Network.new
|
31
|
+
end
|
32
|
+
assert_equal(2,net.activities.size)
|
33
|
+
assert_equal('start',net.activities[:start].reference)
|
34
|
+
assert_equal('finish',net.activities[:finish].reference)
|
35
|
+
assert_equal('Start',net.activities[:start].description)
|
36
|
+
assert_equal('Finish',net.activities[:finish].description)
|
37
|
+
|
38
|
+
assert_nothing_raised do
|
39
|
+
net = Precedence::Network.new('Begin','End')
|
40
|
+
end
|
41
|
+
assert_equal('Begin',net.activities[:start].description)
|
42
|
+
assert_equal('End',net.activities[:finish].description)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_new_activity
|
46
|
+
assert_raises(ArgumentError) do
|
47
|
+
@network.new_activity()
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_nothing_raised do
|
51
|
+
@network.new_activity('a1',1)
|
52
|
+
end
|
53
|
+
assert_equal(3,@network.activities.size)
|
54
|
+
assert_equal('a1',@network.activities['a1'].reference)
|
55
|
+
assert_equal(1,@network.activities['a1'].duration)
|
56
|
+
|
57
|
+
assert_nothing_raised do
|
58
|
+
@network.new_activity('a2',2,'Activity Two')
|
59
|
+
end
|
60
|
+
assert_equal(4,@network.activities.size)
|
61
|
+
assert_equal('a2',@network.activities['a2'].reference)
|
62
|
+
assert_equal('Activity Two',@network.activities['a2'].description)
|
63
|
+
assert_equal(2,@network.activities['a2'].duration)
|
64
|
+
|
65
|
+
assert_nothing_raised do
|
66
|
+
@network.new_activity('a3',3,'Activity Three')
|
67
|
+
end
|
68
|
+
assert_equal(5,@network.activities.size)
|
69
|
+
assert_equal('a3',@network.activities['a3'].reference)
|
70
|
+
assert_equal('Activity Three',@network.activities['a3'].description)
|
71
|
+
assert_equal(3,@network.activities['a3'].duration)
|
72
|
+
|
73
|
+
assert_nothing_raised do
|
74
|
+
@network.new_activity('a4',4,'Activity Four',['a3'])
|
75
|
+
end
|
76
|
+
assert_equal(6,@network.activities.size)
|
77
|
+
assert_equal('a4',@network.activities['a4'].reference)
|
78
|
+
assert_equal('Activity Four',@network.activities['a4'].description)
|
79
|
+
assert_equal(4,@network.activities['a4'].duration)
|
80
|
+
assert_equal(1,@network.activities['a4'].post_activities.size)
|
81
|
+
assert_equal('a3',@network.activities['a4'].post_activities[0].reference)
|
82
|
+
assert_equal('a4',@network.activities['a3'].pre_activities[0].reference)
|
83
|
+
|
84
|
+
assert_nothing_raised do
|
85
|
+
@network.new_activity('a5',5,'Activity Five',['a3'],['a4'])
|
86
|
+
end
|
87
|
+
assert_equal(7,@network.activities.size)
|
88
|
+
assert_equal('a5',@network.activities['a5'].reference)
|
89
|
+
assert_equal('Activity Five',@network.activities['a5'].description)
|
90
|
+
assert_equal(5,@network.activities['a5'].duration)
|
91
|
+
assert_equal(1,@network.activities['a5'].post_activities.size)
|
92
|
+
assert_equal(1,@network.activities['a5'].pre_activities.size)
|
93
|
+
assert_equal('a3',@network.activities['a5'].post_activities[0].reference)
|
94
|
+
assert_equal('a5',@network.activities['a3'].pre_activities[1].reference)
|
95
|
+
assert_equal('a4',@network.activities['a5'].pre_activities[0].reference)
|
96
|
+
assert_equal('a5',@network.activities['a4'].post_activities[1].reference)
|
97
|
+
|
98
|
+
assert_raises(RuntimeError) do
|
99
|
+
@network.new_activity('a6',6,'Activity Six',['a7'])
|
100
|
+
end
|
101
|
+
|
102
|
+
assert_raises(RuntimeError) do
|
103
|
+
@network.new_activity('a6',6,'Activity Six',['a5','a7'])
|
104
|
+
end
|
105
|
+
assert_equal(nil,
|
106
|
+
@network.activities['a5'].pre_activities.detect do |activity|
|
107
|
+
activity.reference == 'a6'
|
108
|
+
end)
|
109
|
+
|
110
|
+
assert_raises(RuntimeError) do
|
111
|
+
@network.new_activity('a6',6,'Activity Six',[],['a5','a7'])
|
112
|
+
end
|
113
|
+
assert_equal(nil,
|
114
|
+
@network.activities['a5'].post_activities.detect do |activity|
|
115
|
+
activity.reference == 'a6'
|
116
|
+
end)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_add_activity
|
120
|
+
assert_nothing_raised do
|
121
|
+
@network.add_activity(@activity1)
|
122
|
+
end
|
123
|
+
assert_equal(3,@network.activities.size)
|
124
|
+
assert_equal(@activity1,@network.activities[@activity1.reference])
|
125
|
+
|
126
|
+
assert_raises(RuntimeError) do
|
127
|
+
@network.add_activity(@activity1)
|
128
|
+
end
|
129
|
+
|
130
|
+
@network = Precedence::Network.new
|
131
|
+
@activity1.add_post_activities(@activity2)
|
132
|
+
assert_raises(RuntimeError) do
|
133
|
+
@network.add_activity(@activity1)
|
134
|
+
end
|
135
|
+
assert_equal(2,@network.activities.size)
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_connect
|
139
|
+
@network.add_activity(@activity1)
|
140
|
+
@network.add_activity(@activity2)
|
141
|
+
|
142
|
+
assert_nothing_raised do
|
143
|
+
@network.connect(@activity1.reference,@activity2.reference)
|
144
|
+
end
|
145
|
+
assert_equal(1,@activity1.post_activities.size)
|
146
|
+
assert_equal(1,@activity2.pre_activities.size)
|
147
|
+
assert_equal('a2',@activity1.post_activities[0].reference)
|
148
|
+
assert_equal('a1',@activity2.pre_activities[0].reference)
|
149
|
+
|
150
|
+
assert_raises(RuntimeError) do
|
151
|
+
@network.connect(@activity1.reference,'bogus reference')
|
152
|
+
end
|
153
|
+
assert_equal(1,@activity1.post_activities.size)
|
154
|
+
assert_equal('a2',@activity1.post_activities[0].reference)
|
155
|
+
|
156
|
+
assert_raises(RuntimeError) do
|
157
|
+
@network.connect('bogus reference','a2')
|
158
|
+
end
|
159
|
+
assert_equal(1,@activity2.pre_activities.size)
|
160
|
+
assert_equal('a1',@activity2.pre_activities[0].reference)
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_fix_connections!
|
164
|
+
@network.add_activity(@activity1)
|
165
|
+
@network.add_activity(@activity2)
|
166
|
+
@network.add_activity(@activity3)
|
167
|
+
@network.connect('start',@activity1.reference)
|
168
|
+
@network.connect(@activity1.reference,@activity2.reference)
|
169
|
+
@network.connect(@activity3.reference,'finish')
|
170
|
+
@network.fix_connections!
|
171
|
+
assert_equal(1,@activity2.post_activities.size)
|
172
|
+
assert_equal('finish',@activity2.post_activities[0].reference)
|
173
|
+
assert_equal(1,@activity3.pre_activities.size)
|
174
|
+
assert_equal('start',@activity3.pre_activities[0].reference)
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_to_dot
|
178
|
+
net = Precedence::Network.new('Begin','End')
|
179
|
+
net.new_activity('act-1-1',3,'System specification')
|
180
|
+
net.new_activity('act-1-2',2,'Review')
|
181
|
+
net.new_activity('act-1-3',2,'System re-specification')
|
182
|
+
net.new_activity('act-2-1',3,'Test tool design')
|
183
|
+
net.new_activity('act-2-2',5,'Test tool implementation')
|
184
|
+
net.new_activity('act-3-1',3,'System design')
|
185
|
+
net.new_activity('act-3-2',12,'System implementation')
|
186
|
+
net.new_activity('act-2-3',10,'System testing')
|
187
|
+
net.connect('act-1-1','act-1-2')
|
188
|
+
net.connect('act-1-2','act-1-3')
|
189
|
+
net.connect('act-1-3','act-3-1')
|
190
|
+
net.connect('act-1-2','act-2-1')
|
191
|
+
net.connect('act-2-1','act-2-2')
|
192
|
+
net.connect('act-2-2','act-3-2')
|
193
|
+
net.connect('act-3-1','act-3-2')
|
194
|
+
net.connect('act-3-2','act-2-3')
|
195
|
+
net.fix_connections!
|
196
|
+
|
197
|
+
assert_nothing_raised do
|
198
|
+
File.open('test_to_dot.dot',File::CREAT|File::TRUNC|File::WRONLY) do|f|
|
199
|
+
f.puts(net.to_dot)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
$stdout.puts("\nTest dot file test_to_dot.dot file generated.")
|
203
|
+
|
204
|
+
if system("dot","-Tpng","-otest_to_dot.png","test_to_dot.dot")
|
205
|
+
$stdout.puts("Test png file test_to_dot.png files generated.")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require('test/unit')
|
2
|
+
|
3
|
+
require('tests/tc_activity')
|
4
|
+
require('tests/tc_network')
|
5
|
+
|
6
|
+
class TS_Precedence < Test::Unit::TestSuite
|
7
|
+
def initialize(name="Precedence Test Suite")
|
8
|
+
super(name)
|
9
|
+
@tests << TC_Activity.suite
|
10
|
+
@tests << TC_StartFinishActivity.suite
|
11
|
+
@tests << TC_ActivityHash.suite
|
12
|
+
@tests << TC_Network.suite
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.10
|
3
|
+
specification_version: 1
|
4
|
+
name: precedence
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.6.0
|
7
|
+
date: 2005-05-15
|
8
|
+
summary: A library for the creation manipulation and analysis of precedence networks.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: farrel@lifson.info
|
12
|
+
homepage: http://precedence.rubyforge.org
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: precedence
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Farrel Lifson
|
29
|
+
files:
|
30
|
+
- lib/precedence
|
31
|
+
- lib/precedence.rb
|
32
|
+
- lib/precedence/activity.rb
|
33
|
+
- lib/precedence/network.rb
|
34
|
+
- tests/tc_activity.rb
|
35
|
+
- tests/tc_network.rb
|
36
|
+
- tests/ts_precedence.rb
|
37
|
+
- README
|
38
|
+
- CHANGELOG
|
39
|
+
- TODO
|
40
|
+
test_files:
|
41
|
+
- tests/ts_precedence.rb
|
42
|
+
rdoc_options: []
|
43
|
+
extra_rdoc_files:
|
44
|
+
- README
|
45
|
+
- CHANGELOG
|
46
|
+
- TODO
|
47
|
+
executables: []
|
48
|
+
extensions: []
|
49
|
+
requirements: []
|
50
|
+
dependencies: []
|