citron 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.ruby CHANGED
@@ -1,50 +1,47 @@
1
- ---
2
- authors:
1
+ ---
2
+ source:
3
+ - PROFILE
4
+ authors:
3
5
  - name: Thomas Sawyer
4
6
  email: transfire@gmail.com
5
- copyrights:
7
+ copyrights:
6
8
  - holder: Thomas Sawyer
7
- year: "2011"
9
+ year: '2011'
8
10
  license: BSD-2-Clause
9
- replacements: []
10
-
11
- conflicts: []
12
-
13
- requirements:
14
- - name: test
11
+ requirements:
12
+ - name: rubytest
15
13
  - name: ae
16
14
  - name: detroit
17
- groups:
15
+ groups:
18
16
  - build
19
17
  development: true
20
18
  - name: reap
21
- groups:
19
+ groups:
22
20
  - build
23
21
  development: true
24
22
  - name: qed
25
- groups:
23
+ groups:
26
24
  - test
27
25
  development: true
28
26
  dependencies: []
29
-
30
- repositories:
27
+ alternatives: []
28
+ conflicts: []
29
+ repositories:
31
30
  - uri: git://github.com/proutils/citron.git
32
31
  scm: git
33
32
  name: upstream
34
- resources:
33
+ resources:
35
34
  home: http://rubyworks.github.com/citron
36
35
  code: http://github.com/rubyworks/citron
37
- load_path:
36
+ extra: {}
37
+ load_path:
38
38
  - lib
39
- extra:
40
- manifest: MANIFEST
41
- alternatives: []
42
-
43
39
  revision: 0
44
40
  name: citron
45
41
  title: Citron
42
+ version: 0.3.0
46
43
  summary: Classic Unit-style Test Framework
47
- description: Citron is a unit testing framework with a classic test-case/test-unit style.
44
+ description: Citron is a unit testing framework with a classic test-case/test-unit
45
+ style.
48
46
  organization: RubyWorks
49
- version: 0.2.0
50
- date: "2011-08-12"
47
+ date: '2012-02-25'
@@ -1,12 +1,18 @@
1
- = COPYRIGHT NOTICES
1
+ # COPYRIGHT
2
2
 
3
- == Citron
4
3
 
5
- Copyright:: (c) 2011 Thomas Sawyer, RubyWorks
6
- License:: BSD-2-Clause
7
- Website:: http://rubyworks.github.com/citron
4
+ ## NOTICES
8
5
 
9
- Copyright 2011 Thomas Sawyer. All rights reserved.
6
+ ### Citron
7
+
8
+ http://rubyworks.github.com/citron
9
+
10
+ * Copyright (c) 2011 Rubyworks (BSD-2-Clause)
11
+
12
+
13
+ ## LICENSES
14
+
15
+ ### BSD-2-Clause
10
16
 
11
17
  Redistribution and use in source and binary forms, with or without
12
18
  modification, are permitted provided that the following conditions are met:
@@ -0,0 +1,22 @@
1
+ # Release History
2
+
3
+ ## 0.3.0 / 2012-02-25
4
+
5
+ This release cleans up the code, deprecates the complex Before and After
6
+ advice, adds soem additional support for RubyTests lesser known features.
7
+
8
+ Changes:
9
+
10
+ * Deprecated Before and After advice.
11
+ * Add support for #unit and #source_location.
12
+ * Setup/terdown is inherited by subcases.
13
+
14
+
15
+ ## 0.2.0 / 2011-08-11
16
+
17
+ This is the first usable release of Citron.
18
+
19
+ Changes:
20
+
21
+ * General improvements.
22
+
@@ -1,20 +1,17 @@
1
- = Citron
1
+ # Citron
2
2
 
