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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 720ee750084f63381ed7032f4c66bcd045e10b6fe96e9a3680bd5347d8ccdaf8
4
- data.tar.gz: 6b8b8c27ab380b898a2d52976ee3156e237041ff7d4f39006b9c3bd33c71b178
3
+ metadata.gz: b72dfc70d7a8d0661cc8db8f80722598819cd167ff8eaeceeb15804088df94f0
4
+ data.tar.gz: 9e3fa802e2efb674630998420f726c32a24021b9eb5bac8df77696ed9e3aeb23
5
5
  SHA512:
6
- metadata.gz: 7faecdb6f83e99f7ddf0216f03bcc1cd0407f14bd9417e84a4887db2d99c0ef7aaed94a33c513b0c487766d0ee7d28363a2e4c4f705774e7ce8fda5ad0406e67
7
- data.tar.gz: d33ea01dc76b139bba94125c4ca747cb07b2ac0c385bd96b27abbb1288e709ee2827d50bad957aad202c39eee2f21d16cb86f9b0b284b5ef804cdb145565ec38
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
- addition (should equal)
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
- For more, try `easytest --help`.
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
- attr_accessor :report
6
+ attr_reader :skipped
7
+ attr_reader :only
7
8
 
8
- def initialize(name:, file:, &block)
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
- @report = nil
16
+ @skipped = skipped
17
+ @only = only
13
18
  end
14
19
 
15
- def run
16
- block.call
17
- true
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
- false
24
+ def skip!
25
+ @skipped = true
29
26
  end
30
27
 
31
- private
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
- def find_location(error)
34
- error.backtrace_locations.find { |loc| loc.path.end_with?("_test.rb") }
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] [...<file, directory, or pattern>]
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
@@ -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 `to_not_raise` instead" if negate?
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 to_not_raise
49
- raise FatalError, "`to_not_raise` requires a block like `expect { ... }.to_not_raise`" unless block
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::NotRaise.new(actual: block).match!
59
+ Matcher::RaiseNothing.new(actual: block).match!
52
60
  end
53
61
 
54
62
  private
@@ -0,0 +1,13 @@
1
+ module Easytest
2
+ module Matcher
3
+ class Include < Base
4
+ def match?
5
+ actual.include? expected
6
+ end
7
+
8
+ def message
9
+ "include"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Easytest
2
+ module Matcher
3
+ class Match < Base
4
+ def match?
5
+ actual.match? expected
6
+ end
7
+
8
+ def message
9
+ "match"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,6 +1,6 @@
1
1
  module Easytest
2
2
  module Matcher
3
- class NotRaise < Base
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
- "not raise"
23
+ "raise nothing"
24
24
  end
25
25
  end
26
26
  end
@@ -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:, error:, file:, location:)
5
+ def initialize(name)
9
6
  @name = name
10
- @error = error
11
- @file = file
12
- @location = location
13
7
  end
14
8
 
15
- def report
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(" #{name}").red.bright} #{Rainbow("(#{error.message})").dimgray}
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("# #{location}").dimgray}
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(" #{name}").red.bright}
45
+ #{Rainbow(" #{name}").red.bright}
40
46
 
41
47
  #{Rainbow(error.message).red}
42
48
 
43
- #{Rainbow("# #{location}").dimgray}
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
@@ -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
- cases_by_file = cases.group_by { |c| c.file }
17
- cases_by_file.each do |file, cases|
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
- if passed
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
- else
38
+ when :failed
27
39
  self.failed_count += 1
28
- reports << c.report.gsub(/^/, " ")
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
- if reports.empty?
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
- summary = ""
117
+ list = []
85
118
 
86
- if failed_count == 0
87
- summary << Rainbow("#{passed_count} passed").green.bright
88
- else
89
- summary << Rainbow("#{failed_count} failed").red.bright
90
- summary << ", #{Rainbow("#{passed_count} passed").green.bright}"
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
- summary << ", #{total_count} total #{Rainbow("(#{file_count} files)").dimgray}"
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Easytest
2
- VERSION = "0.3.1"
2
+ VERSION = "0.5.0"
3
3
  end
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 to_be_false: () -> void
22
- def to_be_true: () -> void
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 to_not_raise: () -> void
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.3.1
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-06 00:00:00.000000000 Z
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