fix 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +1 -5
  5. data/.rubocop.yml +12 -0
  6. data/.travis.yml +12 -3
  7. data/.yardopts +1 -0
  8. data/CODE_OF_CONDUCT.md +13 -0
  9. data/Gemfile +1 -0
  10. data/LICENSE.md +17 -18
  11. data/README.md +70 -78
  12. data/Rakefile +5 -2
  13. data/VERSION.semver +1 -1
  14. data/bin/console +7 -0
  15. data/bin/setup +5 -0
  16. data/certs/gem-fixrb-public_cert.pem +21 -0
  17. data/fix.gemspec +17 -18
  18. data/lib/fix.rb +20 -98
  19. data/lib/fix/helpers/it_helper.rb +32 -0
  20. data/lib/fix/helpers/on_helper.rb +29 -0
  21. data/lib/fix/it.rb +6 -9
  22. data/lib/fix/on.rb +30 -13
  23. data/lib/fix/report.rb +61 -0
  24. data/lib/fix/sandbox.rb +25 -0
  25. data/lib/fix/test.rb +50 -224
  26. data/pkg_checksum +11 -0
  27. metadata +61 -152
  28. metadata.gz.sig +0 -0
  29. data/.coveralls.yml +0 -1
  30. data/bin/fix +0 -5
  31. data/fix.pem +0 -21
  32. data/lib/fix/db.rb +0 -23
  33. data/lib/fix/dsl.rb +0 -17
  34. data/lib/fix/expectation.rb +0 -80
  35. data/lib/fix/expectation_high.rb +0 -15
  36. data/lib/fix/expectation_low.rb +0 -19
  37. data/lib/fix/expectation_medium.rb +0 -21
  38. data/lib/fix/helper/it_helper.rb +0 -12
  39. data/lib/fix/helper/its_helper.rb +0 -20
  40. data/lib/fix/helper/let_accessor_helper.rb +0 -11
  41. data/lib/fix/helper/let_reader_helper.rb +0 -13
  42. data/lib/fix/helper/let_writer_helper.rb +0 -15
  43. data/lib/fix/helper/on_helper.rb +0 -20
  44. data/lib/fix/helper/requirement_helper.rb +0 -44
  45. data/lib/fix/its.rb +0 -13
  46. data/lib/fix/subject.rb +0 -44
  47. data/lib/fix/version.rb +0 -9
  48. data/spec/fix/bin/color_spec.rb +0 -17
  49. data/spec/fix/bin/exit_status_spec.rb +0 -19
  50. data/spec/fix/bin/help_spec.rb +0 -13
  51. data/spec/fix/bin/hide_progress.rb +0 -17
  52. data/spec/fix/bin/spec_helper.rb +0 -3
  53. data/spec/fix/bin/version_spec.rb +0 -9
  54. data/spec/fix/lib/may/error_spec.rb +0 -9
  55. data/spec/fix/lib/may/info_spec.rb +0 -9
  56. data/spec/fix/lib/may/spec_helper.rb +0 -1
  57. data/spec/fix/lib/may/success_spec.rb +0 -9
  58. data/spec/fix/lib/must/error_spec.rb +0 -9
  59. data/spec/fix/lib/must/failure_spec.rb +0 -9
  60. data/spec/fix/lib/must/spec_helper.rb +0 -1
  61. data/spec/fix/lib/must/success_spec.rb +0 -9
  62. data/spec/fix/lib/should/error_spec.rb +0 -9
  63. data/spec/fix/lib/should/info_spec.rb +0 -9
  64. data/spec/fix/lib/should/spec_helper.rb +0 -1
  65. data/spec/fix/lib/should/success_spec.rb +0 -9
  66. data/spec/fix/lib/spec_helper.rb +0 -1
  67. data/spec/fix/lib/success_spec.rb +0 -9
  68. data/spec/fix/spec_helper.rb +0 -1
  69. data/spec/spec_helper.rb +0 -4
  70. data/spec/support.rb +0 -3
  71. data/spec/support/coverage.rb +0 -9
  72. data/spec/support/env.rb +0 -1
  73. data/spec/support/examples/42/app.rb +0 -1
  74. data/spec/support/examples/42/may/error/spec.rb +0 -7
  75. data/spec/support/examples/42/may/error/test.rb +0 -7
  76. data/spec/support/examples/42/may/info/spec.rb +0 -7
  77. data/spec/support/examples/42/may/info/test.rb +0 -7
  78. data/spec/support/examples/42/may/success/spec.rb +0 -12
  79. data/spec/support/examples/42/may/success/test.rb +0 -7
  80. data/spec/support/examples/42/must/error/spec.rb +0 -11
  81. data/spec/support/examples/42/must/error/test.rb +0 -7
  82. data/spec/support/examples/42/must/failure/spec.rb +0 -7
  83. data/spec/support/examples/42/must/failure/test.rb +0 -7
  84. data/spec/support/examples/42/must/success/spec.rb +0 -7
  85. data/spec/support/examples/42/must/success/test.rb +0 -7
  86. data/spec/support/examples/42/should/error/spec.rb +0 -11
  87. data/spec/support/examples/42/should/error/test.rb +0 -7
  88. data/spec/support/examples/42/should/info/spec.rb +0 -7
  89. data/spec/support/examples/42/should/info/test.rb +0 -7
  90. data/spec/support/examples/42/should/success/spec.rb +0 -7
  91. data/spec/support/examples/42/should/success/test.rb +0 -7
  92. data/spec/support/examples/duck/app.rb +0 -16
  93. data/spec/support/examples/duck/success/spec.rb +0 -80
  94. data/spec/support/examples/duck/success/test.rb +0 -7
  95. data/spec/support/immutable.rb +0 -12