3
- {Homepage}[http://rubyworks.github.com/citron] -
4
- {Development}[http://github.com/rubyworks/citron]
3
+ [Website](http://rubyworks.github.com/citron) /
4
+ [Development](http://github.com/rubyworks/citron) /
5
+ [Report Issue](http://github.com/rubyworks/citron/issues) /
5
6
 
6
- Author:: Thomas Sawyer
7
- License:: FreeBSD
8
- Copyright:: (c) 2011 Thomas Sawyer, Rubyworks
9
7
 
8
+ ## Description
10
9
 
11
- == Description
10
+ Citron is a traditional unit test framework. It defines a simple
11
+ domain language for creating classically styled unit tests.
12
12
 
13
- Citron is a classic unit test framework. It defines a simple
14
- domain language for create classic-style tests.
15
13
 
16
-
17
- == Example
14
+ ## Example
18
15
 
19
16
  Here's a fun example.
20
17
 
@@ -55,11 +52,11 @@ Here's a fun example.
55
52
  end
56
53
 
57
54
 
58
- == License
55
+ ## Copyrights
59
56
 
60
- Copyright (c) 2011 Thomas Sawyer, Rubyworks
57
+ Copyright (c) 2011 Rubyworks
61
58
 
62
- Citron is distributed according to the terms of the FreeBSD license.
59
+ Citron is distributable according to the terms of the **FreeBSD** license.
63
60
 
64
- See COPYING.rd for details.
61
+ See COPYING.md for details.
65
62
 
@@ -1,16 +1,16 @@
1
- module Citron
2
- $TEST_SUITE ||= []
1
+ $TEST_SUITE ||= []
3
2
 
4
- require 'citron/test_case'
5
- require 'citron/test_proc'
6
- require 'citron/test_advice'
3
+ module Citron
4
+ require 'citron/world'
7
5
  require 'citron/test_setup'
8
- end
6
+ require 'citron/test_teardown'
7
+ require 'citron/test_proc'
8
+ require 'citron/test_case'
9
9
 
10
- module Citron
11
10
  module DSL
12
-
11
+ #
13
12
  # Define a general test case.
13
+ #
14
14
  def test_case(label, &block)
15
15
  $TEST_SUITE << Citron::TestCase.new(:label=>label, &block)
16
16
  end
@@ -18,6 +18,8 @@ module Citron
18
18
  alias :TestCase :test_case
19
19
  alias :testcase :test_case
20
20
  end
21
+
21
22
  end
22
23
 
23
24
  extend Citron::DSL
25
+
@@ -1,10 +1,3 @@
1
- #require 'citron/pending'
2
- #require 'citron/test_context'
3
- require 'citron/test_advice'
4
- require 'citron/test_setup'
5
- require 'citron/test_proc'
6
- require 'citron/world'
7
-
8
1
  module Citron
9
2
 
10
3
  # Test Case encapsulates a collection of
@@ -18,30 +11,41 @@ module Citron
18
11
  # Brief description of the test case.
19
12
  attr :label
20
13
 
14
+ # Symbol list of tags. Trailing element may be Hash
15
+ # of `symbol => object`.
16
+ attr :tags
17
+
21
18
  # List of tests and sub-cases.
22
19
  attr :tests
23
20
 
24
- # The setup and teardown advice.
21
+ # The setup advice.
25
22
  attr :setup
26
23
 
27
- # Pattern mathing before and after advice.
28
- attr :advice
24
+ # The teardown advice.
25
+ attr :teardown
26
+
27
+ # Code unit that is subject of test case.
28
+ attr :unit
29
29
 
30
30
  # Module for evaluating tests.
31
31
  attr :scope
32
32
 
33
- # A test case +target+ is a class or module.
33
+ private
34
+
35
+ # Initialize new TestCase.
34
36
  #
35
37
  def initialize(settings={}, &block)
36
38
  @context = settings[:context]
37
39
  @label = settings[:label]
38
- @setup = settings[:setup]
40
+ @tags = settings[:tags]
41
+ #@setup = settings[:setup]
39
42
  @skip = settings[:skip]
40
43
 
41
- if @context
42
- @advice = context.advice.clone
43
- else
44
- @advice = TestAdvice.new
44
+ @unit = calc_unit
45
+
46
+ if context
47
+ @setup = context.setup.copy(self) if context.setup
48
+ @teardown = context.teardown.copy(self) if context.teardown
45
49
  end
46
50
 
47
51
  @tests = []
@@ -51,141 +55,235 @@ module Citron
51
55
  @scope.module_eval(&block) if block
52
56
  end
53
57
 
58
+ #
59
+ def calc_unit
60
+ case @label
61
+ when Module, Class
62
+ @label
63
+ when /^(\.|\#|\:\:)\w+/
64
+ if @context && Module === @context.unit
65
+ [@context.unit, @label].join('')
66
+ else
67
+ @label
68
+ end
69
+ end
70
+ end
71
+
72
+ public
73
+
74
+ #
75
+ # Assign the setup procedure
76
+ #
77
+ # @param [TestSetup] test_setup
78
+ #
79
+ def setup=(test_setup)
80
+ @setup = test_setup
81
+ end
82
+
83
+ #
84
+ # Assign the teardown procedure.
85
+ #
86
+ # @param [TestTeardown] test_teardown
87
+ #
88
+ def teardown=(test_teardown)
89
+ @teardown = test_teardown
90
+ end
91
+
92
+ #
93
+ # Add new test or sub-case.
94
+ #
95
+ # @param [TestCase,TestProc] test_obejct
96
+ # Test sub-case or procedure to add to this case.
54
97
  #
55
98
  def <<(test_object)
56
99
  @tests << test_object
57
100
  end
58
101
 
59
- # Iterate over each test and subcase.
102
+ #
103
+ # Iterate over each test and sub-case.
104
+ #
105
+ # @param [Proc] block
106
+ # Iteration procedure.
107
+ #
60
108
  def each(&block)
61
109
  tests.each(&block)
62
110
  end
63
111
 
64
- # Number of tests plus subcases.
112
+ #
113
+ #def call
114
+ # yield
115
+ #end
116
+
117
+ #
118
+ # Number of tests and sub-cases.
119
+ #
120
+ # @return [Fixnum] size
121
+ #
65
122
  def size
66
123
  tests.size
67
124
  end
68
125
 
126
+ #
69
127
  # Subclasses of TestCase can override this to describe
70
128
  # the type of test case they define.
71
- def type
72
- 'Case'
73
- end
129
+ #
130
+ # @return [String]
131
+ #
132
+ #def type
133
+ # 'TestCase'
134
+ #end
74
135
 
136
+ #
137
+ # Test case label.
138
+ #
139
+ # @return [String]
75
140
  #
76
141
  def to_s
77
142
  label.to_s
78
143
  end
79
144
 
145
+ #
146
+ # Is test case to be skipped?
147
+ #
148
+ # @return [Boolean,String]
149
+ # If +false+ or +nil+ if not skipped, otherwise
150
+ # +true+ or a string explain why to skip.
80
151
  #
81
152
  def skip?
82
153
  @skip
83
154
  end
84
155
 
156
+ #
157
+ # Set test case to be skipped.
158
+ #
159
+ # @param [Boolean,String] reason
160
+ # Set to +false+ or +nil+ if not skipped, otherwise
161
+ # +true+ or a string explain why to skip.
85
162
  #
86
163
  def skip=(reason)
87
164
  @skip = reason
88
165
  end
89
166
 
90
- # Run test in the context of this case.
167
+ def test_scope
168
+ @test_scope ||= TestProc::Scope.new(scope)
169
+ end
170
+
171
+ #
172
+ # Run +test+ in the context of this case.
91
173
  #
92
174
  # @param [TestProc] test
93
175
  # The test unit to run.
94
176
  #
95
- def run(test, &block)
96
- advice[:before].each do |matches, block|
97
- if matches.all?{ |match| test.match?(match) }
98
- scope.instance_exec(test, &block) #block.call(unit)
99
- end
100
- end
101
-
102
- block.call
103
-
104
- advice[:after].each do |matches, block|
105
- if matches.all?{ |match| test.match?(match) }
106
- scope.instance_exec(test, &block) #block.call(unit)
107
- end
108
- end
177
+ def run(test)
178
+ setup.call(test_scope) if setup
179
+ #scope.instance_exec(*arguments, &procedure)
180
+ test_scope.instance_eval(&test.procedure)
181
+ teardown.call(test_scope) if teardown
109
182
  end
110
183
 
184
+ # The evaluation scope for a test case.
111
185
  #
112
186
  class Scope < World
113
187
 
114
- # Setup new evaluation scope.
188
+ #
189
+ # Initialize new evaluation scope.
190
+ #
191
+ # @param [TestCase] testcase
192
+ # The test case this scope belongs.
193
+ #
115
194
  def initialize(testcase) #, &code)
116
195
  @_case = testcase
117
196
  @_setup = testcase.setup
118
197
  @_skip = false
119
198
 
120
199
  if testcase.context
121
- extend(testcase.context.scope)
200
+ include(testcase.context.scope)
122
201
  end
123
202
  end
124
203
 
125
- #--
126
- # TODO: Instead of reusing TestCase can we have a TestContext
127
- # that more generically mimics it's context context?
128
- #++
129
-
204
+ #
130
205
  # Create a sub-case.
131
- def Context(label, &block)
206
+ #
207
+ # @param [String] label
208
+ # The breif description of the test case.
209
+ #
210
+ # @param [Array<Symbol,Hash>] tags
211
+ # List of symbols with optional trailing `symbol=>object` hash.
212
+ # These can be used as a means of filtering tests.
213
+ #
214
+ def Context(label, *tags, &block)
132
215
  settings = {
133
216
  :context => @_case,
134
- :setup => @_setup,
217
+ #:setup => @_setup,
135
218
  :skip => @_skip,
136
- :label => label
219
+ :label => label,
220
+ :tags => tags
137
221
  }
222
+
138
223
  testcase = TestCase.new(settings, &block)
224
+
139
225
  @_case.tests << testcase
226
+
140
227
  testcase
141
228
  end
142
229
 
143
230
  alias :context :Context
144
231
 
145
- # Create a test.
146
- def Test(label=nil, &procedure)
232
+ #
233
+ # Create a test, or a parameterized test.
234
+ #
235
+ # @param [String] label
236
+ # The breif description of the test case.
237
+ #
238
+ # @param [Array<Symbol,Hash>] tags
239
+ # List of symbols with optional trailing `symbol=>object` hash.
240
+ # These can be used as a means of filtering tests.
241
+ #
242
+ def Test(label=nil, *tags, &procedure)
243
+ file, line, _ = *caller[0].split(':')
244
+
147
245
  settings = {
148
246
  :context => @_case,
149
- :setup => @_setup,
247
+ #:setup => @_setup,
150
248
  :skip => @_skip,
151
- :label => label
249
+ :label => label,
250
+ :tags => tags,
251
+ :file => file,
252
+ :line => line
152
253
  }
153
- testunit = TestProc.new(settings, &procedure)
154
- if procedure.arity == 0
155
- @_case.tests << testunit
254
+
255
+ if procedure.arity == 0 || (RUBY_VERSION < '1.9' && procedure.arity == -1)
256
+ test = TestProc.new(settings, &procedure)
257
+ @_case.tests << test
258
+ @_test = nil
259
+ test
156
260
  else
157
- @_test = testunit
261
+ @_test = [settings, procedure]
158
262
  end
159
- testunit
160
263
  end
161
264
 
162
265
  alias :test :Test
163
266
 
164
267
  #
268
+ # Actualize a parameterized test.
269
+ #
270
+ # @todo Better name than `Ok` ?
165
271
  #
166
272
  def Ok(*args)
167
- test = @_test
168
- test.arguments = args
169
- @_case << test
170
- @_test = nil
171
- return test
172
- end
273
+ settings, procedure = *@_test
173
274
 
174
- alias :ok :Ok
275
+ test = TestProc.new(settings) do
276
+ procedure.call(*args)
277
+ end
175
278
 
176
- #
177
- #
178
- def No(*args)
179
- test = @_test
180
- test.arguments = args
181
- test.negate = true
182
279
  @_case << test
183
- @_test = nil
280
+
184
281
  return test
185
282
  end
186
283
 
187
- alias :no :No
284
+ alias :ok :Ok
188
285
 
286
+ #
189
287
  # Setup is used to set things up for each unit test.
190
288
  # The setup procedure is run before each unit.
191
289
  #
@@ -193,97 +291,59 @@ module Citron
193
291
  # A brief description of what the setup procedure sets-up.
194
292
  #
195
293
  def Setup(label=nil, &proc)
196
- @_setup = TestSetup.new(@_case, label, &proc)
294
+ if proc
295
+ @_case.setup = TestSetup.new(@_case, label, &proc)
296
+ @_case.teardown = nil # if the setup is reset, then so it the teardown
297
+ else
298
+ @_case.setup
299
+ end
197
300
  end
198
301
 
199
302
  alias :setup :Setup
200
303
 
201
- #alias_method :Concern, :Setup
202
- #alias_method :concern, :Setup
203
-
304
+ #
204
305
  # Teardown procedure is used to clean-up after each unit test.
205
306
  #
206
307
  def Teardown(&proc)
207
- @_setup.teardown = proc
308
+ if proc
309
+ @_case.teardown = TestTeardown.new(@_case, &proc)
310
+ else
311
+ @_case.teardown
312
+ end
208
313
  end
209
314
 
210
315
  alias :teardown :Teardown
211
316
 
212
- # Define a _complex_ before procedure. The #before method allows
213
- # before procedures to be defined that are triggered by a match
214
- # against the unit's target method name or _aspect_ description.
215
- # This allows groups of tests to be defined that share special
216
- # setup code.
217
- #
218
- # @example
219
- # Method :puts do
220
- # Test "standard output (@stdout)" do
221
- # puts "Hello"
222
- # end
223
- #
224
- # Before /@stdout/ do
225
- # $stdout = StringIO.new
226
- # end
227
- #
228
- # After /@stdout/ do
229
- # $stdout = STDOUT
230
- # end
231
- # end
232
317
  #
233
- # @param [Array<Symbol,Regexp>] matches
234
- # List of match critera that must _all_ be matched
235
- # to trigger the before procedure.
318
+ # Mark tests or sub-cases to be skipped. If block is given, then
319
+ # tests defined within the block are skipped. Without a block
320
+ # all subsquent tests defined in a context will be skipped.
236
321
  #
237
- def Before(*matches, &procedure)
238
- @_case.advice[:before][matches] = procedure
239
- end
240
-
241
- alias :before :Before
242
-
243
- # Define a _complex_ after procedure. The #before method allows
244
- # before procedures to be defined that are triggered by a match
245
- # against the unit's target method name or _aspect_ description.
246
- # This allows groups of tests to be defined that share special
247
- # teardown code.
322
+ # @param [Boolean,String] reason
323
+ # Set to +false+ or +nil+ if not skipped, otherwise
324
+ # +true+ or a string explain why to skip.
248
325
  #
249
326
  # @example
250
- # Method :puts do
251
- # Test "standard output (@stdout)" do
252
- # puts "Hello"
253
- # end
254
- #
255
- # Before /@stdout/ do
256
- # $stdout = StringIO.new
257
- # end
258
- #
259
- # After /@stdout/ do
260
- # $stdout = STDOUT
327
+ # skip("awaiting new feature") do
328
+ # test "some test" do
329
+ # ...
261
330
  # end
262
331
  # end
263
332
  #
264
- # @param [Array<Symbol,Regexp>] matches
265
- # List of match critera that must _all_ be matched
266
- # to trigger the after procedure.
267
- #
268
- def After(*matches, &procedure)
269
- @_case.advice[:after][matches] = procedure
270
- end
271
-
272
- alias :after :After
273
-
274
- # Mark tests or subcases to be skipped.
275
- #
276
333
  # @example
277
- # skip("reason for skipping") do
278
- # test "some test" do
279
- # ...
280
- # end
334
+ # skip("not on jruby") if jruby?
335
+ # test "some test" do
336
+ # ...
281
337
  # end
282
338
  #
283
339
  def Skip(reason=true, &block)
284
- @_skip = reason
285
- block.call
286
- @_skip = false
340
+ if block
341
+ @_skip = reason
342
+ block.call if block
343
+ @_skip = false
344
+ else
345
+ @_skip = reason
346
+ end
287
347
  end
288
348
 
289
349
  alias :skip :Skip