easytest 0.1.2 → 0.3.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: 42389cdde1ebd51de0f636f3c5ec0e67ffe842ff91029f71617795799841d47b
4
- data.tar.gz: 559dadc55a86bfc6da11234b05f1fd9a5477311379f94ea41565731516271405
3
+ metadata.gz: 9c1fb5f44f3dd5d049cd6775120712a614f7016a20c7f87d771043642ceb7bb6
4
+ data.tar.gz: '04591bad578ad4351de07ab07467378663cea9e0de2d40930aea5d4a3d132bac'
5
5
  SHA512:
6
- metadata.gz: e4d9cc9b6bc5a76ecccf5f98d076e123eeddabe7a16c42a093050e154c3c32565a80c99301ed615ab0be95e2b7b7e0773088d3d5dc621ddc2fda3f69e28ed184
7
- data.tar.gz: 8a8612f4baf5bc8bc026ecb20fbbe906ad32044f22c9232137dc68b5bb32940d634aed10703d6455f339518bba18c8a433bee66d2ed30afbcff2c93cbe03ec57
6
+ metadata.gz: 718b38f0a0fc35339bdaae214baf115de1ee8d4a94bb20d157f102af5caf08a763580e2946976504443e3b45211fc5d8776668b353c9a9c07e5ed9abddca03e3
7
+ data.tar.gz: 4784ee059e028d9d8a7c6ed23d864182e280ced00d56e502b87d31b032212bde623b50b66fed087583f0ee24eda939900915d8d25fe9081bdf33b020930b7423
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## 0.3.0
6
+
7
+ - Add RBS support.
8
+ - Add CLI help.
9
+ - Fix CLI to aware absolute paths.
10
+
11
+ ## 0.2.0
12
+
13
+ - Add many matchers.
14
+
5
15
  ## 0.1.2
6
16
 
7
17
  - Fix the `easytest` command exit code.