data/lib/fix.rb CHANGED
@@ -1,103 +1,25 @@
1
- require_relative File.join 'fix', 'dsl'
2
- require_relative File.join 'fix', 'version'
3
-
4
- require 'optparse'
5
- require 'set'
1
+ require_relative File.join 'fix', 'test'
6
2
 
7
3
  # Namespace for the Fix framework.
4
+ #
5
+ # @api public
6
+ #
8
7
  module Fix
9
-
10
- # This is the command line top-level run method. Everything starts from here.
11
- def self.run *args
12
- process_args args
13
- file_paths = fetch_file_paths args
14
-
15
- print '> fix'
16
- print ' --color' if defined? COLOR
17
- print ' --debug' if $DEBUG
18
- print ' --hide_progress' if defined? HIDE_PROGRESS
19
- print " --seed #{SEED}" if defined? SEED
20
- print ' --warnings' if $VERBOSE
21
-
22
- puts ' ' + file_paths.to_a.join(' ')
23
-
24
- require_relative File.join 'fix', 'dsl'
25
- file_paths.each {|file_path| require file_path }
26
- end
27
-
28
- def self.process_args args
29
- options = {
30
- color: false,
31
- debug: false,
32
- hide_progress: false,
33
- seed: Random.new_seed,
34
- warnings: false
35
- }
36
-
37
- opt_parser = OptionParser.new do |opts|
38
- opts.banner = 'Usage: fix <files or directories> [options]'
39
-
40
- opts.separator ''
41
- opts.separator 'Specific options:'
42
-
43
- opts.on('--color', 'Enable color in the output.') do
44
- options[:color] = (const_set :COLOR, true)
45
- end
46
-
47
- opts.on('--debug', 'Enable ruby debug') do
48
- options[:debug] = $DEBUG = true
49
- end
50
-
51
- opts.on('--hide_progress', 'Disable progress reporter in the output.') do
52
- options[:hide_progress] = (const_set :HIDE_PROGRESS, true)
53
- end
54
-
55
- opts.on('--seed [INTEGER]', Integer, 'Order of the tests') do |seed|
56
- options[:seed] = seed
57
- end
58
-
59
- opts.on('--warnings', 'Enable ruby warnings') do
60
- options[:warnings] = $VERBOSE = true
61
- end
62
-
63
- opts.separator ''
64
- opts.separator 'Common options:'
65
-
66
- opts.on_tail '--help', 'Show this message' do
67
- puts opts
68
- exit
69
- end
70
-
71
- opts.on_tail '--version', 'Show the version' do
72
- puts VERSION
73
- exit
74
- end
75
- end
76
-
77
- opt_parser.parse! args
78
- const_set :SEED, options.fetch(:seed)
79
- options
80
- end
81
-
82
- def self.fetch_file_paths args
83
- absolute_paths = Set.new
84
-
85
- args.map do |s|
86
- s = File.absolute_path s unless s.start_with? File::SEPARATOR
87
-
88
- if File.directory? s
89
- spec_files = File.join s, '**', '*_spec.rb'
90
- Dir.glob(spec_files).each {|spec_file| absolute_paths.add spec_file }
91
- else
92
- absolute_paths.add s
93
- end
94
- end
95
-
96
- if absolute_paths.empty?
97
- warn 'Sorry, files or directories not found.'
98
- exit 1
99
- end
100
-
101
- absolute_paths
8
+ # Specs are built with this method.
9
+ #
10
+ # @example 42 must be equal to 42
11
+ # describe(42) do
12
+ # it { MUST Equal: 42 }
13
+ # end
14
+ #
15
+ # @param front_object [BasicObject] The front object.
16
+ # @param specs [Proc] The set of specs.
17
+ #
18
+ # @return [ExpectationTarget] The expectation target.
19
+ def self.describe(front_object, &specs)
20
+ t = Test.new(front_object, &specs)
21
+
22
+ puts "#{t.report}"
23
+ exit t.pass?
102
24
  end
