baretest 0.2.4 → 0.4.0.pre1

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 (85) hide show
  1. data/LICENSE.txt +6 -6
  2. data/MANIFEST.txt +40 -18
  3. data/README.rdoc +8 -1
  4. data/bin/baretest +126 -118
  5. data/doc/baretest.rdoc +1 -1
  6. data/doc/mocking_stubbing_test_doubles.rdoc +31 -3
  7. data/doc/news/news-0.3.0.rdoc +7 -0
  8. data/doc/quickref.rdoc +74 -28
  9. data/doc/whats_going_on.rdoc +5 -0
  10. data/doc/writing_tests.rdoc +25 -13
  11. data/examples/components/rack-test.rb +17 -0
  12. data/examples/{tests/irb_mode → irb_mode}/failures.rb +0 -0
  13. data/examples/rake/test.rake +40 -0
  14. data/examples/tests/01_basics_I.rb +34 -0
  15. data/examples/tests/02_basics_II_helpers.rb +25 -0
  16. data/examples/tests/03_basics_III_setup_and_teardown.rb +53 -0
  17. data/examples/tests/04_advanced_I_dependencies.rb +31 -0
  18. data/examples/tests/05_advanced_II_tags.rb +12 -0
  19. data/examples/tests/06_advanced_III_requires.rb +21 -0
  20. data/examples/tests/07_advanced_IV_components.rb +48 -0
  21. data/examples/tests/08_expert_I_setup_variants.rb +46 -0
  22. data/lib/baretest.rb +142 -21
  23. data/lib/baretest/assertion.rb +83 -92
  24. data/lib/baretest/assertion/context.rb +9 -0
  25. data/lib/baretest/assertion/support.rb +88 -61
  26. data/lib/baretest/commandline.rb +268 -0
  27. data/lib/baretest/formatter.rb +58 -0
  28. data/lib/baretest/invalidselectors.rb +24 -0
  29. data/lib/baretest/irb_mode.rb +100 -58
  30. data/lib/baretest/persistence.rb +94 -0
  31. data/lib/baretest/run.rb +138 -37
  32. data/lib/baretest/run/cli.rb +97 -43
  33. data/lib/baretest/run/minimal.rb +2 -1
  34. data/lib/baretest/run/none.rb +21 -0
  35. data/lib/baretest/run/xml.rb +21 -19
  36. data/lib/baretest/setup.rb +2 -0
  37. data/lib/baretest/status.rb +93 -0
  38. data/lib/baretest/suite.rb +185 -59
  39. data/lib/baretest/uid.rb +51 -0
  40. data/lib/baretest/use/mocha.rb +24 -0
  41. data/lib/baretest/use/rack_test.rb +9 -0
  42. data/lib/baretest/use/rr.rb +17 -0
  43. data/lib/baretest/version.rb +18 -4
  44. data/lib/command.rb +36 -0
  45. data/lib/command/argument.rb +11 -0
  46. data/lib/command/decoratinghash.rb +31 -0
  47. data/lib/command/definition.rb +294 -0
  48. data/lib/command/directorynotfounderror.rb +11 -0
  49. data/lib/command/env.rb +11 -0
  50. data/lib/command/filenotfounderror.rb +11 -0
  51. data/lib/command/kernel.rb +14 -0
  52. data/lib/command/nodirectoryerror.rb +11 -0
  53. data/lib/command/nofileerror.rb +11 -0
  54. data/lib/command/option.rb +16 -0
  55. data/lib/command/parser.rb +145 -0
  56. data/lib/command/result.rb +11 -0
  57. data/lib/command/types.rb +33 -0
  58. data/lib/command/version.rb +28 -0
  59. data/test/setup.rb +3 -0
  60. data/test/suite/lib/baretest.rb +0 -178
  61. data/test/suite/lib/baretest/assertion.rb +133 -112
  62. data/test/suite/lib/baretest/assertion/context.rb +40 -0
  63. data/test/suite/lib/baretest/assertion/failure.rb +19 -0
  64. data/test/suite/lib/baretest/assertion/skip.rb +19 -0
  65. data/test/suite/lib/baretest/assertion/support.rb +366 -84
  66. data/test/suite/lib/baretest/run.rb +114 -15
  67. data/test/suite/lib/baretest/suite.rb +70 -29
  68. metadata +46 -24
  69. data/examples/test.rake +0 -65
  70. data/examples/tests/mock_developer/test/helper/mocks.rb +0 -0
  71. data/examples/tests/mock_developer/test/setup.rb +0 -57
  72. data/examples/tests/mock_developer/test/suite/mock_demo.rb +0 -19
  73. data/examples/tests/overview/test.rb +0 -89
  74. data/examples/tests/variations/variations_01.rb +0 -14
  75. data/examples/tests/variations/variations_02.rb +0 -19
  76. data/examples/tests/variations/variations_03.rb +0 -19
  77. data/lib/baretest/mocha.rb +0 -18
  78. data/lib/baretest/rr.rb +0 -16
  79. data/lib/baretest/run/errors.rb +0 -49
  80. data/lib/baretest/skipped.rb +0 -15
  81. data/lib/baretest/skipped/assertion.rb +0 -20
  82. data/lib/baretest/skipped/suite.rb +0 -49
  83. data/test/external/bootstraptest.rb +0 -5
  84. data/test/external/bootstrapwrap.rb +0 -2
  85. data/test/helper/mocks.rb +0 -0