data/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/easytest.svg)](https://badge.fury.io/rb/easytest)
2
+ [![CI](https://github.com/ybiquitous/easytest/actions/workflows/ci.yml/badge.svg)](https://github.com/ybiquitous/easytest/actions/workflows/ci.yml)
2
3
 
3
4
  # Easytest
4
5
 
5
6
  > makes you write tests easily
6
7
 
7
- Easytest is a tiny testing framework with a familiar DSL.
8
+ Easytest is a tiny testing framework for Ruby with a familiar DSL.
8
9
 
9
10
  ## Installation
10
11
 
@@ -39,14 +40,14 @@ end
39
40
  Then, run `easytest`:
40
41
 
41
42
  ```console
42
- $ bundle exec easytest
43
+ $ easytest
43
44
  FAIL test/addition_test.rb
44
45
  ● addition (should equal)
45
46
 
46
47
  Expected: 2
47
48
  Received: 3
48
49
 
49
- at test/addition_test.rb:6:in `block in <top (required)>'
50
+ # test/addition_test.rb:6:in `block in <top (required)>'
50
51
 
51
52
 
52
53
  Tests: 1 failed, 0 passed, 1 total (1 files)
@@ -63,11 +64,13 @@ Oops. Let's fix the failure:
63
64
  Then, run it again:
64
65
 
65
66
  ```console
66
- $ bundle exec easytest
67
+ $ easytest
67
68
  PASS test/addition_test.rb
68
69
 
69
70
  Tests: 1 passed, 1 total (1 files)
70
71
  Time: 0.00077 seconds
71
72
  ```
72
73
 
73
- The test passes! 🎉
74
+ The test now passes! 🎉
75
+
76
+ For more, try `easytest --help`.
data/exe/easytest CHANGED
@@ -3,6 +3,6 @@
3
3
  $LOAD_PATH << File.expand_path("../lib", __dir__)
4
4
  $LOAD_PATH << File.join(Dir.pwd, "test")
5
5
 
6
- require "easytest"
6
+ require "easytest/cli"
7
7
 
8
8
  exit Easytest::CLI.new(ARGV).run
data/lib/easytest/case.rb CHANGED
@@ -15,10 +15,23 @@ module Easytest
15
15
  def run
16
16
  block.call
17
17
  true
18
- rescue UnmatchedError => error
19
- loc = error.backtrace_locations[2]
20
- self.report = Reporter.new(error: error, file: loc.absolute_path, location: loc.to_s).report(name)
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
27
+
21
28
  false
22
29
  end
30
+
31
+ private
32
+
33
+ def find_location(error)
34
+ error.backtrace_locations.find { |loc| loc.path.end_with?("_test.rb") }
35
+ end
23
36
  end
24
37
  end
data/lib/easytest/cli.rb CHANGED
@@ -1,7 +1,23 @@
1
+ require "easytest"
2
+ require "optparse"
3
+
1
4
  module Easytest
2
5
  class CLI
3
6
  SUCCESS = 0
4
7
  FAILURE = 1
8
+ FATAL = 2
9
+
10
+ def run
11
+ exit_code = parse_options
12
+ return exit_code if exit_code
13
+
14
+ Easytest.start
15
+ setup
16
+ successful = Easytest.run
17
+ successful ? SUCCESS : FAILURE
18
+ end
19
+
20
+ private
5
21
 
6
22
  attr_reader :argv
7
23
  attr_reader :start_time
@@ -11,18 +27,72 @@ module Easytest
11
27
  @start_time = Time.now
12
28
  end
13
29
 
14
- def run
15
- Easytest.start
16
- setup
17
- successful = Easytest.run
18
- successful ? SUCCESS : FAILURE
30
+ def parse_options
31
+ options = {}
32
+
33
+ parser = OptionParser.new do |p|
34
+ p.program_name = "easytest"
35
+ p.version = "#{p.program_name} #{Easytest::VERSION}"
36
+
37
+ p.on "--help" do
38
+ options[:help] = true
39
+ end
40
+
41
+ p.on "--version" do
42
+ options[:version] = true
43
+ end
44
+ end
45
+
46
+ begin
47
+ parser.parse!(argv)
48
+
49
+ if options[:help]
50
+ puts help(parser)
51
+ return SUCCESS
52
+ end
53
+
54
+ if options[:version]
55
+ puts parser.version
56
+ return SUCCESS
57
+ end
58
+
59
+ nil
60
+ rescue OptionParser::ParseError => error
61
+ $stderr.puts Rainbow(error.message).red
62
+ FATAL
63
+ end
19
64
  end
20
65
 
21
- private
66
+ def help(parser)
67
+ <<~MSG
68
+ #{Rainbow("USAGE").bright}
69
+ #{parser.program_name} [options] [...<file, directory, or pattern>]
70
+
71
+ #{Rainbow("OPTIONS").bright}
72
+ --help Show help
73
+ --version Show version
74
+
75
+ #{Rainbow("EXAMPLES").bright}
76
+ # Run all tests (test/**/*_test.rb)
77
+ $ easytest
78
+
79
+ # Run only test files
80
+ $ easytest test/example_test.rb
81
+
82
+ # Run only test files in specified directories
83
+ $ easytest test/example
84
+
85
+ # Run only test files that matches specified patterns
86
+ $ easytest example
87
+ MSG
88
+ end
22
89
 
23
90
  def setup
24
91
  Dir.glob(Easytest.test_files_location)
25
- .filter { |file| argv.empty? || argv.any? { |pattern| file.include?(pattern) } }
92
+ .map { |file| File.absolute_path(file) }
93
+ .filter do |file|
94
+ argv.empty? || argv.any? { |pattern| file.include?(pattern) }
95
+ end
26
96
  .each { |test_file| load test_file }
27
97
  end
28
98
  end
@@ -1,7 +1,9 @@
1
1
  module Easytest
2
2
  class Error < StandardError; end
3
3
 
4
- class UnmatchedError < Error
4
+ class FatalError < Error; end
5
+
6
+ class MatchError < Error
5
7
  attr_reader :actual
6
8
  attr_reader :expected
7
9
 
@@ -1,41 +1,67 @@
1
1
  module Easytest
2
2
  class Expectation
3
- attr_reader :actual
4
- attr_reader :block
5
-
6
- def initialize(actual, &block)
7
- @actual = actual
8
- @block = block
3
+ def not
4
+ self.class.new(actual, negate: true, &block)
9
5
  end
10
6
 
11
7
  def to_eq(expected)
12
- Matcher::Equal.new(actual: eval_actual, expected: expected).match!
8
+ Matcher::Equal.new(actual: actual, expected: expected, negate: negate).match!
13
9
  end
10
+ alias to_equal to_eq
14
11
 
15
12
  def to_be(expected)
16
- Matcher::Be.new(actual: eval_actual, expected: expected).match!
13
+ Matcher::Be.new(actual: actual, expected: expected, negate: negate).match!
17
14
  end
18
15
 
19
16
  def to_be_nil
20
- Matcher::BeNil.new(actual: eval_actual).match!
17
+ Matcher::Nil.new(actual: actual, negate: negate).match!
18
+ end
19
+
20
+ def to_be_true
21
+ Matcher::True.new(actual: actual, negate: negate).match!
22
+ end
23
+
24
+ def to_be_false
25
+ Matcher::False.new(actual: actual, negate: negate).match!
26
+ end
27
+
28
+ def to_be_a(expected)
29
+ Matcher::BeA.new(actual: actual, expected: expected, negate: negate).match!
30
+ end
31
+
32
+ def to_be_kind_of(expected)
33
+ Matcher::KindOf.new(actual: actual, expected: expected, negate: negate).match!
34
+ end
35
+
36
+ def to_be_instance_of(expected)
37
+ Matcher::InstanceOf.new(actual: actual, expected: expected, negate: negate).match!
21
38
  end
22
39
 
23
- def to_raise(exception_class)
40
+ def to_raise(expected)
41
+ 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?
43
+ raise FatalError, "`to_raise` requires a Class, String, or Regexp" unless [Class, String, Regexp].any? { expected.is_a? _1 }
24
44
 
45
+ Matcher::Raise.new(actual: block, expected: expected, negate: negate).match!
25
46
  end
26
47
 
27
- def to_not_raise(exception_class)
48
+ def to_not_raise
49
+ raise FatalError, "`to_not_raise` requires a block like `expect { ... }.to_not_raise`" unless block
28
50
 
51
+ Matcher::NotRaise.new(actual: block).match!
29
52
  end
30
53
 
31
54
  private
32
55
 
33
- def eval_actual
34
- if block
35
- block.call
36
- else
37
- actual
38
- end
56
+ attr_reader :actual
57
+ attr_reader :block
58
+ attr_reader :negate
59
+ alias negate? negate
60
+
61
+ def initialize(actual, negate: false, &block)
62
+ @actual = actual
63
+ @block = block
64
+ @negate = negate
39
65
  end
40
66
  end
41
67
  end
@@ -2,9 +2,14 @@ module Easytest
2
2
  module Matcher
3
3
  class Base
4
4
  attr_reader :actual
5
+ attr_reader :expected
6
+ attr_reader :negate
7
+ alias negate? negate
5
8
 
6
- def initialize(actual:)
9
+ def initialize(actual:, expected:, negate: false)
7
10
  @actual = actual
11
+ @expected = expected
12
+ @negate = negate
8
13
  end
9
14
 
10
15
  def match?
@@ -12,17 +17,22 @@ module Easytest
12
17
  end
13
18
 
14
19
  def match!
15
- unless match?
16
- raise UnmatchedError.new(message: message, actual: actual, expected: expected)
17
- end
20
+ matched = match?
21
+ matched = !matched if negate?
22
+ raise_match_error unless matched
18
23
  end
19
24
 
20
- def expected
25
+ def message
21
26
  raise NotImplementedError
22
27
  end
23
28
 
24
- def message
25
- raise NotImplementedError
29
+ def build_error_message
30
+ prefix = negate? ? "not " : ""
31
+ "#{prefix}#{message}"
32
+ end
33
+
34
+ def raise_match_error
35
+ raise MatchError.new(message: build_error_message, actual: actual, expected: expected)
26
36
  end
27
37
  end
28
38
  end
@@ -1,19 +1,12 @@
1
1
  module Easytest
2
2
  module Matcher
3
3
  class Be < Base
4
- attr_reader :expected
5
-
6
- def initialize(actual:, expected:)
7
- super(actual: actual)
8
- @expected = expected
9
- end
10
-
11
4
  def match?
12
5
  actual.equal? expected
13
6
  end
14
7
 
15
8
  def message
16
- "should be same"
9
+ "same"
17
10
  end
18
11
  end
19
12
  end
@@ -0,0 +1,13 @@
1
+ module Easytest
2
+ module Matcher
3
+ class BeA < Base
4
+ def match?
5
+ actual.is_a? expected
6
+ end
7
+
8
+ def message
9
+ "be a"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,26 +1,13 @@
1
1
  module Easytest
2
2
  module Matcher
3
3
  class Equal < Base
4
- attr_reader :expected
5
-
6
- def initialize(actual:, expected:)
7
- super(actual: actual)
8
- @expected = expected
9
- end
10
-
11
4
  def match?
12
5
  actual == expected
13
6
  end
14
7
 
15
8
  def message
16
- "should equal"
9
+ "equal"
17
10
  end
18
-
19
- # def match!
20
- # unless match?
21
- # raise UnmatchedError.new(message: "should equal", actual: actual, expected: expected)
22
- # end
23
- # end
24
11
  end
25
12
  end
26
13
  end
@@ -0,0 +1,17 @@
1
+ module Easytest
2
+ module Matcher
3
+ class False < Base
4
+ def initialize(actual:, negate:)
5
+ super(actual: actual, expected: false, negate: negate)
6
+ end
7
+
8
+ def match?
9
+ actual == expected
10
+ end
11
+
12
+ def message
13
+ "false"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Easytest
2
+ module Matcher
3
+ class InstanceOf < Base
4
+ def match?
5
+ actual.instance_of? expected
6
+ end
7
+
8
+ def message
9
+ "instance of"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Easytest
2
+ module Matcher
3
+ class KindOf < Base
4
+ def match?
5
+ actual.kind_of? expected
6
+ end
7
+
8
+ def message
9
+ "kind of"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,16 +1,16 @@
1
1
  module Easytest
2
2
  module Matcher
3
- class BeNil < Base
4
- def match?
5
- actual.nil?
3
+ class Nil < Base
4
+ def initialize(actual:, negate:)
5
+ super(actual: actual, expected: nil, negate: negate)
6
6
  end
7
7
 
8
- def expected
9
- nil
8
+ def match?
9
+ actual.nil?
10
10
  end
11
11
 
12
12
  def message
13
- "should be nil"
13
+ "nil"
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,27 @@
1
+ module Easytest
2
+ module Matcher
3
+ class NotRaise < Base
4
+ def initialize(actual:)
5
+ super(actual: actual, expected: nil)
6
+ end
7
+
8
+ def match?
9
+ begin
10
+ actual.call
11
+ true
12
+ rescue => error
13
+ @raised_error = error
14
+ false
15
+ end
16
+ end
17
+
18
+ def raise_match_error
19
+ raise MatchError.new(message: build_error_message, actual: @raised_error, expected: expected)
20
+ end
21
+
22
+ def message
23
+ "not raise"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,38 @@
1
+ module Easytest
2
+ module Matcher
3
+ class Raise < Base
4
+ def match?
5
+ begin
6
+ actual.call
7
+ false
8
+ rescue => error
9
+ @raised_error = error
10
+ match_error?(actual: error, expected: expected)
11
+ end
12
+ end
13
+
14
+ def raise_match_error
15
+ raise MatchError.new(message: build_error_message, actual: @raised_error, expected: expected)
16
+ end
17
+
18
+ def message
19
+ "raise"
20
+ end
21
+
22
+ private
23
+
24
+ def match_error?(actual:, expected:)
25
+ case expected
26
+ when Class
27
+ actual.class == expected
28
+ when String
29
+ actual.message == expected
30
+ when Regexp
31
+ actual.message.match? expected
32
+ else
33
+ false
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ module Easytest
2
+ module Matcher
3
+ class True < Base
4
+ def initialize(actual:, negate:)
5
+ super(actual: actual, expected: true, negate: negate)
6
+ end
7
+
8
+ def match?
9
+ actual == expected
10
+ end
11
+
12
+ def message
13
+ "true"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,19 +1,46 @@
1
1
  module Easytest
2
2
  class Reporter
3
- def initialize(error:, file:, location:)
3
+ attr_reader :name
4
+ attr_reader :error
5
+ attr_reader :file
6
+ attr_reader :location
7
+
8
+ def initialize(name:, error:, file:, location:)
9
+ @name = name
4
10
  @error = error
5
11
  @file = file
6
12
  @location = location
7
13
  end
8
14
 
9
- def report(test_name)
15
+ def report
16
+ case error
17
+ when MatchError
18
+ report_match_error
19
+ when FatalError
20
+ report_fatal_error
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def report_match_error
27
+ <<~MSG
28
+ #{Rainbow("● #{name}").red.bright} #{Rainbow("(#{error.message})").dimgray}
29
+
30
+ #{Rainbow("Expected: #{error.expected.inspect}").green}
31
+ #{Rainbow("Received: #{error.actual.inspect}").red}
32
+
33
+ #{Rainbow("# #{location}").dimgray}
34
+ MSG
35
+ end
36
+
37
+ def report_fatal_error
10
38
  <<~MSG
11
- #{Rainbow("● #{test_name}").red.bright} #{Rainbow("(#{@error.message})").dimgray}
39
+ #{Rainbow("● #{name}").red.bright}
12
40
 
13
- #{Rainbow("Expected: #{@error.expected.inspect}").green}
14
- #{Rainbow("Received: #{@error.actual.inspect}").red}
41
+ #{Rainbow(error.message).red}
15
42
 
16
- #{Rainbow("at #{@location}").dimgray}
43
+ #{Rainbow("# #{location}").dimgray}
17
44
  MSG
18
45
  end
19
46
  end
@@ -39,10 +39,12 @@ module Easytest
39
39
  end
40
40
 
41
41
  if no_tests?
42
- puts Rainbow("Oops. No tests found!").red.bright
43
- puts ""
44
- puts "Write `#{Easytest.test_files_location}` files to include at least one `test` block,"
45
- puts "or specify a matching pattern to the `easytest` command."
42
+ $stderr.puts <<~MSG
43
+ #{Rainbow("Oops. No tests found!").red.bright}
44
+
45
+ #{Rainbow("Put `#{Easytest.test_files_location}` files to include at least one test case.").red}
46
+ #{Rainbow("Or specify a pattern that matches an existing test file.").red}
47
+ MSG
46
48
  false
47
49
  else
48
50
  puts ""
@@ -1,3 +1,3 @@
1
1
  module Easytest
2
- VERSION = "0.1.2"
2
+ VERSION = "0.3.0"
3
3
  end
data/lib/easytest.rb CHANGED
@@ -4,18 +4,26 @@ require "rainbow"
4
4
  require_relative "easytest/version"
5
5
 
6
6
  require_relative "easytest/case"
7
- require_relative "easytest/cli"
8
7
  require_relative "easytest/dsl"
9
8
  require_relative "easytest/errors"
10
9
  require_relative "easytest/expectation"
11
- require_relative "easytest/matcher/base"
12
- require_relative "easytest/matcher/be"
13
- require_relative "easytest/matcher/be_nil"
14
- require_relative "easytest/matcher/equal"
15
10
  require_relative "easytest/reporter"
16
11
  require_relative "easytest/runner"
17
12
  require_relative "easytest/utils"
18
13
 
14
+ # Matcher
15
+ require_relative "easytest/matcher/base"
16
+ require_relative "easytest/matcher/be"
17
+ require_relative "easytest/matcher/be_a"
18
+ require_relative "easytest/matcher/equal"
19
+ require_relative "easytest/matcher/false"
20
+ require_relative "easytest/matcher/instance_of"
21
+ require_relative "easytest/matcher/kind_of"
22
+ require_relative "easytest/matcher/nil"
23
+ require_relative "easytest/matcher/not_raise"
24
+ require_relative "easytest/matcher/raise"
25
+ require_relative "easytest/matcher/true"
26
+
19
27
  module Easytest
20
28
  def self.start
21
29
  @runner = Runner.new
data/sig/easytest.rbs ADDED
@@ -0,0 +1,37 @@
1
+ module Easytest
2
+ VERSION: String
3
+
4
+ module DSL
5
+ end
6
+
7
+ class Expectation
8
+ def not: () -> instance
9
+
10
+ def to_eq: (untyped expected) -> void
11
+ alias to_equal to_eq
12
+
13
+ def to_be: (untyped expected) -> untyped
14
+
15
+ def to_be_nil: () -> void
16
+
17
+ def to_be_a: (Class expected) -> void
18
+ def to_be_kind_of: (Class expected) -> void
19
+ def to_be_instance_of: (Class expected) -> void
20
+
21
+ def to_be_false: () -> void
22
+ def to_be_true: () -> void
23
+
24
+ def to_raise: ((Class | String | Regexp) expected) -> void
25
+ def to_not_raise: () -> void
26
+ end
27
+ end
28
+
29
+ module Kernel
30
+ def expect: (untyped actual) -> Easytest::Expectation
31
+ | { () -> void } -> Easytest::Expectation
32
+ end
33
+
34
+ # polyfill
35
+ class Object
36
+ def using: (Module target) -> void
37
+ 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.1.2
4
+ version: 0.3.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-05 00:00:00.000000000 Z
11
+ date: 2022-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
@@ -44,12 +44,20 @@ files:
44
44
  - lib/easytest/expectation.rb
45
45
  - lib/easytest/matcher/base.rb
46
46
  - lib/easytest/matcher/be.rb
47
- - lib/easytest/matcher/be_nil.rb
47
+ - lib/easytest/matcher/be_a.rb
48
48
  - lib/easytest/matcher/equal.rb
49
+ - lib/easytest/matcher/false.rb
50
+ - lib/easytest/matcher/instance_of.rb
51
+ - lib/easytest/matcher/kind_of.rb
52
+ - lib/easytest/matcher/nil.rb
53
+ - lib/easytest/matcher/not_raise.rb
54
+ - lib/easytest/matcher/raise.rb
55
+ - lib/easytest/matcher/true.rb
49
56
  - lib/easytest/reporter.rb
50
57
  - lib/easytest/runner.rb
51
58
  - lib/easytest/utils.rb
52
59
  - lib/easytest/version.rb
60
+ - sig/easytest.rbs
53
61
  homepage: https://github.com/ybiquitous/easytest
54
62
  licenses:
55
63
  - MIT