fix 0.0.1.pre → 0.1.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.travis.yml +4 -2
  4. data/README.md +81 -49
  5. data/Rakefile +17 -0
  6. data/VERSION.semver +1 -1
  7. data/example/duck/README.md +9 -0
  8. data/example/duck/app.rb +3 -0
  9. data/example/duck/lib.rb +14 -0
  10. data/example/duck/spec.rb +31 -0
  11. data/example/duck/test.rb +6 -0
  12. data/fix.gemspec +10 -6
  13. data/lib/fix.rb +3 -17
  14. data/lib/fix/dsl.rb +10 -0
  15. data/lib/fix/expectation.rb +48 -0
  16. data/lib/fix/expectation_high.rb +26 -0
  17. data/lib/fix/expectation_low.rb +44 -0
  18. data/lib/fix/expectation_medium.rb +29 -0
  19. data/lib/fix/expectation_set.rb +8 -0
  20. data/lib/fix/helper/it_helper.rb +12 -0
  21. data/lib/fix/helper/its_helper.rb +12 -0
  22. data/lib/fix/helper/let_accessor_helper.rb +11 -0
  23. data/lib/fix/helper/let_reader_helper.rb +9 -0
  24. data/lib/fix/helper/let_writer_helper.rb +13 -0
  25. data/lib/fix/helper/on_helper.rb +12 -0
  26. data/lib/fix/helper/requirement_helper.rb +44 -0
  27. data/lib/fix/it.rb +14 -0
  28. data/lib/fix/its.rb +14 -0
  29. data/lib/fix/on.rb +20 -0
  30. data/lib/fix/spec.rb +16 -10
  31. data/lib/fix/subject.rb +43 -10
  32. data/lib/fix/test.rb +114 -0
  33. data/lib/fix/version.rb +9 -0
  34. data/spec/TODO +0 -0
  35. data/spec/spec_helper.rb +2 -4
  36. data/spec/support.rb +3 -0
  37. data/spec/support/coverage.rb +3 -0
  38. data/spec/support/env.rb +4 -0
  39. data/spec/support/presenter.rb +0 -0
  40. metadata +85 -22
  41. data/.ruby-version +0 -1
  42. data/bin/fix +0 -58
  43. data/lib/fix/base_matcher.rb +0 -38
  44. data/lib/fix/call.rb +0 -16
  45. data/lib/fix/constant.rb +0 -37
  46. data/lib/fix/expectation_target.rb +0 -41
  47. data/lib/fix/helper.rb +0 -34
  48. data/lib/fix/scope.rb +0 -20
  49. data/logo.png +0 -0
  50. data/logo.svg +0 -19
  51. data/spec/subject_spec.rb +0 -5
