uspec 1.1.2 → 1.2.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: 659b5228eb82a76f457af1da9a275cfdcc5914f03d40083fdca08f79c8b1fac6
4
- data.tar.gz: d89c4ee71c95dc202adf14110a140f9f4d667698f0e8b443a884226b6881e57d
3
+ metadata.gz: b9c8a47af991d099f6804066c5ef9e2d8ac0c4cca8023a919354bc247ee3d901
4
+ data.tar.gz: 14e4c49e40bf1a2cf19553b41c27107c7d13f110978dad55d951242a2e86fcc6
5
5
  SHA512:
6
- metadata.gz: 021b318bd832f4c5f290db67bca30a05e8e545fcc9b633506ab63ce2dc55cf53389885bc42d956e007f76d44245817aaa915f35f940b514eca43cbde32cc0c2a
7
- data.tar.gz: 44f6373981caa474dbb6df5f48f9fcf38c9fc3d59f680e6198940f758c098f4157ce30dc6ad13294cb3bca99c7f659ca60395d5760b11830905144368ef5a8b0
6
+ metadata.gz: b1781f78237157872c0ad40f5c009a4dbed94b78049973feb164f49ea3c042dbcc022ec80d423ee5d69a0d0ca3f0d48dfe4e81a227848500a3af1466c15e015e
7
+ data.tar.gz: 3ecaada229d7bc0ee4a0c3d473654c5544863c11dd390cde47e8e08d25205a5bfe8175de8b96a1a4f93aa9b499b119d702bc8f4723a1aa371b5b134e1af7d371
data/Gemfile CHANGED
@@ -2,3 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in uspec.gemspec
4
4
  gemspec
5
+
6
+ unless ENV['CI'] then
7
+ gem 'pry'
8
+ gem 'pry-doc'
9
+ gem 'pry-theme'
10
+ gem 'pry-coolline'
11
+ end
data/lib/uspec/cli.rb CHANGED
@@ -24,14 +24,32 @@ class Uspec::CLI
24
24
 
25
25
  def invoke
26
26
  run_specs
27
- puts @stats.summary
28
- exit exit_code
27
+ die!
29
28
  end
30
29
 
31
30
  def exit_code
32
31
  [@stats.failure.size, 255].min
33
32
  end
34
33
 
34
+ def handle_interrupt! type = Interrupt
35
+ if SignalException === type || SystemExit === type then
36
+ if type === Module then
37
+ err = type
38
+ msg = "signal"
39
+ else
40
+ err = type.class
41
+ msg = type.message
42
+ end
43
+ puts "Uspec received #{err} #{msg} - exiting!"
44
+ die!
45
+ end
46
+ end
47
+
48
+ def die!
49
+ puts @stats.summary
50
+ exit exit_code
51
+ end
52
+
35
53
  def paths
36
54
  if @paths.empty? then
37
55
  ['spec', 'uspec', 'test'].each do |path|
@@ -62,6 +80,10 @@ class Uspec::CLI
62
80
  end
63
81
  rescue Exception => error
64
82
 
83
+ if SignalException === error || SystemExit === error then
84
+ exit 3
85
+ end
86
+
65
87
  error_file, error_line, _ = error.backtrace.first.split ?:
66
88
 
67
89
  message = <<-MSG
@@ -80,6 +102,8 @@ class Uspec::CLI
80
102
  puts
81
103
  warn message
82
104
  stats.failure << Uspec::Result.new(message, error, caller)
105
+
106
+ dsl.__uspec_cli.handle_interrupt! error
83
107
  end
84
108
 
85
109
  end
data/lib/uspec/dsl.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  require_relative "result"
2
+ require_relative "spec"
2
3
 
3
4
  module Uspec
4
5
  class DSL
5
- USPEC_CLI_BLOCK = -> { @__uspec_dsl.__uspec_cli }
6
- USPEC_STAT_BLOCK = -> { @__uspec_dsl.__uspec_cli.stats }
7
- USPEC_SPEC_BLOCK = ->(description, &block) { @__uspec_dsl.spec description, &block }
8
6
 
9
7
  def initialize cli
10
8
  @__uspec_cli = cli
@@ -18,25 +16,6 @@ module Uspec
18
16
  @__uspec_cli.stats
19
17
  end
20
18
 