103
25
  end
@@ -0,0 +1,32 @@
1
+ module Fix
2
+ # It's helper.
3
+ #
4
+ # @api private
5
+ #
6
+ module ItHelper
7
+ # Add it method to the DSL.
8
+ #
9
+ # @api public
10
+ #
11
+ # @example It must eql "FOO"
12
+ # it { MUST Equal: 'FOO' }
13
+ #
14
+ # @param spec [Proc] A spec to compare against the computed actual value.
15
+ #
16
+ # @return [Array] List of results.
17
+ def it(&spec)
18
+ i = It.new do
19
+ Sandbox.new(@front_object, *@challenges).actual
20
+ end
21
+
22
+ result = begin
23
+ i.instance_eval(&spec)
24
+ rescue Spectus::Result::Fail => f
25
+ f
26
+ end
27
+
28
+ print result.to_char
29
+ results << result
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Fix
2
+ # On's helper.
3
+ #
4
+ # @api private
5
+ #
6
+ module OnHelper
7
+ # Add on method to the DSL.
8
+ #
9
+ # @api public
10
+ #
11
+ # @example On +2, it must equal 44.
12
+ # on(:+, 2) do
13
+ # it { MUST Equal: 44 }
14
+ # end
15
+ #
16
+ # @param method_name [Symbol] The identifier of a method.
17
+ # @param args [Array] A list of arguments.
18
+ # @param block [Proc] A spec to compare against the computed value.
19
+ #
20
+ # @return [Array] List of results.
21
+ def on(method_name, *args, &block)
22
+ o = On.new(@front_object,
23
+ results,
24
+ *@challenges, Spectus::Challenge.new(method_name, *args))
25
+
26
+ o.instance_eval(&block)
27
+ end
28
+ end
29
+ end
@@ -1,13 +1,10 @@
1
- require_relative File.join 'helper', 'requirement_helper'
1
+ require 'spectus/expectation_target'
2
2
 
3
3
  module Fix
4
- class It
5
- include Helper::RequirementHelper
6
-
7
- def initialize object, defs, *args
8
- @object = object
9
- @defs = defs
10
- @args = args
11
- end
4
+ # Wraps the target of an expectation.
5
+ #
6
+ # @api private
7
+ #
8
+ class It < Spectus::ExpectationTarget
12
9
  end
13
10
  end
