fix 0.6.1 → 0.7.0

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 (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