nitrous 1.0.3

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,82 @@
1
+ require 'curses'
2
+
3
+ module Kernel
4
+ def puts(*args)
5
+ $stdout.puts(*args)
6
+ end
7
+ end
8
+
9
+ module Nitrous
10
+ class ProgressBarAwareStandardOut
11
+ def initialize(stdout, progress_bar)
12
+ @stdout, @progress_bar = stdout, progress_bar
13
+ end
14
+
15
+ def write(object)
16
+ @progress_bar.delete_bar
17
+ @stdout.write(object)
18
+ @progress_bar.redraw_bar
19
+ end
20
+
21
+ def print(*args)
22
+ args.each do |arg|
23
+ write(arg)
24
+ end
25
+ end
26
+
27
+ def puts(*args)
28
+ args.each do |arg|
29
+ write("#{arg}\n")
30
+ end
31
+ end
32
+
33
+ def direct_write(object)
34
+ @stdout.write(object)
35
+ end
36
+ end
37
+
38
+ class ProgressBar
39
+ RED = 101
40
+ GREEN = 102
41
+
42
+ attr_accessor :color, :text
43
+
44
+ def initialize(steps)
45
+ @total_steps = steps
46
+ @step = 0
47
+ @color = GREEN
48
+ Curses.init_screen
49
+ @dimensions = [Curses.stdscr.maxx, Curses.stdscr.maxy]
50
+ Curses.close_screen
51
+ $stdout.puts ""
52
+ $stdout = ProgressBarAwareStandardOut.new($stdout, self)
53
+ @text = ""
54
+ end
55
+
56
+ def step
57
+ @step += 1
58
+ draw
59
+ end
60
+
61
+ def draw_bar(color, width)
62
+ content = @text[0..[width, @text.length].min] + " " * [width - @text.length, 0].max
63
+ $stdout.direct_write("\e[#{color}m#{content}\e[0m")
64
+ $stdout.direct_write(@text[(width + 1)..-1]) if @text.length > width
65
+ $stdout.direct_write("\n")
66
+ end
67
+
68
+ def delete_bar
69
+ $stdout.direct_write("\e[1F\e[0K")
70
+ end
71
+
72
+ def draw
73
+ delete_bar
74
+ redraw_bar
75
+ end
76
+
77
+ def redraw_bar
78
+ draw_bar(@color, (@dimensions[0].to_f/@total_steps)*@step)
79
+ STDOUT.flush
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,77 @@
1
+ require 'rails_ext'
2
+ module Nitrous
3
+ class RailsTest < Nitrous::Test
4
+ def created(type)
5
+ lookup(type, ActiveRecord::Base.saved_objects)
6
+ end
7
+
8
+ def assert_created!(type)
9
+ instance = created(type)
10
+ fail("Should have created a #{type}.#{invalid(type) ? " Errors: #{invalid(type).errors.full_messages.to_sentence}" : ''}") unless instance
11
+ yield(instance) if block_given?
12
+ instance
13
+ end
14
+
15
+ def assert_not_created!(type)
16
+ instance = created(type).reload rescue nil
17
+ fail("Should not have created a #{type}. Instance: #{instance.inspect}") if instance
18
+ yield if block_given?
19
+ end
20
+
21
+ def assert_email_sent!(count=1, &block)
22
+ assert_equal! @emails + count, ActionMailer::Base.deliveries.size
23
+ block.call(*ActionMailer::Base.deliveries[-count..-1]) if block_given?
24
+ ensure
25
+ @emails = ActionMailer::Base.deliveries.size
26
+ end
27
+
28
+ def assert_no_email_sent!(&block)
29
+ assert_equal! @emails, ActionMailer::Base.deliveries.size
30
+ block.call if block_given?
31
+ ensure
32
+ @emails = ActionMailer::Base.deliveries.size
33
+ end
34
+
35
+ def invalid(type)
36
+ lookup(type, ActiveRecord::Base.invalid_objects)
37
+ end
38
+
39
+ def destroyed(type)
40
+ lookup(type, ActiveRecord::Base.destroyed_objects)
41
+ end
42
+
43
+ def assert_destroyed!(type)
44
+ instance = destroyed(type)
45
+ fail("Should have destroyed a #{type}.") unless instance
46
+ yield(instance) if block_given?
47
+ instance
48
+ end
49
+
50
+ private
51
+ def lookup(type, list)
52
+ (list[type] && list[type].last) || list[type.to_s.singularize.to_sym]
53
+ end
54
+
55
+ def reset_record_tracking
56
+ if defined?(ActiveRecord)
57
+ ActiveRecord::Base.saved_objects = {}
58
+ ActiveRecord::Base.invalid_objects = {}
59
+ ActiveRecord::Base.destroyed_objects = {}
60
+ end
61
+ @emails = ActionMailer::Base.deliveries.size
62
+ end
63
+
64
+ def nitrous_setup
65
+ super
66
+ reset_record_tracking
67
+ end
68
+
69
+ def nitrous_teardown
70
+ if defined?(ActiveRecord)
71
+ ActiveRecord::Base.send(:subclasses).each do |klass|
72
+ klass.delete_all rescue nil
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,4 @@
1
+ PID_FILE = File.expand_path(File.join(RAILS_ROOT, 'tmp/pids/nitrous_server.pid'))
2
+ if File.exists?(PID_FILE) && !`ps ax | grep "\b#{File.read(PID_FILE)}\b"`.empty?
3
+ `ruby #{File.join(File.dirname(__FILE__), 'daemon_controller.rb')} start #{File.expand_path(RAILS_ROOT)}`
4
+ end
@@ -0,0 +1,121 @@
1
+ require File.dirname(__FILE__) + '/../core_ext'
2
+ require 'nitrous/assertions'
3
+ require 'nitrous/test_block'
4
+ require 'nitrous/test_context'
5
+ require 'nitrous/test_result'
6
+ module Nitrous
7
+ class Test
8
+ include Assertions
9
+
10
+ def self.callbacks
11
+ @@callbacks ||= {:suite_setup => [], :suite_teardown => [], :setup => [], :teardown => []}
12
+ end
13
+
14
+ def callbacks
15
+ self.class.callbacks
16
+ end
17
+
18
+ def self.register_callback(type, &callback)
19
+ callbacks[type] << callback
20
+ end
21
+
22
+ def register_callback(type, &callback)
23
+ self.class.register_callback(type, callback)
24
+ end
25
+
26
+ def self.tests
27
+ @tests ||= []
28
+ end
29
+
30
+ def self.test_classes
31
+ @test_classes ||= []
32
+ end
33
+
34
+ def self.test(name=nil, &block)
35
+ self.tests << TestBlock.new(name, block) unless @single_test
36
+ end
37
+
38
+ def self.stest(name=nil, &block)
39
+ @tests = [TestBlock.new(name, block)]
40
+ @single_test = true;
41
+ end
42
+
43
+ def self.ztest(name=nil, &block)
44
+ self.tests << TestBlock.new(name, block, true) unless @single_test
45
+ end
46
+
47
+ def self.exclude(klass)
48
+ @test_classes.delete(klass)
49
+ end
50
+
51
+ def self.inherited(subclass)
52
+ class << subclass
53
+ def inherited(subclass)
54
+ Nitrous::Test.exclude(self)
55
+ Nitrous::Test.inherited(subclass)
56
+ end
57
+ end
58
+ if !@test_classes
59
+ @test_classes = []
60
+ at_exit do
61
+ callbacks[:suite_setup].each(&:call)
62
+ context = TestContext.create(@test_classes.sum {|klass| klass.tests.size})
63
+ @test_classes.each do |klass|
64
+ klass.run(context)
65
+ end
66
+ context.finish
67
+ callbacks[:suite_teardown].each(&:call)
68
+ exit(context.exit_status)
69
+ end
70
+ end
71
+ @test_classes << subclass
72
+ end
73
+
74
+ def self.run(context=TestContext.new)
75
+ self.new(context).run
76
+ end
77
+
78
+ def initialize(context)
79
+ @context = context
80
+ @test_results = []
81
+ end
82
+
83
+ def self.setup; end
84
+ def self.teardown; end
85
+ def nitrous_setup; end
86
+ def nitrous_teardown; end
87
+ def setup; end
88
+ def teardown; end
89
+
90
+ def collect_errors
91
+ yield
92
+ rescue Exception
93
+ @test_results.last.errors << $!
94
+ @context.failed($!)
95
+ end
96
+
97
+ def running(test)
98
+ @current_test = test
99
+ @test_results << TestResult.new(test)
100
+ end
101
+
102
+ def run
103
+ puts self.class.name
104
+ self.class.setup
105
+ self.class.tests.each do |test_block|
106
+ running(test_block)
107
+ nitrous_setup
108
+ collect_errors do
109
+ callbacks[:setup].each(&:call)
110
+ setup
111
+ test_block.run(self)
112
+ teardown
113
+ callbacks[:teardown].each(&:call)
114
+ end
115
+ nitrous_teardown
116
+ @context.ran_test(test_block, @test_results.last)
117
+ end
118
+ self.class.teardown
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,43 @@
1
+ module Nitrous
2
+ class TestBlock
3
+ def initialize(name, block, skip=false)
4
+ @name, @block, @skip = name, block, skip
5
+ end
6
+
7
+ def run(test)
8
+ test.collect_errors do
9
+ test.instance_eval(&@block) unless self.skip?
10
+ end
11
+ end
12
+
13
+ def filename
14
+ parse_location
15
+ @filename
16
+ end
17
+
18
+ def line
19
+ parse_location
20
+ @line
21
+ end
22
+
23
+ def skip?
24
+ @skip
25
+ end
26
+
27
+ def to_s
28
+ @name || first_line
29
+ end
30
+
31
+ def first_line
32
+ "[ #{File.readlines(filename)[line].strip} ]"
33
+ end
34
+
35
+ private
36
+ def parse_location
37
+ return if @filename && @line
38
+ @block.inspect =~ /#<Proc:[^@]+@([^:]+):(\d+)>/
39
+ @filename = $1
40
+ @line = $2.to_i
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,76 @@
1
+ require 'nitrous/progress_bar'
2
+ module Nitrous
3
+ class TestContext
4
+ def self.gui?
5
+ !!ENV["TM_MODE"] || !!ENV["VIMRUNTIME"]
6
+ end
7
+
8
+ def self.create(test_count)
9
+ if gui?
10
+ TestContext.new(test_count)
11
+ else
12
+ CommandLineTestContext.new(test_count)
13
+ end
14
+ end
15
+
16
+ def initialize(test_count)
17
+ @start_time = Time.now
18
+ @total, @failures, @test, @skip = test_count, 0, 0, 0
19
+ end
20
+
21
+ def ran_test(test, result)
22
+ @test += 1
23
+ @skip += 1 if test.skip?
24
+ puts result
25
+ puts result.errors.map(&:test_output).join("\n\n") + "\n" unless result.errors.empty?
26
+ end
27
+
28
+ def failed(exception)
29
+ @failures += 1
30
+ end
31
+
32
+ def finish
33
+ puts summary_with_benchmark
34
+ end
35
+
36
+ def exit_status
37
+ @failures > 0 ? 1 : 0
38
+ end
39
+
40
+ def summary
41
+ "Test #{@test} of #{@total} -- #{@failures} failure#{@failures == 1 ? '' : 's'} -- #{@skip} skipped"
42
+ end
43
+
44
+ def summary_with_benchmark
45
+ summary + " -- #{Time.now - @start_time} seconds"
46
+ end
47
+ end
48
+
49
+ class CommandLineTestContext < TestContext
50
+ def initialize(test_count)
51
+ super
52
+ @progress_bar = ProgressBar.new(test_count)
53
+ update_text
54
+ end
55
+
56
+ def ran_test(test, result)
57
+ super
58
+ @progress_bar.step
59
+ update_text
60
+ end
61
+
62
+ def update_text
63
+ @progress_bar.text = summary
64
+ end
65
+
66
+ def failed(exception)
67
+ super
68
+ @progress_bar.color = ProgressBar::RED
69
+ end
70
+
71
+ def finish
72
+ @progress_bar.text = summary_with_benchmark
73
+ @progress_bar.draw
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,17 @@
1
+ module Nitrous
2
+ class TestResult
3
+ attr_reader :errors
4
+ def initialize(test)
5
+ @test, @errors = test, []
6
+ end
7
+
8
+ def to_s
9
+ %{ #{@test}: #{pass_fail_skip}}
10
+ end
11
+
12
+ def pass_fail_skip
13
+ return "Skipped" if @test.skip?
14
+ @errors.empty? ? "Passed" : "Failed"
15
+ end
16
+ end
17
+ end
data/lib/rails_ext.rb ADDED
@@ -0,0 +1,60 @@
1
+ if defined?(ActiveRecord)
2
+ unless ActiveRecord::Base.instance_methods.include?('save_with_tracking')
3
+ class ActiveRecord::Base
4
+ cattr_accessor :saved_objects
5
+ cattr_accessor :invalid_objects
6
+ cattr_accessor :destroyed_objects
7
+
8
+ def create_or_update_with_tracking(*args)
9
+ new_record = new_record?
10
+ saved = create_or_update_without_tracking(*args)
11
+ append_instance(ActiveRecord::Base.saved_objects) if new_record && saved
12
+ saved
13
+ end
14
+ alias_method_chain :create_or_update, :tracking
15
+
16
+ def destroy_with_tracking(*args)
17
+ result = destroy_without_tracking(*args)
18
+ append_instance(ActiveRecord::Base.destroyed_objects) if result
19
+ result
20
+ end
21
+ alias_method_chain :destroy, :tracking
22
+
23
+ def validate_with_tracking(*args)
24
+ valid = validate_without_tracking(*args)
25
+ append_instance(ActiveRecord::Base.invalid_objects) if !valid
26
+ valid
27
+ end
28
+ alias_method_chain :validate, :tracking
29
+
30
+ private
31
+ def append_instance(list)
32
+ return if !list
33
+ key = self.class.name.underscore.to_sym
34
+ list[key] ||= []
35
+ list[key] << self
36
+ end
37
+ end
38
+ end
39
+ end
40
+ module Extensions
41
+ module Core
42
+ module Hash
43
+ def to_fields(fields = {}, namespace = nil)
44
+ each do |key, value|
45
+ key = namespace ? "#{namespace}[#{key}]" : key
46
+ case value
47
+ when ::Hash
48
+ value.to_fields(fields, key)
49
+ when ::Array
50
+ fields["#{key}[]"] = value
51
+ else
52
+ fields[key.to_s] = value
53
+ end
54
+ end
55
+ fields
56
+ end
57
+ end
58
+ end
59
+ end
60
+ Hash.send :include, Extensions::Core::Hash