git-ds 0.9.2

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.
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
+