@@ -0,0 +1,29 @@
1
+ require_relative File.join 'expectation_high'
2
+
3
+ module Fix
4
+ class ExpectationMedium < ExpectationHigh
5
+ def evaluate front_object
6
+ subject = Subject.new front_object, *@args
7
+ got = nil
8
+
9
+ Thread.new {
10
+ report = expect { got = subject.actual }.
11
+ public_send target, @matcher => @expected
12
+
13
+ data = presenter report, got
14
+
15
+ Hash[ data.to_a + meta(subject).to_a ]
16
+ }.value
17
+ end
18
+
19
+ private
20
+
21
+ def pass? report
22
+ report.pass? || report.exception.nil?
23
+ end
24
+
25
+ def level
26
+ 2
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ require 'set'
2
+ require 'singleton'
3
+
4
+ module Fix
5
+ class ExpectationSet < Set
6
+ include Singleton
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ module Fix
2
+ module Helper
3
+ module ItsHelper
4
+ def its attribute, *args, &block
5
+ i = Its.new @defs, *(@args + [[attribute] + args])
6
+ i.instance_eval(&block)
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ require_relative File.join '..', 'its'
@@ -0,0 +1,12 @@
1
+ module Fix
2
+ module Helper
3
+ module ItHelper
4
+ def it &block
5
+ i = It.new @defs, *@args
6
+ i.instance_eval(&block)
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ require_relative File.join '..', 'it'
@@ -0,0 +1,11 @@
1
+ require_relative File.join 'let_reader_helper'
2
+ require_relative File.join 'let_writer_helper'
3
+
4
+ module Fix
5
+ module Helper
6
+ module LetAccessorHelper
7
+ include LetReaderHelper
8
+ include LetWriterHelper
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Fix
2
+ module Helper
3
+ module LetReaderHelper
4
+ def method_missing name, *args, &block
5
+ @defs.has_key?(name) ? @defs.fetch(name).call : super
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Fix
2
+ module Helper
3
+ module LetWriterHelper
4
+ def let name, &block
5
+ if @defs.has_key? name
6
+ raise IndexError, 'the given key is already present.'
7
+ else
8
+ @defs.update name => block
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Fix
2
+ module Helper
3
+ module OnHelper
4
+ def on attribute, *args, &block
5
+ i = On.new @defs, *(@args + [[attribute] + args])
6
+ i.instance_eval(&block)
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ require_relative File.join '..', 'on'
@@ -0,0 +1,44 @@
1
+ require_relative File.join 'let_reader_helper'
2
+
3
+ module Fix
4
+ module Helper
5
+ module RequirementHelper
6
+ include Helper::LetReaderHelper
7
+
8
+ def MUST definition
9
+ ExpectationHigh.new true, definition, *@args
10
+ end
11
+
12
+ alias_method :is_REQUIRED_to, :MUST
13
+ alias_method :SHALL, :MUST
14
+
15
+ def MUST_NOT definition
16
+ ExpectationHigh.new false, definition, *@args
17
+ end
18
+
19
+ alias_method :SHALL_NOT, :MUST_NOT
20
+
21
+ def SHOULD definition
22
+ ExpectationMedium.new true, definition, *@args
23
+ end
24
+
25
+ alias_method :is_RECOMMENDED_to, :SHOULD
26
+
27
+ def SHOULD_NOT definition
28
+ ExpectationMedium.new false, definition, *@args
29
+ end
30
+
31
+ alias_method :is_NOT_RECOMMENDED_to, :SHOULD_NOT
32
+
33
+ def MAY definition
34
+ ExpectationLow.new true, definition, *@args
35
+ end
36
+
37
+ alias_method :is_OPTIONAL_to, :MAY
38
+ end
39
+ end
40
+ end
41
+
42
+ require_relative File.join '..', 'expectation_high'
43
+ require_relative File.join '..', 'expectation_low'
44
+ require_relative File.join '..', 'expectation_medium'
data/lib/fix/it.rb ADDED
@@ -0,0 +1,14 @@
1
+ require_relative File.join 'helper', 'requirement_helper'
2
+
3
+ module Fix
4
+ class It
5
+ include Helper::RequirementHelper
6
+
7
+ def initialize defs, *args
8
+ @defs = defs
9
+ @args = args
10
+
11
+ freeze
12
+ end
13
+ end
14
+ end
data/lib/fix/its.rb ADDED
@@ -0,0 +1,14 @@
1
+ require_relative File.join 'helper', 'requirement_helper'
2
+
3
+ module Fix
4
+ class Its
5
+ include Helper::RequirementHelper
6
+
7
+ def initialize defs, *args
8
+ @defs = defs
9
+ @args = args
10
+
11
+ freeze
12
+ end
13
+ end
14
+ end
data/lib/fix/on.rb ADDED
@@ -0,0 +1,20 @@
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
5
+
6
+ module Fix
7
+ class On
8
+ include Helper::ItHelper
9
+ include Helper::ItsHelper
10
+ include Helper::LetAccessorHelper
11
+ include Helper::OnHelper
12
+
13
+ def initialize defs, *args
14
+ @defs = defs
15
+ @args = args
16
+
17
+ freeze
18
+ end
19
+ end
20
+ end
data/lib/fix/spec.rb CHANGED
@@ -1,20 +1,26 @@
1
+ require_relative File.join 'dsl'
2
+ require_relative File.join 'test'
3
+
1
4
  module Fix
2
5
  class Spec
3
- attr_reader :examples
6
+ include DSL
7
+
8
+ def initialize title = nil, &block
9
+ @title = title
10
+ @defs = {}
11
+ @args = []
4
12
 
5
- def initialize *syms, &block
6
- @examples = Set.new
13
+ instance_eval(&block)
7
14
 
8
- const = syms.inject(Object) do |base, const|
9
- base.const_get(const)
10
- end
15
+ freeze
16
+ end
11
17
 
12
- @constant = Constant.new const, @examples
13
- @constant.instance_exec &block if block
18
+ def test front_object, seed: Random.new_seed, color: true, stdout: STDOUT, stderr: STDERR
19
+ Test.new front_object, seed: Random.new_seed, color: true, stdout: STDOUT, stderr: STDERR
14
20
  end
15
21
 
16
- def run
17
- @examples.map {|example| example.value }
22
+ def valid? front_object
23
+ Test.new(front_object).pass?
18
24
  end
19
25
  end
20
26
  end
data/lib/fix/subject.rb CHANGED
@@ -1,22 +1,55 @@
1
1
  module Fix
2
2
  class Subject
3
- attr_reader :object, :examples
3
+ attr_reader :error
4
4
 
