fix 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: af4f77c8e0f75a3f88d2bdb4757cf1f7d122ed3e
4
- data.tar.gz: f80e87cf83afcdcb0f731941769c6f7b95730887
3
+ metadata.gz: 1964b909221b9e975cd2bbaf03ebfe3fbe748fb1
4
+ data.tar.gz: bedaf49f6b9f171ad4abb82817d391b97beafabc
5
5
  SHA512:
6
- metadata.gz: b75d2c1f34987e4bd05bf660ae656ba28cf9e09c4366c21a2a3dbff84e0852a3a8be7d6987451f8596bcfd3ddd73574492639d27bce1bb263780d2195a059b3f
7
- data.tar.gz: ac75678ec541a7481ea4579d5cd0d34a3c0d112a6275021abfa42ab52622bac881ff41ec9f1970cac9066ce851583cd215a7ac6af0baa657809f53b094d4f096
6
+ metadata.gz: fc69cd9da13b6e207270601c1f71a9d489473991edbaa077901cc60a9faec0b53d31db95c57d3174f5f57b8610a4dee551a00ab148a290a2aeb37652c85a9013
7
+ data.tar.gz: fc477c8a857a294bb3a31413f64147b427c5ea7eeb6d53c69f4da37223a012f3339dd4b21bddf3716f15a08185ef02fbfe0dea73ade0b1b1570953a6e85cbd9c
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -1,20 +1,19 @@
1
1
  # Fix
2
2
 
