git-ds 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.rdoc +795 -0
  2. data/doc/Examples.rdoc +36 -0
  3. data/doc/examples/key_value/kv_get.rb +29 -0
  4. data/doc/examples/key_value/kv_init.rb +20 -0
  5. data/doc/examples/key_value/kv_list.rb +28 -0
  6. data/doc/examples/key_value/kv_remove.rb +29 -0
  7. data/doc/examples/key_value/kv_set.rb +39 -0
  8. data/doc/examples/key_value/model.rb +156 -0
  9. data/doc/examples/key_value/test.rb +50 -0
  10. data/doc/examples/test_suite/model.rb +503 -0
  11. data/doc/examples/test_suite/test.rb +173 -0
  12. data/doc/examples/test_suite/ts_add_bug.rb +65 -0
  13. data/doc/examples/test_suite/ts_add_module.rb +74 -0
  14. data/doc/examples/test_suite/ts_add_module_to_test.rb +78 -0
  15. data/doc/examples/test_suite/ts_add_test.rb +77 -0
  16. data/doc/examples/test_suite/ts_add_test_suite.rb +65 -0
  17. data/doc/examples/test_suite/ts_add_test_to_bug.rb +76 -0
  18. data/doc/examples/test_suite/ts_init.rb +20 -0
  19. data/doc/examples/test_suite/ts_list.rb +118 -0
  20. data/doc/examples/test_suite/ts_perform_test.rb +104 -0
  21. data/doc/examples/test_suite/ts_update_bugs.rb +58 -0
  22. data/doc/examples/user_group/model.rb +265 -0
  23. data/doc/examples/user_group/test.rb +64 -0
  24. data/doc/examples/user_group/ug_add_group.rb +39 -0
  25. data/doc/examples/user_group/ug_add_group_user.rb +36 -0
  26. data/doc/examples/user_group/ug_add_user.rb +39 -0
  27. data/doc/examples/user_group/ug_init.rb +20 -0
  28. data/doc/examples/user_group/ug_list.rb +32 -0
  29. data/lib/git-ds.rb +14 -0
  30. data/lib/git-ds/config.rb +53 -0
  31. data/lib/git-ds/database.rb +289 -0
  32. data/lib/git-ds/exec_cmd.rb +107 -0
  33. data/lib/git-ds/index.rb +205 -0
  34. data/lib/git-ds/model.rb +136 -0
  35. data/lib/git-ds/model/db_item.rb +42 -0
  36. data/lib/git-ds/model/fs_item.rb +51 -0
  37. data/lib/git-ds/model/item.rb +428 -0
  38. data/lib/git-ds/model/item_list.rb +97 -0
  39. data/lib/git-ds/model/item_proxy.rb +128 -0
  40. data/lib/git-ds/model/property.rb +144 -0
  41. data/lib/git-ds/model/root.rb +46 -0
  42. data/lib/git-ds/repo.rb +455 -0
  43. data/lib/git-ds/shared.rb +17 -0
  44. data/lib/git-ds/transaction.rb +77 -0
  45. data/tests/ut_database.rb +304 -0
  46. data/tests/ut_git_grit_equiv.rb +195 -0
  47. data/tests/ut_index.rb +203 -0
  48. data/tests/ut_model.rb +360 -0
  49. data/tests/ut_repo.rb +260 -0
  50. data/tests/ut_user_group_model.rb +316 -0
  51. metadata +142 -0