@@ -1,19 +1,36 @@
1
- require_relative File.join 'helper', 'it_helper'
2
- require_relative File.join 'helper', 'its_helper'
3
- require_relative File.join 'helper', 'let_accessor_helper'
4
- require_relative File.join 'helper', 'on_helper' unless defined? Fix::Helper::OnHelper
1
+ require 'spectus/challenge'
2
+ require 'spectus/result/fail'
3
+
4
+ require_relative 'it'
5
+
6
+ %w(it on).each do |helper|
7
+ require_relative File.join 'helpers', "#{helper}_helper"
8
+ end
9
+
10
+ require_relative 'sandbox'
5
11
 
6
12
  module Fix
13
+ # Wraps the target of challenge.
14
+ #
15
+ # @api private
16
+ #
7
17
  class On
8
- include Helper::ItHelper
9
- include Helper::ItsHelper
10
- include Helper::LetAccessorHelper
11
- include Helper::OnHelper
12
-
13
- def initialize object, defs, *args
14
- @object = object
15
- @defs = defs
16
- @args = args
18
+ # Initialize the on class.
19
+ #
20
+ # @param front_object [BasicObject] The front object of the test.
21
+ # @param results [Array] The list of collected results.
22
+ # @param challenges [Array] The list of challenges to apply.
23
+ def initialize(front_object, results, *challenges)
24
+ @front_object = front_object
25
+ @results = results
26
+ @challenges = challenges
17
27
  end
28
+
29
+ # @!attribute [r] results
30
+ #
31
+ # @return [Array] The results.
32
+ attr_reader :results
33
+
34
+ [ItHelper, OnHelper].each { |helper| include helper }
18
35
  end
19
36
  end
@@ -0,0 +1,61 @@
1
+ module Fix
2
+ # The class that is responsible for reporting the result of the test.
3
+ #
4
+ # @api private
5
+ #
6
+ class Report
7
+ # Initialize the report class.
8
+ #
9
+ # @param test [Test] The test.
10
+ def initialize(test)
11
+ @test = test
12
+ end
13
+
14
+ # @!attribute [r] test
15
+ #
16
+ # @return [Test] The result.
17
+ attr_reader :test
18
+
19
+ # The report in plain text.
20
+ #
21
+ # @return [String] The report in plain text.
22
+ def to_s
23
+ "\n" \
24
+ "\n" \
25
+ "#{results_banner.join("\n")}\n" \
26
+ "#{total_time_banner}\n" \
27
+ "#{statistics_banner}\n"
28
+ end
29
+
30
+ private
31
+
32
+ # @private
33
+ def total_time_banner
34
+ "Ran #{test.results.length} tests in #{test.total_time} seconds"
35
+ end
36
+
37
+ # @private
38
+ def results_banner
39
+ test.results.reject { |r| r.to_char == '.' }.map.with_index(1) do |r, i|
40
+ "#{i}. #{r.message}\n" + maybe_backtrace(r)
41
+ end
42
+ end
43
+
44
+ # @private
45
+ def maybe_backtrace(result)
46
+ if result.respond_to?(:backtrace)
47
+ " #{result.backtrace.first}\n"
48
+ else
49
+ ''
50
+ end
51
+ end
52
+
53
+ # @private
54
+ def statistics_banner
55
+ "#{test.statistics.fetch(:pass_percent)}% compliant - " \
56
+ "#{test.statistics.fetch(:total_infos)} infos, " \
57
+ "#{test.statistics.fetch(:total_failures)} failures, " \
58
+ "#{test.statistics.fetch(:total_errors)} errors"
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,25 @@
1
+ module Fix
2
+ # Execute the untested code from the passed challenges.
3
+ #
4
+ # @api private
5
+ #
6
+ class Sandbox
7
+ # Initialize the sandbox class.
8
+ #
9
+ # @param object [BasicObject] The front object of the test.
10
+ # @param challenges [Array] The list of challenges to apply.
11
+ def initialize(object, *challenges)
12
+ @object = object
13
+ @challenges = challenges
14
+ end
15
+
16
+ # The actual value.
17
+ #
18
+ # @return [BasicObject] The actual value.
19
+ def actual
20
+ @challenges.inject(@object) do |subject, challenge|
21
+ subject.public_send(challenge.symbol, *challenge.args)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,253 +1,79 @@
1
- require_relative 'db'
1
+ require_relative 'on'
2
+ require_relative 'report'
2
3
 