@@ -0,0 +1,51 @@
1
+ #--
2
+ # Copyright 2010 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module BareTest
10
+
11
+ # Generate a unique ID.
12
+ # Not using uuid simply to avoid two dependencies (uuid, and uuid's dependency
13
+ # 'macaddr').
14
+ class UID
15
+
16
+ # :nodoc:
17
+ Epoch = Time.utc(2000,1,1).to_i
18
+
19
+ # The numeric value of the uid (an Integer)
20
+ attr_reader :value
21
+
22
+ # Returns a 32byte long String containing a new 16 byte random value
23
+ # in hex representation
24
+ def self.hex_uid
25
+ new.hex
26
+ end
27
+
28
+ # Create a 128bit (16 Byte) long random number
29
+ def initialize
30
+ now = Time.now
31
+
32
+ # Works for the next 100 years - should be enough
33
+ # after that, it'll wrap around.
34
+ time_part_52 = (((now.to_i-Epoch) & 0xffffffff) << 20) + now.usec
35
+
36
+ # Not solid, but for the purposes, should work
37
+ process_part32 = (Thread.current.object_id ^ Process.pid) & 0xfffffffff
38
+
39
+ # Add a bit of random noise
40
+ random_part44 = Kernel.rand(0x100000000000)
41
+
42
+ @value = (random_part44 << 84) + (process_part32 << 52) + time_part_52
43
+ end
44
+
45
+ # Returns a 32byte long String containing the 16 byte random value
46
+ # in hex representation
47
+ def hex
48
+ "%032x" % @value
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,24 @@
1
+ # Original by dominikh
2
+ # Adapted to :use framework by apeiros
3
+
4
+ # This file provides integration with the "mocha" mocking framework.
5
+
6
+
7
+ # Load this file and get integration with the "rr" mocking framework.
8
+
9
+ BareTest.new_component :mocha do
10
+ require 'mocha'
11
+
12
+ BareTest::Assertion::Context.send :include Mocha::API
13
+
14
+ teardown do
15
+ begin
16
+ mocha_verify
17
+ rescue Mocha::ExpectationError => e
18
+ @reason = e.message
19
+ @status = :failure
20
+ ensure
21
+ mocha_teardown
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ BareTest.new_component :rack_test do
2
+ begin
3
+ require 'rubygems'
4
+ rescue LoadError; end
5
+ require 'rack/test'
6
+
7
+ BareTest::Assertion::Context.send :include, Rack::Test::Methods
8
+ BareTest::Assertion::Context.send :attr_reader, :app
9
+ end
@@ -0,0 +1,17 @@
1
+ # Original by Tass`
2
+ # Adapted to :use framework by apeiros
3
+
4
+ BareTest.new_component :rr do
5
+ require 'rr'
6
+
7
+ BareTest::Assertion::Context.send :include, RR::Adapters::RRMethods
8
+
9
+ teardown do
10
+ begin
11
+ ::RR.verify
12
+ rescue ::RR::Errors => e
13
+ @reason = e.message
14
+ @status = :failure
15
+ end
16
+ end
17
+ end
@@ -12,17 +12,31 @@ module BareTest
12
12
  module VERSION
13
13
 
14
14
  # The major version number
15
- MAJOR = 0
15
+ MAJOR = 0
16
16
 
17
17
  # The minor version number
18
- MINOR = 2
18
+ MINOR = 4
19
19
 
20
20
  # The tiny version number