data/doc/Examples.rdoc ADDED
@@ -0,0 +1,36 @@
1
+ =Key-Value datastore
2
+
3
+ {doc/examples/key_value/model.rb}[link:doc/examples/key_value/model_rb.html]
4
+
5
+ KeyValueModel
6
+
7
+ * KeyValueModelItem
8
+
9
+ ==Example
10
+ :include: doc/examples/key_value/test.rb
11
+
12
+ =Test Suite backend
13
+
14
+ {doc/examples/test_suite/model.rb}[link:doc/examples/test_suite/model_rb.html]
15
+
16
+ TestSuiteModel
17
+
18
+ * ModuleModelItem
19
+ * TestSuiteModelItem
20
+ * TestModelItem
21
+ * BugModelItem
22
+
23
+ ==Example
24
+ :include: doc/examples/test_suite/test.rb
25
+
26
+ =User/Group database
27
+
28
+ {doc/examples/user_group/model.rb}[link:doc/examples/user_group/model_rb.html]
29
+
30
+ UserGroupModel
31
+
32
+ * UserModelItem
33
+ * GroupModelItem
34
+
35
+ ==Example
36
+ :include: doc/examples/test_suite/test.rb
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # Get a key:value pair from a database repo
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ # Add examples dir and lib/git-ds to ruby path
6
+ BASE=File.dirname(File.expand_path(__FILE__)\
7
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
8
+ $: << BASE + File::SEPARATOR + 'lib'
9
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
10
+
11
+ require 'key_value/model'
12
+
13
+ if __FILE__ == $0
14
+ if ARGV.count < 1 || ARGV.count > 2
15
+ puts "Usage : #{$0} [FILENAME] KEY"
16
+ puts "Repo dir is assumed to be . if FILENAME is not specified."
17
+ exit -1
18
+ end
19
+
20
+ path = (ARGV.count == 2) ? ARGV.shift : GitDS::Database.top_level
21
+ key = ARGV.shift
22
+
23
+ model = KeyValueModel.new(GitDS::Database.connect(path, false))
24
+ raise "Could not connect to Model!" if not model
25
+
26
+ puts model[key]
27
+
28
+ exit 0
29
+ end
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # Initialize a key/value database repo
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ BASE=File.dirname(File.expand_path(__FILE__)\
6
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
7
+ $: << BASE + File::SEPARATOR + 'lib'
8
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
9
+
10
+ require 'key_value/model'
11
+
12
+ if __FILE__ == $0
13
+ if ARGV.count != 1
14
+ puts "Usage : #{$0} FILENAME"
15
+ exit -1
16
+ end
17
+
18
+ KeyValueModel.new(GitDS::Database.connect(ARGV.shift, true))
19
+ exit 0
20
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+ # List all key:value pairs in a database repo
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ # Add examples dir and lib/git-ds to ruby path
6
+ BASE=File.dirname(File.expand_path(__FILE__)\
7
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
8
+ $: << BASE + File::SEPARATOR + 'lib'
9
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
10
+
11
+ require 'key_value/model'
12
+
13
+ if __FILE__ == $0
14
+ if ARGV.count > 1
15
+ puts "Usage : #{$0} [FILENAME]"
16
+ puts "Repo dir is assumed to be . if FILENAME is not specified."
17
+ exit -1
18
+ end
19
+
20
+ path = (ARGV.count == 1) ? ARGV.shift : GitDS::Database.top_level
21
+
22
+ model = KeyValueModel.new(GitDS::Database.connect(path, false))
23
+ raise "Could not connect to Model!" if not model
24
+
25
+ model.each { |k, v| puts "#{k} : #{v}" }
26
+
27
+ exit 0
28
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # Remove a key:value pair from a database repo
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ # Add examples dir and lib/git-ds to ruby path
6
+ BASE=File.dirname(File.expand_path(__FILE__)\
7
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
8
+ $: << BASE + File::SEPARATOR + 'lib'
9
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
10
+
11
+ require 'key_value/model'
12
+
13
+ if __FILE__ == $0
14
+ if ARGV.count < 1 || ARGV.count > 2
15
+ puts "Usage : #{$0} [FILENAME] KEY"
16
+ puts "Repo dir is assumed to be . if FILENAME is not specified."
17
+ exit -1
18
+ end
19
+
20
+ path = (ARGV.count == 2) ? ARGV.shift : GitDS::Database.top_level
21
+ key = ARGV.shift
22
+
23
+ model = KeyValueModel.new(GitDS::Database.connect(path, false))
24
+ raise "Could not connect to Model!" if not model
25
+
26
+ model.remove key
27
+
28
+ exit 0
29
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # Set a key:value pair in a database repo
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ # Add examples dir and lib/git-ds to ruby path
6
+ BASE=File.dirname(File.expand_path(__FILE__)\
7
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
8
+ $: << BASE + File::SEPARATOR + 'lib'
9
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
10
+
11
+ require 'key_value/model'
12
+
13
+ if __FILE__ == $0
14
+ if ARGV.count < 2 || ARGV.count > 3
15
+ puts "Usage : #{$0} [FILENAME] KEY VALUE"
16
+ puts "Repo dir is assumed to be . if FILENAME is not specified."
17
+ puts "A new GitDS database will be created if FILENAME does not exist."
18
+ exit -1
19
+ end
20
+
21
+ path = ''
22
+ autocreate = false
23
+ if ARGV.count == 3
24
+ path = ARGV.shift
25
+ autocreate = true
26
+ else
27
+ path = GitDS::Database.top_level
28
+ end
29
+ key = ARGV.shift
30
+ val = ARGV.shift
31
+
32
+ model = KeyValueModel.new(GitDS::Database.connect(path, autocreate))
33
+ raise "Could not connect to Model!" if not model
34
+
35
+ # Note: this will automatically be committed:
36
+ model[key] = val
37
+
38
+ exit 0
39
+ end
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+ # :title: GitDS Model Example: Key/Value
3
+ =begin rdoc
4
+ <i>Copyright 2011 Thoughtgang <http://www.thoughtgang.org></i>
5
+
6
+ This example demonstrates a GitDS database that acts as a simple Key:Value
7
+ datastore.
8
+
9
+ ==Usage
10
+
11
+ An example of the usage of this model can be found in the following script:
12
+
13
+ doc/examples/key_value/test.rb
14
+
15
+ This script can be run to generate an example Git-DS repository:
16
+
17
+ bash$ doc/examples/key_value/test.rb
18
+ bash$ cd kv_test.db && qgit &
19
+
20
+ The following command-line utilities are provided for manipulating this
21
+ data model:
22
+
23
+ doc/examples/key_value/kv_get.rb
24
+ doc/examples/key_value/kv_init.rb
25
+ doc/examples/key_value/kv_list.rb
26
+ doc/examples/key_value/kv_remove.rb
27
+ doc/examples/key_value/kv_set.rb
28
+
29
+ ===Initialize a Key:Value datastore
30
+
31
+ model = KeyValueModel.new(GitDS::Database.connect('kv_test.db', true))
32
+
33
+ ===Set a key:value pair
34
+
35
+ model[key] = value
36
+
37
+ ===Get a key:value pair
38
+
39
+ model[key]
40
+
41
+ ===Remove a key:value pair
42
+
43
+ model.remove(key)
44
+
45
+ ===List all key:value pairs
46
+
47
+ model.each { |key, value| ... }
48
+
49
+ =end
50
+
51
+ require 'git-ds/database'
52
+ require 'git-ds/model'
53
+
54
+ # ============================================================================
55
+
56
+ =begin rdoc
57
+ A data model representing a basic Key/Value store.
58
+
59
+ This has the following structure on disk:
60
+ key-value/ : ModelItem class for Key/Value pairs
61
+ key-value/$KEY/value : Property file containing value of key
62
+ =end
63
+
64
+ class KeyValueModel < GitDS::Model
65
+ def initialize(db)
66
+ super db, 'key/value model'
67
+ end
68
+
69
+ =begin rdoc
70
+ Return KeyValudeModelItem for key.
71
+ =end
72
+ def pair(key)
73
+ path = KeyValueModelItem.instance_path(self.root.path, key)
74
+ KeyValueModelItem.new(self, path)
75
+ end
76
+
77
+ =begin rdoc
78
+ Return true if key exists in Model.
79
+ =end
80
+ def include?(key)
81
+ super KeyValueModelItem.instance_path(self.root.path, key)
82
+ end
83
+
84
+ alias :exist? :include?
85
+
86
+ =begin rdoc
87
+ Return value for key if it exists in model, nil otherwise.
88
+ =end
89
+ def [](key)
90
+ return nil if not exist? key
91
+ p = pair(key)
92
+ p ? p.value : nil
93
+ end
94
+
95
+ =begin rdoc
96
+ Set value for key to 'val'. The key/value pair is created if it does not
97
+ already exist.
98
+ =end
99
+ def []=(key, val)
100
+ if self.exist? key
101
+ p = pair(key)
102
+ p.value = val if p
103
+ else
104
+ KeyValueModelItem.create self.root, {:key => key, :value => val}
105
+ end
106
+ end
107
+
108
+ =begin rdoc
109
+ Yield each key, value pair in database.
110
+ =end
111
+ def each
112
+ KeyValueModelItem.list(self.root).each do |k|
113
+ yield [k, self[k]]
114
+ end
115
+ end
116
+
117
+ =begin rdoc
118
+ Remove a key:value pair from the database.
119
+ =end
120
+ def remove(key)
121
+ pair(key).delete
122
+ end
123
+ end
124
+
125
+ =begin rdoc
126
+ A ModelItem class for Key/Value pairs. This assumes that value is a String.
127
+ To support other datatypes, subclass and override the value() accessor.
128
+ =end
129
+ class KeyValueModelItem < GitDS::ModelItem
130
+ name 'key-value'
131
+
132
+ property(:value, '')
133
+
134
+ =begin rdoc
135
+ Use :key as the ident field of the create() Hash.
136
+ =end
137
+ def self.ident_key
138
+ :key
139
+ end
140
+
141
+ alias :key :ident
142
+
143
+ =begin rdoc
144
+ Return the value of the key:value pair.
145
+ =end
146
+ def value
147
+ property(:value)
148
+ end
149
+
150
+ =begin rdoc
151
+ Set the value of the key:value pair.
152
+ =end
153
+ def value=(val)
154
+ set_property(:value, val)
155
+ end
156
+ end
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # Test Key/Value database example
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ BASE=File.dirname(File.expand_path(__FILE__)\
6
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
7
+ $: << BASE + File::SEPARATOR + 'lib'
8
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
9
+
10
+ require 'key_value/model'
11
+
12
+ # ----------------------------------------------------------------------
13
+
14
+ def fill_model(model)
15
+ model.exec do
16
+ {
17
+ :a => 1,
18
+ :b => 2,
19
+ :c => 3
20
+ }.each { |k,v| model[k] = v }
21
+ end
22
+
23
+ model.db.set_author('a user', 'au@users.net')
24
+
25
+ model.exec do
26
+ {
27
+ :a => 999,
28
+ :b => 998,
29
+ :c => 997,
30
+ :d => 996,
31
+ :e => 995
32
+ }.each { |k,v| model[k] = v }
33
+ end
34
+ end
35
+
36
+ # ----------------------------------------------------------------------
37
+ def list_model(model)
38
+ model.each { |k, v| puts "#{k} : #{v}" }
39
+ end
40
+
41
+ # ----------------------------------------------------------------------
42
+ if __FILE__ == $0
43
+ path = (ARGV.count > 0) ? ARGV.shift : 'kv_test.db'
44
+
45
+ db = GitDS::Database.connect(path, true)
46
+ model = KeyValueModel.new(db) if db
47
+ fill_model(model) if model
48
+ list_model(model) if model
49
+ end
50
+
@@ -0,0 +1,503 @@
1
+ #!/usr/bin/env ruby
2
+ # :title: GitDS Model Example: Test Suite
3
+ # :doc:
4
+ =begin rdoc
5
+ <i>Copyright 2011 Thoughtgang <http://www.thoughtgang.org></i>
6
+
7
+ This example is suitable for demonstrating branches, commits, tags, and
8
+ actions by multiple users.
9
+
10
+ The TestSuite model consists of Modules (source code files), Test Suites
11
+ (collections of tests), Tests (specific test instances), and Bugs (bug
12
+ reports). Tests can be associated with modules (which they verify), and Bugs
13
+ can be associated with Tests (which cause them to be manifest). Tests have
14
+ a pass/fail state which is updated over time as they are performed, and Bugs
15
+ have an open/closed state which is updated over time as the Tests which
16
+ detect them pass or fail.
17
+
18
+ Note: This is not a serious proposal for a bug-tracking data model. It is
19
+ intended only to serve as an example of a data model with frequent changes by
20
+ multiple users.
21
+
22
+ ==Usage
23
+
24
+ An example of the usage of this model can be found in the following script:
25
+
26
+ doc/examples/test_suite/test.rb
27
+
28
+ This script can be run to generate an example Git-DS repository:
29
+
30
+ bash$ doc/examples/test_suite/test.rb
31
+ bash$ cd ts_test.db && qgit &
32
+
33
+ The following command-line utilities are provided for manipulating this
34
+ data model:
35
+
36
+ doc/examples/test_suite/ts_add_bug.rb
37
+ doc/examples/test_suite/ts_add_module.rb
38
+ doc/examples/test_suite/ts_add_module_to_test.rb
39
+ doc/examples/test_suite/ts_add_test.rb
40
+ doc/examples/test_suite/ts_add_test_suite.rb
41
+ doc/examples/test_suite/ts_add_test_to_bug.rb
42
+ doc/examples/test_suite/ts_init.rb
43
+ doc/examples/test_suite/ts_list.rb
44
+ doc/examples/test_suite/ts_perform_test.rb
45
+ doc/examples/test_suite/ts_update_bugs.rb
46
+
47
+ ===Initialize a TestSuite database
48
+
49
+ # connect the model, creating it if necessary
50
+ model = TestSuiteModel.new(GitDS::Database.connect('ts_test.db', true))
51
+
52
+ # connect as a specific user (Git author)
53
+ model = TestSuiteModel.new(GitDS::Database.connect_as('ts_test.db'
54
+ username, email))
55
+
56
+ ===Add a Source Module
57
+
58
+ m = model.add_module(path, data)
59
+
60
+ ===Add a Test Suite
61
+
62
+ s = model.add_test_suite(name, description)
63
+
64
+ ===Add Tests to a Test Suite
65
+
66
+ t = s.add_test(name)
67
+
68
+ # Add a test with a list of modules
69
+ modules [ 'path.to.module.1', 'path.to.module.2' ]
70
+ t = suite.add_test(name, modules)
71
+
72
+ # Add a specific Module to a Test
73
+ m = model.module('path.to.module.3'
74
+ t.add_module(m)
75
+
76
+ ===Add a Bug Report
77
+
78
+ b = model.add_bug(name, description)
79
+
80
+ # Add a specific test to a Bug
81
+ s = model.suite('UnitTests')
82
+ t = s.test('test_foo')
83
+ b.add_test(t)
84
+
85
+ ===Updating Tests and Bugs
86
+
87
+ # Pass a block to perform_tests to update each test
88
+ model.perform_tests do |t|
89
+
90
+ # Generate the new pass/fail state and log for the test.
91
+ # In reality, this might invoke and monitor a test method or program.
92
+ passed = false
93
+ log = "RuntimeError in..."
94
+
95
+ # Write the new pass/fail state and log to the test
96
+ t.perform( passed, log )
97
+ end
98
+
99
+ # Update all Bugs to be open or closed depending on the state of their Tests
100
+ model.update_bugs
101
+
102
+ =end
103
+
104
+ require 'git-ds/database'
105
+ require 'git-ds/model'
106
+
107
+ # =============================================================================
108
+
109
+ =begin rdoc
110
+ The model has the following structure in the repo:
111
+
112
+ module/ : ModelItem class
113
+ module/$NAME : ModelItem class instance
114
+ module/$NAME/data : Property (str)
115
+ module/$NAME/path : Property (str)
116
+ bug/ : ModelItem class
117
+ bug/$ID : ModelItem class instance
118
+ bug/$ID/test : ProxyItemList
119
+ bug/$ID/description : Property (str)
120
+ bug/$ID/open : Property (bool)
121
+ test_suite/ : ModelItem class
122
+ test_suite/$ID : ModelItem class instance
123
+ test_suite/description : Property (str)
124
+ test_suite/$ID/test : ModelItem class
125
+ test_suite/$ID/test/$ID : ModelItem class instance
126
+ test_suite/$ID/test/$ID/module : ProxyItemList
127
+ test_suite/$ID/test/$ID/pass : Property (bool)
128
+ test_suite/$ID/test/$ID/log : Property (str)
129
+ test_suite/$ID/test/$ID/timestamp : Property (ts)
130
+ =end
131
+
132
+ class TestSuiteModel < GitDS::Model
133
+ def initialize(db)
134
+ super db, 'test-suite model'
135
+ end
136
+
137
+ =begin rdoc
138
+ Add a Module to the database.
139
+ =end
140
+ def add_module(path, data)
141
+ args = { :ident =>
142
+ path.split(File::SEPARATOR).reject{ |x| x.empty? }.join('.'),
143
+ :name => File.basename(path), :path => File.dirname(path),
144
+ :data => data }
145
+ ModuleModelItem.new self, ModuleModelItem.create(self.root, args)
146
+ end
147
+
148
+ =begin rdoc
149
+ List all Modules in the database.
150
+ =end
151
+ def modules
152
+ ModuleModelItem.list(self.root)
153
+ end
154
+
155
+ =begin rdoc
156
+ Instantiate a Module.
157
+ =end
158
+ def module(ident)
159
+ path = ModuleModelItem.instance_path(self.root.path, ident)
160
+ ModuleModelItem.new self, path
161
+ end
162
+
163
+ =begin rdoc
164
+ Add a Bug to the database.
165
+ =end
166
+ def add_bug(ident, description)
167
+ args = { :ident => ident, :description => description }
168
+ BugModelItem.new self, BugModelItem.create(self.root, args)
169
+ end
170
+
171
+ =begin rdoc
172
+ List the IDs of all Bug in the database.
173
+ =end
174
+ def bugs
175
+ BugModelItem.list(self.root)
176
+ end
177
+
178
+ =begin rdoc
179
+ Instantiate a Bug.
180
+ =end
181
+ def bug(ident)
182
+ BugModelItem.new self, BugModelItem.instance_path(self.root.path, ident)
183
+ end
184
+
185
+ =begin rdoc
186
+ Update the status of all Bugs.
187
+ =end
188
+ def update_bugs
189
+ model = self
190
+ exec {
191
+ model.bugs.each do |ident|
192
+ b = model.bug(ident)
193
+ b.update
194
+ end
195
+ }
196
+ end
197
+
198
+ =begin rdoc
199
+ Add a TestSuite to the database.
200
+ =end
201
+ def add_test_suite(ident, description)
202
+ args = { :ident => ident, :description => description }
203
+ TestSuiteModelItem.new self, TestSuiteModelItem.create(self.root, args)
204
+ end
205
+
206
+ =begin rdoc
207
+ List all TestSuitesin the database.
208
+ =end
209
+ def test_suites
210
+ TestSuiteModelItem.list(self.root)
211
+ end
212
+
213
+ =begin rdoc
214
+ Instantiate a TestSuite.
215
+ =end
216
+ def test_suite(ident)
217
+ path = TestSuiteModelItem.instance_path(self.root.path, ident)
218
+ TestSuiteModelItem.new self, path
219
+ end
220
+
221
+ =begin rdoc
222
+ Perform all tests in all TestSuites.
223
+ This yields each Test to the supplied block.
224
+ =end
225
+ def perform_tests(&block)
226
+ model = self
227
+ exec {
228
+ model.test_suites.each do |ident|
229
+ s = model.test_suite(ident)
230
+ s.perform_tests(&block)
231
+ end
232
+ }
233
+ end
234
+ end
235
+
236
+ # ----------------------------------------------------------------------
237
+ =begin rdoc
238
+ A module for testing. Usually a source code file.
239
+ =end
240
+ class ModuleModelItem < GitDS::FsModelItem
241
+ name 'module'
242
+
243
+ property :name
244
+ property :path
245
+ property :data
246
+
247
+ =begin rdoc
248
+ Contents of the module. This will usually be source code.
249
+ =end
250
+ def data
251
+ property(:data)
252
+ end
253
+
254
+ def data=(val)
255
+ set_property(:data, val)
256
+ end
257
+
258
+ =begin rdoc
259
+ Name of the module in the filesystem.
260
+ =end
261
+ def name
262
+ property(:name)
263
+ end
264
+
265
+ =begin rdoc
266
+ Path of the module in the filesystem.
267
+ =end
268
+ def path
269
+ property(:path)
270
+ end
271
+ end
272
+
273
+ # ----------------------------------------------------------------------
274
+ =begin rdoc
275
+ A collection of tests.
276
+ =end
277
+ class TestSuiteModelItem < GitDS::ModelItem
278
+ name 'test_suite'
279
+
280
+ property :description
281
+
282
+ def initialize(model, path)
283
+ super
284
+ @tests = GitDS::ModelItemList.new(TestModelItem, model, path)
285
+ end
286
+
287
+ =begin rdoc
288
+ Description (e.g. purpose) of the tests.
289
+ =end
290
+ def description
291
+ property(:description)
292
+ end
293
+
294
+ def description=(val)
295
+ set_property(:description, val)
296
+ end
297
+
298
+ =begin rdoc
299
+ List all tests in suite.
300
+ =end
301
+ def tests
302
+ ensure_valid
303
+ @tests.keys
304
+ end
305
+
306
+ =begin rdoc
307
+ Instantiate Test object.
308
+ =end
309
+ def test(ident)
310
+ ensure_valid
311
+ @tests[ident]
312
+ end
313
+
314
+ =begin rdoc
315
+ Add a test to this suite.
316
+ =end
317
+ def add_test( ident, modules = [] )
318
+ ensure_valid
319
+ t = TestModelItem.new @model, @tests.add(self, { :ident => ident } )
320
+ modules.each { |m| t.add_module(m) }
321
+ end
322
+
323
+ =begin rdoc
324
+ Delete a test from this suite.
325
+ =end
326
+ def del_test(ident)
327
+ ensure_valid
328
+ @tests.delete(ident)
329
+ end
330
+
331
+ =begin rdoc
332
+ Perform all tests in this TestSuite.
333
+ This yields each Test to the supplied block. The code in the block is
334
+ expected to update the Test object Properties :pass and :log.
335
+ =end
336
+ def perform_tests(&block)
337
+ suite = self
338
+ @model.exec {
339
+ suite.tests.each do |ident|
340
+ t = suite.test(ident)
341
+ yield t
342
+ end
343
+ }
344
+ end
345
+ end
346
+
347
+ # ----------------------------------------------------------------------
348
+ =begin rdoc
349
+ A specific test.
350
+ This identifies a specific test which is associated with one or more Modules.
351
+ The testing software will invoke the perform method for each test it runs in
352
+ order to update the test results in the database.
353
+ =end
354
+ class TestModelItem < GitDS::ModelItem
355
+ name 'test'
356
+
357
+ property :pass, false
358
+ property :log, ''
359
+ property :timestamp
360
+
361
+ def self.fill(model, item_path, args)
362
+ super
363
+ # Note: by default, all tests are pass=false and timestamp=create_time
364
+ properties[:timestamp].set(model, item_path, Time.now.to_s)
365
+ end
366
+
367
+ def initialize(model, path)
368
+ super
369
+ @modules = GitDS::ProxyItemList.new(ModuleModelItem, model, path)
370
+ end
371
+
372
+ =begin rdoc
373
+ Store the results of performing a test.
374
+ =end
375
+ def perform(pass, log='', timestamp=Time.now)
376
+ set_property(:pass, pass)
377
+ set_property(:log, log)
378
+ set_property(:timestamp, timestamp)
379
+ end
380
+
381
+ =begin rdoc
382
+ The timestamp of the latest run of the test.
383
+ =end
384
+ def timestamp
385
+ ts_property(:timestamp)
386
+ end
387
+
388
+ =begin rdoc
389
+ The result of the latest run of the test.
390
+ =end
391
+ def pass?
392
+ bool_property(:pass)
393
+ end
394
+
395
+ =begin rdoc
396
+ The log from the latest run of the test.
397
+ =end
398
+ def log
399
+ property(:log)
400
+ end
401
+
402
+ =begin rdoc
403
+ List all modules associated with this test.
404
+ =end
405
+ def modules
406
+ ensure_valid
407
+ @modules.keys
408
+ end
409
+
410
+ =begin rdoc
411
+ Associate a module with this test.
412
+ =end
413
+ def add_module(m)
414
+ ensure_valid
415
+ @modules.add(self, m, true)
416
+ end
417
+ end
418
+
419
+ # ----------------------------------------------------------------------
420
+ =begin rdoc
421
+ A bug report. This includes a description of the bug and an open/closed status.
422
+ A Bug is associated with one or more Tests that cause the Bug to occur.
423
+ Bugs should be closed when none of their tests fail; this can be handled
424
+ automatically by calling Bug#update after performing tests.
425
+ =end
426
+ class BugModelItem < GitDS::ModelItem
427
+ name 'bug'
428
+
429
+ property :description
430
+ property :open, true
431
+
432
+ def initialize(model, path)
433
+ super
434
+ @tests = GitDS::ProxyItemList.new(TestModelItem, model, path)
435
+ end
436
+
437
+ =begin rdoc
438
+ Description of the bug and its effects.
439
+ =end
440
+ def description
441
+ property(:description)
442
+ end
443
+
444
+ def description=(val)
445
+ set_property(:description, val)
446
+ end
447
+
448
+ =begin rdoc
449
+ Status of the bug: open or closed?
450
+ =end
451
+ def open?
452
+ bool_property(:open)
453
+ end
454
+
455
+ def open=(val)
456
+ set_property(:open, val)
457
+ end
458
+
459
+ =begin rdoc
460
+ Tests which demonstrate the buig.
461
+ =end
462
+ def tests
463
+ ensure_valid
464
+ @tests.keys
465
+ end
466
+
467
+ =begin rdoc
468
+ Associated a test with this bug.
469
+
470
+ Note: t is a TestModelItem object.
471
+ =end
472
+ def add_test( t )
473
+ ensure_valid
474
+ @tests.add(self, t )
475
+ end
476
+
477
+ =begin rdoc
478
+ Delete a test from this suite.
479
+ =end
480
+ def del_test(ident)
481
+ ensure_valid
482
+ @tests.delete(ident)
483
+ end
484
+
485
+ =begin rdoc
486
+ Update the status of the bug: open if any of the tests fail, closed if all
487
+ of the tests pass.
488
+ =end
489
+ def update
490
+ pass_all = true
491
+ tests.each do |ident|
492
+ test = @tests[ident]
493
+ pass_all = false if not test.pass?
494
+ end
495
+
496
+ # pass_all should equal !open
497
+ if pass_all == open?
498
+ open = (not pass_all)
499
+ end
500
+ end
501
+
502
+ end
503
+