assert 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/README.md +8 -8
  2. data/lib/assert.rb +9 -62
  3. data/lib/assert/assert_runner.rb +15 -30
  4. data/lib/assert/assertions.rb +105 -41
  5. data/lib/assert/cli.rb +1 -1
  6. data/lib/assert/config.rb +56 -0
  7. data/lib/assert/context.rb +44 -150
  8. data/lib/assert/context/setup_dsl.rb +70 -0
  9. data/lib/assert/context/subject_dsl.rb +39 -0
  10. data/lib/assert/context/suite_dsl.rb +20 -0
  11. data/lib/assert/context/test_dsl.rb +51 -0
  12. data/lib/assert/runner.rb +8 -2
  13. data/lib/assert/suite.rb +33 -12
  14. data/lib/assert/test.rb +11 -8
  15. data/lib/assert/utils.rb +23 -11
  16. data/lib/assert/version.rb +1 -1
  17. data/lib/assert/view.rb +9 -7
  18. data/lib/assert/view/base.rb +26 -4
  19. data/lib/assert/view/default_view.rb +1 -1
  20. data/lib/assert/view/helpers/ansi_styles.rb +1 -1
  21. data/lib/assert/view/helpers/common.rb +16 -6
  22. data/test/helper.rb +1 -94
  23. data/test/support/factory.rb +70 -0
  24. data/test/system/running_tests.rb +55 -28
  25. data/test/unit/assert_tests.rb +6 -33
  26. data/test/unit/assertions/assert_block_tests.rb +3 -3
  27. data/test/unit/assertions/assert_empty_tests.rb +6 -4
  28. data/test/unit/assertions/assert_equal_tests.rb +19 -22
  29. data/test/unit/assertions/assert_file_exists_tests.rb +6 -4
  30. data/test/unit/assertions/assert_includes_tests.rb +8 -4
  31. data/test/unit/assertions/assert_instance_of_tests.rb +8 -6
  32. data/test/unit/assertions/assert_kind_of_tests.rb +8 -5
  33. data/test/unit/assertions/assert_match_tests.rb +8 -4
  34. data/test/unit/assertions/assert_nil_tests.rb +6 -4
  35. data/test/unit/assertions/assert_raises_tests.rb +2 -2
  36. data/test/unit/assertions/assert_respond_to_tests.rb +7 -5
  37. data/test/unit/assertions/assert_same_tests.rb +75 -6
  38. data/test/unit/assertions/assert_true_false_tests.rb +116 -0
  39. data/test/unit/assertions_tests.rb +7 -5
  40. data/test/unit/config_tests.rb +58 -0
  41. data/test/unit/context/{setup_teardown_singleton_tests.rb → setup_dsl_tests.rb} +17 -19
  42. data/test/unit/context/subject_dsl_tests.rb +78 -0
  43. data/test/unit/context/suite_dsl_tests.rb +47 -0
  44. data/test/unit/context/{test_should_singleton_tests.rb → test_dsl_tests.rb} +33 -34
  45. data/test/unit/context_tests.rb +19 -15
  46. data/test/unit/runner_tests.rb +9 -3
  47. data/test/unit/suite_tests.rb +20 -23
  48. data/test/unit/test_tests.rb +22 -14
  49. data/test/unit/utils_tests.rb +15 -21
  50. data/test/unit/view_tests.rb +12 -5
  51. metadata +23 -10
  52. data/test/unit/context/basic_singleton_tests.rb +0 -86
