attestify 0.1.0.pre.1

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.
@@ -0,0 +1,6 @@
1
+ module Attestify
2
+ # Utility error that is raised when a test is skipped, preventing
3
+ # further code in the test to run.
4
+ class SkippedError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,89 @@
1
+ require "attestify"
2
+
3
+ module Attestify
4
+ # This is the base class for all Attestify tests.
5
+ class Test
6
+ include Attestify::Assertions
7
+
8
+ def initialize(method)
9
+ @_test_method = method
10
+ @_assertions = Attestify::AssertionResults.new
11
+ end
12
+
13
+ def self.inherited(test_class)
14
+ tests << test_class
15
+ end
16
+
17
+ def self.tests
18
+ @tests ||= []
19
+ end
20
+
21
+ def self.run(reporter, filter = nil)
22
+ runnable_methods.each do |method|
23
+ run_one_method(self, method, reporter, filter)
24
+ end
25
+ end
26
+
27
+ def self.run_one_method(test_class, method, reporter, filter = nil)
28
+ return if filter && !filter.run?(test_class, method)
29
+ reporter.record test_class.new(method).run
30
+ end
31
+
32
+ def self.runnable_methods
33
+ instance_methods.select { |method| method.to_s.start_with?("test_") }
34
+ end
35
+
36
+ def setup
37
+ end
38
+
39
+ def teardown
40
+ end
41
+
42
+ def assertions
43
+ @_assertions
44
+ end
45
+
46
+ def name
47
+ "#{self.class.name}##{@_test_method}"
48
+ end
49
+
50
+ def passed?
51
+ assertions.passed?
52
+ end
53
+
54
+ def errored?
55
+ assertions.errored?
56
+ end
57
+
58
+ def failed?
59
+ assertions.failed?
60
+ end
61
+
62
+ def result_code # rubocop:disable Metrics/MethodLength
63
+ if passed?
64
+ "."
65
+ elsif skipped?
66
+ "S"
67
+ elsif errored?
68
+ "E"
69
+ elsif failed?
70
+ "F"
71
+ else
72
+ "?"
73
+ end
74
+ end
75
+
76
+ def run
77
+ begin
78
+ setup
79
+ send @_test_method
80
+ ensure
81
+ teardown
82
+ end
83
+ rescue => e
84
+ assertions.error = e
85
+ ensure
86
+ return self # rubocop:disable Lint/EnsureReturn
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,162 @@
1
+ module Attestify
2
+ # Holds the tests that will be loaded for a test run.
3
+ class TestList
4
+ attr_reader :dir, :test_helper_file
5
+
6
+ def initialize(files = nil, dir: nil)
7
+ @dir = dir || "./test"
8
+ @provided_files = files
9
+ end
10
+
11
+ def test_helper_file
12
+ @test_helper_file_path ||= File.join(dir, "test_helper.rb")
13
+ @test_helper_file_path if File.file?(@test_helper_file_path)
14
+ end
15
+
16
+ def test_files
17
+ @test_files ||= test_filters.map(&:file)
18
+ end
19
+
20
+ def run?(test_class, method)
21
+ test_filters.any? { |filter| filter.run?(test_class, method) }
22
+ end
23
+
24
+ private
25
+
26
+ def test_filters
27
+ @test_filters ||=
28
+ begin
29
+ if provided_files?
30
+ @provided_files.map { |path| all_file_filters_for(path) }.flatten.compact
31
+ else
32
+ all_file_filters_for(dir) || []
33
+ end
34
+ end
35
+ end
36
+
37
+ def provided_files?
38
+ @provided_files && !@provided_files.empty?
39
+ end
40
+
41
+ def all_file_filters_for(path)
42
+ if File.directory?(path)
43
+ Dir[File.join(path, "**/*_test.rb")].map { |file| Attestify::TestList::FileFilter.new(file) }
44
+ elsif File.file?(path)
45
+ Attestify::TestList::FileFilter.new(path)
46
+ elsif path =~ /:\d+\z/
47
+ Attestify::TestList::FileFilter.with_line(path)
48
+ end
49
+ end
50
+
51
+ # Filters tests that aren't defined in the provided file. If a
52
+ # line is provided, then only the test defined above that line
53
+ # will not be filtered.
54
+ class FileFilter
55
+ attr_reader :file, :line
56
+
57
+ def initialize(file, line = nil)
58
+ @file = file
59
+ @line = line
60
+ end
61
+
62
+ def self.with_line(path_with_line)
63
+ match = /\A(.*):(\d+)\z/.match(path_with_line)
64
+ return unless File.file?(match[1])
65
+ new(match[1], match[2].to_i)
66
+ end
67
+
68
+ def run?(test_class, method)
69
+ file_matches?(test_class, method) && line_matches?(test_class, method)
70
+ end
71
+
72
+ private
73
+
74
+ def file_matches?(test_class, method)
75
+ real_file == Attestify::TestList::RealSourceLocationCache[test_class].real_file(method)
76
+ end
77
+
78
+ def line_matches?(test_class, method)
79
+ if line
80
+ Attestify::TestList::RealSourceLocationCache[test_class].in_method?(method, line)
81
+ else
82
+ true
83
+ end
84
+ end
85
+
86
+ def real_file
87
+ @real_file ||= File.realpath(file)
88
+ end
89
+ end
90
+
91
+ # Helper class to keep track of source locations of methods for
92
+ # tests.
93
+ class TestClassSourceLocations
94
+ def initialize(test_class)
95
+ @test_class = test_class
96
+ end
97
+
98
+ def real_file(method)
99
+ real_source_locations[method].first
100
+ end
101
+
102
+ def in_method?(method, line)
103
+ method_at(line) == method
104
+ end
105
+
106
+ private
107
+
108
+ def method_at(line)
109
+ result = nil
110
+
111
+ runnable_method_lines.each do |source_location|
112
+ return result if source_location.last > line
113
+ result = source_location.first
114
+ end
115
+
116
+ result
117
+ end
118
+
119
+ def runnable_methods
120
+ @runnable_methods ||= @test_class.runnable_methods
121
+ end
122
+
123
+ def runnable_method_lines
124
+ @runnable_method_lines ||= runnable_methods.map do |runnable_method|
125
+ [runnable_method] + real_source_locations[runnable_method]
126
+ end.sort do |a, b| # rubocop:disable Style/MultilineBlockChain
127
+ if a != b
128
+ a.last <=> b.last
129
+ else
130
+ a.first <=> b.first
131
+ end
132
+ end
133
+ end
134
+
135
+ def real_source_locations
136
+ @real_source_locations ||= Hash.new do |hash, method|
137
+ hash[method] = @test_class.instance_method(method).source_location.tap do |result|
138
+ result[0] = File.realpath(result[0])
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ # Helper class to cache source locations TestClassSourceLocations
145
+ # for classes.
146
+ class RealSourceLocationCache
147
+ class << self
148
+ def [](test_class)
149
+ hash[test_class]
150
+ end
151
+
152
+ private
153
+
154
+ def hash
155
+ Thread.current[:Attestify_TestList_RealSourceLocationCache] ||= Hash.new do |hash, test_class|
156
+ hash[test_class] = Attestify::TestList::TestClassSourceLocations.new(test_class)
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,46 @@
1
+ require "attestify"
2
+
3
+ module Attestify
4
+ # A basic test runner to run all tests.
5
+ class TestRunner
6
+ attr_reader :test_list, :reporter
7
+
8
+ def initialize(test_list, reporter)
9
+ @test_list = test_list
10
+ @reporter = reporter
11
+ end
12
+
13
+ def run
14
+ require_helper
15
+ require_tests
16
+ run_tests
17
+ end
18
+
19
+ private
20
+
21
+ def require_helper
22
+ require_real_file test_list.test_helper_file
23
+ end
24
+
25
+ def require_tests
26
+ test_list.test_files.each { |f| require_real_file f }
27
+ end
28
+
29
+ # If we don't require via realpath, some relative paths will be
30
+ # rejected as not being in Ruby's path.
31
+ def require_real_file(file)
32
+ return unless file
33
+ require File.realpath(file)
34
+ end
35
+
36
+ def run_tests
37
+ Attestify::Test.tests.each do |test|
38
+ test.run(reporter, test_list)
39
+ end
40
+ end
41
+
42
+ def report_tests
43
+ reporter.report
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,30 @@
1
+ module Attestify
2
+ # A timer for keeping track of the timing of code.
3
+ class Timer
4
+ attr_reader :duration, :result
5
+
6
+ def initialize
7
+ start_time = Time.new
8
+ @result = yield
9
+ ensure
10
+ end_time = Time.new
11
+ @duration = end_time - start_time
12
+ end
13
+
14
+ def self.time
15
+ Timer.new do
16
+ yield
17
+ end
18
+ end
19
+
20
+ def to_s
21
+ if duration < 1.0
22
+ format("%.1f milliseconds", duration * 1000.0)
23
+ elsif duration < 60.0
24
+ format("%.1f seconds", duration)
25
+ else
26
+ format("%.2f minutes", duration / 60.0)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Attestify
2
+ VERSION = "0.1.0.pre.1".freeze
3
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: attestify
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.1
5
+ platform: ruby
6
+ authors:
7
+ - Mike Virata-Stone
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.40.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.40.0
55
+ description: A small framework for testing your code. It keeps track of assertion
56
+ failures as well as test failures.
57
+ email:
58
+ - mike@virata-stone.com
59
+ executables:
60
+ - attestify
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".rubocop.yml"
66
+ - ".travis.yml"
67
+ - CODE_OF_CONDUCT.md
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - attestify.gemspec
73
+ - bin/console
74
+ - bin/setup
75
+ - exe/attestify
76
+ - lib/attestify.rb
77
+ - lib/attestify/assertion_results.rb
78
+ - lib/attestify/assertions.rb
79
+ - lib/attestify/assertions/output_assertion.rb
80
+ - lib/attestify/cli.rb
81
+ - lib/attestify/color_reporter.rb
82
+ - lib/attestify/mock.rb
83
+ - lib/attestify/rake_task.rb
84
+ - lib/attestify/reporter.rb
85
+ - lib/attestify/skipped_error.rb
86
+ - lib/attestify/test.rb
87
+ - lib/attestify/test_list.rb
88
+ - lib/attestify/test_runner.rb
89
+ - lib/attestify/timer.rb
90
+ - lib/attestify/version.rb
91
+ homepage: https://github.com/smellsblue/attestify
92
+ licenses:
93
+ - MIT
94
+ metadata: {}
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">"
107
+ - !ruby/object:Gem::Version
108
+ version: 1.3.1
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.5.1
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: A new way to test your code
115
+ test_files: []