easytest 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 402f9f4048f129fbd845bc46cd92eb06e9345dff23355ffa9003bd59b88f6e0e
4
+ data.tar.gz: 1f59c66816c8fbbabb77c36a0bf6f0ec2114aad792e3aa7fa69c3b1517e314c1
5
+ SHA512:
6
+ metadata.gz: 320e1266f83153d7695b216d6d9f13832bdcd3e373c35297efb778e9fd75c0471eeeb484ad07b418771b528b1db91b8579f826099fa10550c80b10b2614e5f66
7
+ data.tar.gz: ec873b3bfb646766acaebfbb44fe866227491b3653a86fe85e402b156314306491ea0ffd37a3d5141b16a1e022dca77d046b4a68f9b5f7b3812adde5501cbc7a
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 0.1.0
6
+
7
+ Initial release.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Masafumi Koba
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Easytest
2
+
3
+ > makes you write tests easily
4
+
5
+ Easytest is a tiny testing framework with a familiar DSL.
6
+
7
+ ## Installation
8
+
9
+ via Bundler:
10
+
11
+ ```shell
12
+ bundle add easytest
13
+ ```
14
+
15
+ via gem:
16
+
17
+ ```shell
18
+ gem install easytest
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ Here is a very easy example.
24
+
25
+ First, put `test/addition_test.rb` as below:
26
+
27
+ ```ruby
28
+ require "easytest"
29
+
30
+ using Easytest::DSL
31
+
32
+ test "addition" do
33
+ expect(1 + 2).to_eq 2
34
+ end
35
+ ```
36
+
37
+ Then, run `easytest`:
38
+
39
+ ```console
40
+ $ bundle exec easytest
41
+ FAIL test/addition_test.rb
42
+ ● addition (should equal)
43
+
44
+ Expected: 2
45
+ Received: 3
46
+
47
+ at test/addition_test.rb:6:in `block in <top (required)>'
48
+
49
+
50
+ Tests: 1 failed, 0 passed, 1 total (1 files)
51
+ Time: 0.00087 seconds
52
+ ```
53
+
54
+ Oops. Let's fix the failure:
55
+
56
+ ```diff
57
+ - expect(1 + 2).to_eq 2
58
+ + expect(1 + 2).to_eq 3
59
+ ```
60
+
61
+ Then, run it again:
62
+
63
+ ```console
64
+ $ bundle exec easytest
65
+ PASS test/addition_test.rb
66
+
67
+ Tests: 1 passed, 1 total (1 files)
68
+ Time: 0.00077 seconds
69
+ ```
70
+
71
+ The test passes! 🎉
data/exe/easytest ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << File.expand_path("../lib", __dir__)
4
+ $LOAD_PATH << File.join(Dir.pwd, "test")
5
+
6
+ require "easytest"
7
+
8
+ test_files = Dir.glob("test/**/*_test.rb").filter do |file|
9
+ ARGV.empty? || ARGV.any? { |pattern| file.include?(pattern) }
10
+ end
11
+ test_files.each { |file| load file }
@@ -0,0 +1,24 @@
1
+ module Easytest
2
+ class Case
3
+ attr_reader :name
4
+ attr_reader :file
5
+ attr_reader :block
6
+ attr_accessor :report
7
+
8
+ def initialize(name:, file:, &block)
9
+ @name = name
10
+ @file = file
11
+ @block = block
12
+ @report = nil
13
+ end
14
+
15
+ def run
16
+ block.call
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)
21
+ false
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module Easytest
2
+ module DSL
3
+ refine Kernel do
4
+ def test(name, &block)
5
+ file = caller_locations(1, 1).first.absolute_path
6
+ Easytest.add_case Case.new(name: name, file: file, &block)
7
+ end
8
+
9
+ def expect(actual)
10
+ Expectation.new(actual)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Easytest
2
+ class Error < StandardError; end
3
+
4
+ class UnmatchedError < Error
5
+ attr_reader :actual
6
+ attr_reader :expected
7
+
8
+ def initialize(message:, actual:, expected:)
9
+ super(message)
10
+ @actual = actual
11
+ @expected = expected
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module Easytest
2
+ class Expectation
3
+ def initialize(actual)
4
+ @actual = actual
5
+ end
6
+
7
+ def to_eq(expected)
8
+ Matcher::Equal.new(actual: @actual, expected: expected).match!
9
+ end
10
+
11
+ def to_be(expected)
12
+ Matcher::Be.new(actual: @actual, expected: expected).match!
13
+ end
14
+
15
+ def to_be_nil
16
+ Matcher::BeNil.new(actual: @actual).match!
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ module Easytest
2
+ module Matcher
3
+ class Base
4
+ attr_reader :actual
5
+
6
+ def initialize(actual:)
7
+ @actual = actual
8
+ end
9
+
10
+ def match?
11
+ raise NotImplementedError
12
+ end
13
+
14
+ def match!
15
+ raise NotImplementedError
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module Easytest
2
+ module Matcher
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
+ def match?
12
+ actual.equal? expected
13
+ end
14
+
15
+ def match!
16
+ unless match?
17
+ raise UnmatchedError.new(message: "should be same", actual: actual, expected: expected)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module Easytest
2
+ module Matcher
3
+ class BeNil < Base
4
+ def match?
5
+ actual.nil?
6
+ end
7
+
8
+ def match!
9
+ unless match?
10
+ raise UnmatchedError.new(message: "should be `nil`", actual: actual, expected: nil)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module Easytest
2
+ module Matcher
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
+ def match?
12
+ actual == expected
13
+ end
14
+
15
+ def match!
16
+ unless match?
17
+ raise UnmatchedError.new(message: "should equal", actual: actual, expected: expected)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module Easytest
2
+ class Reporter
3
+ def initialize(error:, file:, location:)
4
+ @error = error
5
+ @file = file
6
+ @location = location
7
+ end
8
+
9
+ def report(test_name)
10
+ <<~MSG
11
+ #{Rainbow("● #{test_name}").red.bright} #{Rainbow("(#{@error.message})").dimgray}
12
+
13
+ #{Rainbow("Expected: #{@error.expected.inspect}").green}
14
+ #{Rainbow("Received: #{@error.actual.inspect}").red}
15
+
16
+ #{Rainbow("at #{@location}").dimgray}
17
+ MSG
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ module Easytest
2
+ module Utils
3
+ module_function
4
+
5
+ def terminal_hyperlink(absolute_path)
6
+ path = Pathname(absolute_path)
7
+ dir = path.relative_path_from(Dir.pwd).dirname.to_s + File::SEPARATOR
8
+ base = path.basename
9
+
10
+ # https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
11
+ "\e]8;;file://#{path}\e\\#{Rainbow(dir).dimgray}#{base}\e]8;;\e\\"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Easytest
2
+ VERSION = "0.1.0"
3
+ end
data/lib/easytest.rb ADDED
@@ -0,0 +1,86 @@
1
+ require "pathname"
2
+ require "rainbow"
3
+
4
+ require_relative "easytest/version"
5
+
6
+ require_relative "easytest/case"
7
+ require_relative "easytest/dsl"
8
+ require_relative "easytest/errors"
9
+ require_relative "easytest/expectation"
10
+ require_relative "easytest/matcher/base"
11
+ require_relative "easytest/matcher/be"
12
+ require_relative "easytest/matcher/be_nil"
13
+ require_relative "easytest/matcher/equal"
14
+ require_relative "easytest/reporter"
15
+ require_relative "easytest/utils"
16
+
17
+ module Easytest
18
+ def self.run
19
+ passed_count = 0
20
+ failed_count = 0
21
+ file_count = 0
22
+
23
+ cases_by_file = cases.group_by { |c| c.file }
24
+ cases_by_file.each do |file, cases|
25
+ file_count += 1
26
+ reports = []
27
+
28
+ cases.each do |c|
29
+ passed = c.run
30
+
31
+ if passed
32
+ passed_count += 1
33
+ else
34
+ failed_count += 1
35
+ reports << c.report.gsub(/^/, " ")
36
+ end
37
+ end
38
+
39
+ link = Utils.terminal_hyperlink(file)
40
+ if reports.empty?
41
+ puts "#{Rainbow(" PASS ").bright.bg(:green)} #{link}"
42
+ else
43
+ puts "#{Rainbow(" FAIL ").bright.bg(:red)} #{link}"
44
+ reports.each { |report| puts report ; puts "" }
45
+ end
46
+ end
47
+
48
+ [passed_count, failed_count, file_count]
49
+ end
50
+
51
+ def self.cases
52
+ @cases ||= []
53
+ end
54
+
55
+ def self.add_case(new_case)
56
+ cases << new_case
57
+ end
58
+ end
59
+
60
+ start_time = Time.now
61
+
62
+ at_exit do
63
+ passed_count, failed_count, file_count = Easytest.run
64
+ total_count = passed_count + failed_count
65
+
66
+ time = Time.now - start_time
67
+
68
+ if total_count == 0
69
+ puts Rainbow("A test suite should have at least one test case!").red.bright
70
+ puts ""
71
+ puts "Please put `test/**/*_test.rb` files or specify valid patterns to the `easytest` command."
72
+ else
73
+ summary = ""
74
+ if failed_count == 0
75
+ summary << Rainbow("#{passed_count} passed").green.bright
76
+ else
77
+ summary << Rainbow("#{failed_count} failed").red.bright
78
+ summary << ", #{Rainbow("#{passed_count} passed").green.bright}"
79
+ end
80
+ summary << ", #{total_count} total #{Rainbow("(#{file_count} files)").dimgray}"
81
+
82
+ puts ""
83
+ puts " #{Rainbow('Tests:').bright} #{summary}"
84
+ puts " #{Rainbow('Time:').bright} #{time.round(5)} seconds"
85
+ end
86
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: easytest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Masafumi Koba
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-10-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rainbow
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ description: Easytest is a tiny testing framework for Ruby with a familiar DSL.
28
+ email:
29
+ - ybiquitous@gmail.com
30
+ executables:
31
+ - easytest
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - CHANGELOG.md
36
+ - LICENSE
37
+ - README.md
38
+ - exe/easytest
39
+ - lib/easytest.rb
40
+ - lib/easytest/case.rb
41
+ - lib/easytest/dsl.rb
42
+ - lib/easytest/errors.rb
43
+ - lib/easytest/expectation.rb
44
+ - lib/easytest/matcher/base.rb
45
+ - lib/easytest/matcher/be.rb
46
+ - lib/easytest/matcher/be_nil.rb
47
+ - lib/easytest/matcher/equal.rb
48
+ - lib/easytest/reporter.rb
49
+ - lib/easytest/utils.rb
50
+ - lib/easytest/version.rb
51
+ homepage: https://github.com/ybiquitous/easytest
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ homepage_uri: https://github.com/ybiquitous/easytest
56
+ source_code_uri: https://github.com/ybiquitous/easytest
57
+ changelog_uri: https://github.com/ybiquitous/easytest/blob/main/CHANGELOG.md
58
+ rubygems_mfa_required: 'true'
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '2.7'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubygems_version: 3.3.7
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: Easy testing for Ruby.
78
+ test_files: []