rutema 2.0.0.pre5 → 2.0.0.pre6

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.
@@ -1,195 +1,208 @@
1
- # Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
2
- require 'ostruct'
3
- require_relative 'parser'
4
- require_relative 'reporter'
5
- module Rutema
6
- #This module defines the "configuration directives" used in the configuration of Rutema
7
- #
8
- #Example
9
- #A configuration file needs as a minimum to define which parser to use and which tests to run.
10
- #
11
- #Since rutema configuration files are valid Ruby code, you can use the full power of the Ruby language including require directives
12
- #
13
- # require 'rake'
14
- # configuration.parser={:class=>Rutema::MinimalXMLParser}
15
- # configuration.tests=FileList['all/of/the/tests/**/*.*']
16
- module ConfigurationDirectives
17
- attr_reader :parser,:runner,:tools,:paths,:tests,:context,:check,:setup,:teardown
18
- attr_accessor :reporters
19
- #Adds a hash of values to the tools hash of the configuration
20
- #
21
- #This hash is then accessible in the parser and reporters as a property of the configuration instance
22
- #
23
- #Required keys:
24
- # :name - the name to use for accessing the path in code
25
- #Example:
26
- # configure do |cfg|
27
- # cfg.tool={:name=>"nunit",:path=>"/bin/nunit",:configuration=>{:important=>"info"}}
28
- # end
29
- #
30
- #The path to nunit can then be accessed in the parser as
31
- # @configuration.tools.nunit[:path]
32
- #
33
- #This way you can pass configuration information for the tools you use
34
- def tool= definition
35
- raise ConfigurationException,"required key :name is missing from #{definition}" unless definition[:name]
36
- @tools[definition[:name]]=definition
37
- end
38
- #Adds a path to the paths hash of the configuration
39
- #
40
- #Required keys:
41
- # :name - the name to use for accessing the path in code
42
- # :path - the path
43
- #Example:
44
- # cfg.path={:name=>"sources",:path=>"/src"}
45
- def path= definition
46
- raise ConfigurationException,"required key :name is missing from #{definition}" unless definition[:name]
47
- raise ConfigurationException,"required key :path is missing from #{definition}" unless definition[:path]
48
- @paths[definition[:name]]=definition[:path]
49
- end
50
-
51
- #Path to the setup specification. (optional)
52
- #
53
- #The setup test runs before every test.
54
- def setup= path
55
- @setup=check_path(path)
56
- end
57
-
58
- #Path to the teardown specification. (optional)
59
- #
60
- #The teardown test runs after every test.
61
- def teardown= path
62
- @teardown=check_path(path)
63
- end
64
-
65
- #Path to the check specification. (optional)
66
- #
67
- #The check test runs once in the beginning before all the tests.
68
- #
69
- #If it fails no tests are run.
70
- def check= path
71
- @check=check_path(path)
72
- end
73
-
74
- #Hash values for passing data to the system. It's supposed to be used in the reporters and contain
75
- #values such as version numbers, tester names etc.
76
- def context= definition
77
- @context||=Hash.new
78
- raise ConfigurationException,"Only accepting hash values as context_data" unless definition.kind_of?(Hash)
79
- @context.merge!(definition)
80
- end
81
-
82
- #Adds the specification identifiers available to this instance of Rutema
83
- #
84
- #These will usually be files, but they can be anything.
85
- #Essentially this is an Array of strings that mean something to your parser
86
- def tests= array_of_identifiers
87
- @tests+=array_of_identifiers.map{|f| full_path(f)}
88
- end
89
-
90
- #A hash defining the parser to use.
91
- #
92
- #The hash is passed as is to the parser constructor and each parser should define the necessary configuration keys.
93
- #
94
- #The only required key from the configurator's point fo view is :class which should be set to the fully qualified name of the class to use.
95
- #
96
- #Example:
97
- # cfg.parser={:class=>Rutema::MinimalXMLParser}
98
- def parser= definition
99
- raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
100
- @parser=definition
101
- end
102
-
103
- #Adds a reporter to the configuration.
104
- #
105
- #As with the parser, the only required configuration key is :class and the definition hash is passed to the class' constructor.
106
- #
107
- #Unlike the parser, you can define multiple reporters.
108
- def reporter= definition
109
- raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
110
- @reporters[definition[:class]]=definition
111
- end
112
-
113
- def init
114
- @reporters={}
115
- @context={}
116
- @tests=[]
117
- @tools=OpenStruct.new
118
- @paths=OpenStruct.new
119
- end
120
- private
121
- #Checks if a path exists and raises a ConfigurationException if not
122
- def check_path path
123
- path=File.expand_path(path)
124
- raise ConfigurationException,"#{path} does not exist" unless File.exists?(path)
125
- return path
126
- end
127
- #Gives back a string of key=value,key=value for a hash
128
- def definition_string definition
129
- msg=Array.new
130
- definition.each{|k,v| msg<<"#{k}=#{v}"}
131
- return msg.join(",")
132
- end
133
-
134
- def full_path filename
135
- return File.expand_path(filename) if File.exists?(filename)
136
- return filename
137
- end
138
- end
139
-
140
- class ConfigurationException<RuntimeError
141
- end
142
-
143
- class Configuration
144
- include ConfigurationDirectives
145
- attr_reader :filename
146
- def initialize config_file
147
- @filename=config_file
148
- init
149
- load_configuration(@filename)
150
- end
151
-
152
- def configure
153
- if block_given?
154
- yield self
155
- end
156
- end
157
-
158
- #Loads the configuration from a file
159
- #
160
- #Use this to chain configuration files together
161
- #==Example
162
- #Say you have on configuration file "first.rutema" that contains all the generic directives and several others that change only one or two things.
163
- #
164
- #You can import the first.rutema file in the other configurations with
165
- # import("first.rutema")
166
- def import filename
167
- fnm = File.expand_path(filename)
168
- if File.exists?(fnm)
169
- load_configuration(fnm)
170
- else
171
- raise ConfigurationException, "Import error: Can't find #{fnm}"
172
- end
173
- end
174
- private
175
- def load_configuration filename
176
- begin
177
- cfg_txt=File.read(filename)
178
- cwd=File.expand_path(File.dirname(filename))
179
- #evaluate in the working directory to enable relative paths in configuration
180
- Dir.chdir(cwd){eval(cfg_txt,binding(),filename,__LINE__)}
181
- rescue ConfigurationException
182
- #pass it on, do not wrap again
183
- raise
184
- rescue SyntaxError
185
- #Just wrap the exception so we can differentiate
186
- raise ConfigurationException.new,"Syntax error in the configuration file '#{filename}':\n#{$!.message}"
187
- rescue NoMethodError
188
- raise ConfigurationException.new,"Encountered an unknown directive in configuration file '#{filename}':\n#{$!.message}"
189
- rescue
190
- #Just wrap the exception so we can differentiate
191
- raise ConfigurationException.new,"#{$!.message}"
192
- end
193
- end
194
- end
1
+ # Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
2
+ require 'ostruct'
3
+ require_relative 'parser'
4
+ require_relative 'reporter'
5
+ module Rutema
6
+ #This module defines the "configuration directives" used in the configuration of Rutema
7
+ #
8
+ #Example
9
+ #A configuration file needs as a minimum to define which parser to use and which tests to run.
10
+ #
11
+ #Since rutema configuration files are valid Ruby code, you can use the full power of the Ruby language including require directives
12
+ #
13
+ # require 'rake'
14
+ # configuration.parser={:class=>Rutema::MinimalXMLParser}
15
+ # configuration.tests=FileList['all/of/the/tests/**/*.*']
16
+ module ConfigurationDirectives
17
+ attr_reader :parser,:runner,:tools,:paths,:tests,:context,:check,:setup,:teardown
18
+ attr_accessor :reporters
19
+ #Adds a hash of values to the tools hash of the configuration
20
+ #
21
+ #This hash is then accessible in the parser and reporters as a property of the configuration instance
22
+ #
23
+ #Required keys:
24
+ # :name - the name to use for accessing the path in code
25
+ #Example:
26
+ # configure do |cfg|
27
+ # cfg.tool={:name=>"nunit",:path=>"/bin/nunit",:configuration=>{:important=>"info"}}
28
+ # end
29
+ #
30
+ #The path to nunit can then be accessed in the parser as
31
+ # @configuration.tools.nunit[:path]
32
+ #
33
+ #This way you can pass configuration information for the tools you use
34
+ def tool= definition
35
+ raise ConfigurationException,"required key :name is missing from #{definition}" unless definition[:name]
36
+ @tools[definition[:name]]=definition
37
+ end
38
+ #Adds a path to the paths hash of the configuration
39
+ #
40
+ #Required keys:
41
+ # :name - the name to use for accessing the path in code
42
+ # :path - the path
43
+ #Example:
44
+ # cfg.path={:name=>"sources",:path=>"/src"}
45
+ def path= definition
46
+ raise ConfigurationException,"required key :name is missing from #{definition}" unless definition[:name]
47
+ raise ConfigurationException,"required key :path is missing from #{definition}" unless definition[:path]
48
+ @paths[definition[:name]]=definition[:path]
49
+ end
50
+
51
+ #Path to the setup specification. (optional)
52
+ #
53
+ #The setup test runs before every test.
54
+ def setup= path
55
+ @setup=check_path(path)
56
+ end
57
+
58
+ #Path to the teardown specification. (optional)
59
+ #
60
+ #The teardown test runs after every test.
61
+ def teardown= path
62
+ @teardown=check_path(path)
63
+ end
64
+
65
+ #Path to the check specification. (optional)
66
+ #
67
+ #The check test runs once in the beginning before all the tests.
68
+ #
69
+ #If it fails no tests are run.
70
+ def check= path
71
+ @check=check_path(path)
72
+ end
73
+
74
+ #Hash values for passing data to the system. It's supposed to be used in the reporters and contain
75
+ #values such as version numbers, tester names etc.
76
+ def context= definition
77
+ @context||=Hash.new
78
+ raise ConfigurationException,"Only accepting hash values as context_data" unless definition.kind_of?(Hash)
79
+ @context.merge!(definition)
80
+ end
81
+
82
+ #Adds the specification identifiers available to this instance of Rutema
83
+ #
84
+ #These will usually be files, but they can be anything.
85
+ #Essentially this is an Array of strings that mean something to your parser
86
+ def tests= array_of_identifiers
87
+ @tests+=array_of_identifiers.map{|f| full_path(f)}
88
+ end
89
+
90
+ #A hash defining the parser to use.
91
+ #
92
+ #The hash is passed as is to the parser constructor and each parser should define the necessary configuration keys.
93
+ #
94
+ #The only required key from the configurator's point fo view is :class which should be set to the fully qualified name of the class to use.
95
+ #
96
+ #Example:
97
+ # cfg.parser={:class=>Rutema::MinimalXMLParser}
98
+ def parser= definition
99
+ raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
100
+ @parser=definition
101
+ end
102
+
103
+ #A hash defining the runner to use.
104
+ #
105
+ #The hash is passed as is to the runner constructor and each runner should define the necessary configuration keys.
106
+ #
107
+ #The only required key from the configurator's point fo view is :class which should be set to the fully qualified name of the class to use.
108
+ #
109
+ #Example:
110
+ # cfg.runner={:class=>Rutema::Runners::NoOp}
111
+ def runner= definition
112
+ raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
113
+ @runner=definition
114
+ end
115
+
116
+ #Adds a reporter to the configuration.
117
+ #
118
+ #As with the parser, the only required configuration key is :class and the definition hash is passed to the class' constructor.
119
+ #
120
+ #Unlike the parser, you can define multiple reporters.
121
+ def reporter= definition
122
+ raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
123
+ @reporters[definition[:class]]=definition
124
+ end
125
+
126
+ def init
127
+ @reporters={}
128
+ @context={}
129
+ @tests=[]
130
+ @tools=OpenStruct.new
131
+ @paths=OpenStruct.new
132
+ end
133
+ private
134
+ #Checks if a path exists and raises a ConfigurationException if not
135
+ def check_path path
136
+ path=File.expand_path(path)
137
+ raise ConfigurationException,"#{path} does not exist" unless File.exist?(path)
138
+ return path
139
+ end
140
+ #Gives back a string of key=value,key=value for a hash
141
+ def definition_string definition
142
+ msg=Array.new
143
+ definition.each{|k,v| msg<<"#{k}=#{v}"}
144
+ return msg.join(",")
145
+ end
146
+
147
+ def full_path filename
148
+ return File.expand_path(filename) if File.exist?(filename)
149
+ return filename
150
+ end
151
+ end
152
+
153
+ class ConfigurationException<RuntimeError
154
+ end
155
+
156
+ class Configuration
157
+ include ConfigurationDirectives
158
+ attr_reader :filename
159
+ def initialize config_file
160
+ @filename=config_file
161
+ init
162
+ load_configuration(@filename)
163
+ end
164
+
165
+ def configure
166
+ if block_given?
167
+ yield self
168
+ end
169
+ end
170
+
171
+ #Loads the configuration from a file
172
+ #
173
+ #Use this to chain configuration files together
174
+ #==Example
175
+ #Say you have on configuration file "first.rutema" that contains all the generic directives and several others that change only one or two things.
176
+ #
177
+ #You can import the first.rutema file in the other configurations with
178
+ # import("first.rutema")
179
+ def import filename
180
+ fnm = File.expand_path(filename)
181
+ if File.exist?(fnm)
182
+ load_configuration(fnm)
183
+ else
184
+ raise ConfigurationException, "Import error: Can't find #{fnm}"
185
+ end
186
+ end
187
+ private
188
+ def load_configuration filename
189
+ begin
190
+ cfg_txt=File.read(filename)
191
+ cwd=File.expand_path(File.dirname(filename))
192
+ #evaluate in the working directory to enable relative paths in configuration
193
+ Dir.chdir(cwd){eval(cfg_txt,binding(),filename,__LINE__)}
194
+ rescue ConfigurationException
195
+ #pass it on, do not wrap again
196
+ raise
197
+ rescue SyntaxError
198
+ #Just wrap the exception so we can differentiate
199
+ raise ConfigurationException.new,"Syntax error in the configuration file '#{filename}':\n#{$!.message}"
200
+ rescue NoMethodError
201
+ raise ConfigurationException.new,"Encountered an unknown directive in configuration file '#{filename}':\n#{$!.message}"
202
+ rescue
203
+ #Just wrap the exception so we can differentiate
204
+ raise ConfigurationException.new,"#{$!.message}"
205
+ end
206
+ end
207
+ end
195
208
  end