21
- def __uspec_eval block
22
- o = Object.new
23
- o.define_singleton_method :__uspec_stats, USPEC_STAT_BLOCK
24
- o.define_singleton_method :__uspec_cli, USPEC_CLI_BLOCK
25
- o.instance_variable_set :@__uspec_cli, @__uspec_cli
26
- o.instance_variable_set :@__uspec_dsl, self
27
- o.define_singleton_method :spec, USPEC_SPEC_BLOCK
28
- o.define_singleton_method :spec_block, &block
29
- self.instance_variables.each do |name|
30
- o.instance_variable_set(name, self.instance_variable_get(name)) unless name.to_s.include? '@__uspec'
31
- end
32
- self.methods(false).each do |name|
33
- o.define_singleton_method name do |*args, &block|
34
- @__uspec_dsl.send name, *args, &block
35
- end unless name.to_s.include? '__uspec'
36
- end
37
- o.spec_block
38
- end
39
-
40
19
  def spec description, &block
41
20
  state = 0
42
21
  print ' -- ', description
@@ -44,7 +23,7 @@ module Uspec
44
23
  if block then
45
24
  begin
46
25
  state = 1
47
- raw_result = __uspec_eval block
26
+ raw_result = ::Uspec::Spec.new(self, description, &block).__uspec_block
48
27
  state = 2
49
28
  rescue Exception => raw_result
50
29
  state = 3
@@ -80,6 +59,7 @@ module Uspec
80
59
  warn message
81
60
  __uspec_stats.failure << Uspec::Result.new(message, error, caller)
82
61
  ensure
62
+ __uspec_cli.handle_interrupt! result.raw
83
63
  return [state, error, result, raw_result]
84
64
  end
85
65
  end
data/lib/uspec/spec.rb ADDED
@@ -0,0 +1,33 @@
1
+ require_relative "result"
2
+
3
+ module Uspec
4
+ class Spec
5
+
6
+ def initialize dsl, description, &block
7
+ @__uspec_description = description
8
+ @__uspec_dsl = dsl
9
+
10
+ dsl.instance_variables.each do |name|
11
+ self.instance_variable_set(name, @__uspec_dsl.instance_variable_get(name)) unless name.to_s.include? '@__uspec'
12
+ end
13
+
14
+ dsl.methods(false).each do |name|
15
+ self.define_singleton_method name do |*args, &block|
16
+ @__uspec_dsl.send name, *args, &block
17
+ end unless name.to_s.include? '__uspec'
18
+ end
19
+
20
+ if block then
21
+ self.define_singleton_method :__uspec_block, &block
22
+ else
23
+ self.define_singleton_method :__uspec_block do
24
+ raise "Uspec: No block provided for `#{@__uspec_description}`"
25
+ end
26
+ end
27
+ end
28
+
29
+ def spec description, &block
30
+ @__uspec_dsl.spec description, &block
31
+ end
32
+ end
33
+ end
data/lib/uspec/stats.rb CHANGED
@@ -11,13 +11,6 @@ module Uspec
11
11
  @pending = Array.new
12
12
  end
13
13
 
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
14
  def results
22
15
  @success + @failure + @pending
23
16
  end
data/lib/uspec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Uspec
2
- VERSION = '1.1.2'
2
+ VERSION = '1.2.0'
3
3
  end
data/uspec/cli_spec.rb CHANGED
@@ -8,8 +8,6 @@ spec 'shows usage' do
8
8
  output.include? 'usage'
9
9
  end
10
10
 
11
- spec 'pending test doesn\'t crash'
12
-
13
11
  spec 'runs a path of specs' do
14
12
  output = capture do
15
13
  path = Pathname.new(__FILE__).parent.parent.join('example_specs').to_s
@@ -47,3 +45,37 @@ spec 'displays information about test file with broken require' do
47
45
 
48
46
  output.include?('cannot load such file') || output
49
47
  end
48
+
49
+ spec 'exit code is the number of failures' do
50
+ expected = 50
51
+ output = capture do
52
+ @__uspec_dsl.__uspec_stats.clear_results! # because we're forking, we will have a copy of the current results
53
+
54
+ expected.times do |count|
55
+ spec "fail ##{count + 1}" do
56
+ false
57
+ end
58
+ end
59
+
60
+ exit @__uspec_dsl.__uspec_cli.exit_code
61
+ end
62
+ actual = $?.exitstatus
63
+
64
+ actual == expected || output
65
+ end
66
+
67
+ spec 'when more than 255 failures, exit status is 255' do
68
+ output = capture do
69
+ @__uspec_dsl.__uspec_stats.clear_results! # because we're forking, we will have a copy of the current results
70
+
71
+ 500.times do
72
+ spec 'fail' do
73
+ false
74
+ end
75
+ end
76
+
77
+ exit @__uspec_dsl.__uspec_cli.exit_code
78
+ end
79
+
80
+ $?.exitstatus == 255 || [$?, output]
81
+ end
data/uspec/dsl_spec.rb CHANGED
@@ -1,5 +1,88 @@
1
1
  require_relative "uspec_helper"
2
2
 