@@ -0,0 +1,51 @@
1
+ require 'assert/macro'
2
+ require 'assert/suite'
3
+ require 'assert/test'
4
+
5
+ module Assert; end
6
+ class Assert::Context
7
+
8
+ module TestDSL
9
+
10
+ def test(desc_or_macro, called_from=nil, first_caller=nil, &block)
11
+ if desc_or_macro.kind_of?(Assert::Macro)
12
+ instance_eval(&desc_or_macro)
13
+ elsif block_given?
14
+ ci = Assert::Suite::ContextInfo.new(self, called_from, first_caller || caller.first)
15
+ test_name = desc_or_macro
16
+
17
+ # create a test from the given code block
18
+ self.suite.tests << Assert::Test.new(test_name, ci, self.suite.config, &block)
19
+ else
20
+ test_eventually(desc_or_macro, called_from, first_caller || caller.first, &block)
21
+ end
22
+ end
23
+
24
+ def test_eventually(desc_or_macro, called_from=nil, first_caller=nil, &block)
25
+ ci = Assert::Suite::ContextInfo.new(self, called_from, first_caller || caller.first)
26
+ test_name = desc_or_macro.kind_of?(Assert::Macro) ? desc_or_macro.name : desc_or_macro
27
+ skip_block = block.nil? ? Proc.new { skip 'TODO' } : Proc.new { skip }
28
+
29
+ # create a test from a proc that just skips
30
+ self.suite.tests << Assert::Test.new(test_name, ci, self.suite.config, &skip_block)
31
+ end
32
+ alias_method :test_skip, :test_eventually
33
+
34
+ def should(desc_or_macro, called_from=nil, first_caller=nil, &block)
35
+ if !desc_or_macro.kind_of?(Assert::Macro)
36
+ desc_or_macro = "should #{desc_or_macro}"
37
+ end
38
+ test(desc_or_macro, called_from, first_caller || caller.first, &block)
39
+ end
40
+
41
+ def should_eventually(desc_or_macro, called_from=nil, first_caller=nil, &block)
42
+ if !desc_or_macro.kind_of?(Assert::Macro)
43
+ desc_or_macro = "should #{desc_or_macro}"
44
+ end
45
+ test_eventually(desc_or_macro, called_from, first_caller || caller.first, &block)
46
+ end
47
+ alias_method :should_skip, :should_eventually
48
+
49
+ end
50
+
51
+ end
data/lib/assert/runner.rb CHANGED
@@ -1,8 +1,14 @@
1
+ require 'assert/suite'
2
+
1
3
  module Assert
2
4
 
3
5
  class Runner
4
6
 
5
- # Runner runs a suite of tests.
7
+ attr_reader :config
8
+
9
+ def initialize(config)
10
+ @config = config
11
+ end
6
12
 
7
13
  def run(suite, view)
8
14
  raise ArgumentError if !suite.kind_of?(Suite)
@@ -27,7 +33,7 @@ module Assert
27
33
  protected
28
34
 
29
35
  def tests_to_run(suite)
30
- srand Assert.config.runner_seed
36
+ srand self.config.runner_seed
31
37
  suite.tests.sort.sort_by { rand suite.tests.size }
32
38
  end
33
39
 
data/lib/assert/suite.rb CHANGED
@@ -3,24 +3,15 @@ require 'assert/test'
3
3
  module Assert
4
4
  class Suite
5
5
 
6
- class ContextInfo
7
- attr_reader :called_from, :klass, :file
8
-
9
- def initialize(klass, called_from=nil, first_caller=nil)
10
- @called_from = called_from || first_caller
11
- @klass = klass
12
- @file = @called_from.gsub(/\:[0-9]+.*$/, '') if @called_from
13
- end
14
- end
15
-
16
6
  TEST_METHOD_REGEX = /^test./
17
7
 
18
8
  # A suite is a set of tests to run. When a test class subclasses
19
9
  # the Context class, that test class is pushed to the suite.
20
10
 
21
- attr_accessor :tests, :test_methods, :start_time, :end_time
11
+ attr_accessor :config, :tests, :test_methods, :start_time, :end_time
22
12
 
23
- def initialize
13
+ def initialize(config)
14
+ @config = config
24
15
  @tests = []
25
16
  @test_methods = []
26
17
  @start_time = 0
@@ -31,6 +22,14 @@ module Assert
31
22
  @end_time - @start_time
32
23
  end
33
24
 