3
4
  module Fix
5
+ # Wraps the target of the specs document.
6
+ #
7
+ # @api private
8
+ #
4
9
  class Test
5
- attr_reader :total_time
6
-
7
- def initialize io = $stdout, color: defined?(COLOR), hide_progress: defined?(HIDE_PROGRESS)
8
- @io = io
9
- @color = color
10
-
10
+ # Initialize the test class.
11
+ #
12
+ # @param front_object [BasicObject] The front object of the test.
13
+ # @param specs [Proc] The specs to test against the object.
14
+ def initialize(front_object, &specs)
11
15
  start_time = Time.now
12
16
 
13
- @results = DB.instance.flat_map do |object, expectations|
14
- expectations.map do |expectation|
15
- if hide_progress
16
- expectation.evaluate object
17
- else
18
- log expectation.evaluate(object)
19
- end
20
- end
21
- end
17
+ g = On.new(front_object, [])
18
+ g.instance_eval(&specs)
22
19
 
20
+ @results = g.results
23
21
  @total_time = Time.now - start_time
24
22
 
25
- @results = @results.sort {|a, b| a.fetch(:level) <=> b.fetch(:level) }
26
-
27
- @io.puts
28
-
29
- %i(errors failures infos).each do |results_with_state|
30
- if reports(results_with_state).any?
31
- @io.puts
32
- @io.puts "# #{results_with_state.capitalize}:"
33
- @io.puts
34
-
35
- reports(results_with_state).each_with_index do |report, index|
36
- @io.print about "#{index.next}. "
37
- @io.puts report
38
- end
39
- end
40
- end
41
-
42
- @io.puts
43
- @io.puts about "Ran #{@results.length} tests in #{@total_time} seconds"
44
- @io.puts statistics
45
-
46
- exit 1 if fail?
47
- end
48
-
49
- def errors
50
- @results.select {|result| state(result) == :error }
51
- end
52
-
53
- def failures
54
- @results.select {|result| state(result) == :failure }
55
- end
56
-
57
- def infos
58
- @results.select {|result| state(result) == :info }
23
+ puts
59
24
  end
60
25
 
61
- def reports results_with_state
62
- __send__(results_with_state).map do |result|
63
- truncate(result.fetch(:object).inspect) +
64
- if result.fetch(:params).any?
65
- '.' +
66
- result.fetch(:params).map.with_index do |args, i|
67
- color = if i == result.fetch(:last_arg)
68
- state result
69
- elsif i > result.fetch(:last_arg)
70
- :pending
71
- else
72
- :default
73
- end
74
-
75
- __send__(color, "#{args.first}" +
76
- if args.length > 1
77
- '(' + args[1..-1].map {|arg| arg.to_s }.join(',') + ')'
78
- else
79
- ''
80
- end
81
- )
82
- end.join('.')
83
- else
84
- ''
85
- end +
86
- '.' +
87
- (
88
- color = if result.fetch(:params).length == result.fetch(:last_arg)
89
- state result
90
- else
91
- :pending
92
- end
26
+ # @!attribute [r] results
27
+ #
28
+ # @return [Array] The results.
29
+ attr_reader :results
93
30
 
94
- __send__(color, "#{result.fetch(:challenge).first}" +
95
- if result.fetch(:challenge).length > 1
96
- '(' + result.fetch(:challenge)[1..-1].map {|arg| arg.inspect }.join(',') + ')'
97
- else
98
- ''
99
- end
100
- )
101
- ) +
102
- ' ' +
103
- expectation_level(result) +
104
- ' ' +
105
- matcher_with_expected_if_given(result) +
106
- returned_value(result)
107
- end
108
- end
31
+ # @!attribute [r] total_time
32
+ #
33
+ # @return [Float] The total time.
34
+ attr_reader :total_time
109
35
 
36
+ # Some statistics.
37
+ #
38
+ # @return [Hash] Some statistics.
110
39
  def statistics
