easytest 0.8.1 → 0.10.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
  SHA256:
3
- metadata.gz: baf1f087a7353d74e8aa021313fd2f00c161af6cf5deb96552a5283e368f947f
4
- data.tar.gz: 9ccc8f17a4911d3bc77abdd3916e4344e2965047ffe7d47d6794d88e6d8dd754
3
+ metadata.gz: 8b46bba7f2013706b78807e3ccda09b44711259717bda01d99d3610ee63436cb
4
+ data.tar.gz: 3231effd59cc137da79ce59eeb1db2acb5bccf58d951f69f4f6ab7ee38f58859
5
5
  SHA512:
6
- metadata.gz: 7d907a3edc843501e6d20b408f358ca5cb0ec19b57a6ee7760577bbceff1fa078635209f439c0b5424ee72e2141c4a54ba51a8bb54c6a823406b55fd21246bd3
7
- data.tar.gz: 7c01539bb3762b24f27f5483e86837a05844b8495c6bb9450557d610e978a9011e8c9012c39bb8c7288d7fd6296b9257583298e8c2255cf74492d271b9b83012
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
- Here is a very easy example.
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
- using Easytest::DSL
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
- Tests: 1 failed, 0 passed, 1 total (1 files)
58
- Time: 0.00087 seconds
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
- Tests: 1 passed, 1 total (1 files)
75
- Time: 0.00077 seconds
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, &block)
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 = parse_options
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 parse_options
31
- options = {}
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
- parser = OptionParser.new do |p|
34
- p.program_name = "easytest"
35
- p.version = "#{p.program_name} #{Easytest::VERSION}"
44
+ op.on "-w", "--watch" do
45
+ options[:watch] = true
46
+ end
36
47
 
37
- p.on "--help" do
48
+ op.on "--help" do
38
49
  options[:help] = true
39
50
  end
40
51
 
41
- p.on "--version" do
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(parser)
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(parser)
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
- #{Rainbow("USAGE").bright}
69
- #{parser.program_name} [options] [<file, directory, or pattern>...]
87
+ #{heading["USAGE"]}
88
+ #{program} [options] [<file, directory, or pattern>...]
70
89
 
71
- #{Rainbow("OPTIONS").bright}
72
- --help Show help
73
- --version Show version
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
- #{Rainbow("EXAMPLES").bright}
76
- # Run all tests (test/**/*_test.rb)
77
- $ easytest
95
+ #{heading["EXAMPLES"]}
96
+ #{secondary["# Run all tests (test/**/*_test.rb)"]}
97
+ #{prompt[]} #{program}
78
98
 
79
- # Run only test files
80
- $ easytest test/example_test.rb
99
+ #{secondary["# Run only test files"]}
100
+ #{prompt[]} #{program} test/example_test.rb
81
101
 
82
- # Run only test files in specified directories
83
- $ easytest test/example
102
+ #{secondary["# Run only test files in given directories"]}
103
+ #{prompt[]} #{program} test/example
84
104
 
85
- # Run only test files that matches specified patterns
86
- $ easytest example
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
- Dir.glob(Easytest.test_files_location)
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 { |test_file| load test_file }
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
- refine Kernel do
4
- def test(name, &block)
5
- Utils.raise_if_no_test_name(name, method: "test")
6
- Easytest.add_case Case.new(name: name, &block)
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
- def before(&block)
10
- Easytest.add_hook Hook.new(type: :before, &block)
11
- end
8
+ def before(&block)
9
+ Easytest.add_hook Hook.new(type: :before, block: block)
10
+ end
12
11
 
13
- def after(&block)
14
- Easytest.add_hook Hook.new(type: :after, &block)
15
- end
12
+ def after(&block)
13
+ Easytest.add_hook Hook.new(type: :after, block: block)
14
+ end
16
15
 
17
- def skip(name, &block)
18
- Utils.raise_if_no_test_name(name, method: "skip")
19
- Easytest.add_case Case.new(name: name, skipped: true, &block)
20
- end
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
- def only(name, &block)
23
- Utils.raise_if_no_test_name(name, method: "only")
24
- Easytest.add_case Case.new(name: name, only: true, &block)
25
- end
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
- def expect(actual = nil, &block)
28
- Expectation.new(actual, &block)
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
@@ -4,7 +4,7 @@ module Easytest
4
4
  attr_reader :type
5
5
  attr_reader :block
6
6
 
7
- def initialize(type:, &block)
7
+ def initialize(type:, block:)
8
8
  raise ArgumentError, "" unless [:before, :after].include?(type)
9
9
 
10
10
  @file = (caller_locations(3, 1)&.first&.absolute_path or raise)
@@ -2,7 +2,7 @@ module Easytest
2
2
  module Matcher
3
3
  class ContainExactly < Base
4
4
  def match?
5
- (actual.to_a - expected).empty?
5
+ (Array(actual) - Array(expected)).empty?
6
6
  end
7
7
 
8
8
  def message
@@ -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
- begin
38
- before_hooks.each { |hook| hook.run(c) }
39
- result, report = c.run
40
- ensure
41
- after_hooks.each { |hook| hook.run(c) }
42
- end
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
- $stderr.puts <<~MSG
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 " #{Rainbow('Tests:').bright} #{summary}"
82
- puts " #{Rainbow('Time:').bright} #{elapsed_time.round(5)} seconds"
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
@@ -1,3 +1,3 @@
1
1
  module Easytest
2
- VERSION = "0.8.1"
2
+ VERSION = "0.10.0"
3
3
  end
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
- "test/**/*_test.rb"
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.8.1
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: 2022-10-13 00:00:00.000000000 Z
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: '2.7'
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.3.7
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: []