nitrous 1.0.3

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