matest 1.2.0 → 1.3.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: 92cbe87cbc8b53490086b363cba0466107e906a5
4
- data.tar.gz: 545125006ca70b8c13ca8b5632183e3832731898
3
+ metadata.gz: 84452e41b4f3cd9abc5a1bbc3f908700a9cc8861
4
+ data.tar.gz: 68d2dabb2017c46bc31eb36d8b67e918e8eddab7
5
5
  SHA512:
6
- metadata.gz: d743771c606770155e344f1bdc5c13118a386bdbc1e28ced772ff97108bbc27482772e5e3a69fec9d9c764d2ed637915cf48974aa48ca45f29d74b22dd6567ed
7
- data.tar.gz: 686cbd8a5ef598ee08564e4c27ce575895b5f30ed6a044f2dfdb79199ef76876cff2da3b133f168a16a5f6f9c48fc9729f04f98cbe2c5aa70d666b3f8e84e7c8
6
+ metadata.gz: 16fa8463a914188a962999097d5c9b54182c56dc5ed3f528cf2a010dcf1bf75ae9b62dfa9d8c61ab6402c8116e6fce2181d2398afb2db80c35db6c822f7abd70
7
+ data.tar.gz: 35dcf6b249937b2a4eed2491dd8d4f2d5ed5c319a1973b45d64189bd38991f4f3127692e084ecb0e0d555810184c3dcffd395159490b7aa676971f6de91d28ad
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
1
  source "https://rubygems.org"
2
- gemspec
2
+ gemspec
3
3
 
data/README.md CHANGED
@@ -74,15 +74,6 @@ This is important, because the assertion will be evaluated and it will provide t
74
74
  The assertion can be any expression that returns a boolean value, BUT IT CANNOT CONTAIN LOCAL VARIABLES.
75
75
  If the assertion contains a local variable and it fails, the code that explains it bit by bit will throw an error.
76
76
 
77
- ### The assertion MUST be idempotent
78
-
79
- Once the code is run, the state of the block gets saved.
80
- If the test fails, the assertion will be re-run a couple of times.
81
- So if you are popping the last element of an array inside the assertion, each time it gets run, you'll be popping the next element on the chain.
82
- The reason for this is that Matest will show you the result of each part of the expression and for that, it needs to re-run each part.
83
-
84
- Removing this constraint is a high priority on my todo list. But I'm considering the threadoffs of doing it. I'll be happy to pair or discuss on this matter.
85
-
86
77
  ## Raising Errors
87
78
 
88
79
  If your test raises an error during the run, youll get an `ERROR` status and you'll see the backtrace.
@@ -162,9 +153,9 @@ In case the test fails, you'll get an extensive explanation about why.
162
153
  To show a trivial example:
163
154
 
