easytest 0.3.1 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +32 -2
- data/lib/easytest/case.rb +21 -19
- data/lib/easytest/cli.rb +1 -1
- data/lib/easytest/dsl.rb +16 -0
- data/lib/easytest/expectation.rb +12 -4
- data/lib/easytest/matcher/include.rb +13 -0
- data/lib/easytest/matcher/match.rb +13 -0
- data/lib/easytest/matcher/{not_raise.rb → raise_nothing.rb} +2 -2
- data/lib/easytest/reporter.rb +34 -16
- data/lib/easytest/runner.rb +60 -17
- data/lib/easytest/utils.rb +10 -0
- data/lib/easytest/version.rb +1 -1
- data/lib/easytest.rb +3 -1
- data/sig/easytest.rbs +13 -4
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b72dfc70d7a8d0661cc8db8f80722598819cd167ff8eaeceeb15804088df94f0
|
4
|
+
data.tar.gz: 9e3fa802e2efb674630998420f726c32a24021b9eb5bac8df77696ed9e3aeb23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 956aa6d38ccbbca19cde275ecd821453c8858ff7ce2652528233a480563304ec71c0c1ace5337904a0895287a26aa088e0bd5a5622d602a43e89bd82e402078c
|
7
|
+
data.tar.gz: ab7b14d3296cf0b37c517ff61f57b5b46b5697c9fd01af278f2fb1ca44ebe11b6f085a14565f8094ea41660a5eebfc7ef123b5d1b542ddfd6281ceef2a4a48e5
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## 0.5.0
|
6
|
+
|
7
|
+
- [Breaking] Rename `to_not_raise` to `to_raise_nothing`.
|
8
|
+
- Add `to_match` matcher.
|
9
|
+
- Add `only` to run only any cases.
|
10
|
+
|
11
|
+
## 0.4.0
|
12
|
+
|
13
|
+
- Add `skip` and `test` without block for todo.
|
14
|
+
- Add `to_include` matcher.
|
15
|
+
|
5
16
|
## 0.3.1
|
6
17
|
|
7
18
|
- Remove polyfill from `.sig` file.
|
data/README.md
CHANGED
@@ -42,7 +42,7 @@ Then, run `easytest`:
|
|
42
42
|
```console
|
43
43
|
$ easytest
|
44
44
|
FAIL test/addition_test.rb
|
45
|
-
|
45
|
+
✕ addition (should equal)
|
46
46
|
|
47
47
|
Expected: 2
|
48
48
|
Received: 3
|
@@ -73,4 +73,34 @@ $ easytest
|
|
73
73
|
|
74
74
|
The test now passes! 🎉
|
75
75
|
|
76
|
-
|
76
|
+
### Skip
|
77
|
+
|
78
|
+
If you want to skip any cases, you can change `test` to `skip`:
|
79
|
+
|
80
|
+
```diff
|
81
|
+
-test "addition" do
|
82
|
+
+skip "addition" do
|
83
|
+
```
|
84
|
+
|
85
|
+
Skipped cases will be reported as "skipped".
|
86
|
+
|
87
|
+
### Only
|
88
|
+
|
89
|
+
If you want to run only any cases, you can use `test` to `only`:
|
90
|
+
|
91
|
+
```diff
|
92
|
+
-test "addition" do
|
93
|
+
+only "addition" do
|
94
|
+
```
|
95
|
+
|
96
|
+
Only cases with `only` will be run, and other cases will be skipped.
|
97
|
+
|
98
|
+
### To-do
|
99
|
+
|
100
|
+
If you want to write to-do cases, you can use `test` without a block:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
test "addition"
|
104
|
+
```
|
105
|
+
|
106
|
+
To-do cases will be reported as "todo".
|
data/lib/easytest/case.rb
CHANGED
@@ -3,35 +3,37 @@ module Easytest
|
|
3
3
|
attr_reader :name
|
4
4
|
attr_reader :file
|
5
5
|
attr_reader :block
|
6
|
-
|
6
|
+
attr_reader :skipped
|
7
|
+
attr_reader :only
|
7
8
|
|
8
|
-
|
9
|
+
alias skipped? skipped
|
10
|
+
alias only? only
|
11
|
+
|
12
|
+
def initialize(name:, file:, skipped: false, only: false, &block)
|
9
13
|
@name = name
|
10
14
|
@file = file
|
11
15
|
@block = block
|
12
|
-
@
|
16
|
+
@skipped = skipped
|
17
|
+
@only = only
|
13
18
|
end
|
14
19
|
|
15
|
-
def
|
16
|
-
block.
|
17
|
-
|
18
|
-
rescue MatchError, FatalError => error
|
19
|
-
loc = find_location(error) or raise
|
20
|
-
|
21
|
-
self.report = Reporter.new(
|
22
|
-
name: name,
|
23
|
-
error: error,
|
24
|
-
file: loc.absolute_path,
|
25
|
-
location: loc.to_s,
|
26
|
-
).report or raise
|
20
|
+
def todo?
|
21
|
+
block.nil?
|
22
|
+
end
|
27
23
|
|
28
|
-
|
24
|
+
def skip!
|
25
|
+
@skipped = true
|
29
26
|
end
|
30
27
|
|
31
|
-
|
28
|
+
def run
|
29
|
+
return [:todo, Reporter.new(name).report_todo] if todo?
|
30
|
+
return [:skipped, Reporter.new(name).report_skip] if skipped?
|
32
31
|
|
33
|
-
|
34
|
-
|
32
|
+
block.call
|
33
|
+
[:passed, nil]
|
34
|
+
rescue MatchError, FatalError => error
|
35
|
+
report = Reporter.new(name).report_error(error) or raise error
|
36
|
+
[:failed, report]
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
data/lib/easytest/cli.rb
CHANGED
@@ -66,7 +66,7 @@ module Easytest
|
|
66
66
|
def help(parser)
|
67
67
|
<<~MSG
|
68
68
|
#{Rainbow("USAGE").bright}
|
69
|
-
#{parser.program_name} [options] [
|
69
|
+
#{parser.program_name} [options] [<file, directory, or pattern>...]
|
70
70
|
|
71
71
|
#{Rainbow("OPTIONS").bright}
|
72
72
|
--help Show help
|
data/lib/easytest/dsl.rb
CHANGED
@@ -2,10 +2,26 @@ module Easytest
|
|
2
2
|
module DSL
|
3
3
|
refine Kernel do
|
4
4
|
def test(name, &block)
|
5
|
+
Utils.raise_if_no_test_name(name, method: "test")
|
6
|
+
|
5
7
|
file = caller_locations(1, 1).first.absolute_path
|
6
8
|
Easytest.add_case Case.new(name: name, file: file, &block)
|
7
9
|
end
|
8
10
|
|
11
|
+
def skip(name, &block)
|
12
|
+
Utils.raise_if_no_test_name(name, method: "skip")
|
13
|
+
|
14
|
+
file = caller_locations(1, 1).first.absolute_path
|
15
|
+
Easytest.add_case Case.new(name: name, file: file, skipped: true, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def only(name, &block)
|
19
|
+
Utils.raise_if_no_test_name(name, method: "only")
|
20
|
+
|
21
|
+
file = caller_locations(1, 1).first.absolute_path
|
22
|
+
Easytest.add_case Case.new(name: name, file: file, only: true, &block)
|
23
|
+
end
|
24
|
+
|
9
25
|
def expect(actual = nil, &block)
|
10
26
|
Expectation.new(actual, &block)
|
11
27
|
end
|
data/lib/easytest/expectation.rb
CHANGED
@@ -37,18 +37,26 @@ module Easytest
|
|
37
37
|
Matcher::InstanceOf.new(actual: actual, expected: expected, negate: negate).match!
|
38
38
|
end
|
39
39
|
|
40
|
+
def to_include(expected)
|
41
|
+
Matcher::Include.new(actual: actual, expected: expected, negate: negate).match!
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_match(expected)
|
45
|
+
Matcher::Match.new(actual: actual, expected: expected, negate: negate).match!
|
46
|
+
end
|
47
|
+
|
40
48
|
def to_raise(expected)
|
41
49
|
raise FatalError, "`to_raise` requires a block like `expect { ... }.to_raise`" unless block
|
42
|
-
raise FatalError, "`not.to_raise` can cause a false positive, so use `
|
50
|
+
raise FatalError, "`not.to_raise` can cause a false positive, so use `to_raise_nothing` instead" if negate?
|
43
51
|
raise FatalError, "`to_raise` requires a Class, String, or Regexp" unless [Class, String, Regexp].any? { expected.is_a? _1 }
|
44
52
|
|
45
53
|
Matcher::Raise.new(actual: block, expected: expected, negate: negate).match!
|
46
54
|
end
|
47
55
|
|
48
|
-
def
|
49
|
-
raise FatalError, "`
|
56
|
+
def to_raise_nothing
|
57
|
+
raise FatalError, "`to_raise_nothing` requires a block like `expect { ... }.to_raise_nothing`" unless block
|
50
58
|
|
51
|
-
Matcher::
|
59
|
+
Matcher::RaiseNothing.new(actual: block).match!
|
52
60
|
end
|
53
61
|
|
54
62
|
private
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Easytest
|
2
2
|
module Matcher
|
3
|
-
class
|
3
|
+
class RaiseNothing < Base
|
4
4
|
def initialize(actual:)
|
5
5
|
super(actual: actual, expected: nil)
|
6
6
|
end
|
@@ -20,7 +20,7 @@ module Easytest
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def message
|
23
|
-
"
|
23
|
+
"raise nothing"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
data/lib/easytest/reporter.rb
CHANGED
@@ -1,47 +1,65 @@
|
|
1
1
|
module Easytest
|
2
2
|
class Reporter
|
3
3
|
attr_reader :name
|
4
|
-
attr_reader :error
|
5
|
-
attr_reader :file
|
6
|
-
attr_reader :location
|
7
4
|
|
8
|
-
def initialize(name
|
5
|
+
def initialize(name)
|
9
6
|
@name = name
|
10
|
-
@error = error
|
11
|
-
@file = file
|
12
|
-
@location = location
|
13
7
|
end
|
14
8
|
|
15
|
-
def
|
9
|
+
def report_error(error)
|
16
10
|
case error
|
17
11
|
when MatchError
|
18
|
-
report_match_error
|
12
|
+
report_match_error(error)
|
19
13
|
when FatalError
|
20
|
-
report_fatal_error
|
14
|
+
report_fatal_error(error)
|
21
15
|
end
|
22
16
|
end
|
23
17
|
|
18
|
+
def report_skip
|
19
|
+
Rainbow("⚠ skipped \"#{name}\"").yellow
|
20
|
+
end
|
21
|
+
|
22
|
+
def report_todo
|
23
|
+
Rainbow("✎ todo \"#{name}\"").magenta
|
24
|
+
end
|
25
|
+
|
24
26
|
private
|
25
27
|
|
26
|
-
def report_match_error
|
28
|
+
def report_match_error(error)
|
29
|
+
loc = find_location(error)
|
30
|
+
|
27
31
|
<<~MSG
|
28
|
-
#{Rainbow("
|
32
|
+
#{Rainbow("✕ #{name}").red.bright} #{Rainbow("(#{error.message})").dimgray}
|
29
33
|
|
30
34
|
#{Rainbow("Expected: #{error.expected.inspect}").green}
|
31
35
|
#{Rainbow("Received: #{error.actual.inspect}").red}
|
32
36
|
|
33
|
-
#{Rainbow(
|
37
|
+
#{Rainbow(format_location(loc)).dimgray}
|
34
38
|
MSG
|
35
39
|
end
|
36
40
|
|
37
|
-
def report_fatal_error
|
41
|
+
def report_fatal_error(error)
|
42
|
+
loc = find_location(error)
|
43
|
+
|
38
44
|
<<~MSG
|
39
|
-
#{Rainbow("
|
45
|
+
#{Rainbow("✕ #{name}").red.bright}
|
40
46
|
|
41
47
|
#{Rainbow(error.message).red}
|
42
48
|
|
43
|
-
#{Rainbow(
|
49
|
+
#{Rainbow(format_location(loc)).dimgray}
|
44
50
|
MSG
|
45
51
|
end
|
52
|
+
|
53
|
+
def find_location(error)
|
54
|
+
location = error.backtrace_locations.find do |loc|
|
55
|
+
loc.path.end_with?("_test.rb")
|
56
|
+
end
|
57
|
+
location or raise "Not found test location from #{error.inspect}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def format_location(location)
|
61
|
+
path = Pathname(location.absolute_path).relative_path_from(Dir.pwd)
|
62
|
+
"# #{path}:#{location.lineno}:in `#{location.label}'"
|
63
|
+
end
|
46
64
|
end
|
47
65
|
end
|
data/lib/easytest/runner.rb
CHANGED
@@ -3,39 +3,72 @@ module Easytest
|
|
3
3
|
attr_reader :start_time
|
4
4
|
attr_accessor :passed_count
|
5
5
|
attr_accessor :failed_count
|
6
|
+
attr_accessor :skipped_count
|
7
|
+
attr_accessor :todo_count
|
6
8
|
attr_accessor :file_count
|
7
9
|
|
8
10
|
def initialize(start_time: Time.now)
|
9
11
|
@start_time = start_time
|
10
12
|
@passed_count = 0
|
11
13
|
@failed_count = 0
|
14
|
+
@skipped_count = 0
|
15
|
+
@todo_count = 0
|
12
16
|
@file_count = 0
|
13
17
|
end
|
14
18
|
|
15
19
|
def run
|
16
|
-
|
17
|
-
|
20
|
+
include_only_case = cases.any?(&:only?)
|
21
|
+
|
22
|
+
cases.group_by(&:file).each do |file, cases_per_file|
|
18
23
|
self.file_count += 1
|
24
|
+
|
19
25
|
reports = []
|
20
26
|
|
21
|
-
cases.each do |c|
|
22
|
-
passed = c.run
|
23
27
|
|
24
|
-
|
28
|
+
cases_per_file.each do |c|
|
29
|
+
if include_only_case && !c.only?
|
30
|
+
c.skip!
|
31
|
+
end
|
32
|
+
|
33
|
+
result, report = c.run
|
34
|
+
|
35
|
+
case result
|
36
|
+
when :passed
|
25
37
|
self.passed_count += 1
|
26
|
-
|
38
|
+
when :failed
|
27
39
|
self.failed_count += 1
|
28
|
-
|
40
|
+
when :skipped
|
41
|
+
self.skipped_count += 1
|
42
|
+
when :todo
|
43
|
+
self.todo_count += 1
|
44
|
+
else
|
45
|
+
raise "Unknown result: #{result.inspect}"
|
29
46
|
end
|
47
|
+
|
48
|
+
reports << [result, report] if report
|
30
49
|
end
|
31
50
|
|
32
51
|
link = Utils.terminal_hyperlink(file)
|
33
|
-
|
52
|
+
|
53
|
+
if reports.none? { |result, _| result == :failed }
|
34
54
|
puts "#{Rainbow(" PASS ").bright.bg(:green)} #{link}"
|
35
55
|
else
|
36
56
|
puts "#{Rainbow(" FAIL ").bright.bg(:red)} #{link}"
|
37
|
-
reports.each { |report| puts report ; puts "" }
|
38
57
|
end
|
58
|
+
|
59
|
+
reports
|
60
|
+
.sort_by do |result, _|
|
61
|
+
case result
|
62
|
+
when :skipped, :todo
|
63
|
+
0
|
64
|
+
else
|
65
|
+
1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
.each do |result, report|
|
69
|
+
puts report.gsub(/^/, " ").gsub(/^\s+$/, "")
|
70
|
+
puts "" if result == :failed
|
71
|
+
end
|
39
72
|
end
|
40
73
|
|
41
74
|
if no_tests?
|
@@ -65,7 +98,7 @@ module Easytest
|
|
65
98
|
private
|
66
99
|
|
67
100
|
def total_count
|
68
|
-
passed_count + failed_count
|
101
|
+
passed_count + failed_count + skipped_count + todo_count
|
69
102
|
end
|
70
103
|
|
71
104
|
def all_passed?
|
@@ -81,16 +114,26 @@ module Easytest
|
|
81
114
|
end
|
82
115
|
|
83
116
|
def summary
|
84
|
-
|
117
|
+
list = []
|
85
118
|
|
86
|
-
if failed_count
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
119
|
+
if failed_count > 0
|
120
|
+
list << Rainbow("#{failed_count} failed").red.bright
|
121
|
+
end
|
122
|
+
|
123
|
+
if skipped_count > 0
|
124
|
+
list << Rainbow("#{skipped_count} skipped").yellow.bright
|
91
125
|
end
|
92
126
|
|
93
|
-
|
127
|
+
if todo_count > 0
|
128
|
+
list << Rainbow("#{todo_count} todo").magenta.bright
|
129
|
+
end
|
130
|
+
|
131
|
+
list << Rainbow("#{passed_count} passed").green.bright
|
132
|
+
|
133
|
+
files_text = "#{file_count} #{Utils.pluralize("file", file_count)}"
|
134
|
+
list << "#{total_count} total #{Rainbow("(#{files_text})").dimgray}"
|
135
|
+
|
136
|
+
list.join(", ")
|
94
137
|
end
|
95
138
|
end
|
96
139
|
end
|
data/lib/easytest/utils.rb
CHANGED
@@ -10,5 +10,15 @@ module Easytest
|
|
10
10
|
# https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
|
11
11
|
"\e]8;;file://#{path}\e\\#{Rainbow(dir).dimgray}#{base}\e]8;;\e\\"
|
12
12
|
end
|
13
|
+
|
14
|
+
def raise_if_no_test_name(name, method:)
|
15
|
+
if name.nil? || name.empty?
|
16
|
+
raise FatalError.new("`#{method}` requires a name")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def pluralize(singular, count)
|
21
|
+
count == 1 ? singular : "#{singular}s"
|
22
|
+
end
|
13
23
|
end
|
14
24
|
end
|
data/lib/easytest/version.rb
CHANGED
data/lib/easytest.rb
CHANGED
@@ -17,11 +17,13 @@ require_relative "easytest/matcher/be"
|
|
17
17
|
require_relative "easytest/matcher/be_a"
|
18
18
|
require_relative "easytest/matcher/equal"
|
19
19
|
require_relative "easytest/matcher/false"
|
20
|
+
require_relative "easytest/matcher/include"
|
20
21
|
require_relative "easytest/matcher/instance_of"
|
21
22
|
require_relative "easytest/matcher/kind_of"
|
23
|
+
require_relative "easytest/matcher/match"
|
22
24
|
require_relative "easytest/matcher/nil"
|
23
|
-
require_relative "easytest/matcher/not_raise"
|
24
25
|
require_relative "easytest/matcher/raise"
|
26
|
+
require_relative "easytest/matcher/raise_nothing"
|
25
27
|
require_relative "easytest/matcher/true"
|
26
28
|
|
27
29
|
module Easytest
|
data/sig/easytest.rbs
CHANGED
@@ -11,22 +11,31 @@ module Easytest
|
|
11
11
|
alias to_equal to_eq
|
12
12
|
|
13
13
|
def to_be: (untyped expected) -> untyped
|
14
|
-
|
15
14
|
def to_be_nil: () -> void
|
15
|
+
def to_be_false: () -> void
|
16
|
+
def to_be_true: () -> void
|
16
17
|
|
17
18
|
def to_be_a: (Class expected) -> void
|
18
19
|
def to_be_kind_of: (Class expected) -> void
|
19
20
|
def to_be_instance_of: (Class expected) -> void
|
20
21
|
|
21
|
-
def
|
22
|
-
|
22
|
+
def to_include: (untyped expected) -> void
|
23
|
+
|
24
|
+
def to_match: (untyped expected) -> void
|
23
25
|
|
24
26
|
def to_raise: ((Class | String | Regexp) expected) -> void
|
25
|
-
def
|
27
|
+
def to_raise_nothing: () -> void
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
module Kernel
|
32
|
+
# TODO: Can we avoid `RBS::DuplicatedMethodDefinitionError` "::Kernel#test has duplicated definitions"?
|
33
|
+
# def test: (String name) ?{ () -> void } -> void
|
34
|
+
|
35
|
+
def skip: (String name) { () -> void } -> void
|
36
|
+
|
37
|
+
def only: (String name) { () -> void } -> void
|
38
|
+
|
30
39
|
def expect: (untyped actual) -> Easytest::Expectation
|
31
40
|
| { () -> void } -> Easytest::Expectation
|
32
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easytest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masafumi Koba
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rainbow
|
@@ -47,11 +47,13 @@ files:
|
|
47
47
|
- lib/easytest/matcher/be_a.rb
|
48
48
|
- lib/easytest/matcher/equal.rb
|
49
49
|
- lib/easytest/matcher/false.rb
|
50
|
+
- lib/easytest/matcher/include.rb
|
50
51
|
- lib/easytest/matcher/instance_of.rb
|
51
52
|
- lib/easytest/matcher/kind_of.rb
|
53
|
+
- lib/easytest/matcher/match.rb
|
52
54
|
- lib/easytest/matcher/nil.rb
|
53
|
-
- lib/easytest/matcher/not_raise.rb
|
54
55
|
- lib/easytest/matcher/raise.rb
|
56
|
+
- lib/easytest/matcher/raise_nothing.rb
|
55
57
|
- lib/easytest/matcher/true.rb
|
56
58
|
- lib/easytest/reporter.rb
|
57
59
|
- lib/easytest/runner.rb
|