test_runner-assert 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/test_runner/assert.rb +21 -0
- data/lib/test_runner/assert/assertion.rb +116 -0
- data/lib/test_runner/assert/check.rb +53 -0
- data/lib/test_runner/assert/checks.rb +76 -0
- data/lib/test_runner/assert/checks/registry.rb +31 -0
- data/lib/test_runner/assert/errors.rb +46 -0
- data/lib/test_runner/assert/syntax.rb +94 -0
- data/lib/test_runner/plugin.rb +1 -0
- metadata +65 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f2ad4a61cd4c9e7215b788fc7e00d56c845ea72c
|
4
|
+
data.tar.gz: 3b875c966207c7deccf95176bf046202c8aafa6f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f9e864c1933698e42c931e154a4b81fd1fd06b9fc17c636e561622574c9a7e5ea6c025df3a91d588c27da46d272a349ab3f1f51629850e5a67babe506b0fbb07
|
7
|
+
data.tar.gz: b7a313ef50f282b5705ee14518b14e2465a7e6efc592d28e7aaafec2fc0bd5b49cacfa213b04ddc9a0a564b0f44a4c1a7bf85e3e8f1f156da9ed1715919ded18
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "test_runner"
|
2
|
+
|
3
|
+
require_relative "assert/assertion"
|
4
|
+
require_relative "assert/check"
|
5
|
+
require_relative "assert/checks"
|
6
|
+
require_relative "assert/errors"
|
7
|
+
require_relative "assert/syntax"
|
8
|
+
|
9
|
+
module TestRunner
|
10
|
+
module Assert
|
11
|
+
def self.inspect object, truncate = 100
|
12
|
+
raw = object.inspect
|
13
|
+
return raw if raw.size <= truncate
|
14
|
+
"#{raw[0..truncate - 2]} …\""
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included target
|
19
|
+
Assert::Syntax.infect target
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module TestRunner
|
2
|
+
module Assert
|
3
|
+
class Assertion
|
4
|
+
attr_reader :fails
|
5
|
+
attr_reader :passes
|
6
|
+
attr_accessor :source
|
7
|
+
|
8
|
+
def initialize subject_proc, checks
|
9
|
+
@subject_proc = subject_proc
|
10
|
+
@checks = checks
|
11
|
+
@passes = []
|
12
|
+
@fails = []
|
13
|
+
@trace = caller_locations
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
perform_checks
|
18
|
+
freeze
|
19
|
+
raise to_error if failed?
|
20
|
+
subject
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_checks
|
24
|
+
@checks.map do |check_name, argument|
|
25
|
+
TestRunner::Config.internal_logger.debug "Resolving check #{check_name.inspect}, arg=#{argument.inspect}"
|
26
|
+
resolve_check check_name, argument
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def failed?
|
31
|
+
fails.any?
|
32
|
+
end
|
33
|
+
|
34
|
+
def file
|
35
|
+
@trace[0].path
|
36
|
+
end
|
37
|
+
|
38
|
+
def freeze
|
39
|
+
passes.freeze
|
40
|
+
fails.freeze
|
41
|
+
end
|
42
|
+
|
43
|
+
def line
|
44
|
+
@trace[0].lineno
|
45
|
+
end
|
46
|
+
|
47
|
+
def passed?
|
48
|
+
not failed?
|
49
|
+
end
|
50
|
+
|
51
|
+
def perform_checks
|
52
|
+
build_checks.each do |check|
|
53
|
+
check.evaluate
|
54
|
+
ary = if check.passed? then passes else fails end
|
55
|
+
ary.push check
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def resolve_check check_name, argument
|
60
|
+
check = Checks.resolve check_name do
|
61
|
+
check_name = :include if check_name == :includes
|
62
|
+
argument = [check_name, *argument]
|
63
|
+
Checks[:predicate]
|
64
|
+
end
|
65
|
+
check.new subject_thunk, argument
|
66
|
+
end
|
67
|
+
|
68
|
+
def subject
|
69
|
+
subject_thunk.call
|
70
|
+
end
|
71
|
+
|
72
|
+
def subject_thunk
|
73
|
+
@subject_thunk ||= SubjectThunk.new @subject_proc
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_error
|
77
|
+
AssertionFailed.new self
|
78
|
+
end
|
79
|
+
|
80
|
+
def trace
|
81
|
+
BacktraceFilter.(@trace)
|
82
|
+
end
|
83
|
+
|
84
|
+
class Refutation < Assertion
|
85
|
+
def build_checks
|
86
|
+
super.each &:negate
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class SubjectThunk
|
91
|
+
def initialize block
|
92
|
+
@block = block
|
93
|
+
end
|
94
|
+
|
95
|
+
def call
|
96
|
+
return @subject if subject_resolved?
|
97
|
+
@subject = @block.call
|
98
|
+
end
|
99
|
+
|
100
|
+
def expect_error
|
101
|
+
raise "called after initially fetched" if subject_resolved?
|
102
|
+
@block.call
|
103
|
+
nothing_raised = true
|
104
|
+
rescue => error
|
105
|
+
@subject = error
|
106
|
+
ensure
|
107
|
+
raise NothingRaised.new if nothing_raised
|
108
|
+
end
|
109
|
+
|
110
|
+
def subject_resolved?
|
111
|
+
instance_variable_defined? :@subject
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module TestRunner
|
2
|
+
module Assert
|
3
|
+
class Check
|
4
|
+
singleton_class.send :attr_reader, :block, :name
|
5
|
+
|
6
|
+
attr :argument
|
7
|
+
|
8
|
+
def initialize subject_thunk, argument
|
9
|
+
@argument = argument
|
10
|
+
@subject_thunk = subject_thunk
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluate
|
14
|
+
self.class.block.call self, @argument
|
15
|
+
freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def expect_error
|
19
|
+
@subject_thunk.expect_error
|
20
|
+
end
|
21
|
+
|
22
|
+
def fail message
|
23
|
+
passed = negated? ^ yield
|
24
|
+
@fail_message = message unless passed
|
25
|
+
end
|
26
|
+
|
27
|
+
def fail_message
|
28
|
+
"expected #{Assert.inspect subject} to#{" not" if negated?} #{@fail_message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def failed?
|
32
|
+
@fail_message ? true : false
|
33
|
+
end
|
34
|
+
|
35
|
+
def negated?
|
36
|
+
@negated ? true : false
|
37
|
+
end
|
38
|
+
|
39
|
+
def negate
|
40
|
+
@negated = !@negated
|
41
|
+
end
|
42
|
+
|
43
|
+
def passed?
|
44
|
+
not failed?
|
45
|
+
end
|
46
|
+
|
47
|
+
def subject
|
48
|
+
@expected_error or @subject_thunk.call
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module TestRunner
|
2
|
+
module Assert
|
3
|
+
module Checks
|
4
|
+
require_relative "checks/registry"
|
5
|
+
extend Registry
|
6
|
+
|
7
|
+
register :equals do |check, object|
|
8
|
+
obj_inspect = Assert.inspect object
|
9
|
+
|
10
|
+
if Assert.inspect(check.subject) == obj_inspect and not check.negated?
|
11
|
+
fail_message = "equal other object (no difference in #inspect output)"
|
12
|
+
else
|
13
|
+
fail_message = "equal #{obj_inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
check.fail fail_message do check.subject == object end
|
17
|
+
end
|
18
|
+
|
19
|
+
register :included_in do |check, list|
|
20
|
+
check.fail "be included in #{Assert.inspect list}" do
|
21
|
+
list.include? check.subject
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
register :kind_of do |check, type|
|
26
|
+
check.fail "be a kind of #{type}" do
|
27
|
+
check.subject.kind_of? type
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
register :matches do |check, matcher|
|
32
|
+
check.fail "match #{Assert.inspect matcher}" do
|
33
|
+
check.subject.match matcher
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
register :predicate do |check, argument|
|
38
|
+
name, *args = argument
|
39
|
+
method_name = "#{name}?"
|
40
|
+
method = check.subject.method method_name
|
41
|
+
|
42
|
+
if method.arity == 0
|
43
|
+
expect_truth = args.all?
|
44
|
+
message = "be #{name}"
|
45
|
+
result = check.subject.public_send method_name
|
46
|
+
result = result ^ !expect_truth
|
47
|
+
else
|
48
|
+
result = check.subject.public_send method_name, *args
|
49
|
+
args = args.map &Assert.method(:inspect)
|
50
|
+
message = "#{name} #{args * ', '}"
|
51
|
+
end
|
52
|
+
|
53
|
+
check.fail message do result end
|
54
|
+
end
|
55
|
+
|
56
|
+
register :raises do |check, error_type|
|
57
|
+
check.expect_error
|
58
|
+
check.fail "be a #{Assert.inspect error_type}" do
|
59
|
+
check.subject.is_a? error_type
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
register :responds_to do |check, method_name|
|
64
|
+
check.fail "respond to ##{method_name}" do
|
65
|
+
check.subject.respond_to? method_name
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
register :truthy do |check, arg|
|
70
|
+
check.fail "be #{arg ? "truthy" : "falsey"}" do
|
71
|
+
!arg ^ check.subject
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module TestRunner
|
2
|
+
module Assert
|
3
|
+
module Checks
|
4
|
+
module Registry
|
5
|
+
def self.extended base
|
6
|
+
base.instance_variable_set :@registry, {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.define check_name, block
|
10
|
+
klass = Class.new Check
|
11
|
+
klass.instance_variable_set :@block, block
|
12
|
+
constant_name = Util.to_camel_case check_name
|
13
|
+
const_set constant_name, klass
|
14
|
+
klass
|
15
|
+
end
|
16
|
+
|
17
|
+
attr :registry
|
18
|
+
|
19
|
+
def register check_name, &block
|
20
|
+
registry[check_name] = Registry.define check_name, block
|
21
|
+
end
|
22
|
+
|
23
|
+
def resolve check_name, &block
|
24
|
+
block ||= -> * do raise MissingCheck.new check_name end
|
25
|
+
registry.fetch check_name, &block
|
26
|
+
end
|
27
|
+
alias_method :[], :resolve
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module TestRunner
|
2
|
+
module Assert
|
3
|
+
Error ||= Class.new StandardError
|
4
|
+
|
5
|
+
class AssertionFailed < Error
|
6
|
+
attr :assertion
|
7
|
+
|
8
|
+
def initialize assertion
|
9
|
+
@assertion = assertion
|
10
|
+
end
|
11
|
+
|
12
|
+
def backtrace
|
13
|
+
assertion.trace.map &:to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
failures = assertion.fails.map do |failed_check|
|
18
|
+
failed_check.fail_message
|
19
|
+
end
|
20
|
+
if failures.size > 1
|
21
|
+
"Assertion failure:\n\n * #{failures * "\n * "}\n"
|
22
|
+
else
|
23
|
+
"Assertion failure: #{failures * ", "}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class MissingCheck < Error
|
29
|
+
attr :check_name
|
30
|
+
|
31
|
+
def initialize check_name
|
32
|
+
@check_name = check_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s
|
36
|
+
"could not resolve check #{check_name.inspect}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class NothingRaised < Error
|
41
|
+
def to_s
|
42
|
+
"expected subject block to raise an error"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module TestRunner
|
2
|
+
module Assert
|
3
|
+
class Syntax < Module
|
4
|
+
MISSING = :__test_runner_assert_arg_missing__
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def infect target
|
8
|
+
instance = new
|
9
|
+
if target.is_a? Class
|
10
|
+
target.send :include, instance
|
11
|
+
else
|
12
|
+
target.extend instance
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Public: assert is designed to be called a number of different ways,
|
17
|
+
# from 0 to 2 positional arguments, and maybe a block.
|
18
|
+
#
|
19
|
+
# subject_or_checks - the first optional argument passed in
|
20
|
+
# checks - the second optional argument passed in
|
21
|
+
# block - the &block parameter
|
22
|
+
#
|
23
|
+
# Valid examples:
|
24
|
+
#
|
25
|
+
# assert :raises => Error do … end
|
26
|
+
# assert "foo"
|
27
|
+
# assert 3, :included_in => [6, 3]
|
28
|
+
# assert [6, 3], :includes => 3
|
29
|
+
# assert :equal => 4 do 2 + 2 end
|
30
|
+
#
|
31
|
+
# Invalid examples:
|
32
|
+
#
|
33
|
+
# # Can't determine if the block or 2 is the subject
|
34
|
+
# assert 2, :equals => 4 do ̒… end
|
35
|
+
# # There's no subject at all
|
36
|
+
# assert :incuded_in => 4
|
37
|
+
#
|
38
|
+
# Returns two arguments, the subject, and a checks hash. If the checks
|
39
|
+
# would be empty, returns { :truthy => true }. The subject will always be
|
40
|
+
# a Proc that gets lazy evaluated when the assertion is checked.
|
41
|
+
def decode_assert_arguments subject_or_checks, checks, block
|
42
|
+
if checks == MISSING
|
43
|
+
if subject_or_checks == MISSING
|
44
|
+
missing_subject! unless block
|
45
|
+
subject_thunk = block
|
46
|
+
checks = { :truthy => true }
|
47
|
+
elsif block
|
48
|
+
ambiguous_subject! unless subject_or_checks.is_a? Hash
|
49
|
+
subject_thunk = block
|
50
|
+
checks = subject_or_checks
|
51
|
+
else
|
52
|
+
subject_thunk = -> do subject_or_checks end
|
53
|
+
checks = { :truthy => true }
|
54
|
+
end
|
55
|
+
else
|
56
|
+
ambiguous_subject! if block
|
57
|
+
subject_thunk = -> do subject_or_checks end
|
58
|
+
end
|
59
|
+
[subject_thunk, checks]
|
60
|
+
end
|
61
|
+
|
62
|
+
def ambiguous_subject!
|
63
|
+
raise ArgumentError, "cannot supply a block subject *and* a positional subject"
|
64
|
+
end
|
65
|
+
|
66
|
+
def missing_subject!
|
67
|
+
raise ArgumentError, "must supply either a positional subject *or* a block subject (but not both)"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def extended base
|
72
|
+
graft base.singleton_class
|
73
|
+
end
|
74
|
+
|
75
|
+
def included base
|
76
|
+
graft base
|
77
|
+
end
|
78
|
+
|
79
|
+
def graft base
|
80
|
+
method_body = -> method_name, assertion_class, syntax do
|
81
|
+
define_method method_name do |arg1 = MISSING, arg2 = MISSING, &block|
|
82
|
+
subject_thunk, checks = syntax.decode_assert_arguments arg1, arg2, block
|
83
|
+
assertion = assertion_class.new subject_thunk, checks
|
84
|
+
assertion.source = self
|
85
|
+
assertion.()
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
base.class_exec :assert, Assertion, self.class, &method_body
|
90
|
+
base.class_exec :refute, Assertion::Refutation, self.class, &method_body
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "test_runner/assert"
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: test_runner-assert
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathan Ladd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: test-runner
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Adds a powerful and simple assert implementation to test-runner
|
28
|
+
email: nathanladd+github@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/test_runner/assert.rb
|
34
|
+
- lib/test_runner/assert/assertion.rb
|
35
|
+
- lib/test_runner/assert/check.rb
|
36
|
+
- lib/test_runner/assert/checks.rb
|
37
|
+
- lib/test_runner/assert/checks/registry.rb
|
38
|
+
- lib/test_runner/assert/errors.rb
|
39
|
+
- lib/test_runner/assert/syntax.rb
|
40
|
+
- lib/test_runner/plugin.rb
|
41
|
+
homepage: https://github.com/ntl/test-runner
|
42
|
+
licenses:
|
43
|
+
- MIT
|
44
|
+
metadata: {}
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 2.4.5.1
|
62
|
+
signing_key:
|
63
|
+
specification_version: 4
|
64
|
+
summary: Adds a powerful and simple assert implementation to test-runner
|
65
|
+
test_files: []
|