164
155
  ```ruby
165
- scope "hola" do
156
+ scope do
166
157
  let(:three) { 3 }
167
- spec "chau" do
158
+ spec "Printing Failing Specs" do
168
159
  one = 2
169
160
  two = 2
170
161
  @one_plus_two_plus_three = one + two + three
@@ -182,7 +173,7 @@ F
182
173
 
183
174
  ### Messages ###
184
175
 
185
- [FAILING] chau
176
+ [FAILING] Printing Failing Specs
186
177
  Location:
187
178
  spec/matest_specs/printing_assertion_spec.rb:3:
188
179
  Assertion:
@@ -1,208 +1,15 @@
1
1
  require "matest/version"
2
+
3
+ require "matest/runner"
4
+ require "matest/example_group"
5
+ require "matest/example"
2
6
  require "matest/example_block"
7
+ require "matest/let"
8
+ require "matest/skip_me"
3
9
  require "matest/spec_status"
4
10
  require "matest/spec_printer"
5
-
11
+ require "matest/top_level_methods"
6
12
 
7
13
  module Matest
8
- class Runner
9
- attr_reader :example_groups
10
- attr_reader :info
11
- attr_reader :printer
12
-
13
- def initialize(options={})
14
- @example_groups = []
15
- @info = {}
16
- @printer = options[:printer] || SpecPrinter.new
17
- end
18
-
19
- def self.runner
20
- @runner ||= new
21
- end
22
-
23
- def <<(example_group)
24
- example_groups << example_group
25
- end
26
-
27
- def load_file(file)
28
- load(file)
29
- end
30
-
31
- def execute!
32
- example_groups.each do |current_group|
33
- current_group.execute!
34
- end
35
- printer.print(self)
36
- end
37
- end
38
-
39
- class SkipMe; end
40
-
41
- class Example
42
- def initialize(example_block, description, lets)
43
- @example_block__for_internal_use = ExampleBlock.new(example_block)
44
- @description__for_internal_use = description
45
- lets.each do |let|
46
- self.class.let(let.var_name, &let.block)
47
- send(let.var_name) if let.bang
48
- end
49
- end
50
-
51
- def example_block
52
- @example_block__for_internal_use
53
- end
54
-
55
- def description
56
- @description__for_internal_use
57
- end
58
-
59
- def call
60
- instance_eval(&example_block.block)
61
- end
62
-
63
- def self.let(var_name, &block)
64
- define_method(var_name) do
65
- instance_variable_set(:"@#{var_name}__from_let", block.call)
66
- end
67
- end
68
-
69
- def self.local_var(var_name)
70
- define_method(var_name) do
71
- instance_variable_get(:"@#{var_name}")
72
- end
73
- define_method("#{var_name}=") do |value|
74
- instance_variable_set(:"@#{var_name}", value)
75
- end
76
- end
77
-
78
- def track_variables
79
- instance_variables.reject {|var|
80
- var.to_s =~ /__for_internal_use\Z/ || var.to_s =~ /__from_let\Z/
81
- }.map {|var| [var, instance_variable_get(var)] }
82
- end
83
-
84
- def track_lets
85
- instance_variables.select {|var|
86
- var.to_s =~ /__from_let\Z/
87
- }.map {|var|
88
- name = var.to_s
89
- name["__from_let"] = ""
90
- name[0] = ""
91
- [name, instance_variable_get(var)]
92
- }
93
- end
94
-
95
- def without_block
96
- the_new = self.clone
97
- the_new.instance_variable_set(:@example_block__for_internal_use, nil)
98
- the_new
99
- end
100
-
101
- end
102
-
103
- class Let
104
- attr_reader :var_name
105
- attr_reader :block
106
- attr_reader :bang
107
-
108
- def initialize(var_name, block, bang=false)
109
- @var_name = var_name
110
- @block = block
111
- @bang = bang
112
- end
113
- end
114
-
115
- class ExampleGroup
116
- attr_reader :scope_block
117
- attr_reader :specs
118
- attr_reader :lets
119
- attr_reader :statuses
120
-
121
- def initialize(scope_block)
122
- @scope_block = scope_block
123
- @specs = []
124
- @lets = []
125
- @statuses = []
126
- end
127
-
128
- def spec(description=nil, &block)
129
- current_example = block_given? ? block : ->(*) { Matest::SkipMe.new }
130
- specs << Example.new(current_example, description, lets)
131
- end
132
-
133
- def execute!
134
- instance_eval(&scope_block)
135
- specs.shuffle.each do |spec, desc|
136
- res = run_spec(spec)
137
- print res
138
- end
139
-
140
- end
141
-
142
- def xspec(description=nil, &block)
143
- spec(description)
144
- end
145
-
146
- alias :it :spec
147
- alias :xit :xspec
148
-
149
- alias :test :spec
150
- alias :xtest :xspec
151
-
152
- alias :example :spec
153
- alias :xexample :xspec
154
-
155
-
156
- def self.let(var_name, &block)
157
- define_method(var_name) do
158
- instance_variable_set(:"@#{var_name}", block.call)
159
- end
160
- end
161
-
162
- def let(var_name, bang=false, &block)
163
- lets << Let.new(var_name, block, bang=false)
164
- end
165
-
166
- def let!(var_name, &block)
167
- lets << Let.new(var_name, block, bang=true)
168
- end
169
-
170
- def run_spec(spec)
171
- status = begin
172
- result = spec.call
173
- status_class = case result
174
- when true
175
- Matest::SpecPassed
176
- when false
177
- Matest::SpecFailed
178
- when Matest::SkipMe
179
- Matest::SpecSkipped
180
- else
181
- Matest::NotANaturalAssertion
182
- end
183
- status_class.new(spec, result)
184
- rescue Exception => e
185
- Matest::ExceptionRaised.new(spec, e, spec.description)
186
- end
187
- @statuses << status
188
- status
189
- end
190
- end
191
- end
192
-
193
- def scope(description=nil, &block)
194
- Matest::Runner.runner << Matest::ExampleGroup.new(block)
195
- end
196
-
197
- def xscope(description=nil, &block)
198
- # no-op
199
14
  end
200
15
 
201
- alias :describe :scope
202
- alias :xdescribe :xscope
203
-
204
- alias :context :scope
205
- alias :xcontext :xscope
206
-
207
- alias :group :scope
208
- alias :xgroup :xscope
@@ -0,0 +1,47 @@
1
+ module Matest
2
+ class EvalErr
3
+ def initialize(str)
4
+ @string = str
5
+ end
6
+ def size
7
+ inspect.size
8
+ end
9
+ def to_s
10
+ @string
11
+ end
12
+ def inspect
13
+ @string
14
+ end
15
+ end
16
+
17
+ class Evaluator
18
+ def initialize(example, block)
19
+ @example = example
20
+ @block = block
21
+ end
22
+
23
+ def eval_string(exp_string)
24
+ limit_length(eval_in_context(exp_string).inspect)
25
+ rescue StandardError => ex
26
+ EvalErr.new("#{ex.class}: #{ex.message}")
27
+ end
28
+
29
+ private
30
+
31
+ MAX_INSPECT_SIZE = 2000
32
+
33
+ def limit_length(string)
34
+ if string.size > MAX_INSPECT_SIZE
35
+ string[0..MAX_INSPECT_SIZE] + " (...truncated...)"
36
+ else
37
+ string
38
+ end
39
+ end
40
+
41
+ def eval_in_context(exp_string)
42
+ exp_proc = "proc { #{exp_string} }"
43
+ blk = eval(exp_proc, @block.binding)
44
+ @example.instance_eval(&blk)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,92 @@
1
+ module Matest
2
+ class Example
3
+ def initialize(example_block, description, lets)
4
+ @example_block__for_internal_use = ExampleBlock.new(example_block)
5
+ @description__for_internal_use = description
6
+ @lets__for_internal_use = lets
7
+ lets.each do |let|
8
+ self.class.let(let.var_name, &let.block)
9
+ send(let.var_name) if let.bang
10
+ end
11
+ end
12
+
13
+ def lets
14
+ @lets__for_internal_use
15
+ end
16
+
17
+ def example_block
18
+ @example_block__for_internal_use
19
+ end
20
+
21
+ def description
22
+ @description__for_internal_use
23
+ end
24
+
25
+ def call
26
+ instance_eval(&example_block.block)
27
+ end
28
+
29
+ def self.let(var_name, &block)
30
+ define_method(var_name) do
31
+ instance_variable_set(:"@#{var_name}__from_let", block.call)
32
+ end
33
+ end
34
+
35
+ def self.local_var(var_name)
36
+ define_method(var_name) do
37
+ instance_variable_get(:"@#{var_name}")
38
+ end
39
+ define_method("#{var_name}=") do |value|
40
+ instance_variable_set(:"@#{var_name}", value)
41
+ end
42
+ end
43
+
44
+ def track_variables
45
+ instance_variables.reject {|var|
46
+ var.to_s =~ /__for_internal_use\Z/ || var.to_s =~ /__from_let\Z/
47
+ }.map {|var| [var, instance_variable_get(var)] }
48
+ end
49
+
50
+ def track_lets
51
+ instance_variables.select {|var|
52
+ var.to_s =~ /__from_let\Z/
53
+ }.map {|var|
54
+ name = var.to_s
55
+ name["__from_let"] = ""
56
+ name[0] = ""
57
+ [name, instance_variable_get(var)]
58
+ }
59
+ end
60
+
61
+ # def without_block
62
+ # the_new = self.clone
63
+ # the_new.instance_variable_set(:@example_block__for_internal_use, nil)
64
+ # the_new
65
+ # end
66
+
67
+ def just_before_assertion
68
+ # return a clone of self, but with
69
+ ExampleBeforeAssertion.new(example_block.block, description, lets)
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ class ExampleBeforeAssertion < Example
76
+ def initialize(example_block, description, lets)
77
+ super
78
+ set_state
79
+ end
80
+
81
+ def set_state
82
+ before_sexp = example_block.sexp[0..-2]
83
+ @code = Sorcerer.source(before_sexp)
84
+ eval(@code)
85
+ end
86
+
87
+ def before_assertion_block
88
+ eval("proc { #{@code} }")
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,80 @@
1
+ module Matest
2
+ class ExampleGroup
3
+ attr_reader :scope_block
4
+ attr_reader :specs
5
+ attr_reader :lets
6
+ attr_reader :statuses
7
+
8
+ attr_accessor :printer
9
+
10
+ def initialize(scope_block)
11
+ @scope_block = scope_block
12
+ @specs = []
13
+ @lets = []
14
+ @statuses = []
15
+ end
16
+
17
+ def spec(description=nil, &block)
18
+ current_example = block_given? ? block : ->(*) { Matest::SkipMe.new }
19
+ specs << Example.new(current_example, description, lets)
20
+ end
21
+
22
+ def execute!
23
+ instance_eval(&scope_block)
24
+ specs.shuffle.each do |spec, desc|
25
+ res = run_spec(spec)
26
+ printer.print(res)
27
+ end
28
+
29
+ end
30
+
31
+ def xspec(description=nil, &block)
32
+ spec(description)
33
+ end
34
+
35
+ alias :it :spec
36
+ alias :xit :xspec
37
+
38
+ alias :test :spec
39
+ alias :xtest :xspec
40
+
41
+ alias :example :spec
42
+ alias :xexample :xspec
43
+
44
+
45
+ def self.let(var_name, &block)
46
+ define_method(var_name) do
47
+ instance_variable_set(:"@#{var_name}", block.call)
48
+ end
49
+ end
50
+
51
+ def let(var_name, bang=false, &block)
52
+ lets << Let.new(var_name, block, bang=false)
53
+ end
54
+
55
+ def let!(var_name, &block)
56
+ lets << Let.new(var_name, block, bang=true)
57
+ end
58
+
59
+ def run_spec(spec)
60
+ status = begin
61
+ result = spec.call
62
+ status_class = case result
63
+ when true
64
+ Matest::SpecPassed
65
+ when false
66
+ Matest::SpecFailed
67
+ when Matest::SkipMe
68
+ Matest::SpecSkipped
69
+ else
70
+ Matest::NotANaturalAssertion
71
+ end
72
+ status_class.new(spec, result)
73
+ rescue Exception => e
74
+ Matest::ExceptionRaised.new(spec, e, spec.description)
75
+ end
76
+ @statuses << status
77
+ status
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,13 @@
1
+ module Matest
2
+ class Let
3
+ attr_reader :var_name
4
+ attr_reader :block
5
+ attr_reader :bang
6
+
7
+ def initialize(var_name, block, bang=false)
8
+ @var_name = var_name
9
+ @block = block
10
+ @bang = bang
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,34 @@
1
+ module Matest
2
+ class Runner
3
+ attr_reader :example_groups
4
+ attr_reader :info
5
+ attr_reader :printer
6
+
7
+ def initialize(options={})
8
+ @example_groups = []
9
+ @info = {}
10
+ @printer = options[:printer] || SpecPrinter.new
11
+ end
12
+
13
+ def self.runner
14
+ @runner ||= new
15
+ end
16
+
17
+ def <<(example_group)
18
+ example_group.printer = printer
19
+ example_groups << example_group
20
+ end
21
+
22
+ def load_file(file)
23
+ load(file)
24
+ end
25
+
26
+ def execute!
27
+ example_groups.each do |current_group|
28
+ current_group.execute!
29
+ end
30
+ printer.print_messages(self)
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,3 @@
1
+ module Matest
2
+ class SkipMe; end
3
+ end
@@ -1,53 +1,12 @@
1
- module Matest
2
- class EvalErr
3
- def initialize(str)
4
- @string = str
5
- end
6
- def size
7
- inspect.size
8
- end
9
- def to_s
10
- @string
11
- end
12
- def inspect
13
- @string
14
- end
15
- end
16
-
17
- class Evaluator
18
- def initialize(example, block)
19
- # @example = Marshal.load( Marshal.dump(example) )
20
- @example = example
21
- @block = block
22
- end
23
-
24
- def eval_string(exp_string)
25
- limit_length(eval_in_context(exp_string).inspect)
26
- rescue StandardError => ex
27
- EvalErr.new("#{ex.class}: #{ex.message}")
28
- end
29
-
30
- private
31
-
32
- MAX_INSPECT_SIZE = 2000
33
-
34
- def limit_length(string)
35
- if string.size > MAX_INSPECT_SIZE
36
- string[0..MAX_INSPECT_SIZE] + " (...truncated...)"
37
- else
38
- string
39
- end
40
- end
41
-
42
- def eval_in_context(exp_string)
43
- exp_proc = "proc { #{exp_string} }"
44
- blk = eval(exp_proc, @block.binding)
45
- @example.instance_eval(&blk)
46
- end
47
- end
1
+ require "matest/evaluator"
48
2
 
3
+ module Matest
49
4
  class SpecPrinter
50
- def print(runner)
5
+ def print(res)
6
+ super res
7
+ end
8
+
9
+ def print_messages(runner)
51
10
  puts "\n\n### Messages ###"
52
11
 
53
12
  statuses = []
@@ -86,6 +45,11 @@ module Matest
86
45
  if status.is_a?(Matest::NotANaturalAssertion)
87
46
  runner.info[:success] = false
88
47
  puts " # => #{status.result.inspect}"
48
+ puts "Explanation:"
49
+ subexpressions = Sorcerer.subexpressions(status.example.example_block.assertion_sexp).reverse.uniq.reverse
50
+ subexpressions.each do |code|
51
+ print_subexpression(code, status)
52
+ end
89
53
  end
90
54
  if status.is_a?(Matest::ExceptionRaised)
91
55
  runner.info[:success] = false
@@ -101,16 +65,17 @@ module Matest
101
65
  end
102
66
 
103
67
  def print_subexpression(code, status)
104
- result = Evaluator.new(status.example, status.example.example_block.block).eval_string(code)
68
+ just_before_assertion = status.example.just_before_assertion
69
+ result = Evaluator.new(just_before_assertion, just_before_assertion.before_assertion_block).eval_string(code)
105
70
  if result.class != Matest::EvalErr
106
71
  puts <<-CODE
107
- "#{code}" =>
108
- #{result}
72
+ #{code}
73
+ # => #{result}
109
74
  CODE
110
75
  else
111
76
  puts <<-CODE
112
77
  The assertion couldn't be explained.
113
- The error message was:
78
+ The error message was:
114
79
  #{result}
115
80
  Make sure you are not calling any local vaiables on your code assertion.
116
81
  CODE
@@ -0,0 +1,16 @@
1
+ def scope(description=nil, &block)
2
+ Matest::Runner.runner << Matest::ExampleGroup.new(block)
3
+ end
4
+
5
+ def xscope(description=nil, &block)
6
+ # no-op
7
+ end
8
+
9
+ alias :describe :scope
10
+ alias :xdescribe :xscope
11
+
12
+ alias :context :scope
13
+ alias :xcontext :xscope
14
+
15
+ alias :group :scope
16
+ alias :xgroup :xscope
@@ -1,3 +1,3 @@
1
1
  module Matest
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -1,35 +1,29 @@
1
- scope "hola" do
1
+ scope do
2
2
  let(:three) { 3 }
3
- xspec "chau" do
3
+ spec "variables and lets" do
4
4
  one = 2
5
5
  two = 2
6
6
 
7
7
  @one_plus_two_plus_three = one + two + three
8
8
  @res = 3
9
+
9
10
  @one_plus_two_plus_three.to_i == @res
10
11
  end
11
12
 
12
- xspec "again?" do
13
+ spec "again?" do
13
14
  @arr = %w[a b c d e]
14
15
 
15
16
  @arr.pop == "k"
16
17
  end
17
18
 
18
- spec do
19
- a = 4
20
-
21
- a == 5
22
- end
23
- end
19
+ spec "not natural" do
20
+ one = 2
21
+ two = 2
24
22
 
25
- # @one_plus_two == @res.to_i => false
26
- # @one_plus_two => 4
27
- # @res => "3"
28
- # @res.to_i => 3
23
+ @one_plus_two_plus_three = one + two + three
24
+ @res = 3
29
25
 
26
+ @res = @one_plus_two_plus_three.to_i + @res.to_i
27
+ end
30
28
 
31
- ## ON EXAMPLE
32
- # on call:
33
- # - run the spec without the assertion
34
- # - save the state
35
- # - and then run the assertion.
29
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Federico Iachetti
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-11 00:00:00.000000000 Z
11
+ date: 2015-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -67,9 +67,16 @@ files:
67
67
  - Rakefile
68
68
  - bin/matest
69
69
  - lib/matest.rb
70
+ - lib/matest/evaluator.rb
71
+ - lib/matest/example.rb
70
72
  - lib/matest/example_block.rb
73
+ - lib/matest/example_group.rb
74
+ - lib/matest/let.rb
75
+ - lib/matest/runner.rb
76
+ - lib/matest/skip_me.rb
71
77
  - lib/matest/spec_printer.rb
72
78
  - lib/matest/spec_status.rb
79
+ - lib/matest/top_level_methods.rb
73
80
  - lib/matest/version.rb
74
81
  - matest.gemspec
75
82
  - spec/matest_spec.rb