3
+ spec 'catches errors' do
4
+ output = capture do
5
+ spec 'exception' do
6
+ raise 'test exception'
7
+ end
8
+ end
9
+
10
+ output.include?('Exception') || output
11
+ end
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') || output
21
+ end
22
+
23
+ spec 'Uspec exits when sent a termination signal' do
24
+ path = Pathname.new(__FILE__).parent.join('test_specs', 'kill_this_spec')
25
+
26
+ stdin, allout, thread = Open3.popen2e "uspec/test_specs/kill_this_script.sh \"#{path}\""
27
+ stdin.close
28
+ output = allout.read
29
+
30
+ begin
31
+ Process.waitpid(thread.pid)
32
+ rescue Errno::ECHILD
33
+ nil
34
+ end
35
+
36
+ summary_match = output.match(/0.*successful.*,.*1.*failed.*,.*0.*pending/)
37
+ no_copy_match = output.match(/2.{0,5}pending/) # previous versions continued after "exiting"
38
+
39
+ (!!summary_match && !no_copy_match) || output
40
+ end
41
+
42
+ spec 'complains when spec block returns non boolean' do
43
+ output = capture do
44
+ spec 'whatever' do
45
+ "string"
46
+ end
47
+ end
48
+
49
+ output.include?('Failed') || output
50
+ end
51
+
52
+ spec 'marks test as pending when no block supplied' do
53
+ path = Pathname.new(__FILE__).parent.join('test_specs', 'pending_spec')
54
+
55
+ output = capture do
56
+ exec "bin/uspec #{path}"
57
+ end
58
+
59
+ output.include?('1 pending') || output
60
+ end
61
+
62
+ spec 'should not define DSL methods on arbitrary objects' do
63
+ !(Array.respond_to? :spec)
64
+ end
65
+
66
+ spec 'when return used in spec, capture it as an error' do
67
+ path = Pathname.new(__FILE__).parent.join('test_specs', 'return_spec')
68
+
69
+ output = capture do
70
+ exec "bin/uspec #{path}"
71
+ end
72
+
73
+ output.include?('Invalid return') || output.include?('Spec did not return a boolean value') || output
74
+ end
75
+
76
+ spec 'when break used in spec, capture it as an error' do
77
+ path = Pathname.new(__FILE__).parent.join('test_specs', 'break_spec')
78
+
79
+ output = capture do
80
+ exec "bin/uspec #{path}"
81
+ end
82
+
83
+ output.include?('Invalid break') || output.include?('Spec did not return a boolean value') || output
84
+ end
85
+
3
86
  spec 'when instance variables are defined in the DSL instance, they are available in the spec body' do
4
87
  path = Pathname.new(__FILE__).parent.join('test_specs', 'ivar_spec')
5
88
 
@@ -0,0 +1,12 @@
1
+ require_relative 'uspec_helper'
2
+
3
+ spec 'stats can be inspected' do
4
+ actual = @__uspec_dsl.__uspec_stats.inspect
5
+ actual.include?("failure") || actual
6
+ end
7
+
8
+ spec 'stats inspect does not have any stray whitespace' do
9
+ output = @__uspec_dsl.__uspec_stats.inspect
10
+ match = output.match(/ |\n/)
11
+ match == nil
12
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env sh
2
+
3
+ command_exists() { command -v "$1" 1>&- 2>&-; }
4
+
5
+ THISDIR="$(realpath "$(dirname "$0")")"
6
+ ROOTDIR="$(realpath "$THISDIR/../..")"
7
+
8
+ path="$1"
9
+ name="$(basename "$path")"
10
+
11
+ if ! [ -f "$path" ]; then
12
+ echo "file not found: $path"
13
+ exit 255
14
+ fi
15
+
16
+ mkdir -v -p tmp
17
+ if command_exists bundle; then
18
+ bundle exec "$ROOTDIR/bin/uspec" "$path" > "tmp/$name.output" 2>&1 &
19
+ else
20
+ "$ROOTDIR/bin/uspec" "$path" > "tmp/$name.output" 2>&1 &
21
+ fi
22
+
23
+ pid=$!
24
+ sleep 1
25
+ kill $pid
26
+ cat "tmp/$name.output"
27
+ rm -v "tmp/$name.output"
@@ -0,0 +1,8 @@
1
+ spec 'nap time, i sure hope no one kills me in my sleep' do
2
+ sleep 10
3
+ true
4
+ end
5
+
6
+ spec 'how did we get here?'
7
+
8
+ spec 'something probably went wrong'
@@ -1,6 +1,3 @@
1
-
2
1
  require_relative "../uspec_helper"
3
2
 
4
3
  spec "why is this broken??"
5
-
6
-
@@ -1,4 +1,9 @@
1
- require 'pry'
1
+ begin
2
+ require 'pry'
3
+ rescue LoadError => err
4
+ nil
5
+ end
6
+ require 'open3'
2
7
 
