guard-phpunit2 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 25e1c7f4051f51755b045436eacfd314d3d3c561
4
+ data.tar.gz: ff726d26e443aed564382611d7b730be0e62d15e
5
+ SHA512:
6
+ metadata.gz: 40c41dff5824407ca8bd0dc31c2566da9a2fa23ed4933a2c51f885026d1a846c37affafa9460c37200c3235fc66791bf6334db8fe730d8c93f04b7ab919f9f79
7
+ data.tar.gz: 4eccfb676173ae0b94d5a16af0fc264df88f080969578c79e52d434ee8b383e70d785a6fe2680ec7f8db9c391f741b495b2e4bf0e281d48daee2b5d99622af5f
data/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ ## 0.1.4 - August 09, 2012
2
+
3
+ - [#2][]: Add support for Windows.
4
+
5
+ ## 0.1.3 - June 15, 2012
6
+
7
+ - [#3][]: Support Guard v1.1 API.
8
+
9
+ ## 0.1.2 - January 26, 2012
10
+
11
+ - Fix checking phpunit existence on zsh.
12
+ - Update Guard to it's first gold release.
13
+ - Small bug fixes.
14
+
15
+ ## 0.1.1 - January 03, 2012
16
+
17
+ - Update gem dependencies.
18
+ - Small bug fixes.
19
+
20
+ ## 0.1.0 - November 30, 2011
21
+
22
+ - Add detection for phpunit existence.
23
+ - Add the `:keep_failed` option.
24
+ - Add the `:all_after_pass` option.
25
+ - Refactor a portion of the code and small bug fixes.
26
+
27
+ ## 0.0.2 - 0.0.3 - November 25, 2011
28
+
29
+ - Small bug fixes.
30
+
31
+ ## 0.0.1 - November 24, 2011
32
+
33
+ - Initial release.
34
+
35
+ <!--- The following link definition list is generated by PimpMyChangelog --->
36
+ [#2]: https://github.com/Maher4Ever/guard-phpunit/issues/2
37
+ [#3]: https://github.com/Maher4Ever/guard-phpunit/issues/3
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2011 by Maher Sallam
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,106 @@
1
+ Guard::PHPUnit [![Build Status](https://secure.travis-ci.org/Maher4Ever/guard-phpunit.png)](http://travis-ci.org/Maher4Ever/guard-phpunit) [![Dependency Status](https://gemnasium.com/Maher4Ever/guard-phpunit.png?branch=master)](https://gemnasium.com/Maher4Ever/guard-phpunit)
2
+ ==============
3
+
4
+ Guard-phpunit allows you to automatically run [PHPUnit][6] tests when sources
5
+ are modified. It helps with integrating test-driven development (TDD) into
6
+ your development process: Just launch guard-phpunit before you start working
7
+ and it will notify you about the status of your tests!
8
+
9
+ *Note*: Although guard-phpunit should work with any [PHP][7] version [PHPUnit][6] supports,
10
+ it has only been tested on [PHP][7] 5.3.8 and 5.4.4.
11
+
12
+ Install
13
+ -------
14
+
15
+ Please be sure to have [PHP][7], [PHPUnit][6] and [Ruby][1] installed on your machine before
16
+ you proceed with the installation.
17
+
18
+ The latest versions of [Ruby][1] come with a packages-manager called `gem`. `gem` can be used to
19
+ install various packages, including guard-phpunit.
20
+
21
+ To install guard-phpunit, run the following command in the terminal:
22
+
23
+ ```shell
24
+ $ gem install guard-phpunit
25
+ ```
26
+
27
+ Usage
28
+ -----
29
+
30
+ Please read the [Guard usage documentation][3].
31
+
32
+ Guardfile
33
+ ---------
34
+
35
+ Guard-phpunit can be used with any kind of [PHP][7] projects that uses PHPUnit as
36
+ its testing framwork. Please read the [Guard documentation][3] for more information
37
+ about the Guardfile DSL.
38
+
39
+ By default, guard-phpunit will use the current working directory (pwd) to
40
+ search for tests and run them on start (if you enabled the `:all_on_start` option).
41
+
42
+ ### Example PHP project
43
+
44
+ The [PHPUnit documentaion][4] uses the [Object Freezer][5] library as an example on how
45
+ to organize tests. This project uses the `Tests` directory for its tests.
46
+
47
+ An example of the Guardfile for the same project would look
48
+ something like:
49
+
50
+ ```ruby
51
+ guard 'phpunit', :tests_path => 'Tests', :cli => '--colors' do
52
+ # Watch tests files
53
+ watch(%r{^.+Test\.php$})
54
+
55
+ # Watch library files and run their tests
56
+ watch(%r{^Object/(.+)\.php}) { |m| "Tests/#{m[1]}Test.php" }
57
+ end
58
+ ```
59
+
60
+ Options
61
+ -------
62
+
63
+ The following options can be passed to Guard::PHPUnit:
64
+
65
+ ```ruby
66
+ :all_on_start => false # Run all tests on startup.
67
+ # default: true
68
+
69
+ :all_after_pass => false # Run all tests after changed tests pass. This ensures
70
+ # that the process of making changed tests pass didn't
71
+ # break something else.
72
+ # default: true
73
+
74
+ :keep_failed => false # Remember failed tests and keep running them with
75
+ # each change until they pass.
76
+ # default: true
77
+
78
+ :tests_path => 'tests' # Relative path to the tests directory. This path
79
+ # is used when running all the tests.
80
+ # default: the current working directory (pwd)
81
+
82
+ :cli => '--colors' # The options passed to the phpunit command
83
+ # when running the tests.
84
+ # default: nil
85
+ ```
86
+
87
+ Development
88
+ -----------
89
+
90
+ * Source hosted at [GitHub](https://github.com/Maher4Ever/guard-phpunit)
91
+ * Report issues/Questions/Feature requests on [GitHub Issues](https://github.com/Maher4Ever/guard-phpunit/issues)
92
+
93
+ Pull requests are very welcome! Make sure your patches are well tested. Please create a topic branch for every separate change
94
+ you make.
95
+
96
+ Author
97
+ ------
98
+
99
+ [Maher Sallam](https://github.com/Maher4Ever)
100
+
101
+ [1]:http://ruby-lang.org
102
+ [3]:https://github.com/guard/guard#readme
103
+ [4]:http://www.phpunit.de/manual/current/en/
104
+ [5]:https://github.com/sebastianbergmann/php-object-freezer/
105
+ [6]:http://www.phpunit.de
106
+ [7]:http://php.net
@@ -0,0 +1,64 @@
1
+ module Guard
2
+ class PHPUnit2
3
+
4
+ # The Guard::PHPUnit formatter parses the output
5
+ # of phpunit which gets printed by the progress
6
+ # printer.
7
+ #
8
+ module Formatter
9
+ class << self
10
+
11
+ # Parses the tests output.
12
+ #
13
+ # @param [String] text the output of phpunit.
14
+ # @return [Hash] the parsed results
15
+ #
16
+ def parse_output(text)
17
+ results = {
18
+ :tests => look_for_words_in('test', text),
19
+ :failures => look_for_words_in('failure', text),
20
+ :errors => look_for_words_in('error', text),
21
+ :pending => look_for_words_in(['skipped', 'incomplete'], text),
22
+ :duration => look_for_duration_in(text)
23
+ }
24
+ results.freeze
25
+ end
26
+
27
+ private
28
+
29
+ # Searches for a list of strings in the tests output
30
+ # and returns the total number assigned to these strings.
31
+ #
32
+ # @param [String, Array<String>] string_list the words
33
+ # @param [String] text the tests output
34
+ # @return [Integer] the total number assigned to the words
35
+ #
36
+ def look_for_words_in(strings_list, text)
37
+ count = 0
38
+ strings_list = Array(strings_list)
39
+ strings_list.each do |s|
40
+ text =~ %r{
41
+ (\d+) # count of what we are looking for
42
+ [ ] # then a space
43
+ #{s}s? # then the string
44
+ .* # then whatever
45
+ \Z # start looking at the end of the text
46
+ }x
47
+ count += $1.to_i unless $1.nil?
48
+ end
49
+ count
50
+ end
51
+
52
+ # Searches for the duration in the tests output
53
+ #
54
+ # @param [String] text the tests output
55
+ # @return [Integer] the duration
56
+ #
57
+ def look_for_duration_in(text)
58
+ text =~ %r{Finished in (\d)+ seconds?.*\Z}m
59
+ $1.nil? ? 0 : $1.to_i
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,54 @@
1
+ module Guard
2
+ class PHPUnit2
3
+
4
+ # The Guard::PHPUnit inspector verfies that the changed paths
5
+ # are valid for Guard::PHPUnit.
6
+ #
7
+ module Inspector
8
+ class << self
9
+
10
+ attr_accessor :tests_path
11
+
12
+ # Clean the changed paths and return only valid
13
+ # PHPUnit tests files.
14
+ #
15
+ # @param [Array<String>] paths the changed paths
16
+ # @return [Array<String>] the valid tests files
17
+ #
18
+ def clean(paths)
19
+ paths.uniq!
20
+ paths.compact!
21
+ paths = paths.select { |p| test_file?(p) }
22
+ clear_tests_files_list
23
+ paths
24
+ end
25
+
26
+ private
27
+
28
+ # Checks if the paths is a valid test file.
29
+ #
30
+ # @param [String] path the test path
31
+ # @return [Boolean] whether the path a valid test or not
32
+ #
33
+ def test_file?(path)
34
+ tests_files.include?(path)
35
+ end
36
+
37
+ # Scans the tests path and keeps a list of all
38
+ # tests paths.
39
+ #
40
+ def tests_files
41
+ @tests_files ||= Dir.glob( File.join(tests_path, '**', '*Test.php') )
42
+ end
43
+
44
+ # Clears the list of PHPUnit tests.
45
+ #
46
+ # @see #clean
47
+ #
48
+ def clear_tests_files_list
49
+ @tests_files = nil
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,68 @@
1
+ module Guard
2
+ class PHPUnit2
3
+
4
+ # The Guard::PHPUnit notifier displays a notification pop-up
5
+ # with the tests results.
6
+ #
7
+ module Notifier
8
+ class << self
9
+
10
+ # Displays a system notification.
11
+ #
12
+ # @param [String] message the message to show
13
+ # @param [Hash] options the notifier options
14
+ #
15
+ def notify(message, options)
16
+ ::Guard::Notifier.notify(message, options)
17
+ end
18
+
19
+ # Displays a notification about the tests results.
20
+ #
21
+ # @param [Hash] test_results the parsed tests results
22
+ # @option test_results [Integer] :tests tests count
23
+ # @option test_results [Integer] :failures failures count
24
+ # @option test_results [Integer] :errors count count
25
+ # @option test_results [Integer] :pending pending tests count
26
+ # @option test_results [Integer] :duration tests duration
27
+ #
28
+ def notify_results(test_results)
29
+ notify(message(test_results), {
30
+ :title => 'PHPUnit results',
31
+ :image => image(test_results)
32
+ })
33
+ end
34
+
35
+ private
36
+
37
+ # Formats the message for the tests results notifier.
38
+ #
39
+ # @param (see .notify)
40
+ # @return [String] the message
41
+ #
42
+ def message(results)
43
+ message = "#{results[:tests]} tests, #{results[:failures]} failures"
44
+ message << "\n#{results[:errors]} errors" if results[:errors] > 0
45
+ message << " (#{results[:pending]} pending)" if results[:pending] > 0
46
+ message << "\nin #{results[:duration]} seconds"
47
+ message
48
+ end
49
+
50
+ # Returns the appropriate image for the tests results.
51
+ #
52
+ # @param (see .notify)
53
+ # @return [Symbol] the image symbol
54
+ #
55
+ def image(results)
56
+ case
57
+ when results[:failures] + results[:errors] > 0
58
+ :failed
59
+ when results[:pending] > 0
60
+ :pending
61
+ else
62
+ :success
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,193 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+
4
+ module Guard
5
+ class PHPUnit2
6
+
7
+ # The Guard::PHPUnit runner handles running the tests, displaying
8
+ # their output and notifying the user about the results.
9
+ #
10
+ module Runner
11
+ class << self
12
+
13
+ # The exittcode phpunit returns when the tests contain failures
14
+ #
15
+ PHPUNIT_FAILURES_EXITCODE = 1
16
+
17
+ # The exittcode phpunit returns when the tests contain errors
18
+ #
19
+ PHPUNIT_ERRORS_EXITCODE = 2
20
+
21
+ # Runs the PHPUnit tests and displays notifications
22
+ # about the results.
23
+ #
24
+ # @param [Array<Strings>] path to the tests files.
25
+ # @param (see PHPUnit#initialize)
26
+ # @return [Boolean] whether the tests were run successfully
27
+ #
28
+ def run(paths, options = {})
29
+ paths = Array(paths)
30
+
31
+ return false if paths.empty?
32
+
33
+ unless phpunit_exists?
34
+ UI.error('phpunit is not installed on your machine.', :reset => true)
35
+ return false
36
+ end
37
+
38
+ run_tests(paths, options)
39
+ end
40
+
41
+ private
42
+
43
+ # Checks that phpunit is installed on the user's
44
+ # machine.
45
+ #
46
+ # @return [Boolean] The status of phpunit
47
+ #
48
+ def phpunit_exists?
49
+ `phpunit --version`
50
+ true
51
+ rescue Errno::ENOENT
52
+ false
53
+ end
54
+
55
+ # Executes the testing command on the tests
56
+ # and returns the status of this process.
57
+ #
58
+ # @param (see #run)
59
+ # @param (see #run)
60
+ #
61
+ def run_tests(paths, options)
62
+
63
+ notify_start(paths, options)
64
+
65
+ if paths.length == 1
66
+ tests_path = paths.first
67
+ output = execute_command phpunit_command(tests_path, options)
68
+ else
69
+ create_tests_folder_for(paths) do |tests_folder|
70
+ output = execute_command phpunit_command(tests_folder, options)
71
+ end
72
+ end
73
+
74
+ # print the output to the terminal
75
+ UI.info output
76
+
77
+ # return false in case the system call fails with no status!
78
+ return false if $?.nil?
79
+
80
+ if $?.success? or tests_contain_failures? or tests_contain_errors?
81
+ notify_results(output, options)
82
+ else
83
+ notify_failure(options)
84
+ end
85
+
86
+ $?.success?
87
+ end
88
+
89
+ # Displays the start testing notification.
90
+ #
91
+ # @param (see #run)
92
+ # @param (see #run)
93
+ #
94
+ def notify_start(paths, options)
95
+ message = options[:message] || "Running: #{paths.join(' ')}"
96
+ UI.info(message, :reset => true)
97
+ end
98
+
99
+ # Displays a notification about the tests results.
100
+ #
101
+ # @param [String] output the tests output
102
+ # @param (see #run)
103
+ #
104
+ def notify_results(output, options)
105
+ return if options[:notification] == false
106
+ results = Formatter.parse_output(output)
107
+ Notifier.notify_results(results)
108
+ end
109
+
110
+ # Displays a notification about failing to run the tests
111
+ #
112
+ # @param (see #run)
113
+ #
114
+ def notify_failure(options)
115
+ return if options[:notification] == false
116
+ Notifier.notify('Failed! Check the console', :title => 'PHPUnit results', :image => :failed)
117
+ end
118
+
119
+ # Checks the exitstatus of the phpunit command
120
+ # for a sign of failures in the tests.
121
+ #
122
+ # @return [Boolean] whether the tests contain failures or not
123
+ #
124
+ def tests_contain_failures?
125
+ $?.exitstatus == PHPUNIT_FAILURES_EXITCODE
126
+ end
127
+
128
+ # Checks the exitstatus of the phpunit command
129
+ # for a sign of errors in the tests.
130
+ #
131
+ # @return [Boolean] whether the tests contain errors or not
132
+ #
133
+ def tests_contain_errors?
134
+ $?.exitstatus == PHPUNIT_ERRORS_EXITCODE
135
+ end
136
+
137
+ # Creates a temporary folder which has links to
138
+ # the tests paths. This method is used because PHPUnit
139
+ # can't run multiple tests files at the same time and generate
140
+ # one result for them.
141
+ #
142
+ # @param (see #run)
143
+ # @yield [String] d the temporary dir for the tests
144
+ #
145
+ def create_tests_folder_for(paths)
146
+ Dir.mktmpdir('guard_phpunit') do |d|
147
+ symlink_paths_to_tests_folder(paths, d)
148
+ yield d
149
+ end
150
+ end
151
+
152
+ # Creates symbolic links inside the folder pointing
153
+ # back to the paths.
154
+ #
155
+ # @see #create_tests_folder_for
156
+ #
157
+ # @param (see #run)
158
+ # @param [String] the folder in which the links must be made
159
+ #
160
+ def symlink_paths_to_tests_folder(paths, folder)
161
+ paths.each do |p|
162
+ FileUtils.mkdir_p( File.join(folder, File.dirname(p) ) ) unless File.dirname(p) == '.'
163
+ FileUtils.ln_s(Pathname.new(p).realpath, File.join(folder, p))
164
+ end
165
+ end
166
+
167
+ # Generates the phpunit command for the tests paths.
168
+ #
169
+ # @param (see #run)
170
+ # @param (see #run)
171
+ # @see #run_tests
172
+ #
173
+ def phpunit_command(path, options)
174
+ cmd_parts = []
175
+ cmd_parts << "phpunit"
176
+ cmd_parts << options[:cli] if options[:cli]
177
+ cmd_parts << path
178
+
179
+ cmd_parts.join(' ')
180
+ end
181
+
182
+ # Executes a system command and returns the output.
183
+ #
184
+ # @param [String] command the command to be run
185
+ # @return [String] the output of the executed command
186
+ #
187
+ def execute_command(command)
188
+ %x{#{command}}
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,3 @@
1
+ guard 'phpunit2', :cli => '--colors' do
2
+ watch(%r{^.+Test\.php$})
3
+ end
@@ -0,0 +1,5 @@
1
+ module Guard
2
+ module PHPUnit2
3
+ VERSION = '0.2.1'
4
+ end
5
+ end
@@ -0,0 +1,112 @@
1
+ require 'guard'
2
+ require 'guard/guard'
3
+
4
+ module Guard
5
+
6
+ # The PHPUnit guard gets notified about system
7
+ # events.
8
+ #
9
+ class PHPUnit2 < Guard
10
+
11
+ autoload :Inspector, 'guard/phpunit2/inspector'
12
+ autoload :Formatter, 'guard/phpunit2/formatter'
13
+ autoload :Notifier, 'guard/phpunit2/notifier'
14
+ autoload :Runner, 'guard/phpunit2/runner'
15
+
16
+ DEFAULT_OPTIONS = {
17
+ :all_on_start => true,
18
+ :all_after_pass => true,
19
+ :keep_failed => true,
20
+ :cli => nil,
21
+ :tests_path => Dir.pwd
22
+ }
23
+
24
+ # Initialize Guard::PHPUnit.
25
+ #
26
+ # @param [Array<Guard::Watcher>] watchers the watchers in the Guard block
27
+ # @param [Hash] options the options for the Guard
28
+ # @option options [Boolean] :all_on_start run all tests on start
29
+ # @option options [Boolean] :all_after_pass run all tests after failed tests pass
30
+ # @option options [Boolean] :keep_failed remember failed tests or not
31
+ # @option options [String] :cli The CLI arguments passed to phpunit
32
+ # @option options [String] :tests_path the path where all tests exist
33
+ #
34
+ def initialize(watchers = [], options = {})
35
+ defaults = DEFAULT_OPTIONS.clone
36
+ @options = defaults.merge(options)
37
+ super(watchers, @options)
38
+
39
+ @failed_paths = []
40
+ @previous_failed = false
41
+
42
+ Inspector.tests_path = @options[:tests_path]
43
+ end
44
+
45
+ # Gets called once when Guard starts.
46
+ #
47
+ # @raise [:task_has_failed] when stop has failed
48
+ #
49
+ def start
50
+ run_all if options[:all_on_start]
51
+ end
52
+
53
+ # Gets called when all tests should be run.
54
+ #
55
+ # @raise (see #start)
56
+ #
57
+ def run_all
58
+ success = Runner.run(options[:tests_path], options.merge(
59
+ :message => 'Running all tests'
60
+ ))
61
+
62
+ @previous_failed = !success
63
+ throw :task_has_failed unless success
64
+ end
65
+
66
+ # Gets called when the watched tests have changes.
67
+ #
68
+ # @param [Array<String>] paths to the changed tests
69
+ # @raise (see #start)
70
+ #
71
+ def run_on_changes(paths)
72
+ paths = Inspector.clean(paths + @failed_paths)
73
+ success = Runner.run(paths, options)
74
+
75
+ update_failed_paths(success, paths)
76
+ run_all_after_pass(success)
77
+ throw :task_has_failed unless success
78
+ end
79
+
80
+ private
81
+
82
+ # Adds or removes path to the failed_paths bassed
83
+ # on the tests result.
84
+ #
85
+ # @param [Boolean] tests_passed whether the tests passed or not
86
+ # @param [Array<String>] paths the tests paths
87
+ #
88
+ def update_failed_paths(tests_passed, paths)
89
+ return unless @options[:keep_failed]
90
+
91
+ if tests_passed
92
+ @failed_paths -= paths
93
+ else
94
+ @failed_paths += paths
95
+ end
96
+ end
97
+
98
+ # Runs all tests after the failed tests pass.
99
+ #
100
+ # @param (see .update_failed_paths)
101
+ #
102
+ def run_all_after_pass(tests_passed)
103
+ return unless @options[:all_after_pass]
104
+
105
+ if tests_passed
106
+ run_all if @previous_failed
107
+ else
108
+ @previous_failed = true
109
+ end
110
+ end
111
+ end
112
+ end
File without changes
@@ -0,0 +1,11 @@
1
+ E
2
+
3
+ Errors:
4
+
5
+ 1) NumberTest::testMathStillWorks
6
+ NumberException: Division by zero!
7
+ # /home/maher/Projects/php/PHPUnit-Progress/Tests/_files/Number.php:61
8
+ # /home/maher/Projects/php/PHPUnit-Progress/Tests/_files/NumberTest.php:81
9
+
10
+ Finished in 0 seconds
11
+ 1 test, 0 assertions, 1 errors