25
+ def test_rate
26
+ get_rate(self.tests.size, self.run_time.to_f)
27
+ end
28
+
29
+ def result_rate
30
+ get_rate(self.results.size, self.run_time.to_f)
31
+ end
32
+
34
33
  alias_method :ordered_tests, :tests
35
34
 
36
35
  def results
@@ -91,6 +90,12 @@ module Assert
91
90
  end
92
91
  alias_method :shutdown, :teardown
93
92
 
93
+ def inspect
94
+ "#<#{self.class}:#{'0x0%x' % (object_id << 1)}"\
95
+ " test_count=#{self.test_count.inspect}"\
96
+ " result_count=#{self.result_count.inspect}>"
97
+ end
98
+
94
99
  protected
95
100
 
96
101
  def setups
@@ -118,6 +123,22 @@ module Assert
118
123
  methods.uniq.delete_if {|method_name| method_name !~ TEST_METHOD_REGEX }
119
124
  end
120
125
 
126
+ private
127
+
128
+ def get_rate(count, time)
129
+ time == 0 ? 0.0 : (count.to_f / time.to_f)
130
+ end
131
+
132
+ class ContextInfo
133
+ attr_reader :called_from, :klass, :file
134
+
135
+ def initialize(klass, called_from=nil, first_caller=nil)
136
+ @called_from = called_from || first_caller
137
+ @klass = klass
138
+ @file = @called_from.gsub(/\:[0-9]+.*$/, '') if @called_from
139
+ end
140
+ end
141
+
121
142
  end
122
143
 
123
144
  end
data/lib/assert/test.rb CHANGED
@@ -7,15 +7,18 @@ module Assert
7
7
  # a Test is some code/method to run in the scope of a Context. After a
8
8
  # a test runs, it should have some assertions which are its results.
9
9
 
10
- attr_reader :name, :code, :context_info
10
+ attr_reader :name, :context_info, :config, :code
11
11
  attr_accessor :results, :output
12
12
 
13
- def initialize(name, suite_context_info, code = nil, &block)
14
- @context_info = suite_context_info
15
- @name = name_from_context(name)
16
- @code = (code || block)
13
+ def initialize(name, suite_ci, config, opts = nil, &block)
14
+ @context_info = suite_ci
15
+ @name, @config = name_from_context(name), config
16
+
17
+ o = opts || {}
18
+ @code = o[:code] || block || Proc.new{}
19
+
17
20
  @results = Result::Set.new
18
- @output = ""
21
+ @output = ""
19
22
  end
20
23
 
21
24
  def context_class
@@ -25,7 +28,7 @@ module Assert
25
28
  def run(&result_callback)
26
29
  # setup the a new test run
27
30
  @results = Result::Set.new(result_callback)
28
- run_scope = self.context_class.new(self)
31
+ run_scope = self.context_class.new(self, self.config)
29
32
 
30
33
  # run the test, capturing its output
31
34
  begin
@@ -114,7 +117,7 @@ module Assert
114
117
  end
115
118
 
116
119
  def capture_output(&block)
117
- if Assert.config.capture_output == true
120
+ if self.config.capture_output == true
118
121
  orig_stdout = $stdout.clone
119
122
  $stdout = capture_io
120
123
  block.call
data/lib/assert/utils.rb CHANGED
@@ -6,9 +6,8 @@ module Assert
6
6
 
7
7
  # show objects in a human-readable manner. Either inspects or pretty-prints
8
8
  # them depending on settings.
9
-
10
- def self.show(obj)
11
- out = Assert.config.pp_objects ? Assert.config.pp_proc.call(obj) : obj.inspect
9
+ def self.show(obj, config)
10
+ out = config.pp_objects ? config.pp_proc.call(obj) : obj.inspect
12
11
  out = out.encode(Encoding.default_external) if defined?(Encoding)
13
12
  out
14
13
  end
@@ -16,13 +15,11 @@ module Assert
16
15
  # show objects in a human-readable manner and make the output diff-able. This