111
- color = if errors.any?
112
- :error
113
- elsif failures.any?
114
- :failure
115
- else
116
- :success
117
- end
118
-
119
- percents = if @results.empty?
120
- 100
121
- else
122
- (@results.count {|result| result.fetch(:pass) != false }) / @results.length.to_f * 100
123
- end
40
+ {
41
+ pass_percent: pass_percent,
42
+ total_infos: results.count { |r| r.to_char == 'I' },
43
+ total_failures: results.count { |r| r.to_char == 'F' },
44
+ total_errors: results.count { |r| r.to_char == 'E' }
45
+ }
46
+ end
124
47
 
125
- __send__ color, "#{percents.round}% compliant - " + [
126
- "#{infos.length} infos",
127
- "#{failures.length} failures",
128
- "#{errors.length} errors"
129
- ].join(', ')
48
+ # The report of the test.
49
+ #
50
+ # @return [Report] The report of the test.
51
+ def report
52
+ Report.new(self)
130
53
  end
131
54
 
55
+ # The state of the test.
56
+ #
57
+ # @return [Boolean] Return true if the test pass.
132
58
  def pass?
133
- !@results.any? {|result| result.fetch(:pass) == false }
59
+ results.all?(&:result?)
134
60
  end
135
61
 
62
+ # @return [Boolean] Return false if the test fail.
136
63
  def fail?
137
64
  !pass?
138
65
  end
139
66
 
140
67
  private
141
68
 
142
- def truncate string
143
- if string.length > 16
144
- string[0..16].concat '[...]'
145
- else
146
- string
147
- end
148
- end
149
-
150
- def returned_value result
151
- if result.fetch(:exception).nil?
152
- about ' # => got ' + result.fetch(:got).inspect
153
- else
154
- about ' # => raised ' + result.fetch(:exception).inspect
155
- end
156
- end
157
-
158
- def expectation_level result
159
- case result.fetch :level
160
- when 1
161
- if result.fetch :negated
162
- 'MUST_NOT'
163
- else
164
- 'MUST'
165
- end
166
- when 2
167
- if result.fetch :negated
168
- 'SHOULD_NOT'
169
- else
170
- 'SHOULD'
171
- end
172
- when 3
173
- 'MAY'
174
- end
175
- end
176
-
177
- def matcher_with_expected_if_given result
178
- definition = Array result.fetch :definition
179
- definition.flatten(1)[0].to_s + if definition.flatten(1).length > 1
180
- ' ' + definition.flatten(1)[1].inspect
181
- else
182
- ''
183
- end
184
- end
185
-
186
- def log result
187
- @io.print __send__ state(result), char(result)
188
-
189
- result
190
- end
191
-
192
- def colorize state, string
193
- if @color
194
- "\e[#{state}m#{string}\e[0m"
195
- else
196
- string
197
- end
198
- end
199
-
200
- def about string
201
- colorize 37, string
202
- end
203
-
204
- def default string
205
- colorize 30, string
206
- end
207
-
208
- def error string
209
- colorize 31, string
210
- end
211
-
212
- def success string
213
- colorize 32, string
214
- end
215
-
216
- def pending string
217
- colorize 33, string
218
- end
219
-
220
- def info string
221
- colorize 34, string
222
- end
223
-
224
- def failure string
225
- colorize 35, string
226
- end
227
-
228
- # Returns the state of the expectation.
229
- def state data
230
- if data.fetch :pass
231
- :success
232
- elsif data.fetch(:pass).nil?
233
- :info
234
- elsif data.fetch(:exception).nil?
235
- :failure
236
- else
237
- :error
238
- end
239
- end
240
-
241
- # Returns a char as the result of the expectation.
242
- def char data
243
- if data.fetch :pass
244
- '.'
245
- elsif data.fetch(:pass).nil?
246
- 'I'
247
- elsif data.fetch(:exception).nil?
248
- 'F'
69
+ # @private
70
+ #
71
+ # @return [Fixnum] Return the percentage of passing specs.
72
+ def pass_percent
73
+ if results.empty?
74
+ 100
249
75
  else
250
- 'E'
76
+ (results.count(&:result?) / results.length.to_f * 100).round
251
77
  end
252
78
  end
253
79
  end