3
- [![Build Status](https://travis-ci.org/cyril/fix.rb.svg?branch=master)](https://travis-ci.org/cyril/fix.rb)
4
- [![Coverage Status](http://img.shields.io/coveralls/cyril/fix.rb.svg?branch=master)](https://coveralls.io/r/cyril/fix.rb)
5
- [![Dependency Status](https://gemnasium.com/cyril/fix.rb.svg)](https://gemnasium.com/cyril/fix.rb)
3
+ [![Build Status](https://travis-ci.org/fixrb/fix.svg?branch=master)](https://travis-ci.org/fixrb/fix)
4
+ [![Coverage Status](http://img.shields.io/coveralls/fixrb/fix.svg?branch=master)](https://coveralls.io/r/fixrb/fix)
5
+ [![Dependency Status](https://gemnasium.com/fixrb/fix.svg)](https://gemnasium.com/fixrb/fix)
6
6
  [![Gem Version](http://img.shields.io/gem/v/fix.svg)](https://rubygems.org/gems/fix)
7
- [![Inline docs](http://inch-ci.org/github/cyril/fix.rb.svg?branch=master)](http://inch-ci.org/github/cyril/fix.rb)
7
+ [![Inline docs](http://inch-ci.org/github/fixrb/fix.svg?branch=master)](http://inch-ci.org/github/fixrb/fix)
8
8
  [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)](http://rubydoc.info/gems/fix/frames)
9
- [![License](http://img.shields.io/:license-MIT-38c800.svg)](http://cyril.mit-license.org/)
10
9
 
11
10
  > Specing framework for Ruby.
12
11
 
13
12
  ## Contact
14
13
 
15
14
  * Home page: http://fixrb.org/
16
- * Bugs/issues: https://github.com/cyril/fix.rb/issues
17
- * Support: https://stackoverflow.com/questions/tagged/fix-ruby
15
+ * Bugs/issues: https://github.com/fixrb/fix/issues
16
+ * Support: https://stackoverflow.com/questions/tagged/fixrb
18
17
 
19
18
  ## Rubies
20
19
 
@@ -44,7 +43,7 @@ $ gem install fix
44
43
 
45
44
  ### Minimalist
46
45
 
47
- With ~400 lignes of **simple code** built on top of [Spectus expectation library](cyril/spectus.rb), facilities such as benchmarking and mocking are not supported. Fix offers however a **consistent** syntax to **DRY** and focus your BDD.
46
+ With ~400 lignes of **simple code** built on top of [Spectus expectation library](https://github.com/fixrb/spectus), facilities such as benchmarking and mocking are not supported. Fix offers however a **consistent** syntax to **DRY** and focus your BDD.
48
47
 
49
48
  ### Resistant
50
49
 
@@ -107,11 +106,11 @@ ruby duck_spec.rb
107
106
 
108
107
  .....
109
108
  Finished in 0.001033 seconds.
110
- 5 tests, 0 failures, 0 errors
109
+ 100% compliant (5 specs, 0 infos, 0 failures, 0 errors)
111
110
 
112
111
  ## Contributing
113
112
 
114
- 1. [Fork it](https://github.com/cyril/fix.rb/fork)
113
+ 1. [Fork it](https://github.com/fixrb/fix/fork)
115
114
  2. Create your feature branch (`git checkout -b my-new-feature`)
116
115
  3. Commit your changes (`git commit -am 'Add some feature'`)
117
116
  4. Push to the branch (`git push origin my-new-feature`)
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.5.0
data/bin/fix ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fix'
4
+
5
+ Fix.run(*ARGV)
@@ -4,5 +4,5 @@
4
4
  $ ./test.rb
5
5
  ......
6
6
  Finished in 0.001181 seconds.
7
- 6 tests, 0 failures, 0 errors
7
+ 100% compliant (6 specs, 0 infos, 0 failures, 0 errors)
8
8
  ```
@@ -9,6 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.license = 'MIT'
10
10
 
11
11
  spec.files = `git ls-files -z`.split("\x0")
12
+ spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
12
13
  spec.test_files = spec.files.grep(%r{^spec/})
13
14
  spec.require_paths = ['lib']
14
15
  spec.required_ruby_version = '>= 2.0.0'
data/lib/fix.rb CHANGED
@@ -1,6 +1,95 @@
1
- require_relative File.join 'fix', 'dsl'
2
1
  require_relative File.join 'fix', 'version'
3
2
 
3
+ require 'optparse'
4
+ require 'set'
5
+
4
6
  # Namespace for the Fix framework.
5
7
  module Fix
8
+
9
+ # This is the command line top-level run method. Everything starts from here.
10
+ def self.run *args
11
+ process_args args
12
+ file_paths = fetch_file_paths args
13
+
14
+ print "> fix --seed #{SEED}"
15
+ print ' --color' if defined? COLOR
16
+ print ' --debug' if $DEBUG
17
+ print ' --warnings' if $VERBOSE
18
+
19
+ puts ' ' + file_paths.to_a.join(' ')
20
+
21
+ require_relative File.join 'fix', 'dsl'
22
+ file_paths.each {|file_path| require file_path }
23
+ end
24
+
25
+ def self.process_args args
26
+ options = {
27
+ seed: Random.new_seed,
28
+ color: false,
29
+ debug: false,
30
+ warnings: false
31
+ }
32
+
33
+ opt_parser = OptionParser.new do |opts|
34
+ opts.banner = 'Usage: fix <files or directories> [options]'
35
+
36
+ opts.separator ''
37
+ opts.separator 'Specific options:'
38
+
39
+ opts.on('-c', '--color', 'Enable color in the output.') do
40
+ options[:color] = (const_set :COLOR, true)
41
+ end
42
+
43
+ opts.on('-s [INTEGER]', '--seed [INTEGER]', Integer, 'Order of the tests') do |seed|
44
+ options[:seed] = seed
45
+ end
46
+
47
+ opts.on('-d', '--debug', 'Enable ruby debug') do
48
+ options[:debug] = $DEBUG = true
49
+ end
50
+
51
+ opts.on('-w', '--warnings', 'Enable ruby warnings') do
52
+ options[:warnings] = $VERBOSE = true
53
+ end
54
+
55
+ opts.separator ''
56
+ opts.separator 'Common options:'
57
+
58
+ opts.on_tail '-h', '--help', 'Show this message' do
59
+ puts opts
60
+ exit
61
+ end
62
+
63
+ opts.on_tail '--version', 'Show the version' do
64
+ puts VERSION
65
+ exit
66
+ end
67
+ end
68
+
69
+ opt_parser.parse! args
70
+ const_set :SEED, options.fetch(:seed)
71
+ options.freeze
72
+ end
73
+
74
+ def self.fetch_file_paths args
75
+ absolute_paths = Set.new
76
+
77
+ args.map do |s|
78
+ s = File.absolute_path s unless s.start_with? '/'
79
+
80
+ if File.directory? s
81
+ spec_files = File.join s, '**', '*_spec.rb'
82
+ Dir.glob(spec_files).each {|spec_file| absolute_paths.add spec_file }
83
+ else
84
+ absolute_paths.add s
85
+ end
86
+ end
87
+
88
+ if absolute_paths.empty?
89
+ warn 'Sorry, files or directories not found.'
90
+ exit 1
91
+ end
92
+
93
+ absolute_paths.freeze
94
+ end
6
95
  end
@@ -1,7 +1,7 @@
1
1
  require 'singleton'
2
2
 
3
3
  module Fix
4
- random = Random.new
4
+ random = Random.new(defined?(SEED) ? SEED : Random.new_seed)
5
5
 
6
6
  db = Class.new Hash do
7
7
  include Singleton
@@ -12,6 +12,6 @@ module Fix
12
12
  @object = object
13
13
  end
14
14
 
15
- at_exit { Test.new if $!.nil? or $!.kind_of?(SystemExit) }
15
+ at_exit { Test.new if $!.nil? }
16
16
  end
17
17
  end
@@ -1,6 +1,7 @@
1
1
  require 'set'
2
2
  require 'spectus'
3
3
  require_relative 'db'
4
+ require_relative 'subject'
4
5
 
5
6
  module Fix
6
7
  class Expectation
@@ -9,10 +10,10 @@ module Fix
9
10
  attr_reader :priority
10
11
 
11
12
  def initialize object, positive, definition, *args
12
- @positive = positive
13
- @matcher, @expected = definition.to_a.flatten 1
14
- @args = args
15
- @priority = DB.instance.random.rand
13
+ @positive = positive
14
+ @definition = definition
15
+ @args = args
16
+ @priority = DB.instance.random.rand
16
17
 
17
18
  freeze
18
19
 
@@ -26,10 +27,6 @@ module Fix
26
27
 
27
28
  private
28
29
 
29
- def pass? result, _subject = nil
30
- result.equal? true
31
- end
32
-
33
30
  def exception result
34
31
  result unless [ true, false ].include? result
35
32
  end
@@ -38,12 +35,11 @@ module Fix
38
35
  !@positive
39
36
  end
40
37
 
41
- def presenter result, got, subject = nil
38
+ def presenter result, got, subject
42
39
  {
43
- pass: pass?(result, subject),
40
+ pass: pass(result, subject),
44
41
  negated: negated?,
45
- matcher: @matcher,
46
- expected: @expected,
42
+ definition: @definition,
47
43
  exception: exception(result),
48
44
  got: got
49
45
  }
@@ -51,10 +47,10 @@ module Fix
51
47
 
52
48
  def meta subject
53
49
  {
54
- level: level,
55
- params: subject.params,
56
- challenge: subject.challenge,
57
- subject_exception: subject.error
50
+ level: level,
51
+ params: subject.params,
52
+ challenge: subject.challenge,
53
+ last_arg: subject.last_arg
58
54
  }
59
55
  end
60
56
 
@@ -1,5 +1,4 @@
1
1
  require_relative 'expectation'
2
- require_relative 'subject'
3
2
 
4
3
  module Fix
5
4
  class ExpectationHigh < Expectation
@@ -8,17 +7,19 @@ module Fix
8
7
  got = nil
9
8
 
10
9
  Thread.new {
11
- report = expect { got = subject.actual }.
12
- public_send target, @matcher => @expected
10
+ report = expect { got = subject.actual }.public_send target, @definition
11
+ data = presenter report, got, subject
13
12
 
14
- data = presenter report, got
15
-
16
- Hash[ data.to_a + meta(subject).to_a ]
13
+ Hash[ data.to_a + meta(subject).to_a ].merge object: front_object
17
14
  }.value
18
15
  end
19
16
 
20
17
  private
21
18
 
19
+ def pass result, _subject
20
+ result.equal? true
21
+ end
22
+
22
23
  def level
23
24
  1
24
25
  end
@@ -7,20 +7,18 @@ module Fix
7
7
  got = nil
8
8
 
9
9
  Thread.new {
10
- report = expect { got = subject.actual }.
11
- public_send target, @matcher => @expected
10
+ report = expect { got = subject.actual }.public_send target, @definition
11
+ data = presenter report, got, subject
12
12
 
13
- data = presenter report, got, subject
14
-
15
- Hash[ data.to_a + meta(subject).to_a ]
13
+ Hash[ data.to_a + meta(subject).to_a ].merge object: front_object
16
14
  }.value
17
15
  end
18
16
 
19
17
  private
20
18
 
21
- def pass? result, subject
19
+ def pass result, subject
22
20
  if subject.implemented?
23
- exception(result).nil?
21
+ super
24
22
  else
25
23
  true
26
24
  end
@@ -7,19 +7,17 @@ module Fix
7
7
  got = nil
8
8
 
9
9
  Thread.new {
10
- report = expect { got = subject.actual }.
11
- public_send target, @matcher => @expected
10
+ report = expect { got = subject.actual }.public_send target, @definition
11
+ data = presenter report, got, subject
12
12
 
13
- data = presenter report, got
14
-
15
- Hash[ data.to_a + meta(subject).to_a ]
13
+ Hash[ data.to_a + meta(subject).to_a ].merge object: front_object
16
14
  }.value
17
15
  end
18
16
 
19
17
  private
20
18
 
21
- def pass? result, _subject
22
- super || exception(result).nil?
19
+ def pass result, _subject
20
+ super || (exception(result).nil? ? nil : false)
23
21
  end
24
22
 
25
23
  def level
@@ -1,36 +1,33 @@
1
1
  module Fix
2
2
  class Subject
3
- attr_reader :error
3
+ attr_reader :last_arg
4
4
 
5
5
  def initialize input, *args
6
- @input = input
7
- @args = args
8
- @error = nil
9
-
10
- @implemented = nil
6
+ @args = args
7
+ @error = nil
8
+ @implemented = nil
9
+ @last_arg = -1
11
10
 
12
11
  begin
13
- param_id = 0
14
12
  @cache_value = params.inject(input) do |mem, param|
15
- param_id = param_id.next
16
- @implemented = mem.respond_to? param.first, false
13
+ @implemented = mem.respond_to? param.first, false
14
+ @last_arg = @last_arg.next
15
+
17
16
  mem.public_send(*param)
18
17
  end
19
- rescue => e
20
- @error = {
21
- exception: e,
22
- param_id: param_id
23
- }
18
+
19
+ @last_arg = @last_arg.next
20
+ rescue => @error
24
21
  end
25
22
 
26
23
  freeze
27
24
  end
28
25
 
29
26
  def actual
30
- if valid?
27
+ if @error.nil?
31
28
  @cache_value.public_send(*challenge)
32
29
  else
33
- raise @error.fetch :exception
30
+ raise @error
34
31
  end
35
32
  end
36
33
 
@@ -43,13 +40,7 @@ module Fix
43
40
  end
44
41
 
45
42
  def implemented?
46
- @implemented && valid? && @cache_value.respond_to?(challenge.first, false)
47
- end
48
-
49
- private
50
-
51
- def valid?
52
- @error.nil?
43
+ @implemented && @error.nil? && @cache_value.respond_to?(challenge.first, false)
53
44
  end
54
45
  end
55
46
  end
@@ -4,35 +4,104 @@ module Fix
4
4
  class Test
5
5
  attr_reader :total_time
6
6
 
7
- def initialize color: true, stdout: $stdout, stderr: $stderr
8
- @options = { color: color, stdout: stdout, stderr: stderr }
7
+ def initialize io = $stdout, color: defined?(COLOR)
8
+ @io = io
9
+ @color = color
9
10
 
10
11
  start_time = Time.now
11
- @results = DB.instance.map do |object, expectations|
12
- expectations.map do |expectation|
13
- log expectation.evaluate object
14
- end
15
- end.flatten 1
12
+
13
+ @results = DB.instance.flat_map do |object, expectations|
14
+ expectations.map {|expectation| log expectation.evaluate(object) }
15
+ end
16
+
16
17
  @total_time = Time.now - start_time
17
18
 
18
- @options.fetch(:stdout).puts about "\nFinished in #{@total_time} seconds."
19
- @options.fetch(:stdout).puts statistics
19
+ @results = @results.sort {|a, b| a.fetch(:level) <=> b.fetch(:level) }
20
+
21
+ @io.puts
22
+
23
+ %i(errors failures infos).each do |results_with_state|
24
+ if reports(results_with_state).any?
25
+ @io.puts
26
+ @io.puts "# #{results_with_state.capitalize}:"
27
+ @io.puts
28
+
29
+ reports(results_with_state).each_with_index do |report, index|
30
+ @io.print about "#{index.next}. "
31
+ @io.puts report
32
+ end
33
+ end
34
+ end
35
+
36
+ @io.puts
37
+ @io.puts about "Finished in #{@total_time} seconds."
38
+ @io.puts statistics
20
39
 
21
40
  freeze
22
41
  end
23
42
 
24
- def pass?
25
- @results.all? {|result| state(result) == :success }
43
+ def errors
44
+ @results.select {|result| state(result) == :error }
26
45
  end
27
46
 
28
- def fail?
29
- !pass?
47
+ def failures
48
+ @results.select {|result| state(result) == :failure }
30
49
  end
31
50
 
32
- def statistics
33
- errors = @results.select {|result| state(result) == :error }
34
- failures = @results.select {|result| state(result) == :failure }
51
+ def infos
52
+ @results.select {|result| state(result) == :info }
53
+ end
54
+
55
+ def reports results_with_state
56
+ __send__(results_with_state).map do |result|
57
+ result.fetch(:object).inspect +
58
+ if result.fetch(:params).any?
59
+ '.' +
60
+ result.fetch(:params).map.with_index do |args, i|
61
+ color = if i == result.fetch(:last_arg)
62
+ state result
63
+ elsif i > result.fetch(:last_arg)
64
+ :pending
65
+ else
66
+ :default
67
+ end
68
+
69
+ __send__(color, "#{args.first}" +
70
+ if args.length > 1
71
+ '(' + args[1..-1].map {|arg| arg.to_s }.join(',') + ')'
72
+ else
73
+ ''
74
+ end
75
+ )
76
+ end.join('.')
77
+ else
78
+ ''
79
+ end +
80
+ '.' +
81
+ (
82
+ color = if result.fetch(:params).length == result.fetch(:last_arg)
83
+ state result
84
+ else
85
+ :pending
86
+ end
87
+
88
+ __send__(color, "#{result.fetch(:challenge).first}" +
89
+ if result.fetch(:challenge).length > 1
90
+ '(' + result.fetch(:challenge)[1..-1].map {|arg| arg.to_s }.join(',') + ')'
91
+ else
92
+ ''
93
+ end
94
+ )
95
+ ) +
96
+ ' ' +
97
+ expectation_level(result) +
98
+ ' ' +
99
+ matcher_with_expected_if_given(result) +
100
+ returned_value(result)
101
+ end
102
+ end
35
103
 
104
+ def statistics
36
105
  color = if errors.any?
37
106
  :error
38
107
  elsif failures.any?
@@ -41,32 +110,74 @@ module Fix
41
110
  :success
42
111
  end
43
112
 
44
- __send__ color, [
45
- "#{@results.length} tests",
113
+ percents = (@results.count {|result| result.fetch(:pass) != false }) / @results.length.to_f * 100
114
+
115
+ __send__ color, "#{percents.round}% compliant (" + [
116
+ "#{@results.length} specs",
117
+ "#{infos.length} infos",
46
118
  "#{failures.length} failures",
47
119
  "#{errors.length} errors"
48
- ].join(', ')
120
+ ].join(', ') + ')'
121
+ end
122
+
123
+ def pass?
124
+ !@results.any? {|result| result.fetch(:pass) == false }
125
+ end
126
+
127
+ def fail?
128
+ !pass?
49
129
  end
50
130
 
51
131
  private
52
132
 
53
- def log result
54
- color = state result
55
- std = (color == :success ? :stdout : :stderr)
133
+ def returned_value result
134
+ if result.fetch(:exception).nil?
135
+ about ' # => got ' + result.fetch(:got).inspect
136
+ else
137
+ about ' # => raised ' + result.fetch(:exception).inspect
138
+ end
139
+ end
56
140
 
57
- @options.fetch(std).print __send__ color, char(result)
141
+ def expectation_level result
142
+ case result.fetch :level
143
+ when 1
144
+ result.fetch(:negated) ? 'MUST_NOT' : 'MUST'
145
+ when 2
146
+ result.fetch(:negated) ? 'SHOULD_NOT' : 'SHOULD'
147
+ when 3
148
+ 'MAY'
149
+ end
150
+ end
151
+
152
+ def matcher_with_expected_if_given result
153
+ definition = Array result.fetch(:definition)
154
+
155
+ definition.flatten(1)[0].to_s +
156
+ if definition.flatten(1).length > 1
157
+ ' ' + definition.flatten(1)[1].inspect
158
+ else
159
+ ''
160
+ end
161
+ end
162
+
163
+ def log result
164
+ @io.print __send__ state(result), char(result)
58
165
 
59
166
  result
60
167
  end
61
168
 
62
169
  def colorize state, string
63
- @options[:color] ? "\e[#{state}m#{string}\e[0m" : string
170
+ @color ? "\e[#{state}m#{string}\e[0m" : string
64
171
  end
65
172
 
66
173
  def about string
67
174
  colorize 37, string
68
175
  end
69
176
 
177
+ def default string
178
+ colorize 30, string
179
+ end
180
+
70
181
  def error string
71
182
  colorize 31, string
72
183
  end
@@ -79,7 +190,7 @@ module Fix
79
190
  colorize 33, string
80
191
  end
81
192
 
82
- def matcher string
193
+ def info string
83
194
  colorize 34, string
84
195
  end
85
196
 
@@ -91,6 +202,8 @@ module Fix
91
202
  def state data
92
203
  if data.fetch :pass
93
204
  :success
205
+ elsif data.fetch(:pass).nil?
206
+ :info
94
207
  elsif data.fetch(:exception).nil?
95
208
  :failure
96
209
  else
@@ -102,6 +215,8 @@ module Fix
102
215
  def char data
103
216
  if data.fetch :pass
104
217
  '.'
218
+ elsif data.fetch(:pass).nil?
219
+ 'I'
105
220
  elsif data.fetch(:exception).nil?
106
221
  'F'
107
222
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Wack
@@ -30,7 +30,7 @@ cert_chain:
30
30
  sQCgS9KCAyZ+aWNO1bUJcE3Bx1XXkMO3JEyVR1CoEcexg5Ci03/lAm7lL84DmlKR
31
31
  3I7UWtomapPFbzC0J/5jzQ==
32
32
  -----END CERTIFICATE-----
33
- date: 2014-09-29 00:00:00.000000000 Z
33
+ date: 2014-10-05 00:00:00.000000000 Z
34
34
  dependencies:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: spectus
@@ -105,7 +105,8 @@ dependencies:
105
105
  description: Specing framework for Ruby.
106
106
  email:
107
107
  - cyril@sashite.com
108
- executables: []
108
+ executables:
109
+ - fix
109
110
  extensions: []
110
111
  extra_rdoc_files: []
111
112
  files:
@@ -117,6 +118,7 @@ files:
117
118
  - README.md
118
119
  - Rakefile
119
120
  - VERSION.semver
121
+ - bin/fix
120
122
  - example/duck/README.md
121
123
  - example/duck/app.rb
122
124
  - example/duck/lib.rb
metadata.gz.sig CHANGED
Binary file