infinity_test 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/.gitignore +10 -0
  2. data/.infinity_test +8 -0
  3. data/.rspec +1 -0
  4. data/.rvmrc +1 -0
  5. data/Gemfile +11 -0
  6. data/Rakefile +49 -0
  7. data/Readme.markdown +92 -0
  8. data/Tasks +5 -0
  9. data/VERSION.yml +5 -0
  10. data/bin/infinity_test +7 -0
  11. data/buzz_images/buzz_lightyear.jpg +0 -0
  12. data/buzz_images/buzz_lightyear_continencia.gif +0 -0
  13. data/buzz_images/to_infinity_and_beyond.png +0 -0
  14. data/features/infinity_test.feature +36 -0
  15. data/features/support/env.rb +1 -0
  16. data/images/faces/failure.png +0 -0
  17. data/images/faces/pending.png +0 -0
  18. data/images/faces/sucess.png +0 -0
  19. data/images/hands/failure.png +0 -0
  20. data/images/hands/pending.png +0 -0
  21. data/images/hands/sucess.png +0 -0
  22. data/images/mario_bros/failure.jpg +0 -0
  23. data/images/mario_bros/pending.jpg +0 -0
  24. data/images/mario_bros/sucess.jpg +0 -0
  25. data/images/rails/failure.png +0 -0
  26. data/images/rails/pending.png +0 -0
  27. data/images/rails/sucess.png +0 -0
  28. data/images/rubies/failure.png +0 -0
  29. data/images/rubies/pending.png +0 -0
  30. data/images/rubies/sucess.png +0 -0
  31. data/images/simpson/failure.gif +0 -0
  32. data/images/simpson/pending.jpg +0 -0
  33. data/images/simpson/sucess.jpg +0 -0
  34. data/images/street_fighter/failure.gif +0 -0
  35. data/images/street_fighter/pending.gif +0 -0
  36. data/images/street_fighter/sucess.jpg +0 -0
  37. data/images/toy_story/failure.gif +0 -0
  38. data/images/toy_story/pending.png +0 -0
  39. data/images/toy_story/sucess.png +0 -0
  40. data/infinity_test.gemspec +168 -0
  41. data/lib/infinity_test.rb +31 -0
  42. data/lib/infinity_test/application.rb +168 -0
  43. data/lib/infinity_test/binary_path.rb +21 -0
  44. data/lib/infinity_test/command.rb +57 -0
  45. data/lib/infinity_test/configuration.rb +157 -0
  46. data/lib/infinity_test/continuous_testing.rb +62 -0
  47. data/lib/infinity_test/dependencies.rb +45 -0
  48. data/lib/infinity_test/notifications/growl.rb +15 -0
  49. data/lib/infinity_test/notifications/lib_notify.rb +11 -0
  50. data/lib/infinity_test/options.rb +52 -0
  51. data/lib/infinity_test/rspec.rb +87 -0
  52. data/lib/infinity_test/runner.rb +30 -0
  53. data/lib/infinity_test/test_unit.rb +74 -0
  54. data/lib/infinity_test/test_unit_loader.rb +5 -0
  55. data/spec/factories/buzz/lib/buzz.rb +0 -0
  56. data/spec/factories/buzz/spec/buzz_spec.rb +0 -0
  57. data/spec/factories/company/lib/company.rb +0 -0
  58. data/spec/factories/company/test/company_test.rb +0 -0
  59. data/spec/factories/images/failure.png +0 -0
  60. data/spec/factories/images/pending.png +0 -0
  61. data/spec/factories/images/sucess.png +0 -0
  62. data/spec/factories/infinity_test +5 -0
  63. data/spec/factories/infinity_test_example +7 -0
  64. data/spec/factories/slinky/spec/slinky/slinky_spec.rb +0 -0
  65. data/spec/factories/travel/lib/travel.rb +0 -0
  66. data/spec/factories/travel/test/partner_test.rb +0 -0
  67. data/spec/factories/travel/test/travel_test.rb +0 -0
  68. data/spec/factories/wood/lib/wood.rb +0 -0
  69. data/spec/factories/wood/spec/wood_spec.rb +0 -0
  70. data/spec/infinity_test/application_spec.rb +149 -0
  71. data/spec/infinity_test/command_spec.rb +47 -0
  72. data/spec/infinity_test/configuration_spec.rb +196 -0
  73. data/spec/infinity_test/continuous_testing_spec.rb +7 -0
  74. data/spec/infinity_test/notifications/growl_spec.rb +9 -0
  75. data/spec/infinity_test/notifications/lib_notify_spec.rb +9 -0
  76. data/spec/infinity_test/options_spec.rb +69 -0
  77. data/spec/infinity_test/rspec_spec.rb +189 -0
  78. data/spec/infinity_test/runner_spec.rb +34 -0
  79. data/spec/infinity_test/test_unit_spec.rb +182 -0
  80. data/spec/infinity_test_spec.rb +29 -0
  81. data/spec/spec.opts +1 -0
  82. data/spec/spec_helper.rb +67 -0
  83. metadata +226 -0
