guard-unity 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +99 -0
- data/Rakefile +6 -0
- data/guard-unity-test.sublime-workspace +455 -0
- data/guard-unity.gemspec +29 -0
- data/lib/guard/unity.rb +45 -0
- data/lib/guard/unity/notifier.rb +24 -0
- data/lib/guard/unity/notifier/alert.rb +35 -0
- data/lib/guard/unity/notifier/cli.rb +79 -0
- data/lib/guard/unity/options.rb +26 -0
- data/lib/guard/unity/parser.rb +64 -0
- data/lib/guard/unity/runner.rb +45 -0
- data/lib/guard/unity/templates/Guardfile +3 -0
- data/lib/guard/unity/version.rb +5 -0
- data/spec/fixtures/UnitTestResults.xml +32 -0
- data/spec/guard/unity-test/notifier/alert_spec.rb +44 -0
- data/spec/guard/unity-test/notifier/cli_spec.rb +25 -0
- data/spec/guard/unity-test/notifier_spec.rb +25 -0
- data/spec/guard/unity-test/options_spec.rb +17 -0
- data/spec/guard/unity-test/parser_spec.rb +17 -0
- data/spec/guard/unity-test/runner_spec.rb +38 -0
- data/spec/guard/unity_test_spec.rb +110 -0
- data/spec/spec_helper.rb +24 -0
- metadata +192 -0
data/guard-unity.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'guard/unity/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'guard-unity'
|
8
|
+
spec.version = Guard::UnityVersion::VERSION
|
9
|
+
spec.authors = ['Thomas Muntaner']
|
10
|
+
spec.email = ['thomas.muntaner@gmail.com']
|
11
|
+
spec.description = %q{Guard gem for Unity3D Test Tools}
|
12
|
+
spec.summary = %q{guard-unity automatically runs Unity Test Tools on file changes}
|
13
|
+
spec.homepage = 'https://github.com/rubyrainbows/guard-unity-test'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_dependency 'guard', '~> 2.0'
|
21
|
+
spec.add_dependency 'nokogiri', '~> 1.6'
|
22
|
+
spec.add_dependency 'formatador', '~> 0.2'
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.1'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 2.14'
|
27
|
+
spec.add_development_dependency 'rspec-core', '~> 2.14'
|
28
|
+
spec.add_development_dependency 'rspec-mocks', '~> 2.14'
|
29
|
+
end
|
data/lib/guard/unity.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'guard'
|
2
|
+
require 'guard/plugin'
|
3
|
+
|
4
|
+
module Guard
|
5
|
+
class Unity < Plugin
|
6
|
+
|
7
|
+
require 'guard/unity/runner'
|
8
|
+
require 'guard/unity/options'
|
9
|
+
|
10
|
+
attr_accessor :runner, :options
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
super
|
14
|
+
@options = Options.with_defaults(options)
|
15
|
+
@runner = Runner.new(@options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def start
|
19
|
+
_show_start_message
|
20
|
+
puts runner.run if _should_test_on_start?
|
21
|
+
end
|
22
|
+
|
23
|
+
def run_on_modifications(paths)
|
24
|
+
puts runner.run
|
25
|
+
end
|
26
|
+
|
27
|
+
def reload
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_all
|
31
|
+
puts runner.run
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def _show_start_message
|
37
|
+
::Guard::UI::info 'Guard::Unity is running'
|
38
|
+
end
|
39
|
+
|
40
|
+
def _should_test_on_start?
|
41
|
+
options[:test_on_start]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Guard
|
2
|
+
class Unity
|
3
|
+
class Notifier
|
4
|
+
|
5
|
+
require 'guard/unity/notifier/alert'
|
6
|
+
require 'guard/unity/notifier/cli'
|
7
|
+
|
8
|
+
TITLE = 'Unity Tests Results'
|
9
|
+
|
10
|
+
attr_accessor :alert, :cli
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@alert = options[:alert] || Guard::Unity::Notifier::Alert.new
|
14
|
+
@cli = options[:cli] || Guard::Unity::Notifier::CLI.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def notify(results)
|
18
|
+
alert.notify(results, TITLE)
|
19
|
+
cli.notify(results)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Guard
|
2
|
+
class Unity
|
3
|
+
class Notifier
|
4
|
+
class Alert
|
5
|
+
|
6
|
+
def notify(results, title)
|
7
|
+
image = _image(results)
|
8
|
+
message = _message(results)
|
9
|
+
::Guard::Notifier::notify(message, {title: title, image: image})
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def _image(results)
|
15
|
+
return :failed if results[:failures] > 0
|
16
|
+
return :failed if results[:errors] > 0
|
17
|
+
:success
|
18
|
+
end
|
19
|
+
|
20
|
+
def _message(results)
|
21
|
+
message = "#{results[:tests]} tests\n"
|
22
|
+
message << "#{results[:failures]} failures\n" if results[:failures]
|
23
|
+
message << "#{results[:errors]} errors\n" if results[:errors]
|
24
|
+
message << "#{results[:ignored]} ignored\n" if results[:ignored]
|
25
|
+
message << "#{results[:skipped]} skipped\n" if results[:skipped]
|
26
|
+
message << "#{results[:inconclusive]} inconclusive\n" if results[:inconclusive]
|
27
|
+
message << "#{results[:invalid]} invalid\n" if results[:invalid]
|
28
|
+
message << "#{results[:not_run]} not run\n" if results[:not_run]
|
29
|
+
message
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Guard
|
2
|
+
class Unity
|
3
|
+
class Notifier
|
4
|
+
class CLI
|
5
|
+
|
6
|
+
require 'formatador'
|
7
|
+
|
8
|
+
attr_accessor :formatador
|
9
|
+
|
10
|
+
SEPARATOR = '-'*100
|
11
|
+
|
12
|
+
def initialize(options={})
|
13
|
+
@formatador = options[:formatador] || Formatador.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def notify(results={})
|
17
|
+
cases = results[:test_cases] || []
|
18
|
+
table = []
|
19
|
+
errors = []
|
20
|
+
|
21
|
+
cases.each do |test_case|
|
22
|
+
table << _row(test_case)
|
23
|
+
errors << _error(test_case) if test_case[:failed]
|
24
|
+
end
|
25
|
+
_display_results results
|
26
|
+
_display_table table
|
27
|
+
_display_errors errors
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def _display_results(results)
|
33
|
+
table = [{
|
34
|
+
'Tests' => results[:tests],
|
35
|
+
'Failures' => results[:failures],
|
36
|
+
'Errors' => results[:errors],
|
37
|
+
'Ignored' => results[:ignored],
|
38
|
+
'Skipped' => results[:skipped],
|
39
|
+
'Inconclusive' => results[:inconclusive],
|
40
|
+
'Invalid' => results[:invalid],
|
41
|
+
'Not Run' => results[:not_run]
|
42
|
+
}]
|
43
|
+
formatador.display_table table, ['Tests', 'Failures', 'Errors', 'Ignored', 'Skipped', 'Inconclusive', 'Invalid', 'Not Run']
|
44
|
+
formatador.display_line
|
45
|
+
end
|
46
|
+
|
47
|
+
def _display_table(table)
|
48
|
+
formatador.display_table table
|
49
|
+
end
|
50
|
+
|
51
|
+
def _display_errors(errors)
|
52
|
+
formatador.display_line
|
53
|
+
formatador.display_line SEPARATOR
|
54
|
+
formatador.display_line "| [red]Failures[/]"
|
55
|
+
formatador.display_line SEPARATOR
|
56
|
+
count = 1
|
57
|
+
errors.each do |error|
|
58
|
+
formatador.display_line
|
59
|
+
formatador.display_line "#{count}: #{error[:name]}:\n"
|
60
|
+
formatador.display_line "[red]#{error[:message]}[/]\n" unless error[:message] == ""
|
61
|
+
formatador.display_line "[red]#{error[:stack]}[/]\n" unless error[:stack] == ""
|
62
|
+
formatador.display_line SEPARATOR
|
63
|
+
count = count + 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def _row(test_case)
|
68
|
+
success = (test_case[:failed]) ? '[red]Failed[/]' : '[green]Success[/]'
|
69
|
+
{name: test_case[:name], success: success}
|
70
|
+
end
|
71
|
+
|
72
|
+
def _error(test_case)
|
73
|
+
{name: test_case[:name], message: test_case[:message], stack: test_case[:stack]}
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Guard
|
2
|
+
class Unity
|
3
|
+
module Options
|
4
|
+
|
5
|
+
DEFAULTS = {
|
6
|
+
test_on_start: true,
|
7
|
+
project_path: Dir.pwd,
|
8
|
+
unity: '/Applications/Unity/Unity.app/Contents/MacOS/Unity',
|
9
|
+
results_path: Dir.pwd + '/UnitTestResults.xml'
|
10
|
+
}
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def with_defaults(options={})
|
14
|
+
opts = DEFAULTS.merge(options)
|
15
|
+
opts[:project_path] = clean_directory(opts[:project_path]) # needs to be formatted for cli
|
16
|
+
opts
|
17
|
+
end
|
18
|
+
|
19
|
+
def clean_directory(dir)
|
20
|
+
dir.gsub(' ', '\ ')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Guard
|
2
|
+
class Unity
|
3
|
+
class Parser
|
4
|
+
|
5
|
+
require 'nokogiri'
|
6
|
+
|
7
|
+
attr_accessor :options, :doc
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
@options = options
|
11
|
+
@doc = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse()
|
15
|
+
{
|
16
|
+
tests: _get('total'),
|
17
|
+
failures: _get('failures'),
|
18
|
+
errors: _get('errors'),
|
19
|
+
ignored: _get('ignored'),
|
20
|
+
not_run: _get('not-run'),
|
21
|
+
inconclusive: _get('inconclusive'),
|
22
|
+
invalid: _get('invalid'),
|
23
|
+
skipped: _get('skipped'),
|
24
|
+
test_cases: _testCases
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def _get (find)
|
31
|
+
doc ||= _getXMLFile
|
32
|
+
node = doc.at_xpath("/test-results/@" + find)
|
33
|
+
(node == nil) ? 0 : node.value.to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
def _testCases()
|
37
|
+
doc ||= _getXMLFile
|
38
|
+
nodes = doc.xpath("test-results/test-suite/results/test-case")
|
39
|
+
cases = []
|
40
|
+
|
41
|
+
nodes.each do |node|
|
42
|
+
message = node.at_xpath('failure/message') || node.at_xpath('reason/message')
|
43
|
+
stack = node.at_xpath('failure/stack-trace') || node.at_xpath('reason/stack-trace')
|
44
|
+
cases << {
|
45
|
+
name: node['name'],
|
46
|
+
failed: (node['success'] == 'False') ? true : false,
|
47
|
+
message: (message) ? message.text.gsub("\n",'').strip : "",
|
48
|
+
stack: (stack) ? stack.text.gsub("\n",'').strip : ""
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
cases
|
53
|
+
end
|
54
|
+
|
55
|
+
def _getXMLFile()
|
56
|
+
f = File.open(options[:results_path])
|
57
|
+
doc = Nokogiri::XML(f)
|
58
|
+
f.close
|
59
|
+
doc
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Guard
|
2
|
+
class Unity
|
3
|
+
class Runner
|
4
|
+
|
5
|
+
require 'guard/unity/parser'
|
6
|
+
require 'guard/unity/notifier'
|
7
|
+
|
8
|
+
attr_accessor :options, :parser, :notifier
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@options = options
|
12
|
+
@parser = options[:parser] || Guard::Unity::Parser.new(options)
|
13
|
+
@notifier = options[:notifier] || Guard::Unity::Notifier.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
_run
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def _run
|
23
|
+
UI.info 'Guard::Unity - Starting Tests. Results will be displayed when finished testing.'
|
24
|
+
output = _execute_command _command
|
25
|
+
notifier.notify(parser.parse) if $?.success?
|
26
|
+
output
|
27
|
+
end
|
28
|
+
|
29
|
+
def _command
|
30
|
+
cmd = []
|
31
|
+
|
32
|
+
cmd << options[:unity]
|
33
|
+
cmd << '-projectPath ' + options[:project_path]
|
34
|
+
cmd << '-batchmode -executeMethod UnityTest.UnitTestView.RunAllTestsBatch'
|
35
|
+
|
36
|
+
cmd.join ' '
|
37
|
+
end
|
38
|
+
|
39
|
+
def _execute_command(command)
|
40
|
+
%x{#{command}}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<!--This file represents the results of running a test suite-->
|
3
|
+
<test-results name="Unity Tests" total="21" errors="1" failures="2" not-run="2" inconclusive="4" ignored="1" skipped="1" invalid="0">
|
4
|
+
<environment />
|
5
|
+
<culture-info current-culture="" current-uiculture="" />
|
6
|
+
<test-suite name="Unit Tests" type="Assembly" executed="True" result="Failure" success="False" time="0.400">
|
7
|
+
<results>
|
8
|
+
<test-case name="test 1" executed="True" result="Success" success="True">
|
9
|
+
</test-case>
|
10
|
+
<test-case name="test 2" executed="True" result="Skipped" success="False">
|
11
|
+
<reason>
|
12
|
+
<message>
|
13
|
+
Message
|
14
|
+
</message>
|
15
|
+
<stack-trace>
|
16
|
+
foo
|
17
|
+
</stack-trace>
|
18
|
+
</reason>
|
19
|
+
</test-case>
|
20
|
+
<test-case name="test 3" executed="True" result="Failure" success="False">
|
21
|
+
<failure>
|
22
|
+
<message>
|
23
|
+
Message
|
24
|
+
</message>
|
25
|
+
<stack-trace>
|
26
|
+
foo
|
27
|
+
</stack-trace>
|
28
|
+
</failure>
|
29
|
+
</test-case>
|
30
|
+
</results>
|
31
|
+
</test-suite>
|
32
|
+
</test-results>
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Guard::Unity::Notifier do
|
4
|
+
|
5
|
+
let (:results) {
|
6
|
+
{
|
7
|
+
tests: 100,
|
8
|
+
errors: 0,
|
9
|
+
failures: 0
|
10
|
+
}
|
11
|
+
}
|
12
|
+
let (:subject) { Guard::Unity::Notifier::Alert.new}
|
13
|
+
|
14
|
+
describe '#notify' do
|
15
|
+
|
16
|
+
it 'should give a success message' do
|
17
|
+
@results = results
|
18
|
+
::Guard::Notifier::should_receive(:notify).with(message(@results), {image: :success, title: Guard::Unity::Notifier::TITLE})
|
19
|
+
subject.notify(@results, Guard::Unity::Notifier::TITLE)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should give failed message' do
|
23
|
+
@results = results.merge(failures: 1)
|
24
|
+
::Guard::Notifier::should_receive(:notify).with(message(@results), {image: :failed, title: Guard::Unity::Notifier::TITLE})
|
25
|
+
subject.notify(@results, Guard::Unity::Notifier::TITLE)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should give error message' do
|
29
|
+
@results = results.merge(errors: 1)
|
30
|
+
::Guard::Notifier::should_receive(:notify).with(message(@results), {image: :failed, title: Guard::Unity::Notifier::TITLE})
|
31
|
+
subject.notify(@results, Guard::Unity::Notifier::TITLE)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
# taken from the class to make testing easier
|
37
|
+
def message(results)
|
38
|
+
message = "#{results[:tests]} tests\n"
|
39
|
+
message << "#{results[:failures]} failures\n"
|
40
|
+
message << "#{results[:errors]} errors\n"
|
41
|
+
message
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|