17
16
  # expands on the basic `show` util by escaping newlines and making object id
18
17
  # hex-values generic.
19
-
20
- def self.show_for_diff(obj)
21
- show(obj).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
18
+ def self.show_for_diff(obj, config)
19
+ show(obj, config).gsub(/\\n/, "\n").gsub(/:0x[a-fA-F0-9]{4,}/m, ':0xXXXXXX')
22
20
  end
23
21
 
24
22
  # open a tempfile and yield it
25
-
26
23
  def self.tempfile(name, content)
27
24
  require "tempfile"
28
25
  Tempfile.open(name) do |tmpfile|
@@ -32,14 +29,12 @@ module Assert
32
29
  end
33
30
 
34
31
  # Get a proc that uses stdlib `PP.pp` to pretty print objects
35
-
36
32
  def self.stdlib_pp_proc(width = nil)
37
33
  require 'pp'
38
- Proc.new{ |obj| "\n#{PP.pp(obj, '', width || 79).strip}\n" }
34
+ Proc.new{ |obj| PP.pp(obj, '', width || 79).strip }
39
35
  end
40
36
 
41
37
  # Return true if if either show output has newlines or is bigger than 29 chars
42
-
43
38
  def self.default_use_diff_proc
44
39
  Proc.new do |exp_show_output, act_show_output|
45
40
  exp_show_output.include?("\n") || exp_show_output.size > 29 ||
@@ -47,12 +42,13 @@ module Assert
47
42
  end
48
43
  end
49
44
 
45
+ # use `diff` system cmd to show exp/act show output
50
46
  def self.syscmd_diff_proc(syscmd = "diff --unified=-1")
51
47
  Proc.new do |exp_show_output, act_show_output|
52
48
  result = ""
53
49
  tempfile('exp_show_output', exp_show_output) do |a|
54
50
  tempfile('act_show_output', act_show_output) do |b|
55
- result = `#{syscmd} #{a.path} #{b.path}`
51
+ result = `#{syscmd} #{a.path} #{b.path}`.strip
56
52
  result.sub!(/^\-\-\- .+/, "--- expected")
57
53
  result.sub!(/^\+\+\+ .+/, "+++ actual")
58
54
  result = "--- expected\n+++ actual" if result.empty?
@@ -62,6 +58,22 @@ module Assert
62
58
  end
63
59
  end
64
60
 
61
+ # use git to determine which files have changes
62
+ def self.git_changed_proc
63
+ Proc.new do |config, test_paths|
64
+ files = []
65
+ cmd = [
66
+ "git diff --no-ext-diff --name-only", # changed files
67
+ "git ls-files --others --exclude-standard" # added files
68
+ ].map{ |c| "#{c} -- #{test_paths.join(' ')}" }.join(' && ')
69
+ Assert::CLI.bench('Load only changed files') do
70
+ files = `#{cmd}`.split("\n")
71
+ end
72
+ puts Assert::CLI.debug_msg(" `#{cmd}`") if config.debug
73
+ files
74
+ end
75
+ end
76
+
65
77
  end
66
78
 
67
79
  # alias for brevity
@@ -1,3 +1,3 @@
1
1
  module Assert
2
- VERSION = "2.4.0"
2
+ VERSION = "2.5.0"
3
3
  end
data/lib/assert/view.rb CHANGED
@@ -6,16 +6,18 @@ module Assert::View
6
6
  # require views by passing either a full path to the view ruby file
7
7
  # or passing the name of a view installed in ~/.assert/views
8
8
 
9
- def self.require_user_view(view)
10
- views_file = File.join(Assert.config.user_test_dir, 'views', view, 'lib', view)
9
+ def self.require_user_view(view_name)
10
+ views_file = File.expand_path(
11
+ File.join("#{ENV['HOME']}/.assert/views", view_name, 'lib', view_name)
12
+ )
11
13
 
