easytest 0.8.1 → 0.10.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 +15 -0
- data/README.md +16 -6
- data/lib/easytest/case.rb +1 -1
- data/lib/easytest/cli.rb +78 -27
- data/lib/easytest/dsl.rb +20 -22
- data/lib/easytest/hook.rb +1 -1
- data/lib/easytest/matcher/contain_exactly.rb +1 -1
- data/lib/easytest/runner.rb +41 -30
- data/lib/easytest/version.rb +1 -1
- data/lib/easytest.rb +7 -3
- data/sig/easytest.rbs +18 -21
- metadata +21 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b46bba7f2013706b78807e3ccda09b44711259717bda01d99d3610ee63436cb
|
4
|
+
data.tar.gz: 3231effd59cc137da79ce59eeb1db2acb5bccf58d951f69f4f6ab7ee38f58859
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eabd062a3db5062f77ea92a9316d148709af73e3f49d1ed8100eec9229273cc92a37a95fc6ebe671d487e0ecec4f7c38dc34347deb9a0d14c83a263488886115
|
7
|
+
data.tar.gz: 285b5df16fdd009212d0890fb3df87c9a8aba76f1019713060aca6e349beacb91591a6ddacafcf4b5d72bf120348c0017537e140938dcc6e6313d9e883db77f3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## 0.10.0
|
6
|
+
|
7
|
+
- **Breaking:** Change refinement to `extend` in an anonymous module. The usage should change as follows:
|
8
|
+
```diff
|
9
|
+
-using Easytest::DSL
|
10
|
+
+extend Easytest::DSL
|
11
|
+
```
|
12
|
+
- **Breaking:** Drop support for Ruby 2.7 (End-of-Life on March 31, 2023)
|
13
|
+
- Remove extra whitespaces from console output.
|
14
|
+
|
15
|
+
## 0.9.0
|
16
|
+
|
17
|
+
- Add watch mode (`--watch`).
|
18
|
+
- Improve type coverage.
|
19
|
+
|
5
20
|
## 0.8.1
|
6
21
|
|
7
22
|
- Improve type-checking.
|
data/README.md
CHANGED
@@ -27,14 +27,14 @@ You can read more about Easytest on the [official website](https://ybiquitous.gi
|
|
27
27
|
|
28
28
|
## Usage
|
29
29
|
|
30
|
-
|
30
|
+
This section explains easy usage.
|
31
31
|
|
32
32
|
First, put `test/addition_test.rb` as below:
|
33
33
|
|
34
34
|
```ruby
|
35
35
|
require "easytest"
|
36
36
|
|
37
|
-
|
37
|
+
extend Easytest::DSL
|
38
38
|
|
39
39
|
test "addition" do
|
40
40
|
expect(1 + 2).to_eq 2
|
@@ -54,8 +54,8 @@ $ easytest
|
|
54
54
|
# test/addition_test.rb:6:in `block in <top (required)>'
|
55
55
|
|
56
56
|
|
57
|
-
|
58
|
-
|
57
|
+
Tests: 1 failed, 0 passed, 1 total (1 files)
|
58
|
+
Time: 0.00087 seconds
|
59
59
|
```
|
60
60
|
|
61
61
|
Oops. Let's fix the failure:
|
@@ -71,8 +71,8 @@ Then, run it again:
|
|
71
71
|
$ easytest
|
72
72
|
PASS test/addition_test.rb
|
73
73
|
|
74
|
-
|
75
|
-
|
74
|
+
Tests: 1 passed, 1 total (1 files)
|
75
|
+
Time: 0.00077 seconds
|
76
76
|
```
|
77
77
|
|
78
78
|
The test now passes! 🎉
|
@@ -126,3 +126,13 @@ test "addition"
|
|
126
126
|
```
|
127
127
|
|
128
128
|
To-do cases will be reported as "todo".
|
129
|
+
|
130
|
+
### Watch
|
131
|
+
|
132
|
+
If you want to run tests immediately when changing code, specify the `--watch` option:
|
133
|
+
|
134
|
+
```shell
|
135
|
+
easytest --watch
|
136
|
+
```
|
137
|
+
|
138
|
+
This *watch* mode is useful during development.
|
data/lib/easytest/case.rb
CHANGED
@@ -9,7 +9,7 @@ module Easytest
|
|
9
9
|
alias skipped? skipped
|
10
10
|
alias only? only
|
11
11
|
|
12
|
-
def initialize(name:, skipped: false, only: false,
|
12
|
+
def initialize(name:, skipped: false, only: false, block: nil)
|
13
13
|
@name = name
|
14
14
|
@file = (caller_locations(3, 1)&.first&.absolute_path or raise)
|
15
15
|
@block = block
|
data/lib/easytest/cli.rb
CHANGED
@@ -8,9 +8,14 @@ module Easytest
|
|
8
8
|
FATAL = 2
|
9
9
|
|
10
10
|
def run
|
11
|
-
exit_code =
|
11
|
+
exit_code = parse_argv
|
12
12
|
return exit_code if exit_code
|
13
13
|
|
14
|
+
if watch?
|
15
|
+
watch_files
|
16
|
+
return SUCCESS
|
17
|
+
end
|
18
|
+
|
14
19
|
Easytest.start
|
15
20
|
setup
|
16
21
|
successful = Easytest.run
|
@@ -21,33 +26,41 @@ module Easytest
|
|
21
26
|
|
22
27
|
attr_reader :argv
|
23
28
|
attr_reader :start_time
|
29
|
+
attr_reader :options
|
30
|
+
attr_reader :parser
|
24
31
|
|
25
32
|
def initialize(argv)
|
26
33
|
@argv = argv
|
27
34
|
@start_time = Time.now
|
35
|
+
@options = {}
|
36
|
+
@parser = init_parser
|
28
37
|
end
|
29
38
|
|
30
|
-
def
|
31
|
-
|
39
|
+
def init_parser
|
40
|
+
OptionParser.new do |op|
|
41
|
+
op.program_name = "easytest"
|
42
|
+
op.version = "#{op.program_name} #{Easytest::VERSION}"
|
32
43
|
|
33
|
-
|
34
|
-
|
35
|
-
|
44
|
+
op.on "-w", "--watch" do
|
45
|
+
options[:watch] = true
|
46
|
+
end
|
36
47
|
|
37
|
-
|
48
|
+
op.on "--help" do
|
38
49
|
options[:help] = true
|
39
50
|
end
|
40
51
|
|
41
|
-
|
52
|
+
op.on "--version" do
|
42
53
|
options[:version] = true
|
43
54
|
end
|
44
55
|
end
|
56
|
+
end
|
45
57
|
|
58
|
+
def parse_argv
|
46
59
|
begin
|
47
60
|
parser.parse!(argv)
|
48
61
|
|
49
62
|
if options[:help]
|
50
|
-
puts help
|
63
|
+
puts help
|
51
64
|
return SUCCESS
|
52
65
|
end
|
53
66
|
|
@@ -63,37 +76,75 @@ module Easytest
|
|
63
76
|
end
|
64
77
|
end
|
65
78
|
|
66
|
-
def help
|
79
|
+
def help
|
80
|
+
program = Rainbow(parser.program_name).green
|
81
|
+
heading = ->(text) { Rainbow(text).bright }
|
82
|
+
secondary = ->(text) { Rainbow(text).dimgray }
|
83
|
+
option = ->(text) { Rainbow(text).yellow }
|
84
|
+
prompt = ->() { Rainbow("$").cyan }
|
85
|
+
|
67
86
|
<<~MSG
|
68
|
-
#{
|
69
|
-
#{
|
87
|
+
#{heading["USAGE"]}
|
88
|
+
#{program} [options] [<file, directory, or pattern>...]
|
70
89
|
|
71
|
-
#{
|
72
|
-
--
|
73
|
-
--
|
90
|
+
#{heading["OPTIONS"]}
|
91
|
+
#{option["-w, --watch"]} Watch file changes and rerun test
|
92
|
+
#{option["--help"]} Show help
|
93
|
+
#{option["--version"]} Show version
|
74
94
|
|
75
|
-
#{
|
76
|
-
# Run all tests (test/**/*_test.rb)
|
77
|
-
|
95
|
+
#{heading["EXAMPLES"]}
|
96
|
+
#{secondary["# Run all tests (test/**/*_test.rb)"]}
|
97
|
+
#{prompt[]} #{program}
|
78
98
|
|
79
|
-
# Run only test files
|
80
|
-
|
99
|
+
#{secondary["# Run only test files"]}
|
100
|
+
#{prompt[]} #{program} test/example_test.rb
|
81
101
|
|
82
|
-
# Run only test files in
|
83
|
-
|
102
|
+
#{secondary["# Run only test files in given directories"]}
|
103
|
+
#{prompt[]} #{program} test/example
|
84
104
|
|
85
|
-
# Run only test files that matches
|
86
|
-
|
105
|
+
#{secondary["# Run only test files that matches given patterns"]}
|
106
|
+
#{prompt[]} #{program} example
|
87
107
|
MSG
|
88
108
|
end
|
89
109
|
|
90
110
|
def setup
|
91
|
-
|
92
|
-
.map { |file| File.absolute_path(file) }
|
111
|
+
test_files
|
93
112
|
.filter do |file|
|
94
113
|
argv.empty? || argv.any? { |pattern| file.include?(pattern) }
|
95
114
|
end
|
96
|
-
.each {
|
115
|
+
.each { load_test_file(_1) }
|
116
|
+
end
|
117
|
+
|
118
|
+
def load_test_file(file)
|
119
|
+
load(file, true)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_files
|
123
|
+
Dir.glob(Easytest.test_files_location).map do |file|
|
124
|
+
File.absolute_path(file)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def watch?
|
129
|
+
options[:watch] == true
|
130
|
+
end
|
131
|
+
|
132
|
+
def watch_files
|
133
|
+
require "listen"
|
134
|
+
listener = Listen.to(Easytest.test_dir, only: /_test\.rb$/) do |modified, added|
|
135
|
+
Easytest.start(no_tests_forbidden: false)
|
136
|
+
test_files.intersection(modified + added).each { load_test_file(_1) }
|
137
|
+
Easytest.run
|
138
|
+
end
|
139
|
+
listener.start
|
140
|
+
|
141
|
+
begin
|
142
|
+
puts "Start watching \"#{Easytest.test_files_location}\" changed. Press Ctrl-C to stop."
|
143
|
+
sleep
|
144
|
+
rescue Interrupt
|
145
|
+
puts
|
146
|
+
puts "Stopped watching."
|
147
|
+
end
|
97
148
|
end
|
98
149
|
end
|
99
150
|
end
|
data/lib/easytest/dsl.rb
CHANGED
@@ -1,32 +1,30 @@
|
|
1
1
|
module Easytest
|
2
2
|
module DSL
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
end
|
3
|
+
def test(name, &block)
|
4
|
+
Utils.raise_if_no_test_name(name, method: "test")
|
5
|
+
Easytest.add_case Case.new(name: name, block: block)
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def before(&block)
|
9
|
+
Easytest.add_hook Hook.new(type: :before, block: block)
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def after(&block)
|
13
|
+
Easytest.add_hook Hook.new(type: :after, block: block)
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
def skip(name, &block)
|
17
|
+
Utils.raise_if_no_test_name(name, method: "skip")
|
18
|
+
Easytest.add_case Case.new(name: name, skipped: true, block: block)
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
def only(name, &block)
|
22
|
+
Utils.raise_if_no_test_name(name, method: "only")
|
23
|
+
Easytest.add_case Case.new(name: name, only: true, block: block)
|
24
|
+
end
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
end
|
26
|
+
def expect(actual = nil, &block)
|
27
|
+
Expectation.new(actual, &block)
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
data/lib/easytest/hook.rb
CHANGED
data/lib/easytest/runner.rb
CHANGED
@@ -1,21 +1,5 @@
|
|
1
1
|
module Easytest
|
2
2
|
class Runner
|
3
|
-
attr_reader :start_time
|
4
|
-
attr_accessor :passed_count
|
5
|
-
attr_accessor :failed_count
|
6
|
-
attr_accessor :skipped_count
|
7
|
-
attr_accessor :todo_count
|
8
|
-
attr_accessor :file_count
|
9
|
-
|
10
|
-
def initialize(start_time: Time.now)
|
11
|
-
@start_time = start_time
|
12
|
-
@passed_count = 0
|
13
|
-
@failed_count = 0
|
14
|
-
@skipped_count = 0
|
15
|
-
@todo_count = 0
|
16
|
-
@file_count = 0
|
17
|
-
end
|
18
|
-
|
19
3
|
def run
|
20
4
|
include_only_case = cases.any?(&:only?)
|
21
5
|
hooks_by_file = hooks.group_by(&:file)
|
@@ -27,6 +11,7 @@ module Easytest
|
|
27
11
|
before_hooks = hooks.filter(&:before?)
|
28
12
|
after_hooks = hooks.filter(&:after?)
|
29
13
|
|
14
|
+
# @type var reports: Array[[Symbol, String]]
|
30
15
|
reports = []
|
31
16
|
|
32
17
|
cases_per_file.each do |c|
|
@@ -34,12 +19,13 @@ module Easytest
|
|
34
19
|
c.skip!
|
35
20
|
end
|
36
21
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
22
|
+
result, report =
|
23
|
+
begin
|
24
|
+
before_hooks.each { |hook| hook.run(c) }
|
25
|
+
c.run
|
26
|
+
ensure
|
27
|
+
after_hooks.each { |hook| hook.run(c) }
|
28
|
+
end
|
43
29
|
|
44
30
|
case result
|
45
31
|
when :passed
|
@@ -69,17 +55,12 @@ module Easytest
|
|
69
55
|
end
|
70
56
|
|
71
57
|
if no_tests?
|
72
|
-
|
73
|
-
#{Rainbow("Oops. No tests found!").red.bright}
|
74
|
-
|
75
|
-
#{Rainbow("Put `#{Easytest.test_files_location}` files to include at least one test case.").red}
|
76
|
-
#{Rainbow("Or specify a pattern that matches an existing test file.").red}
|
77
|
-
MSG
|
58
|
+
print_error_for_no_tests if no_tests_forbidden?
|
78
59
|
false
|
79
60
|
else
|
80
61
|
puts ""
|
81
|
-
puts "
|
82
|
-
puts "
|
62
|
+
puts "#{Rainbow('Tests:').bright} #{summary}"
|
63
|
+
puts "#{Rainbow('Time:').bright} #{elapsed_time.round(5)} seconds"
|
83
64
|
all_passed?
|
84
65
|
end
|
85
66
|
end
|
@@ -102,6 +83,26 @@ module Easytest
|
|
102
83
|
|
103
84
|
private
|
104
85
|
|
86
|
+
attr_reader :start_time
|
87
|
+
attr_reader :no_tests_forbidden
|
88
|
+
alias no_tests_forbidden? no_tests_forbidden
|
89
|
+
|
90
|
+
attr_accessor :passed_count
|
91
|
+
attr_accessor :failed_count
|
92
|
+
attr_accessor :skipped_count
|
93
|
+
attr_accessor :todo_count
|
94
|
+
attr_accessor :file_count
|
95
|
+
|
96
|
+
def initialize(start_time: Time.now, no_tests_forbidden: true)
|
97
|
+
@start_time = start_time
|
98
|
+
@no_tests_forbidden = no_tests_forbidden
|
99
|
+
@passed_count = 0
|
100
|
+
@failed_count = 0
|
101
|
+
@skipped_count = 0
|
102
|
+
@todo_count = 0
|
103
|
+
@file_count = 0
|
104
|
+
end
|
105
|
+
|
105
106
|
def total_count
|
106
107
|
passed_count + failed_count + skipped_count + todo_count
|
107
108
|
end
|
@@ -114,6 +115,15 @@ module Easytest
|
|
114
115
|
total_count == 0
|
115
116
|
end
|
116
117
|
|
118
|
+
def print_error_for_no_tests
|
119
|
+
$stderr.puts <<~MSG
|
120
|
+
#{Rainbow("Oops. No tests found!").red.bright}
|
121
|
+
|
122
|
+
#{Rainbow("Put `#{Easytest.test_files_location}` files to include at least one test case.").red}
|
123
|
+
#{Rainbow("Or specify a pattern that matches an existing test file.").red}
|
124
|
+
MSG
|
125
|
+
end
|
126
|
+
|
117
127
|
def print_reports(reports)
|
118
128
|
unexecuted = [:skipped, :todo]
|
119
129
|
indent = " "
|
@@ -133,6 +143,7 @@ module Easytest
|
|
133
143
|
end
|
134
144
|
|
135
145
|
def summary
|
146
|
+
# @type var list: Array[String]
|
136
147
|
list = []
|
137
148
|
|
138
149
|
if failed_count > 0
|
data/lib/easytest/version.rb
CHANGED
data/lib/easytest.rb
CHANGED
@@ -32,8 +32,8 @@ require_relative "easytest/matcher/satisfy"
|
|
32
32
|
require_relative "easytest/matcher/true"
|
33
33
|
|
34
34
|
module Easytest
|
35
|
-
def self.start
|
36
|
-
@runner = Runner.new
|
35
|
+
def self.start(no_tests_forbidden: true)
|
36
|
+
@runner = Runner.new(no_tests_forbidden: no_tests_forbidden)
|
37
37
|
end
|
38
38
|
|
39
39
|
def self.add_case(new_case)
|
@@ -48,7 +48,11 @@ module Easytest
|
|
48
48
|
@runner.run
|
49
49
|
end
|
50
50
|
|
51
|
+
def self.test_dir
|
52
|
+
"test"
|
53
|
+
end
|
54
|
+
|
51
55
|
def self.test_files_location
|
52
|
-
"
|
56
|
+
"#{test_dir}/**/*_test.rb"
|
53
57
|
end
|
54
58
|
end
|
data/sig/easytest.rbs
CHANGED
@@ -5,6 +5,24 @@ module Easytest
|
|
5
5
|
|
6
6
|
# Define methods for the Easytest DSL.
|
7
7
|
module DSL
|
8
|
+
# Define a test case. If omitting a block, the case is considered a to-do.
|
9
|
+
def test: (String name) ?{ () -> void } -> void
|
10
|
+
|
11
|
+
# Run the given block before each test case.
|
12
|
+
def before: () { (Easytest::Case case) -> void } -> void
|
13
|
+
|
14
|
+
# Run the given block after each test case.
|
15
|
+
def after: () { (Easytest::Case case) -> void } -> void
|
16
|
+
|
17
|
+
# Skip the given test case.
|
18
|
+
def skip: (String name) { () -> void } -> void
|
19
|
+
|
20
|
+
# Run only the given test case.
|
21
|
+
def only: (String name) { () -> void } -> void
|
22
|
+
|
23
|
+
# Expect the given object or block to satisfy some criterion.
|
24
|
+
def expect: (untyped actual) -> Easytest::Expectation
|
25
|
+
| { () -> void } -> Easytest::Expectation
|
8
26
|
end
|
9
27
|
|
10
28
|
# An expectation in test cases.
|
@@ -69,24 +87,3 @@ module Easytest
|
|
69
87
|
attr_reader name: String
|
70
88
|
end
|
71
89
|
end
|
72
|
-
|
73
|
-
module Kernel
|
74
|
-
# TODO: Can we avoid `RBS::DuplicatedMethodDefinitionError` "::Kernel#test has duplicated definitions"?
|
75
|
-
# def test: (String name) ?{ () -> void } -> void
|
76
|
-
|
77
|
-
# Run the given block before each test case.
|
78
|
-
def before: () { (Easytest::Case case) -> void } -> void
|
79
|
-
|
80
|
-
# Run the given block after each test case.
|
81
|
-
def after: () { (Easytest::Case case) -> void } -> void
|
82
|
-
|
83
|
-
# Skip the given test case.
|
84
|
-
def skip: (String name) { () -> void } -> void
|
85
|
-
|
86
|
-
# Run only the given test case.
|
87
|
-
def only: (String name) { () -> void } -> void
|
88
|
-
|
89
|
-
# Expect the given object or block to satisfy some criterion.
|
90
|
-
def expect: (untyped actual) -> Easytest::Expectation
|
91
|
-
| { () -> void } -> Easytest::Expectation
|
92
|
-
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easytest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Masafumi Koba
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: listen
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.7'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rainbow
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,7 +87,7 @@ metadata:
|
|
73
87
|
source_code_uri: https://github.com/ybiquitous/easytest
|
74
88
|
changelog_uri: https://github.com/ybiquitous/easytest/blob/main/CHANGELOG.md
|
75
89
|
rubygems_mfa_required: 'true'
|
76
|
-
post_install_message:
|
90
|
+
post_install_message:
|
77
91
|
rdoc_options: []
|
78
92
|
require_paths:
|
79
93
|
- lib
|
@@ -81,15 +95,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
95
|
requirements:
|
82
96
|
- - ">="
|
83
97
|
- !ruby/object:Gem::Version
|
84
|
-
version: '
|
98
|
+
version: '3.0'
|
85
99
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - ">="
|
88
102
|
- !ruby/object:Gem::Version
|
89
103
|
version: '0'
|
90
104
|
requirements: []
|
91
|
-
rubygems_version: 3.
|
92
|
-
signing_key:
|
105
|
+
rubygems_version: 3.4.10
|
106
|
+
signing_key:
|
93
107
|
specification_version: 4
|
94
108
|
summary: Easy testing for Ruby.
|
95
109
|
test_files: []
|