3
8
  require_relative '../lib/uspec'
4
9
  extend Uspec
data/uspec/uspec_spec.rb CHANGED
@@ -1,77 +1 @@
1
1
  require_relative 'uspec_helper'
2
-
3
- spec 'catches errors' do
4
- output = capture do
5
- spec 'exception' do
6
- raise 'test exception'
7
- end
8
- end
9
-
10
- output.include?('Exception') || output
11
- end
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') || output
21
- end
22
-
23
- spec 'complains when spec block returns non boolean' do
24
- output = capture do
25
- spec 'whatever' do
26
- "string"
27
- end
28
- end
29
-
30
- output.include?('Failed') || output
31
- end
32
-
33
- spec 'marks test as pending when no block supplied' do
34
- output = capture do
35
- spec 'pending test'
36
- end
37
-
38
- output.include?('pending') || output
39
- end
40
-
41
- spec 'should not define DSL methods on arbitrary objects' do
42
- !(Array.respond_to? :spec)
43
- end
44
-
45
- spec 'exit code is the number of failures' do
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
52
- false
53
- end
54
- end
55
-
56
- exit __uspec_cli.exit_code
57
- end
58
- actual = $?.exitstatus
59
-
60
- actual == expected || output
61
- end
62
-
63
- spec 'when more than 255 failures, exit status is 255' do
64
- output = capture do
65
- __uspec_stats.clear_results! # because we're forking, we will have a copy of the current results
66
-
67
- 500.times do
68
- spec 'fail' do
69
- false
70
- end
71
- end
72
-
73
- exit __uspec_cli.exit_code
74
- end
75
-
76
- $?.exitstatus == 255 || [$?, output]
77
- end
data/uspec.gemspec CHANGED
@@ -22,8 +22,5 @@ Gem::Specification.new do |gem|
22
22
  # technically should still work in 2.0 but some of the test suite won't pass
23
23
  gem.required_ruby_version = ">= 2.1"
24
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"
25
+ gem.add_dependency "that_object_is_so_basic", ">= 0.0.5"
29
26
  end
metadata CHANGED
@@ -1,57 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony M. Cook
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-20 00:00:00.000000000 Z
11
+ date: 2024-02-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: that_object_is_so_basic
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.0.5
20
20
  type: :runtime
21
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
22
  version_requirements: !ruby/object:Gem::Requirement
37
23
  requirements:
38
24
  - - ">="
39
25
  - !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'
26
+ version: 0.0.5
55
27
  description: Uspec is a shiny little spec framework for your apps! Unlike other testing
56
28
  frameworks there's no need for matchers, there can only be one assertion per test,
57
29
  and you never have to worry that your tests lack assertions.
@@ -79,17 +51,20 @@ files:
79
51
  - lib/uspec/cli.rb
80
52
  - lib/uspec/dsl.rb
81
53
  - lib/uspec/result.rb
54
+ - lib/uspec/spec.rb
82
55
  - lib/uspec/stats.rb
83
56
  - lib/uspec/terminal.rb
84
57
  - lib/uspec/version.rb
85
58
  - uspec.gemspec
86
59
  - uspec/cli_spec.rb
87
60
  - uspec/dsl_spec.rb
88
- - uspec/jump_spec.rb
89
61
  - uspec/result_spec.rb
62
+ - uspec/stats_spec.rb
90
63
  - uspec/test_specs/break_spec
91
64
  - uspec/test_specs/broken_require_spec
92
65
  - uspec/test_specs/ivar_spec
66
+ - uspec/test_specs/kill_this_script.sh
67
+ - uspec/test_specs/kill_this_spec
93
68
  - uspec/test_specs/method_spec
94
69
  - uspec/test_specs/pending_spec
95
70
  - uspec/test_specs/return_spec
data/uspec/jump_spec.rb DELETED
@@ -1,21 +0,0 @@
1
- require_relative "uspec_helper"
2
-
3
- spec 'when return used in spec, capture it as an error' do
4
- path = Pathname.new(__FILE__).parent.join('test_specs', 'return_spec')
5
-
6
- output = capture do
7
- exec "bin/uspec #{path}"
8
- end
9
-
10
- output.include?('Invalid return') || output.include?('Spec did not return a boolean value') || output
11
- end
12
-
13
- spec 'when break used in spec, capture it as an error' do
14
- path = Pathname.new(__FILE__).parent.join('test_specs', 'break_spec')
15
-
16
- output = capture do
17
- exec "bin/uspec #{path}"
18
- end
19
-
20
- output.include?('Invalid break') || output.include?('Spec did not return a boolean value') || output
21
- end