12
- if File.exists?(view) || File.exists?(view+'.rb')
13
- require view
14
- elsif File.exists?(views_file+'.rb')
14
+ if File.exists?(view_name) || File.exists?(view_name + '.rb')
15
+ require view_name
16
+ elsif File.exists?(views_file + '.rb')
15
17
  require views_file
16
18
  else
17
- msg = "[WARN] Can't find or require #{view.inspect} view."
18
- msg << " Did you install it in `~/.assert/views`?" if !view.match(/\A\//)
19
+ msg = "[WARN] Can't find or require #{view_name.inspect} view."
20
+ msg << " Did you install it in `~/.assert/views`?" if !view_name.match(/\A\//)
19
21
  warn msg
20
22
  end
21
23
  end
@@ -1,3 +1,5 @@
1
+ require 'assert/config'
2
+ require 'assert/suite'
1
3
  require 'assert/result'
2
4
 
3
5
  module Assert::View
@@ -17,13 +19,33 @@ module Assert::View
17
19
  option 'skip_abbrev', 'S'
18
20
  option 'error_abbrev', 'E'
19
21
 
20
- def initialize(output_io, suite=nil)
21
- @output_io, @suite = output_io, suite
22
+ attr_reader :config, :suite
23
+
24
+ def initialize(output_io, *args)
25
+ @output_io = output_io
26
+ @suite, @config = [
27
+ args.last.kind_of?(Assert::Suite) ? args.pop : nil,
28
+ args.last.kind_of?(Assert::Config) ? args.pop : nil
29
+ ]
30
+
22
31
  @output_io.sync = true if @output_io.respond_to?(:sync=)
23
32
  end
24
33
 
25
- def view; self; end
26
- def suite; @suite || Assert.suite; end
34
+ def is_tty?
35
+ !!@output_io.isatty
36
+ end
37
+
38
+ def view
39
+ self
40
+ end
41
+
42
+ def config
43
+ @config ||= Assert.config
44
+ end
45
+
46
+ def suite
47
+ @suite ||= Assert.suite
48
+ end
27
49
 
28
50
  def fire(callback, *args)
29
51
  self.send(callback, *args)
@@ -68,7 +68,7 @@ module Assert::View
68
68
 
69
69
  puts "#{result_count_statement}: #{styled_results_sentence}"
70
70
  puts
71
- puts "(#{run_time} seconds)"
71
+ puts "(#{run_time} seconds, #{test_rate} tests/s, #{result_rate} results/s)"
72
72
  end
73
73
 
74
74
  end
@@ -9,7 +9,7 @@ module Assert::View::Helpers
9
9
  end
10
10
 
11
11
  def ansi_styled_msg(msg, styles=[])
12
- if !(style = ansi_style(*styles)).empty?
12
+ if !(style = ansi_style(*styles)).empty? && self.is_tty?
13
13
  style + msg + ANSI.send(:reset)
14
14
  else
15
15
  msg
@@ -6,13 +6,8 @@ module Assert::View::Helpers
6
6
  receiver.class_eval{ extend ClassMethods }
7
7
  end
8
8
 
9
- # get the formatted suite run time
10
- def run_time(format='%.6f')
11
- format % self.suite.run_time
12
- end
13
-
14
9
  def runner_seed
15
- Assert.config.runner_seed
10
+ self.config.runner_seed
16
11
  end
17
12
 
18
13
  def count(type)
@@ -27,6 +22,21 @@ module Assert::View::Helpers
27
22
  self.count(:pass) == self.count(:results)
28
23
  end
29
24
 
25
+ # get the formatted suite run time
26
+ def run_time(format = '%.6f')
27
+ format % self.suite.run_time
28
+ end
29
+
30
+ # get the formatted suite test rate
31
+ def test_rate(format = '%.6f')
32
+ format % self.suite.test_rate
33
+ end
34
+
35
+ # get the formatted suite result rate
36
+ def result_rate(format = '%.6f')
37
+ format % self.suite.result_rate
38
+ end
39
+
30
40
  # get a uniq list of contexts for the test suite
31
41
  def suite_contexts
32
42
  @suite_contexts ||= self.suite.tests.inject([]) do |contexts, test|
data/test/helper.rb CHANGED
@@ -7,97 +7,4 @@ $LOAD_PATH.unshift(ROOT_PATH)
7
7
 
8
8
  # require pry for debugging (`binding.pry`)
9
9
  require 'pry'
10
-
11
- # Force tests to run without halting on failures (needed so all tests will run
12
- # properly). For halt on fail behavior testing, the context of those tests
13
- # configures Assert temporarily as needed.
14
-
15
- class Assert::Context
16
- def setup
17
- Assert.config.halt_on_fail false
18
- # Note: don't mess with the `capture_output` setting in this setup block. Doing
19
- # so will break the capture output tests. If you really need to set it one
20
- # way or the other, do so in the `.assert.rb` local settings file.
21
- end
22
-
23
- # a context for use in testing all the different context singleton methods
24
- class ContextSingletonTests < Assert::Context
25
- desc "Assert context singleton"
26
- setup do
27
- @orig_assert_suite = Assert.suite
28
- Assert.config.suite TEST_ASSERT_SUITE
29
- @test = Factory.test
30
- @context_class = @test.context_class
31
- end
32
- teardown do
33
- TEST_ASSERT_SUITE.tests.clear
34
- Assert.config.suite @orig_assert_suite
35
- end
36
- subject{ @context_class }
37
-
38
- end
39
-
40
- end
41
-
42
-
43
- # A Suite for use in the tests. It is seperate from `Assert.suite`
44
- # (which is the actual suite being used to run the tests). Don't use
45
- # `Assert.suite` in your tests, use TEST_ASSERT_SUITE
46
-
47
- TEST_ASSERT_SUITE = Assert::Suite.new
48
-
49
- # A context for use in the tests and also in the `context_class` factory. This
50
- # will ensure any contexts defined as part of the tests will add their methods
51
- # to `TEST_ASSERT_SUITE`
52
-
53
- class TestContext < Assert::Context
54
- def self.method_added(meth)
55
- if meth.to_s =~ Assert::Suite::TEST_METHOD_REGEX
56
- ci = Assert::Suite::ContextInfo.new(self, Factory.context_info_called_from)
57
- TEST_ASSERT_SUITE.tests << Assert::Test.new(meth.to_s, ci, meth)
58
- end
59
- end
60
- end
61
-
62
- module Factory
63
-
64
- def self.context_info_called_from
65
- "/path/to_file.rb:1234"
66
- end
67
-
68
- def self.context_info(context_class)
69
- Assert::Suite::ContextInfo.new(context_class, context_info_called_from)
70
- end
71
-
72
- # Generate an anonymous `Context` inherited from `TestContext` by default.
73
- # This provides a common interface for all contexts used in testing.
74
-
75
- def self.context_class(inherit_from=nil, &block)
76
- inherit_from ||= TestContext
77
- klass = Class.new(inherit_from, &block)
78
- default = (const_name = "FactoryAssertContext").dup
79
-
80
- while(Object.const_defined?(const_name)) do
81
- const_name = "FactoryAssertContext#{rand(Time.now.to_i)}"
82
- end
83
- Object.const_set(const_name, klass)
84
- klass
85
- end
86
-
87
- # Generate a no-op test for use in testing.
88
-
89
- def self.test(*args, &block)
90
- name = (args[0] || "a test").to_s
91
- context_info = args[1] || self.context_info(self.context_class)
92
- test_block = (block || args[2] || ::Proc.new{})
93
-
94
- Assert::Test.new(name, context_info, &test_block)
95
- end
96
-
97
- # Generate a skip result for use in testing.
98
-
99
- def self.skip_result(name, exception)
100
- Assert::Result::Skip.new(Factory.test(name), exception)
101
- end
102
-
103
- end
10
+ require 'test/support/factory'