21
- TINY = 4
21
+ TINY = 0
22
+
23
+ # Prerelease number - nil for release versions
24
+ PRERELEASE = 1
25
+
26
+ # The version as a string
27
+ STRING = %{#{MAJOR}.#{MINOR||0}.#{TINY||0}#{".pre#{PRERELEASE}" if PRERELEASE}}
28
+
29
+ # The version as an array
30
+ ARRAY = [MAJOR || 0, MINOR || 0, TINY || 0, PRERELEASE].compact
22
31
 
23
32
  # The version as a string
24
33
  def self.to_s
25
- "#{MAJOR}.#{MINOR||0}.#{TINY||0}"
34
+ STRING
35
+ end
36
+
37
+ # The version as an array
38
+ def self.to_a
39
+ ARRAY
26
40
  end
27
41
  end
28
42
  end
data/lib/command.rb ADDED
@@ -0,0 +1,36 @@
1
+ #--
2
+ # Copyright 2010 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'command/kernel'
10
+ require 'command/nofileerror'
11
+ require 'command/nodirectoryerror'
12
+ require 'command/filenotfounderror'
13
+ require 'command/directorynotfounderror'
14
+ require 'command/types'
15
+ require 'command/argument'
16
+ require 'command/option'
17
+ require 'command/env'
18
+ require 'command/result'
19
+ require 'command/decoratinghash'
20
+ require 'command/definition'
21
+ require 'command/parser'
22
+
23
+
24
+
25
+ module Command
26
+ def self.define(*args, &block)
27
+ @main = Definition.new(*args, &block)
28
+ @main
29
+ end
30
+
31
+ def self.with(argv, &block)
32
+ parser = Parser.new($command, argv)
33
+ parser.instance_eval(&block)
34
+ parser
35
+ end
36
+ end
@@ -0,0 +1,11 @@
1
+ #--
2
+ # Copyright 2009-2010 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module Command
10
+ Argument = Struct.new(:name, :bare, :usage, :type, :description)
11
+ end
@@ -0,0 +1,31 @@
1
+ #--
2
+ # Copyright 2009-2010 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module Command
10
+ class DecoratingHash < Hash
11
+ attr_accessor :target
12
+
13
+ def self.new(target)
14
+ obj = super() do |h,k| h.target && h.target[k] end
15
+ obj.target = target
16
+ obj
17
+ end
18
+
19
+ alias own_size size unless method_defined? :own_size
20
+ alias own_length own_size
21
+
22
+ def size
23
+ @target ? keys.size : super
24
+ end
25
+ alias length size
26
+
27
+ def keys
28
+ @target ? (super | @target.keys) : super
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,294 @@
1
+ #--
2
+ # Copyright 2010 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ module Command
10
+ class Definition
11
+ RequiredOptionArgument = /[A-Z][A-Z_]*/
12
+ OptionArgument = /\[#{RequiredOptionArgument}\]|#{RequiredOptionArgument}/
13
+ ShortOption = /\A-[A-Za-z](?: #{OptionArgument})?\z/
14
+ NegationSequence = /\[(?:no-|with-|without-)\]/
15
+ LongOption = /\A--
16
+ (?:
17
+ #{NegationSequence}?[A-Za-z][A-Za-z0-9_-]* |
18
+ [A-Za-z][A-Za-z0-9_-]*#{NegationSequence}[A-Za-z0-9][A-Za-z0-9_-]
19
+ )
20
+ (?:\x20#{OptionArgument})?\z
21
+ /x
22
+
23
+ def self.create_argument(*args)
24
+ name = Symbol === args.first && args.shift
25
+ usage = args.shift
26
+ bare = usage[/\w+/]
27
+ type = Symbol === args.first && args.shift
28
+ description = args.shift
29
+
30
+ Argument.new(name, bare, usage, type, description)
31
+ end
32
+
33
+ # valid arguments:
34
+ # name # --> copy from parent
35
+ # name, short[, long][, type][, description]
36
+ # name, long[, type][, description]
37
+ #
38
+ # short can be
39
+ # * '-?' (short option without argument)
40
+ # * '-? REQUIRED' (short option with required argument)
41
+ # * '-? [OPTIONAL]' (short option with optional
42
+ # where ? is any of A-Za-z
43
+ # examples:
44
+ # * '-a'
45
+ # * '-a [OPTIONAL_ARG]'
46
+ # * '-a REQUIRED_ARG'
47
+ #
48
+ # long can be
49
+ # * '--?' (short option without argument)
50
+ # * '--? REQUIRED' (short option with required argument)
51
+ # * '--? [OPTIONAL]' (short option with optional
52
+ # where ? is [A-Za-z0-9][A-Za-z0-9-_]*
53
+ # It may contain a negation sequence, which is one of '[no-]', '[with-]', '[without-]'
54
+ # examples:
55
+ # * '--colored'
56
+ # * '--[no-]colors'
57
+ # * '--port PORT'
58
+ # * '--foo [OPTIONAL_ARG]'
59
+ #
60
+ # Only one of short and long may have the argument declared.
61
+ # Usually you'll have the argument in long and only have it in short if
62
+ # there's no long at all.
63
+ #
64
+ # type can be
65
+ # * :Virtual
66
+ # * :Boolean
67
+ # * :String (default)
68
+ # * :Integer
69
+ # * :Float
70
+ # * :Octal
71
+ # * :Hex
72
+ # * :File - requires the provided path to exist and be a file
73
+ # * :Directory - requires the provided path to exist and be a directory
74
+ # * :Path
75
+ #
76
+ # Exceptions (incomplete):
77
+ # * ArgumentError with single argument if it doesn't identify an inheritable option
78
+ # * ArgumentError on invalid short definition
79
+ # * ArgumentError on invalid long definition
80
+ # * ArgumentError on option argument declaration in both, short and long definition
81
+ # * ArgumentError on invalid/unsupported type
82
+ def self.create_option(name, *args)
83
+ case args.first when nil, /\A-[^- ]/ then
84
+ short = args.shift
85
+ end
86
+ case args.first when nil, /\A--[^- ]/ then
87
+ long = args.shift
88
+ end
89
+ case args.first when nil, Symbol then
90
+ type = args.shift
91
+ end
92
+ declaration = short ? [short,long].compact.join(", ") : " #{long}"
93
+ description = args.shift
94
+
95
+ raise ArgumentError, "Too many arguments" unless args.empty?
96
+ raise ArgumentError, "Invalid short declaration: #{short.inspect}" unless (short.nil? || short =~ ShortOption)
97
+ raise ArgumentError, "Invalid long declaration: #{long.inspect}" unless (long.nil? || long =~ LongOption)
98
+ raise ArgumentError, "Argument declaration must only be in one of short and long" if (short && long && short =~ /\s/ && long =~ /\s/)
99
+
100
+ necessity = :none
101
+ extract_argument = nil
102
+ extract_argument = short if short =~ /\s/
103
+ extract_argument = long if long =~ /\s/
104
+ if extract_argument then
105
+ flag, *argument = extract_argument.split(/ /)
106
+ extract_argument.replace(flag) # long/short should only contain the flag, not the argument declaration as well
107
+ raise ArgumentError, "Multiple arguments for an option not yet supported" if argument.size > 1
108
+ if argument.empty?
109
+ necessity = :none
110
+ elsif argument.first =~ /\A\[.*\]\z/ then
111
+ necessity = :optional
112
+ else
113
+ necessity = :required
114
+ end
115
+ end
116
+
117
+ negated = nil
118
+ if long =~ NegationSequence then
119
+ negated = long.delete('[]')
120
+ long = long.gsub(NegationSequence, '')
121
+ end
122
+
123
+ Option.new(name, short, long, negated, necessity, type, declaration, description)
124
+ end
125
+
126
+
127
+ attr_reader :arguments
128
+ attr_reader :arguments_by_name
129
+ attr_reader :default_options
130
+ attr_reader :options_by_name
131
+ attr_reader :options_by_flag
132
+ attr_reader :commands_by_name
133
+ attr_reader :default_command
134
+ attr_reader :argument_position
135
+ attr_reader :env_by_variable
136
+ attr_reader :parent # parent= must update the DecoratingHashes
137
+
138
+ def initialize(parent=nil, default_command=nil, default_options={}, &block)
139
+ @default_command = default_command
140
+ @default_options = DecoratingHash.new(@parent && @parent.default_options).update(default_options)
141
+ @elements = []
142
+ @parent = parent
143
+ @arguments_by_name = DecoratingHash.new(@parent && @parent.arguments_by_name)
144
+ @options_by_name = DecoratingHash.new(@parent && @parent.options_by_name)
145
+ @options_by_flag = DecoratingHash.new(@parent && @parent.options_by_flag)
146
+ @commands_by_name = DecoratingHash.new(@parent && @parent.commands_by_name)
147
+ @env_by_variable = DecoratingHash.new(@parent && @parent.env_by_variable)
148
+ @argument_position = {}
149
+ @text = []
150
+ @placeholders = {}
151
+ @content_for = [@elements]
152
+ instance_eval(&block) if block
153
+ end
154
+
155
+ def [](command)
156
+ command ? @commands_by_name[command] : self
157
+ end
158
+
159
+ def content_for(placeholder)
160
+ @placeholders[placeholder] ||= []
161
+ @content_for << @placeholders[placeholder]
162
+ yield(self)
163
+ @content_for.pop
164
+ end
165
+
166
+ def usage_text(elements=@elements)
167
+ longest_arg_bare = elements.grep(Argument).max { |a,b|
168
+ a.bare.size <=> b.bare.size
169
+ }
170
+ longest_option = elements.grep(Option).max { |a,b|
171
+ a.declaration.size <=> b.declaration.size
172
+ }
173
+ longest_env_name = elements.grep(Env).max { |a,b|
174
+ a.variable.size <=> b.variable.size
175
+ }
176
+ longest_arg_bare = longest_arg_bare && longest_arg_bare.bare.size
177
+ longest_option = longest_option && longest_option.declaration.size
178
+ longest_env_name = longest_env_name && longest_env_name.variable.size
179
+ arguments = elements.grep(Argument)
180
+
181
+ elements.map { |e|
182
+ case e
183
+ when :usage
184
+ "Usage: #{File.basename($0)} #{arguments.map{|a|a.usage}.join(' ')}\n"
185
+ when Symbol # placeholder
186
+ usage_text(@placeholders[e])
187
+ when Option
188
+ sprintf " %*s%s\n",
189
+ -(longest_option+2),
190
+ e.declaration,
191
+ e.description
192
+ when Env
193
+ sprintf "* %*s%s\n",
194
+ -longest_env_name-2,
195
+ e.variable,
196
+ @options_by_name[e.name].description
197
+ when String
198
+ e+"\n"
199
+ when Argument
200
+ indent = "\n "+(" "*longest_arg_bare)
201
+ sprintf " %*s%s\n",
202
+ -(longest_arg_bare+3),
203
+ "#{e.bare}:",
204
+ e.description.to_s.gsub(/\n/, indent)
205
+ when Definition
206
+ else
207
+ "unimplemented(#{e.class})"
208
+ end
209
+ }.join('')
210
+ end
211
+
212
+ def usage
213
+ @content_for.last << :usage
214
+ end
215
+
216
+ def argument(*args)
217
+ unless @argument_position[args.first]
218
+ @argument_position[args.first] = @argument_position.size
219
+ end
220
+
221
+ if args.size == 1 then
222
+ argument = @arguments_by_name[args.first]
223
+ raise ArgumentError, "No argument with name #{args.first.inspect} in any parent found." unless argument
224
+ else
225
+ argument = self.class.create_argument(*args)
226
+ @arguments_by_name[argument.name] = argument
227
+ end
228
+ @content_for.last << argument
229
+
230
+ argument
231
+ end
232
+
233
+ def virtual_argument(*args)
234
+ if args.size == 1 then
235
+ argument = @arguments_by_name[args.first]
236
+ raise ArgumentError, "No argument with name #{args.first.inspect} in any parent found." unless argument
237
+ else
238
+ argument = self.class.create_argument(*args)
239
+ @arguments_by_name[argument.name] = argument
240
+ end
241
+
242
+ @content_for.last << argument
243
+ argument
244
+ end
245
+
246
+ def option(*args)
247
+ if args.size == 1 then
248
+ inherited_option = @options_by_name[args.first]
249
+ raise ArgumentError, "No inherited option #{args.first.inspect}" unless inherited_option
250
+ @content_for.last << inherited_option
251
+
252
+ inherited_option
253
+ else
254
+ option = self.class.create_option(*args)
255
+
256
+ @options_by_name[option.name] = option
257
+ @options_by_flag[option.short] = option
258
+ @options_by_flag[option.long] = option
259
+ @options_by_flag[option.negated] = option
260
+ @content_for.last << option
261
+
262
+ option
263
+ end
264
+ end
265
+ alias o option
266
+
267
+ def text(*args)
268
+ if args.size == 2 then
269
+ indent, text = *args
270
+ text = text.gsub(/^/, indent)
271
+ else
272
+ text = args.first
273
+ end
274
+ @text << text
275
+ @content_for.last << text
276
+ end
277
+
278
+ def placeholder(identifier)
279
+ @content_for.last << identifier
280
+ end
281
+
282
+ def env_option(name, variable)
283
+ env = Env.new(name, variable)
284
+ @env_by_variable[variable] = env
285
+ @content_for.last << env
286
+ end
287
+
288
+ def command(*args, &block)
289
+ definition = Definition.new(self, *args, &block)
290
+ @commands_by_name[args.first] = definition
291
+ @content_for.last << definition
292
+ end
293
+ end
294
+ end