attestify 0.1.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []