uspec 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +21 -0
- data/.editorconfig +11 -0
- data/.rubocop.yml +56 -0
- data/README.markdown +49 -42
- data/bin/uspec +1 -1
- data/lib/uspec.rb +4 -4
- data/lib/uspec/cli.rb +46 -25
- data/lib/uspec/dsl.rb +45 -10
- data/lib/uspec/result.rb +111 -0
- data/lib/uspec/stats.rb +28 -15
- data/lib/uspec/terminal.rb +47 -0
- data/lib/uspec/version.rb +1 -1
- data/uspec.gemspec +14 -4
- data/uspec/cli_spec.rb +8 -8
- data/uspec/result_spec.rb +70 -0
- data/uspec/uspec_spec.rb +25 -5
- metadata +56 -9
- data/.travis.yml +0 -23
- data/lib/uspec/formatter.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adfc4745c3e11f9afa82923366d86c5515745666b98606ded26418cb520b9bb9
|
4
|
+
data.tar.gz: b62be6efc2f67ba658c2701b6984764d7fdb36e0acc79f1e20378efeef1c534c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b89e9ab10352cbe0d18278c1d5aa823b72d3d9c40dbf49d0c2791b6f92748841d2018e6ac1ddee04016fa40c6353a76c94d8c6c7bfe11c7197a60606e38180b5
|
7
|
+
data.tar.gz: 51dc3f357ffff68b6e7ffc3d1a81376ad2755813490a2749e55bbcef6142ae3432f92076b7dcd5599625f55fb77ce6a8f099612972119bf90f24315e30d7f688
|
@@ -0,0 +1,21 @@
|
|
1
|
+
version: 2.1
|
2
|
+
orbs:
|
3
|
+
ruby: circleci/ruby@0.1.2
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
docker:
|
8
|
+
- image: circleci/ruby:2.6.3-stretch-node
|
9
|
+
executor: ruby/default
|
10
|
+
steps:
|
11
|
+
- checkout
|
12
|
+
- run:
|
13
|
+
name: Which bundler?
|
14
|
+
command: bundle -v
|
15
|
+
- ruby/bundle-install
|
16
|
+
test:
|
17
|
+
executor: ruby/default
|
18
|
+
steps:
|
19
|
+
- run:
|
20
|
+
name: Uspec tests
|
21
|
+
command: bundle exec uspec
|
data/.editorconfig
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Rubocop override settings
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: 2.0
|
5
|
+
|
6
|
+
Metrics/LineLength:
|
7
|
+
Max: 120
|
8
|
+
Exclude:
|
9
|
+
- config_module.gemspec
|
10
|
+
- "uspec/**/*"
|
11
|
+
|
12
|
+
Naming/PredicateName:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Style/PreferredHashMethods:
|
16
|
+
Exclude:
|
17
|
+
- "**/*"
|
18
|
+
|
19
|
+
Style/Documentation:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Style/MethodDefParentheses:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/ParallelAssignment:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Style/SingleLineMethods:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/Alias:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Style/CaseEquality:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Style/SymbolArray:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Bundler/OrderedGems:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/StringLiterals:
|
44
|
+
EnforcedStyle: double_quotes
|
45
|
+
|
46
|
+
Style/StringLiteralsInInterpolation:
|
47
|
+
EnforcedStyle: double_quotes
|
48
|
+
|
49
|
+
Layout/AccessModifierIndentation:
|
50
|
+
EnforcedStyle: outdent
|
51
|
+
|
52
|
+
Style/EnforcedStyleForMultiline:
|
53
|
+
EnforcedStyle: consistent_comma
|
54
|
+
|
55
|
+
Naming/RescuedExceptionsVariableName:
|
56
|
+
PreferredName: error
|
data/README.markdown
CHANGED
@@ -3,29 +3,45 @@ Uspec
|
|
3
3
|
|
4
4
|
Uspec is a shiny little testing framework for your apps!
|
5
5
|
|
6
|
-
[![
|
7
|
-
[![
|
6
|
+
[![Gem Version](https://img.shields.io/gem/v/uspec.svg?style=for-the-badge)](https://rubygems.org/gems/uspec/)
|
7
|
+
[![Build Status](https://img.shields.io/circleci/build/github/acook/uspec.svg?style=for-the-badge)](https://app.circleci.com/pipelines/github/acook/uspec)
|
8
|
+
[![Code Climate](https://img.shields.io/codeclimate/maintainability/acook/uspec.svg?style=for-the-badge)](https://codeclimate.com/github/acook/uspec)
|
8
9
|
|
9
10
|
Philosophy / Why Uspec?
|
10
11
|
-----------------------
|
11
12
|
|
12
13
|
> Uspec is just Ruby!
|
13
14
|
|
14
|
-
Unlike other testing frameworks there's no need for special matchers,
|
15
|
-
there can only be one assertion per test,
|
15
|
+
Unlike other testing frameworks there's no need for special matchers,
|
16
|
+
there can only be one assertion per test,
|
16
17
|
and you never have to worry that your tests lack assertions.
|
17
18
|
|
18
|
-
That's because when the `spec` block is evaluated the return value is used (in a very ruby-like way)
|
19
|
-
to determine the
|
19
|
+
That's because when the `spec` block is evaluated the return value is used (in a very ruby-like way)
|
20
|
+
to determine if the test has passed or failed. Standard Ruby comparisons are your friend!
|
20
21
|
No more digging around in your test framework's documentation to figure out what matcher you're supposed to use.
|
21
22
|
This also means *no monkey patching* core classes!
|
22
23
|
|
23
|
-
Uspec's output is in beautiful ansi technicolor,
|
24
|
+
Uspec's output is in beautiful ansi technicolor,
|
24
25
|
with red for failures, green for successes, and yellow for pending specs. Here's a screenshot:
|
25
26
|
|
26
27
|
![Screenshot!](http://i.imgur.com/M2F5YvO.png)
|
27
28
|
|
28
|
-
Uspec is tiny, painless, and easy to use. Download it and give it a
|
29
|
+
Uspec is tiny, painless, and easy to use. Download it and give it a try!
|
30
|
+
|
31
|
+
Example
|
32
|
+
-------
|
33
|
+
|
34
|
+
Uspec is **just Ruby**. The DSL is minimal - there's only one method to remember!
|
35
|
+
|
36
|
+
Writing a spec is easy:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
spec 'AwesomeMcCoolname.generate creates a cool name' do
|
40
|
+
AwesomeMcCoolname.generate.include? 'Cool'
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
That's it!
|
29
45
|
|
30
46
|
Installation
|
31
47
|
------------
|
@@ -38,7 +54,7 @@ And then execute:
|
|
38
54
|
|
39
55
|
$ bundle
|
40
56
|
|
41
|
-
Or install it
|
57
|
+
Or install it directly with:
|
42
58
|
|
43
59
|
$ gem install uspec
|
44
60
|
|
@@ -46,46 +62,31 @@ Or install it yourself as:
|
|
46
62
|
Quickstart
|
47
63
|
----------
|
48
64
|
|
49
|
-
0. Create a `
|
65
|
+
0. Create a `uspec` directory to keep your specs in.
|
50
66
|
1. Name your specs ending with `_spec.rb`.
|
51
|
-
2. Write some specs in Ruby using the `spec` method.
|
67
|
+
2. Write some specs in Ruby using the `spec` method (example above).
|
52
68
|
2. Use the included `uspec` executable to run your specs.
|
53
69
|
|
54
|
-
**Hint:** A lot of people also put `require_relative 'spec_helper'`
|
70
|
+
**Hint:** A lot of people also put `require_relative 'spec_helper'` at the top of their test files for sharing code between tests.
|
55
71
|
|
56
|
-
Usage
|
57
|
-
|
72
|
+
Commandline Usage
|
73
|
+
-----------------
|
58
74
|
|
59
|
-
```
|
75
|
+
```
|
60
76
|
$ uspec --help
|
61
77
|
uspec - minimalistic ruby testing framework
|
62
78
|
usage: uspec [<file_or_path>...]
|
63
79
|
```
|
64
80
|
|
65
|
-
- Without arguments the `uspec` command will automatially look for `
|
81
|
+
- Without arguments the `uspec` command will automatially look for a `uspec` directory and load any `*_spec.rb` files inside them.
|
66
82
|
- You can also pass in arbitrary files and it will attempt to run them as specs.
|
67
|
-
- If you pass in directories `uspec` will
|
68
|
-
- Uspec will return
|
69
|
-
|
70
|
-
Syntax
|
71
|
-
------
|
72
|
-
|
73
|
-
Uspec is **just Ruby**. The DSL is minimal - there's only one method to remember!
|
74
|
-
|
75
|
-
Writing a spec is easy:
|
76
|
-
|
77
|
-
```ruby
|
78
|
-
spec 'AwesomeMcCoolname.generate creates a cool name' do
|
79
|
-
AwesomeMcCoolname.generate.include? 'Cool'
|
80
|
-
end
|
81
|
-
```
|
82
|
-
|
83
|
-
That's it!
|
83
|
+
- If you pass in directories `uspec` will scan for and run any specs inside them.
|
84
|
+
- Uspec will return the number of failures as its status code to the commandline, 0 if none.
|
84
85
|
|
85
86
|
Output
|
86
87
|
------
|
87
88
|
|
88
|
-
|
89
|
+
A brief explanation of `uspec`'s output to show you what it can do!
|
89
90
|
|
90
91
|
### Success
|
91
92
|
|
@@ -157,7 +158,7 @@ When you run the test Uspec will helpfully display:
|
|
157
158
|
Tips & Tricks
|
158
159
|
-------------
|
159
160
|
|
160
|
-
Because there's no matchers and only one method there's no
|
161
|
+
Because there's no matchers and only one method there's no need for specialized reference documentation, but here are some ideas to get you going!
|
161
162
|
|
162
163
|
### String matching
|
163
164
|
|
@@ -190,8 +191,8 @@ What if you want to test that an error has occured? Just use Ruby!
|
|
190
191
|
spec 'calling AwesomeMcCoolname.awesomeness without specifying the awesomeness level should explode' do
|
191
192
|
begin
|
192
193
|
AwesomeMcCoolname.awesomeness
|
193
|
-
rescue => error
|
194
|
-
error.
|
194
|
+
rescue ArgumentError => error
|
195
|
+
error.message.include?("Needs awesomeness level!") || raise
|
195
196
|
end
|
196
197
|
end
|
197
198
|
```
|
@@ -200,6 +201,11 @@ If there's no error, then Uspec will see the result of the method call (whatever
|
|
200
201
|
If the wrong Exception is raised, then because of reraising (by just calling `raise` without parameters),
|
201
202
|
Ruby will dutifully pass along the error for Uspec to display.
|
202
203
|
|
204
|
+
Mocks, Spies, Stubs, and More!
|
205
|
+
-----------------------
|
206
|
+
|
207
|
+
Since `uspec` is a very straight forward testing utility it is easy to use any of the standard Ruby mocking frameworks with it. However, the [Impasta gem](https://github.com/acook/impasta) was made specifically for simple but comprehensive mocking, stubbing, and spying.
|
208
|
+
|
203
209
|
Assertions & Debugging
|
204
210
|
----------------------
|
205
211
|
|
@@ -212,7 +218,7 @@ require 'uspec'
|
|
212
218
|
|
213
219
|
class MyFoo
|
214
220
|
extend Uspec::DSL
|
215
|
-
|
221
|
+
|
216
222
|
def assert
|
217
223
|
spec 'foo is valid' do
|
218
224
|
false
|
@@ -223,19 +229,20 @@ end
|
|
223
229
|
MyFoo.new.assert
|
224
230
|
```
|
225
231
|
|
226
|
-
|
232
|
+
Assertions will be displayed as they occur, success or failure along with any informative output.
|
233
|
+
If there are any specs that fail, when your application exits its error code will equal the number of failures.
|
227
234
|
|
228
235
|
```
|
229
236
|
$ ruby foo.rb
|
230
237
|
-- foo is valid: false
|
231
238
|
$ echo $?
|
232
|
-
|
239
|
+
1
|
233
240
|
```
|
234
241
|
|
235
242
|
Uspec is just Ruby
|
236
243
|
------------------
|
237
244
|
|
238
|
-
If for some reason you don't want to use the `uspec` command, you can `require 'uspec'` and `extend Uspec::DSL`.
|
245
|
+
If for some reason you don't want to use the `uspec` command, you can `require 'uspec'` and `extend Uspec::DSL`.
|
239
246
|
From there you can just run the file with ruby: `ruby my_test_spec.rb`
|
240
247
|
|
241
248
|
Contributing
|
@@ -250,4 +257,4 @@ Contributing
|
|
250
257
|
Author
|
251
258
|
------
|
252
259
|
|
253
|
-
> Anthony M. Cook 2013-
|
260
|
+
> Anthony M. Cook 2013-2020
|
data/bin/uspec
CHANGED
data/lib/uspec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative 'uspec/version'
|
2
|
-
require_relative 'uspec/formatter'
|
3
2
|
require_relative 'uspec/dsl'
|
4
3
|
require_relative 'uspec/stats'
|
5
4
|
|
@@ -9,9 +8,10 @@ module Uspec
|
|
9
8
|
exit 2
|
10
9
|
end
|
11
10
|
|
11
|
+
# this method used to be how we injected the spec method
|
12
12
|
def self.extended object
|
13
|
-
object.
|
13
|
+
#unless object.respond_to? :spec
|
14
|
+
# object.extend Uspec::DSL
|
15
|
+
#end
|
14
16
|
end
|
15
17
|
end
|
16
|
-
|
17
|
-
at_exit { exit Uspec::Stats.exit_code }
|
data/lib/uspec/cli.rb
CHANGED
@@ -2,29 +2,34 @@ require 'pathname'
|
|
2
2
|
require_relative '../uspec'
|
3
3
|
|
4
4
|
class Uspec::CLI
|
5
|
-
|
6
|
-
|
7
|
-
warn "uspec - minimalistic ruby testing framework"
|
8
|
-
warn "usage: #{File.basename $0} [<file_or_path>...]"
|
9
|
-
end
|
5
|
+
def initialize args
|
6
|
+
usage unless (args & %w[-h --help -? /? -v --version]).empty?
|
10
7
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
@paths = args
|
9
|
+
@pwd = Pathname.pwd.freeze
|
10
|
+
@stats = Uspec::Stats.new
|
11
|
+
@dsl = Uspec::DSL.new self
|
12
|
+
end
|
13
|
+
attr :stats, :dsl
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
usage
|
21
|
-
end
|
22
|
-
end
|
15
|
+
def usage
|
16
|
+
warn "uspec v#{::Uspec::VERSION} - minimalistic ruby testing framework"
|
17
|
+
warn "usage: #{File.basename $0} [<file_or_path>...]"
|
18
|
+
exit 1
|
23
19
|
end
|
24
20
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
21
|
+
def run_specs
|
22
|
+
run_paths
|
23
|
+
end
|
24
|
+
|
25
|
+
def invoke
|
26
|
+
run_specs
|
27
|
+
puts @stats.summary
|
28
|
+
exit exit_code
|
29
|
+
end
|
30
|
+
|
31
|
+
def exit_code
|
32
|
+
[@stats.failure.size, 255].min
|
28
33
|
end
|
29
34
|
|
30
35
|
def paths
|
@@ -44,21 +49,37 @@ class Uspec::CLI
|
|
44
49
|
end
|
45
50
|
|
46
51
|
def run path
|
52
|
+
spec = nil
|
47
53
|
if path.directory? then
|
48
54
|
Pathname.glob(path.join('**', '**_spec.rb')).each do |spec|
|
49
55
|
run spec
|
50
56
|
end
|
51
57
|
elsif path.exist? then
|
52
58
|
puts "#{path.basename path.extname}:"
|
53
|
-
|
59
|
+
dsl.instance_eval(path.read, path.to_s)
|
54
60
|
else
|
55
61
|
warn "path not found: #{path}"
|
56
62
|
end
|
57
|
-
rescue
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
rescue Exception => error
|
64
|
+
|
65
|
+
error_file, error_line, _ = error.backtrace.first.split ?:
|
66
|
+
|
67
|
+
message = <<-MSG
|
68
|
+
#{error.class} : #{error.message}
|
69
|
+
|
70
|
+
Uspec encountered an error when loading a test file.
|
71
|
+
This is probably a typo in the test file or the file it is testing.
|
72
|
+
|
73
|
+
If you think this is a bug in Uspec please report it: https://github.com/acook/uspec/issues/new
|
74
|
+
|
75
|
+
Error occured when loading test file `#{spec || path}`.
|
76
|
+
The origin of the error may be in file `#{error_file}` on line ##{error_line}.
|
77
|
+
|
78
|
+
\t#{error.backtrace[0,3].join "\n\t"}
|
79
|
+
MSG
|
80
|
+
puts
|
81
|
+
warn message
|
82
|
+
self.class.stats.failure << Uspec::Result.new(message, error, caller)
|
62
83
|
end
|
63
84
|
|
64
85
|
end
|
data/lib/uspec/dsl.rb
CHANGED
@@ -1,20 +1,55 @@
|
|
1
|
+
require_relative "result"
|
2
|
+
|
1
3
|
module Uspec
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
class DSL
|
5
|
+
def initialize cli
|
6
|
+
@__uspec_cli = cli
|
7
|
+
end
|
8
|
+
|
9
|
+
def __uspec_cli
|
10
|
+
@__uspec_cli
|
11
|
+
end
|
12
|
+
|
13
|
+
def __uspec_stats
|
14
|
+
@__uspec_cli.stats
|
15
|
+
end
|
6
16
|
|
17
|
+
def spec description
|
7
18
|
print ' -- ', description
|
8
19
|
|
9
|
-
|
20
|
+
if block_given? then
|
21
|
+
begin
|
22
|
+
raw_result = yield
|
23
|
+
rescue Exception => raw_result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
result = Result.new description, raw_result, caller
|
10
28
|
|
11
|
-
|
12
|
-
result
|
13
|
-
rescue => result
|
29
|
+
unless block_given? then
|
30
|
+
result.pending!
|
14
31
|
end
|
15
32
|
|
16
|
-
|
17
|
-
|
33
|
+
if result.success?
|
34
|
+
__uspec_stats.success << result
|
35
|
+
elsif result.pending?
|
36
|
+
stats.pending << result
|
37
|
+
else
|
38
|
+
__uspec_stats.failure << result
|
39
|
+
end
|
40
|
+
|
41
|
+
print ': ', result.pretty, "\n"
|
42
|
+
rescue => error
|
43
|
+
message = <<-MSG
|
44
|
+
#{error.class} : #{error.message}
|
45
|
+
|
46
|
+
Uspec encountered an internal error, please report this bug: https://github.com/acook/uspec/issues/new
|
47
|
+
|
48
|
+
\t#{error.backtrace.join "\n\t"}
|
49
|
+
MSG
|
50
|
+
puts
|
51
|
+
warn message
|
52
|
+
__uspec_stats.failure << Uspec::Result.new(message, error, caller)
|
18
53
|
end
|
19
54
|
end
|
20
55
|
end
|
data/lib/uspec/result.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
require_relative "terminal"
|
2
|
+
require "toisb"
|
3
|
+
|
4
|
+
module Uspec
|
5
|
+
class Result
|
6
|
+
include Terminal
|
7
|
+
|
8
|
+
def initialize spec, raw, source
|
9
|
+
@spec = spec
|
10
|
+
@raw = raw
|
11
|
+
@source = source
|
12
|
+
@handler = ::TOISB.wrap raw
|
13
|
+
end
|
14
|
+
attr_reader :spec, :raw, :source, :handler
|
15
|
+
|
16
|
+
def pretty
|
17
|
+
if raw == true then
|
18
|
+
green raw
|
19
|
+
elsif raw == false then
|
20
|
+
red raw
|
21
|
+
elsif pending? then
|
22
|
+
yellow 'pending'
|
23
|
+
elsif Exception === raw then
|
24
|
+
[
|
25
|
+
red('Exception'), vspace,
|
26
|
+
hspace, 'Spec encountered an Exception ', newline,
|
27
|
+
hspace, 'in spec at ', source.first, vspace,
|
28
|
+
hspace, message, vspace,
|
29
|
+
white(trace)
|
30
|
+
].join
|
31
|
+
else
|
32
|
+
[
|
33
|
+
red('Failed'), vspace,
|
34
|
+
hspace, 'Spec did not return a boolean value ', newline,
|
35
|
+
hspace, 'in spec at ', source.first, vspace,
|
36
|
+
hspace, red(subklassinfo), inspector, newline
|
37
|
+
].join
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def trace
|
42
|
+
raw.backtrace.inject(String.new) do |text, line|
|
43
|
+
text << "#{hspace}#{line}#{newline}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def message
|
48
|
+
"#{red subklassinfo}#{raw.message}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def subklassinfo
|
52
|
+
"#{handler.subklassinfo}: "
|
53
|
+
end
|
54
|
+
|
55
|
+
# Attempts to inspect an object
|
56
|
+
def inspector
|
57
|
+
if String === raw && raw.include?(?\n) then
|
58
|
+
# if object is a multiline string, display it unescaped
|
59
|
+
[
|
60
|
+
vspace,
|
61
|
+
hspace, yellow('"""'), newline,
|
62
|
+
raw, normal, newline,
|
63
|
+
hspace, yellow('"""')
|
64
|
+
].join
|
65
|
+
else
|
66
|
+
handler.inspector!
|
67
|
+
end
|
68
|
+
rescue Exception => error
|
69
|
+
return handler.simple_inspector if error.message.include? handler.get_id
|
70
|
+
|
71
|
+
error_file, error_line, _ = error.backtrace[4].split ?:
|
72
|
+
|
73
|
+
<<-MSG
|
74
|
+
|
75
|
+
#{error.class} : #{error.message}
|
76
|
+
|
77
|
+
Uspec detected a bug in your source code!
|
78
|
+
Calling #inspect on an object will recusively call #inspect on its instance variables and contents.
|
79
|
+
If one of those contained objects does not have an #inspect method you will see this message.
|
80
|
+
You will also get this message if your #inspect method or one of its callees raises an exception.
|
81
|
+
This is most likely to happen with BasicObject and its subclasses.
|
82
|
+
|
83
|
+
If you think this is a bug in Uspec please report it: https://github.com/acook/uspec/issues/new
|
84
|
+
|
85
|
+
Error may have occured in test `#{spec}` in file `#{error_file}` on line ##{error_line}.
|
86
|
+
|
87
|
+
\t#{error.backtrace.join "\n\t"}
|
88
|
+
MSG
|
89
|
+
end
|
90
|
+
|
91
|
+
def success?
|
92
|
+
raw == true
|
93
|
+
end
|
94
|
+
|
95
|
+
def failure?
|
96
|
+
raw != true && !@pending
|
97
|
+
end
|
98
|
+
|
99
|
+
def pending?
|
100
|
+
!!@pending
|
101
|
+
end
|
102
|
+
|
103
|
+
def pending!
|
104
|
+
@pending = true
|
105
|
+
end
|
106
|
+
|
107
|
+
def inspect
|
108
|
+
"#{self.class} for `#{spec}` -> #{pretty}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/lib/uspec/stats.rb
CHANGED
@@ -1,23 +1,36 @@
|
|
1
1
|
module Uspec
|
2
2
|
class Stats
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
def initialize
|
4
|
+
clear_results!
|
5
|
+
end
|
6
|
+
attr :success, :failure, :pending
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
def clear_results!
|
9
|
+
@success = Array.new
|
10
|
+
@failure = Array.new
|
11
|
+
@pending = Array.new
|
12
|
+
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
def inspect
|
15
|
+
<<-INFO
|
16
|
+
#{super} Failures: #{exit_code}
|
17
|
+
#{results.map{|r| r.inspect}.join "\n\t" }
|
18
|
+
INFO
|
19
|
+
end
|
20
|
+
|
21
|
+
def results
|
22
|
+
@success + @failure + @pending
|
23
|
+
end
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
25
|
+
def summary
|
26
|
+
[
|
27
|
+
"test summary: ",
|
28
|
+
Uspec::Terminal.green("#{@success.size} successful"),
|
29
|
+
", ",
|
30
|
+
Uspec::Terminal.red("#{@failure.size} failed"),
|
31
|
+
", ",
|
32
|
+
Uspec::Terminal.yellow("#{@pending.size} pending")
|
33
|
+
].join
|
21
34
|
end
|
22
35
|
end
|
23
36
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Uspec
|
2
|
+
module Terminal
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def colors
|
6
|
+
{
|
7
|
+
red: 1,
|
8
|
+
green: 2,
|
9
|
+
yellow: 3,
|
10
|
+
white: 7
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def color hue, text = nil
|
15
|
+
"#{esc "3#{colors[hue]};1"}#{text}#{normal unless text.nil?}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def esc seq
|
19
|
+
"\e[#{seq}m"
|
20
|
+
end
|
21
|
+
|
22
|
+
def normal text=nil
|
23
|
+
"#{esc 0}#{text}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def hspace
|
27
|
+
' '
|
28
|
+
end
|
29
|
+
|
30
|
+
def vspace
|
31
|
+
"#{newline}#{newline}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def newline
|
35
|
+
$/
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing name, *args, &block
|
39
|
+
if colors.keys.include? name then
|
40
|
+
color name, *args
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/uspec/version.rb
CHANGED
data/uspec.gemspec
CHANGED
@@ -1,19 +1,29 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "uspec/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "uspec"
|
8
8
|
gem.version = Uspec::VERSION
|
9
|
-
gem.authors = ["Anthony Cook"]
|
10
|
-
gem.email = ["
|
9
|
+
gem.authors = ["Anthony M. Cook"]
|
10
|
+
gem.email = ["github@anthonymcook.com"]
|
11
11
|
gem.description = %q{Uspec is a shiny little spec framework for your apps! Unlike other testing frameworks there's no need for matchers, there can only be one assertion per test, and you never have to worry that your tests lack assertions.}
|
12
12
|
gem.summary = %q{a shiny little spec framework for your apps!}
|
13
13
|
gem.homepage = "http://github.com/acook/uspec#readme"
|
14
|
+
gem.license = "MIT"
|
14
15
|
|
15
16
|
gem.files = `git ls-files`.split($/)
|
16
17
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
18
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
19
|
gem.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# due to require_relative semantics in 1.9.x and issues with BasicObject support in 2.0
|
22
|
+
# technically should still work in 2.0 but some of the test suite won't pass
|
23
|
+
gem.required_ruby_version = ">= 2.1"
|
24
|
+
|
25
|
+
gem.add_dependency "that_object_is_so_basic", "~> 0.0.5"
|
26
|
+
|
27
|
+
gem.add_development_dependency "pry"
|
28
|
+
gem.add_development_dependency "pry-doc"
|
19
29
|
end
|
data/uspec/cli_spec.rb
CHANGED
@@ -12,25 +12,25 @@ end
|
|
12
12
|
spec 'runs a path of specs' do
|
13
13
|
output = capture do
|
14
14
|
path = Pathname.new(__FILE__).parent.parent.join('example_specs').to_s
|
15
|
-
Uspec::CLI.
|
15
|
+
Uspec::CLI.new(Array(path)).run_specs
|
16
16
|
end
|
17
17
|
|
18
|
-
output.include?
|
18
|
+
output.include?('I love passing tests') || output
|
19
19
|
end
|
20
20
|
|
21
21
|
spec 'runs an individual spec' do
|
22
22
|
output = capture do
|
23
23
|
path = Pathname.new(__FILE__).parent.parent.join('example_specs', 'example_spec.rb').to_s
|
24
|
-
Uspec::CLI.
|
24
|
+
Uspec::CLI.new(Array(path)).run_specs
|
25
25
|
end
|
26
26
|
|
27
|
-
output.include?
|
27
|
+
output.include?('I love passing tests') || output
|
28
28
|
end
|
29
29
|
|
30
|
-
spec '
|
30
|
+
spec 'broken requires in test files count as test failures' do
|
31
31
|
path = Pathname.new(__FILE__).parent.join('test_specs', 'broken_require_spec')
|
32
32
|
|
33
|
-
capture do
|
33
|
+
output = capture do
|
34
34
|
exec "bin/uspec #{path}"
|
35
35
|
end
|
36
36
|
|
@@ -44,5 +44,5 @@ spec 'displays information about test file with broken require' do
|
|
44
44
|
exec "bin/uspec #{path}"
|
45
45
|
end
|
46
46
|
|
47
|
-
output.include?
|
48
|
-
end
|
47
|
+
output.include?('cannot load such file') || output
|
48
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative "uspec_helper"
|
2
|
+
|
3
|
+
bo = BasicObject.new
|
4
|
+
|
5
|
+
spec "#pretty doesn't die when given a BasicObject" do
|
6
|
+
result = Uspec::Result.new "BasicObject Result", bo, []
|
7
|
+
expected = "#<BasicObject:"
|
8
|
+
actual = result.pretty
|
9
|
+
actual.include?(expected) || actual
|
10
|
+
end
|
11
|
+
|
12
|
+
# If we don't prefix the classname with "::", Ruby defines it under an anonymous class
|
13
|
+
class ::TestObject < BasicObject; end
|
14
|
+
obj = TestObject.new
|
15
|
+
|
16
|
+
spec "ensure BasicObject subclasses work" do
|
17
|
+
result = Uspec::Result.new "BasicObject Subclass Result", obj, []
|
18
|
+
expected = "#<BasicObject/TestObject:"
|
19
|
+
actual = result.pretty
|
20
|
+
actual.include?(expected) || result.pretty
|
21
|
+
end
|
22
|
+
|
23
|
+
spec "display basic info about Object" do
|
24
|
+
result = Uspec::Result.new "Object Result", Object.new, []
|
25
|
+
expected = "Object < BasicObject"
|
26
|
+
actual = result.pretty
|
27
|
+
actual.include?(expected) || result.pretty
|
28
|
+
end
|
29
|
+
|
30
|
+
spec "display basic info about Array" do
|
31
|
+
result = Uspec::Result.new "Array Result", [], []
|
32
|
+
expected = "Array < Object"
|
33
|
+
actual = result.pretty
|
34
|
+
actual.include?(expected) || result.pretty
|
35
|
+
end
|
36
|
+
|
37
|
+
spec "display basic info about Array class" do
|
38
|
+
result = Uspec::Result.new "Array Class Result", Array, []
|
39
|
+
#expected = "Class < ???" # TODO: Make classes display nicer in TOISB
|
40
|
+
expected = "#<Class:Object> < #<Class:BasicObject>: \e[0mArray"
|
41
|
+
actual = result.pretty
|
42
|
+
actual.include?(expected) || result.pretty
|
43
|
+
end
|
44
|
+
|
45
|
+
parent = [obj]
|
46
|
+
|
47
|
+
spec "ensure parent object of BasicObject subclasses get a useful error message" do
|
48
|
+
result = Uspec::Result.new "BasicObject Parent Result", parent, []
|
49
|
+
expected = "BasicObject and its subclasses"
|
50
|
+
actual = result.pretty
|
51
|
+
actual.include?(expected) || result.inspector
|
52
|
+
end
|
53
|
+
|
54
|
+
class ::InspectFail; def inspect; raise RuntimeError, "This error is intentional and part of the test."; end; end
|
55
|
+
inspect_fail = InspectFail.new
|
56
|
+
|
57
|
+
spec "display a useful error message when a user-defined inspect method fails" do
|
58
|
+
result = Uspec::Result.new "Inspect Fail Result", inspect_fail, []
|
59
|
+
expected = "raises an exception"
|
60
|
+
actual = result.pretty
|
61
|
+
actual.include?(expected) || result.inspector
|
62
|
+
end
|
63
|
+
|
64
|
+
spec "display strings more like their actual contents" do
|
65
|
+
expected = "this string:\nshould display \e[42;2mproperly"
|
66
|
+
result = Uspec::Result.new "Inspect Fail Result", expected, []
|
67
|
+
actual = result.pretty
|
68
|
+
actual.include?(expected) || result.inspector
|
69
|
+
end
|
70
|
+
|
data/uspec/uspec_spec.rb
CHANGED
@@ -10,6 +10,16 @@ spec 'catches errors' do
|
|
10
10
|
output.include? 'Exception'
|
11
11
|
end
|
12
12
|
|
13
|
+
spec 'catches even non-StandardError-subclass exceptions' do
|
14
|
+
output = capture do
|
15
|
+
spec 'not implemented error' do
|
16
|
+
raise ::NotImplementedError, 'test exception'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
output.include? 'Exception'
|
21
|
+
end
|
22
|
+
|
13
23
|
spec 'complains when spec block returns non boolean' do
|
14
24
|
output = capture do
|
15
25
|
spec 'whatever' do
|
@@ -17,7 +27,7 @@ spec 'complains when spec block returns non boolean' do
|
|
17
27
|
end
|
18
28
|
end
|
19
29
|
|
20
|
-
output.include? '
|
30
|
+
output.include? 'Failed'
|
21
31
|
end
|
22
32
|
|
23
33
|
spec 'marks test as pending when no block supplied' do
|
@@ -33,24 +43,34 @@ spec 'should not define DSL methods on arbitrary objects' do
|
|
33
43
|
end
|
34
44
|
|
35
45
|
spec 'exit code is the number of failures' do
|
36
|
-
|
37
|
-
|
38
|
-
|
46
|
+
expected = 50
|
47
|
+
output = capture do
|
48
|
+
__uspec_stats.clear_results! # because we're forking, we will have a copy of the current results
|
49
|
+
|
50
|
+
expected.times do |count|
|
51
|
+
spec "fail ##{count + 1}" do
|
39
52
|
false
|
40
53
|
end
|
41
54
|
end
|
55
|
+
|
56
|
+
exit __uspec_cli.exit_code
|
42
57
|
end
|
58
|
+
actual = $?.exitstatus
|
43
59
|
|
44
|
-
|
60
|
+
actual == expected || puts("", output) || $?
|
45
61
|
end
|
46
62
|
|
47
63
|
spec 'if more than 255 failures, exit status is 255' do
|
48
64
|
capture do
|
65
|
+
__uspec_stats.clear_results! # because we're forking, we will have a copy of the current results
|
66
|
+
|
49
67
|
500.times do
|
50
68
|
spec 'fail' do
|
51
69
|
false
|
52
70
|
end
|
53
71
|
end
|
72
|
+
|
73
|
+
exit __uspec_cli.exit_code
|
54
74
|
end
|
55
75
|
|
56
76
|
$?.exitstatus == 255 || $?
|
metadata
CHANGED
@@ -1,29 +1,73 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Anthony Cook
|
7
|
+
- Anthony M. Cook
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2021-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: that_object_is_so_basic
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry-doc
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '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'
|
13
55
|
description: Uspec is a shiny little spec framework for your apps! Unlike other testing
|
14
56
|
frameworks there's no need for matchers, there can only be one assertion per test,
|
15
57
|
and you never have to worry that your tests lack assertions.
|
16
58
|
email:
|
17
|
-
-
|
59
|
+
- github@anthonymcook.com
|
18
60
|
executables:
|
19
61
|
- uspec
|
20
62
|
extensions: []
|
21
63
|
extra_rdoc_files: []
|
22
64
|
files:
|
65
|
+
- ".circleci/config.yml"
|
66
|
+
- ".editorconfig"
|
23
67
|
- ".gitignore"
|
68
|
+
- ".rubocop.yml"
|
24
69
|
- ".ruby-gemset"
|
25
70
|
- ".ruby-version"
|
26
|
-
- ".travis.yml"
|
27
71
|
- Gemfile
|
28
72
|
- LICENSE.txt
|
29
73
|
- README.markdown
|
@@ -34,16 +78,19 @@ files:
|
|
34
78
|
- lib/uspec.rb
|
35
79
|
- lib/uspec/cli.rb
|
36
80
|
- lib/uspec/dsl.rb
|
37
|
-
- lib/uspec/
|
81
|
+
- lib/uspec/result.rb
|
38
82
|
- lib/uspec/stats.rb
|
83
|
+
- lib/uspec/terminal.rb
|
39
84
|
- lib/uspec/version.rb
|
40
85
|
- uspec.gemspec
|
41
86
|
- uspec/cli_spec.rb
|
87
|
+
- uspec/result_spec.rb
|
42
88
|
- uspec/test_specs/broken_require_spec
|
43
89
|
- uspec/uspec_helper.rb
|
44
90
|
- uspec/uspec_spec.rb
|
45
91
|
homepage: http://github.com/acook/uspec#readme
|
46
|
-
licenses:
|
92
|
+
licenses:
|
93
|
+
- MIT
|
47
94
|
metadata: {}
|
48
95
|
post_install_message:
|
49
96
|
rdoc_options: []
|
@@ -53,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
100
|
requirements:
|
54
101
|
- - ">="
|
55
102
|
- !ruby/object:Gem::Version
|
56
|
-
version: '
|
103
|
+
version: '2.1'
|
57
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
105
|
requirements:
|
59
106
|
- - ">="
|
data/.travis.yml
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
|
3
|
-
rvm:
|
4
|
-
- 2.2.3
|
5
|
-
- 2.0.0
|
6
|
-
- 1.9.3
|
7
|
-
- 1.9.2
|
8
|
-
|
9
|
-
- jruby-19mode
|
10
|
-
- ruby-head
|
11
|
-
|
12
|
-
before_install:
|
13
|
-
- gem update bundler
|
14
|
-
before_script:
|
15
|
-
- bundle exec gem list
|
16
|
-
script: bundle exec uspec
|
17
|
-
|
18
|
-
matrix:
|
19
|
-
allow_failures:
|
20
|
-
- rvm: ruby-head
|
21
|
-
- rvm: jruby-19mode
|
22
|
-
|
23
|
-
sudo: false
|
data/lib/uspec/formatter.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
module Uspec
|
2
|
-
class Formatter
|
3
|
-
def colors
|
4
|
-
{
|
5
|
-
red: 1,
|
6
|
-
green: 2,
|
7
|
-
yellow: 3,
|
8
|
-
white: 7
|
9
|
-
}
|
10
|
-
end
|
11
|
-
|
12
|
-
def color hue, text = nil
|
13
|
-
esc("3#{colors[hue]};1") + "#{text}#{normal}"
|
14
|
-
end
|
15
|
-
|
16
|
-
def esc seq
|
17
|
-
"\e[#{seq}m"
|
18
|
-
end
|
19
|
-
|
20
|
-
def normal text=nil
|
21
|
-
esc(0) + text.to_s
|
22
|
-
end
|
23
|
-
|
24
|
-
def colorize result, source
|
25
|
-
if result == true then
|
26
|
-
green result
|
27
|
-
elsif result == false then
|
28
|
-
red result
|
29
|
-
elsif result.is_a? Exception then
|
30
|
-
[
|
31
|
-
red('Exception'), vspace,
|
32
|
-
hspace, 'Spec encountered an Exception ', newline,
|
33
|
-
hspace, 'in spec at ', source.first, vspace,
|
34
|
-
hspace, message(result), vspace,
|
35
|
-
white(trace result)
|
36
|
-
].join
|
37
|
-
else
|
38
|
-
[
|
39
|
-
red('Unknown Result'), vspace,
|
40
|
-
hspace, 'Spec did not return a boolean value ', newline,
|
41
|
-
hspace, 'in spec at ', source.first, vspace,
|
42
|
-
hspace, red(classinfo(result)), result.inspect, newline
|
43
|
-
].join
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def trace error
|
48
|
-
error.backtrace.inject(String.new) do |text, line|
|
49
|
-
text << hspace + line + newline
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def message error
|
54
|
-
red(classinfo error) + error.message
|
55
|
-
end
|
56
|
-
|
57
|
-
def classinfo object
|
58
|
-
"#{classify object} < #{superclass object}: "
|
59
|
-
end
|
60
|
-
|
61
|
-
def classify object
|
62
|
-
object.is_a?(Module) ? object : object.class
|
63
|
-
end
|
64
|
-
|
65
|
-
def superclass object
|
66
|
-
classify(object).superclass
|
67
|
-
end
|
68
|
-
|
69
|
-
def hspace
|
70
|
-
' '
|
71
|
-
end
|
72
|
-
|
73
|
-
def vspace
|
74
|
-
newline + newline
|
75
|
-
end
|
76
|
-
|
77
|
-
def newline
|
78
|
-
$/
|
79
|
-
end
|
80
|
-
|
81
|
-
def method_missing name, *args, &block
|
82
|
-
if colors.keys.include? name then
|
83
|
-
color name, *args
|
84
|
-
else
|
85
|
-
super
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|