@@ -0,0 +1,31 @@
1
+ require 'infinity_test/dependencies'
2
+
3
+ module InfinityTest
4
+ autoload :Application, 'infinity_test/application'
5
+ autoload :BinaryPath, 'infinity_test/binary_path'
6
+ autoload :Command, 'infinity_test/command'
7
+ autoload :Configuration, 'infinity_test/configuration'
8
+ autoload :ContinuousTesting, 'infinity_test/continuous_testing'
9
+ autoload :Options, 'infinity_test/options'
10
+ autoload :Rspec, 'infinity_test/rspec'
11
+ autoload :Runner, 'infinity_test/runner'
12
+ autoload :TestUnit, 'infinity_test/test_unit'
13
+
14
+ def self.application
15
+ @application ||= Application.new
16
+ end
17
+
18
+ def self.configuration
19
+ @configuration ||= Configuration.new
20
+ end
21
+
22
+ def self.start!
23
+ Runner.new(Options.new(ARGV)).run!
24
+ end
25
+
26
+ module Notifications
27
+ autoload :Growl, 'infinity_test/notifications/growl'
28
+ autoload :LibNotify, 'infinity_test/notifications/lib_notify'
29
+ end
30
+
31
+ end
@@ -0,0 +1,168 @@
1
+ module InfinityTest
2
+ class Application
3
+ include Notifications
4
+
5
+ attr_accessor :config, :library_directory_pattern
6
+
7
+ # Initialize the Application object with the configuration instance to
8
+ # load configuration and set properly
9
+ #
10
+ def initialize
11
+ @config = InfinityTest.configuration
12
+ @library_directory_pattern = "^lib/*/(.*)\.rb"
13
+ end
14
+
15
+ # Load the Configuration file
16
+ #
17
+ # Load first global file in => ~/.infinity_test
18
+ # After load the project file => ./.infinity_test
19
+ #
20
+ # If the Project file has the same methods in the global, will override the configurations
21
+ #
22
+ # Example:
23
+ #
24
+ # ~/.infinity_test -> infinity_test { notifications :growl }
25
+ #
26
+ # ./.infinity_test -> infinity_test { notifications :lib_notify } # High Priority
27
+ #
28
+ # After the load the Notifications Framework will be Lib Notify
29
+ #
30
+ def load_configuration_file
31
+ load_global_configuration # Separate global and local configuration
32
+ load_project_configuration # because it's more easy to test
33
+ end
34
+
35
+ def sucess_image
36
+ config.sucess_image
37
+ end
38
+
39
+ def failure_image
40
+ config.failure_image
41
+ end
42
+
43
+ def pending_image
44
+ config.pending_image
45
+ end
46
+
47
+ # Return the block object setting in the config file
48
+ #
49
+ def before_callback
50
+ config.before_callback
51
+ end
52
+
53
+ # Return the block object setting in the config file
54
+ #
55
+ def after_callback
56
+ config.after_callback
57
+ end
58
+
59
+ # Return the rubies setting in the config file or the command line
60
+ #
61
+ def rubies
62
+ config.rubies
63
+ end
64
+
65
+ def construct_commands
66
+ test_framework.construct_commands
67
+ end
68
+
69
+ def test_directory_pattern
70
+ test_framework.test_directory_pattern
71
+ end
72
+
73
+ # Return a instance of the test framework class
74
+ #
75
+ def test_framework
76
+ @test_framework ||= setting_test_framework
77
+ end
78
+
79
+ # Return a instance of the Notification Framework class
80
+ #
81
+ def notification_framework
82
+ @notification_framework ||= setting_notification
83
+ end
84
+
85
+ def run!(commands)
86
+ before_callback.call if before_callback
87
+ commands.each do |ruby_version, command|
88
+ puts; puts "* { :ruby => #{ruby_version} }"
89
+ puts command if verbose?
90
+ command = Command.new(:ruby_version => ruby_version, :command => command).run!
91
+ notify!(:results => command.results, :ruby_version => ruby_version)
92
+ end
93
+ after_callback.call if after_callback
94
+ end
95
+
96
+ def notify!(options)
97
+ message = parse_results(options[:results])
98
+ notification_framework.notify(:title => options[:ruby_version], :message => message, :image => image_to_show)
99
+ end
100
+
101
+ def parse_results(results)
102
+ test_framework.parse_results(results)
103
+ end
104
+
105
+ def image_to_show
106
+ if test_framework.failure?
107
+ failure_image
108
+ elsif test_framework.pending?
109
+ pending_image
110
+ else
111
+ sucess_image
112
+ end
113
+ end
114
+
115
+ def run_changed_lib_file(file)
116
+ file = File.basename(file[1])
117
+ files = test_framework.all_files.grep(/#{file}/i)
118
+ run_commands_for_file(files.join(' ')) unless files.empty?
119
+ end
120
+
121
+ def run_changed_test_file(file)
122
+ run_commands_for_file(file)
123
+ end
124
+
125
+ def run_commands_for_file(file)
126
+ commands = test_framework.construct_commands(file)
127
+ run!(commands)
128
+ end
129
+
130
+ def verbose?
131
+ config.verbose
132
+ end
133
+
134
+ private
135
+
136
+ def setting_test_framework
137
+ case config.test_framework
138
+ when :rspec
139
+ Rspec.new :rubies => rubies
140
+ when :test_unit
141
+ TestUnit.new :rubies => rubies
142
+ end
143
+ end
144
+
145
+ def setting_notification
146
+ case config.notification_framework
147
+ when :growl
148
+ Growl.new
149
+ when :lib_notify
150
+ LibNotify.new
151
+ end
152
+ end
153
+
154
+ def load_global_configuration
155
+ load_file :file => File.expand_path('~/.infinity_test')
156
+ end
157
+
158
+ def load_project_configuration
159
+ load_file :file => './.infinity_test'
160
+ end
161
+
162
+ def load_file(options)
163
+ file = options[:file]
164
+ load(file) if File.exist?(file)
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,21 @@
1
+ module InfinityTest
2
+ module BinaryPath
3
+
4
+ def rvm_bin_path(environment, binary)
5
+ "~/.rvm/gems/#{environment.expanded_name}/bin/#{binary}"
6
+ end
7
+
8
+ def print_message(gem_name, ruby_version)
9
+ puts "\n Ruby => #{ruby_version}: I searched the #{gem_name} binary path and I don't find nothing. You have the #{gem_name} installed in this version?"
10
+ end
11
+
12
+ def search_binary(binary_name, options)
13
+ File.expand_path(rvm_bin_path(options[:environment], binary_name))
14
+ end
15
+
16
+ def have_binary?(binary)
17
+ File.exist?(binary)
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ module InfinityTest
2
+ class Command
3
+ attr_accessor :command, :results, :line, :ruby_version
4
+
5
+ # Create new Command object that receive the ruby_version and the command string
6
+ #
7
+ def initialize(options={})
8
+ @command = options[:command]
9
+ @ruby_version = options[:ruby_version]
10
+ @results = []
11
+ @line = []
12
+ end
13
+
14
+ # Code taken in Autotest gem and change a little
15
+ #
16
+ def run!
17
+ old_sync = $stdout.sync
18
+ $stdout.sync = true
19
+ begin
20
+ open("| #{@command}", "r") do |file|
21
+ until file.eof? do
22
+ test_line = file.getc
23
+ break unless test_line
24
+ putc(test_line)
25
+ @line.push(test_line)
26
+ push_in_the_results(test_line)
27
+ end
28
+ end
29
+ ensure
30
+ $stdout.sync = old_sync
31
+ end
32
+ @results = @results.join
33
+ self
34
+ end
35
+
36
+ # Push in the results the test line
37
+ # If have in the Ruby Enterpise Edition pack the numbers return. Join otherwise.
38
+ #
39
+ def push_in_the_results(test_line)
40
+ if end_of_line?(test_line)
41
+ @results.push(ree? ? @line.pack('c*') : @line.join)
42
+ @line.clear
43
+ end
44
+ end
45
+
46
+ # Using Ruby Enterprise Edition?
47
+ #
48
+ def ree?
49
+ RVM::Environment.current_ruby_string =~ /ree/
50
+ end
51
+
52
+ def end_of_line?(test_line)
53
+ test_line == ?\n
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,157 @@
1
+ module InfinityTest
2
+ class Configuration
3
+
4
+ SUPPORTED_FRAMEWORKS = [:growl, :lib_notify] # :snarl, :lib_notify
5
+
6
+ attr_accessor :notification_framework, :sucess_image, :failure_image, :pending_image, :rubies, :test_framework,
7
+ :exceptions_to_ignore, :before_callback, :after_callback, :verbose
8
+
9
+ IMAGES_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'images'))
10
+
11
+ # Initialize the Configuration object that keeps the images, callbacks, rubies
12
+ # and the test framework
13
+ #
14
+ def initialize
15
+ @default_dir_image = File.join(IMAGES_DIR, 'simpson')
16
+ @sucess_image = 'sucess'
17
+ @failure_image = 'failure'
18
+ @pending_image = 'pending'
19
+ @test_framework = :test_unit
20
+ @verbose = false
21
+ end
22
+
23
+ # Set the notification framework to use with Infinity Test.
24
+ # The supported Notification Frameworks are:
25
+ #
26
+ # * Growl
27
+ # * Lib-Notify
28
+ #
29
+ # Here is the example of little Domain Specific Language to use:
30
+ #
31
+ # notifications :growl do
32
+ # # block
33
+ # end
34
+ #
35
+ def notifications(framework, &block)
36
+ raise NotificationFrameworkDontSupported, "Notification :#{framework} don't supported. The Frameworks supported are: #{SUPPORTED_FRAMEWORKS.join(',')}" unless SUPPORTED_FRAMEWORKS.include?(framework)
37
+ @notification_framework = framework
38
+ yield self if block_given?
39
+ self
40
+ end
41
+
42
+ # Set the Success and Failure image to show in the notification framework
43
+ #
44
+ # show_images :failure => 'Users/tomas/images/my_custom_image.png', :sucess => 'custom_image.jpg'
45
+ #
46
+ # Or you cant set modes(directory) for show images (please see the images folder in => http://github.com/tomas-stefano/infinity_test/tree/master/images/ )
47
+ #
48
+ # show_images :mode => :simpson # => This will show images in the folder http://github.com/tomas-stefano/infinity_test/tree/master/images/simpson
49
+ # show_images :mode => :street_fighter # => This will show images in folder http://github.com/tomas-stefano/infinity_test/tree/master/images/street_fighter
50
+ # show_images :mode => '~/My/Mode' # => This will show images in the '~/My/Mode' directory
51
+ #
52
+ # The Convention in images folder is to set sucess, failure and pending images, and
53
+ # Infinity test will work on these names in the notification framework
54
+ #
55
+ def show_images(options={})
56
+ switch_mode!(options[:mode]) if options[:mode]
57
+ @sucess_image = setting_image(options[:sucess]) || search_image(@sucess_image)
58
+ @failure_image = setting_image(options[:failure]) || search_image(@failure_image)
59
+ @pending_image = setting_image(options[:pending]) || search_image(@pending_image)
60
+ end
61
+
62
+ # Switch the image directory to show
63
+ #
64
+ def switch_mode!(mode)
65
+ case mode
66
+ when Symbol
67
+ @default_dir_image = File.join(IMAGES_DIR, mode.to_s)
68
+ when String
69
+ @default_dir_image = File.expand_path(File.join(mode))
70
+ end
71
+ end
72
+
73
+ def setting_image(image)
74
+ image unless image.equal?(:default)
75
+ end
76
+
77
+ # Search the sucess, failure or pending images and return the first in the pattern
78
+ #
79
+ def search_image(file)
80
+ Dir.glob(File.join(@default_dir_image, file) + '*').first
81
+ end
82
+
83
+ # The options method to set:
84
+ #
85
+ # * test framework
86
+ # * ruby versions
87
+ #
88
+ # Here is the example of Little Domain Language:
89
+ #
90
+ # use :rubies => ['1.9.1', '1.9.2'], :test_framework => :rspec
91
+ #
92
+ # use :rubies => [ '1.8.7-p249', '1.9.2@rails3'], :test_framework => :test_unit
93
+ #
94
+ def use(options={})
95
+ rubies = options[:rubies]
96
+ @rubies = (rubies.is_a?(Array) ? rubies.join(',') : rubies) || []
97
+ @test_framework = options[:test_framework] || @test_framework
98
+ @verbose = options[:verbose] || @verbose
99
+ if options[:gemset]
100
+ @rubies = @rubies.split(',').collect { |ruby| ruby << "@#{options[:gemset]}" }.join(',')
101
+ end
102
+ end
103
+
104
+ # Method to use to ignore some dir/files changes
105
+ #
106
+ # Example:
107
+ #
108
+ # ignore :exceptions => %w(.svn .hg .git vendor tmp config rerun.txt)
109
+ #
110
+ # This is useless right now in the Infinity Test because the library
111
+ # only monitoring lib and test/spec/feature folder.
112
+ #
113
+ def ignore(options={})
114
+ @exceptions_to_ignore = options[:exceptions] || []
115
+ end
116
+
117
+ # Callback method to run anything you want, before the run the test suite command
118
+ #
119
+ # Example:
120
+ #
121
+ # before_run do
122
+ # clear :terminal
123
+ # end
124
+ #
125
+ def before_run(&block)
126
+ @before_callback = block
127
+ end
128
+
129
+ # Callback method to run anything you want, after the run the test suite command
130
+ #
131
+ # Example:
132
+ #
133
+ # after_run do
134
+ # # some code that I want to run after all the rubies run
135
+ # end
136
+ #
137
+ def after_run(&block)
138
+ @after_callback = block
139
+ end
140
+
141
+ # Clear the terminal (Useful in the before callback)
142
+ #
143
+ def clear(option)
144
+ system('clear') if option == :terminal
145
+ end
146
+
147
+ end
148
+ end
149
+
150
+ class NotificationFrameworkDontSupported < StandardError
151
+ end
152
+
153
+ def infinity_test(&block)
154
+ configuration = InfinityTest.configuration
155
+ configuration.instance_eval(&block)
156
+ configuration
157
+ end
@@ -0,0 +1,62 @@
1
+ module InfinityTest
2
+ class ContinuousTesting
3
+ attr_accessor :application, :global_commands
4
+
5
+ def initialize(options)
6
+ @application = options[:application]
7
+ @global_commands = @application.construct_commands
8
+ end
9
+
10
+ # Start the Continuous Testing Server and begin to audit the files for changes
11
+ #
12
+ def start!
13
+ run!(@global_commands)
14
+ initialize_watchr!
15
+ end
16
+
17
+ def run!(commands)
18
+ @application.run!(commands) unless commands.empty?
19
+ end
20
+
21
+ ##################
22
+ # Watchr Methods #
23
+ #################
24
+
25
+ def initialize_watchr!
26
+ script = Watchr::Script.new
27
+ # add_rule script, :rule => @application.library_directory_pattern
28
+ watch_lib_folder(script, @application.library_directory_pattern)
29
+ add_rule script, :rule => @application.test_directory_pattern
30
+ add_signal
31
+ Watchr::Controller.new(script, Watchr.handler.new).run
32
+ end
33
+
34
+ def watch_lib_folder(script, library_directory_pattern)
35
+ script.watch(library_directory_pattern) do |file|
36
+ @application.run_changed_lib_file(file)
37
+ end
38
+ end
39
+
40
+ def add_rule(script, options={})
41
+ script.watch(options[:rule]) do |file|
42
+ @application.run_changed_test_file(file)
43
+ end
44
+ end
45
+
46
+ def add_signal
47
+ Signal.trap 'INT' do
48
+ if @sent_an_int then
49
+ puts " Shutting down now"
50
+ exit
51
+ else
52
+ puts " Interrupt a second time to quit"
53
+ @sent_an_int = true
54
+ Kernel.sleep 1.1
55
+ run! @global_commands
56
+ @sent_an_int = false
57
+ end
58
+ end
59
+ end
60
+
61
+ end
62
+ end