5
- def initialize object, examples
6
- @examples = examples
7
- @object = object
5
+ def initialize input, *args
6
+ @input = input
7
+ @args = args
8
+ @error = nil
9
+
10
+ @implemented = nil
11
+
12
+ begin
13
+ param_id = 0
14
+ @cache_value = params.inject(input) do |mem, param|
15
+ param_id = param_id.next
16
+ @implemented = mem.respond_to? param.first, false
17
+ mem.public_send(*param)
18
+ end
19
+ rescue => e
20
+ @error = {
21
+ exception: e,
22
+ param_id: param_id
23
+ }
24
+ end
25
+
26
+ freeze
27
+ end
28
+
29
+ def actual
30
+ if valid?
31
+ @cache_value.public_send(*challenge)
32
+ else
33
+ raise @error.fetch :exception
34
+ end
35
+ end
36
+
37
+ def params
38
+ @args[0..-2]
8
39
  end
9
40
 
10
- def expect value
11
- ExpectationTarget.new value
41
+ def challenge
42
+ @args.last
12
43
  end
13
44
 
14
- def should matcher
15
- @examples << Thread.new { expect(@object).to matcher }
45
+ def implemented?
46
+ @implemented && valid? && @cache_value.respond_to?(challenge.first, false)
16
47
  end
17
48
 
18
- def should_not matcher
19
- @examples << Thread.new { expect(@object).not_to matcher }
49
+ private
50
+
51
+ def valid?
52
+ @error.nil?
20
53
  end
21
54
  end
22
55
  end
data/lib/fix/test.rb ADDED
@@ -0,0 +1,114 @@
1
+ require_relative File.join 'expectation_set'
2
+
3
+ module Fix
4
+ class Test
5
+ attr_reader :total_time
6
+
7
+ def initialize front_object, seed: Random.new_seed, color: true, stdout: STDOUT, stderr: STDERR
8
+ @options = { color: color, stdout: stdout, stderr: stderr }
9
+ @options.fetch(:stdout).puts about "Run options: --seed #{seed}"
10
+
11
+ random = Random.new seed
12
+ expectations = ExpectationSet.instance.to_a.shuffle(random: random)
13
+
14
+ start_time = Time.now
15
+ @results = expectations.map do |expectation|
16
+ log expectation.evaluate front_object
17
+ end
18
+ @total_time = Time.now - start_time
19
+
20
+ @options.fetch(:stdout).puts about "\nFinished in #{@total_time} seconds."
21
+ @options.fetch(:stdout).puts statistics
22
+
23
+ freeze
24
+ end
25
+
26
+ def pass?
27
+ @results.all? {|result| state(result) == :success }
28
+ end
29
+
30
+ def fail?
31
+ !pass?
32
+ end
33
+
34
+ def statistics
35
+ errors = @results.select {|result| state(result) == :error }
36
+ failures = @results.select {|result| state(result) == :failure }
37
+
38
+ color = if errors.any?
39
+ :error
40
+ elsif failures.any?
41
+ :failure
42
+ else
43
+ :success
44
+ end
45
+
46
+ __send__ color, [
47
+ "#{@results.length} tests",
48
+ "#{failures.length} failures",
49
+ "#{errors.length} errors"
50
+ ].join(', ')
51
+ end
52
+
53
+ private
54
+
55
+ def log result
56
+ color = state result
57
+ std = (color == :success ? :stdout : :stderr)
58
+
59
+ @options.fetch(std).print __send__ color, char(result)
60
+
61
+ result
62
+ end
63
+
64
+ def colorize state, string
65
+ @options[:color] ? "\e[#{state}m#{string}\e[0m" : string
66
+ end
67
+
68
+ def about string
69
+ colorize 37, string
70
+ end
71
+
72
+ def error string
73
+ colorize 31, string
74
+ end
75
+
76
+ def success string
77
+ colorize 32, string
78
+ end
79
+
80
+ def pending string
81
+ colorize 33, string
82
+ end
83
+
84
+ def matcher string
85
+ colorize 34, string
86
+ end
87
+
88
+ def failure string
89
+ colorize 35, string
90
+ end
91
+
92
+ # Returns the state of the expectation.
93
+ def state data
94
+ if data.fetch :pass
95
+ :success
96
+ elsif data.fetch(:exception).nil?
97
+ :failure
98
+ else
99
+ :error
100
+ end
101
+ end
102
+
103
+ # Returns a char as the result of the expectation.
104
+ def char data
105
+ if data.fetch :pass
106
+ '.'
107
+ elsif data.fetch(:exception).nil?
108
+ 'F'
109
+ else
110
+ 'E'
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,9 @@
1
+ require 'pathname'
2
+
3
+ module Fix
4
+
5
+ # Gem version
6
+ VERSION = File.open(
7
+ Pathname.new(__FILE__).join '..', '..', '..', 'VERSION.semver'
8
+ ).read.chomp.to_sym
9
+ end