theotokos 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.travis.yml +6 -0
  2. data/Gemfile +5 -0
  3. data/LICENSE +20 -0
  4. data/README.md +16 -0
  5. data/Rakefile +30 -0
  6. data/bin/theotokos +20 -0
  7. data/html/Chart.min.js +10 -0
  8. data/html/bootstrap-collapse.js +167 -0
  9. data/html/bootstrap.min.css +9 -0
  10. data/html/jquery.min.js +2 -0
  11. data/lib/assertion/test_assertion.rb +44 -0
  12. data/lib/config/app_config_params.rb +40 -0
  13. data/lib/config/app_logger.rb +48 -0
  14. data/lib/engine/execution_initializer.rb +115 -0
  15. data/lib/engine/executor.rb +128 -0
  16. data/lib/engine/parser.rb +39 -0
  17. data/lib/engine/soap_executor.rb +101 -0
  18. data/lib/helper/app_helper.rb +99 -0
  19. data/lib/helper/hook_helper.rb +49 -0
  20. data/lib/helper/html_helper.rb +633 -0
  21. data/lib/model/execution.rb +16 -0
  22. data/lib/model/test.rb +79 -0
  23. data/lib/model/test_app_result.rb +91 -0
  24. data/lib/model/test_result.rb +22 -0
  25. data/lib/model/test_status.rb +68 -0
  26. data/lib/model/test_suite.rb +80 -0
  27. data/lib/model/test_suite_result.rb +54 -0
  28. data/lib/model/text_operator.rb +34 -0
  29. data/lib/model/ws_config.rb +48 -0
  30. data/lib/net/soap_net.rb +58 -0
  31. data/lib/report/chart_factory.rb +68 -0
  32. data/lib/report/console.rb +94 -0
  33. data/lib/report/default_locale +64 -0
  34. data/lib/report/html.rb +55 -0
  35. data/lib/report/json.rb +19 -0
  36. data/lib/report/reporter.rb +76 -0
  37. data/lib/requires.rb +43 -0
  38. data/lib/theotokos.rb +56 -0
  39. data/lib/version.rb +8 -0
  40. data/test/app-cfg.yml +10 -0
  41. data/test/config/ws-config.yml +8 -0
  42. data/test/unit/assertion/test_test_assertion.rb +72 -0
  43. data/test/unit/config/test_app_config_params.rb +35 -0
  44. data/test/unit/engine/test_execution_initializer.rb +22 -0
  45. data/test/unit/engine/test_parser.rb +35 -0
  46. data/test/unit/model/test_execution.rb +29 -0
  47. data/test/unit/model/test_test.rb +42 -0
  48. data/test/unit/model/test_test_app_result.rb +115 -0
  49. data/test/unit/model/test_test_status.rb +66 -0
  50. data/test/unit/model/test_test_suite.rb +92 -0
  51. data/test/unit/model/test_test_suite_result.rb +77 -0
  52. data/test/unit/model/test_text_operator.rb +40 -0
  53. data/test/unit/model/test_ws_config.rb +31 -0
  54. data/test/unit/report/test_json.rb +42 -0
  55. data/test/ws-test-models/do_something.yml +9 -0
  56. data/test/ws-test-models/project1/look_for_stuff.yml +4 -0
  57. data/theotokos.gemspec +25 -0
  58. metadata +155 -0
data/lib/model/test.rb ADDED
@@ -0,0 +1,79 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class Test
5
+
6
+ def initialize
7
+ @error_expected = @skip = false
8
+ yield self if block_given?
9
+
10
+ @tags ||= []
11
+ @input ||= {}
12
+ @output ||= {}
13
+ @ws_security ||= {}
14
+
15
+ _config_tags @tags
16
+ _validation
17
+ end
18
+
19
+ attr_accessor :name, :description, :tags, :input, :output, :ws_security, :error_expected, :error, :skip
20
+
21
+ def to_hash
22
+ { :name => @name, :description => @description, :error_expected => @error_expected,
23
+ :tags => @tags, :input => @input, :output => @output, :ws_security => @ws_security, :skip => @skip }
24
+ end
25
+
26
+ def has_tag?(tag)
27
+ @tags.each {|t| return true if tag == t }
28
+ false
29
+ end
30
+
31
+ private
32
+ def _config_tags(t)
33
+ self.tags = if t.instance_of? String
34
+ t.split(/[,\s]/).select {|t| !t.empty? }
35
+ elsif t.instance_of? Array
36
+ t
37
+ else
38
+ []
39
+ end
40
+ end
41
+
42
+ def _validation
43
+ _validate_input
44
+ _validate_output
45
+ _validate_ws_security
46
+ end
47
+
48
+ def _validate_input
49
+ raise 'Input of test model must be a Hash' unless @input.instance_of? Hash
50
+ end
51
+
52
+ def _validate_output
53
+ raise 'Output of test model must be a Hash' unless @output.instance_of? Hash
54
+ if @output['file']
55
+ raise "test > output > file >> '#{@output['file']}' does not exist" unless File.exist? Helper.format_ws_output_path(@output['file'])
56
+ end
57
+
58
+ if @output['text']
59
+ raise 'test > output > text must be a Hash' unless @output['text'].instance_of? Hash
60
+ hash = @output['text']
61
+ unless (hash.has_key?('equals') || hash.has_key?('contains') || hash.has_key?('not_contains') || hash.has_key?('regex'))
62
+ raise 'test > output > text must have one o those keys [equals, contains, not_contains, regex]'
63
+ end
64
+ end
65
+ end
66
+
67
+ def _validate_ws_security
68
+ raise 'Ws-security of test model must be a Hash' unless @ws_security.instance_of? Hash
69
+ unless @ws_security.keys.empty?
70
+ unless (@ws_security.has_key?('login') && @ws_security.has_key?('password'))
71
+ raise 'test > output > ws-security must have configured login and password keys'
72
+ end
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,91 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class TestAppResult
5
+
6
+ def initialize
7
+ @success = false
8
+ @broken_suites = []
9
+ yield self if block_given?
10
+ end
11
+
12
+ attr_accessor :suites, :date_report
13
+ attr_reader :total_failures, :total_success, :broken_suites
14
+
15
+ def calculate_totals
16
+ @total_failures = @total_success = 0
17
+ @broken_suites.clear
18
+ return if @suites.nil?
19
+
20
+ @suites.each do |suite|
21
+ suite.calculate_totals
22
+ if suite.error?
23
+ @total_failures += 1
24
+ @broken_suites << suite
25
+ end
26
+ @total_success += 1 if suite.success?
27
+ end
28
+
29
+ @success = @total_failures == 0
30
+ end
31
+
32
+ def success?
33
+ @success
34
+ end
35
+
36
+ def error?
37
+ !success?
38
+ end
39
+
40
+ def total_suites
41
+ (@suites.nil?) ? 0 : @suites.size
42
+ end
43
+
44
+ def total_test_cases
45
+ return 0 if @suites.nil?
46
+
47
+ total = 0
48
+ @suites.each {|suite| total += suite.test_results.size }
49
+ total
50
+ end
51
+
52
+ def success_failures_stats
53
+ {
54
+ :success => { :total => @total_success, :stat => ((@total_success * 100 / @suites.size).to_f.round 2) },
55
+ :failures => { :total => @total_failures, :stat => ((@total_failures * 100 / @suites.size).to_f.round 2) }
56
+ }
57
+ end
58
+
59
+ def tags_stats
60
+ tags = {}
61
+ @suites.each do |suite|
62
+ suite.test_results.each do |test|
63
+ test_tags = suite.model.tags | test.tags
64
+ if test_tags.empty?
65
+ tags[:none] = tags[:none].to_i + 1
66
+ next
67
+ end
68
+
69
+ test_tags.each {|tag| tags[tag.to_sym] = tags[tag.to_sym].to_i + 1 }
70
+ end
71
+ end
72
+
73
+ total = self.total_test_cases.to_f
74
+ tags.each do |k, v|
75
+ stat = (v * 100 / total).to_f.round 2
76
+ tags[k] = { :total => v, :stat => stat }
77
+ end
78
+
79
+ tags
80
+ end
81
+
82
+ def to_hash
83
+ { :total_failures => @total_failures, :total_success => @total_success, :date_report => @date_report,
84
+ :broken_suites => ((@broken_suites) ? @broken_suites.map {|s| s.to_hash } : @broken_suites),
85
+ :suites => ((@suites) ? @suites.map {|s| s.to_hash } : @suites) }
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,22 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class TestResult
5
+
6
+ def initialize
7
+ @error_expected = skip = false
8
+ yield self if block_given?
9
+ end
10
+
11
+ attr_accessor :name, :description, :tags, :status, :error, :test_expectation, :test_actual, :error_expected, :filter, :skip
12
+
13
+ def to_hash
14
+ { :name => @name, :description => @description, :tags => @tags, :status => ((@status) ? @status.to_hash : @status),
15
+ :error => @error, :test_expectation => @test_expectation, :test_actual => @test_actual,
16
+ :error_expected => @error_expected, :filter => ((@filter) ? @filter.to_hash : @filter), :skip => @skip }
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,68 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class TestStatus
5
+
6
+ def initialize(opt = {})
7
+ if block_given?
8
+ yield self
9
+ else
10
+ _load_properties opt
11
+ end
12
+ end
13
+
14
+ attr_accessor :test_file_status, :test_text_status
15
+ attr_writer :error
16
+
17
+ def success?
18
+ return !@error unless @error.nil?
19
+
20
+ if (@test_file_status.nil? && @test_text_status.nil?)
21
+ nil
22
+ elsif (@test_file_status == true)
23
+ (@test_text_status.nil? || _validate_test_text_status == true)
24
+ elsif (_validate_test_text_status == true)
25
+ (@test_file_status == true || @test_file_status.nil?)
26
+ else
27
+ false
28
+ end
29
+ end
30
+
31
+ def error?
32
+ return @error unless @error.nil?
33
+
34
+ ok = success?
35
+ ok.nil? ? nil : !ok
36
+ end
37
+
38
+ def to_s
39
+ "Model::TestStatus @error: #{@error}, @test_file_status: #{@test_file_status}, @test_text_status: #{@test_text_status}"
40
+ end
41
+
42
+ def to_hash
43
+ { :test_file_status => @test_file_status, :test_text_status => @test_text_status,
44
+ :error => @error }
45
+ end
46
+
47
+ private
48
+ def _load_properties(opt)
49
+ @test_file_status = opt[:test_file_status]
50
+ @test_text_status = opt[:test_text_status]
51
+ @error = opt[:error]
52
+ end
53
+
54
+ def _validate_test_text_status
55
+ ok = false
56
+ return ok if @test_text_status.nil?
57
+
58
+ @test_text_status.each_value do |v|
59
+ ok = v
60
+ break if ok == false
61
+ end
62
+ ok
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,80 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class TestSuite
5
+
6
+ def initialize(opt = {})
7
+ if block_given?
8
+ yield self
9
+ _config_tags @tags
10
+ else
11
+ _load_properties opt
12
+ end
13
+ @tests ||= Array.new
14
+ end
15
+
16
+ attr_accessor :source, :wsdl, :service, :description, :tags, :tests
17
+
18
+ def validate_model!
19
+ raise Exception, 'WS test model must be provided.' if @source.nil? || @source.empty?
20
+ raise Exception, "WSDL's URL must be provided." if @wsdl.nil? || @wsdl.empty?
21
+ raise Exception, 'Service name (service to be tested) must be provided.' if @service.nil? || @service.empty?
22
+ end
23
+
24
+ def has_tag?(tag)
25
+ (@tags + @tests.map {|t| t.tags }.flatten).each {|t| return true if t == tag }
26
+ false
27
+ end
28
+
29
+ def name
30
+ regex = Regexp.new ENV['ws.test.models.path'].sub(/\/$/, '')
31
+ name =@source.sub regex, ''
32
+ name.sub! /^\//, ''
33
+
34
+ name.sub('.yml', '').split('/').join('_')
35
+ end
36
+
37
+ def to_hash
38
+ { :source => @source, :wsdl => @wsdl, :service => @service, :descriptio => @description,
39
+ :tags => @tags, :tests => ((@tests) ? @tests.map {|t| t.to_hash } : @tests) }
40
+ end
41
+
42
+ private
43
+ def _load_properties(opt)
44
+ self.source = opt[:source]
45
+ self.wsdl = opt[:wsdl]
46
+ self.service = opt[:service]
47
+ self.description = opt[:description]
48
+
49
+ _config_tags opt[:tags]
50
+ @tests = _load_tests opt[:tests]
51
+ end
52
+
53
+ def _config_tags(t)
54
+ self.tags = if t.instance_of? String
55
+ t.split(/[,\s]/).select {|t| !t.empty? }
56
+ elsif t.instance_of? Array
57
+ t
58
+ else
59
+ []
60
+ end
61
+ end
62
+
63
+ def _load_tests(array)
64
+ array ||= []
65
+ data = []
66
+ array.each do |test|
67
+ data << Test.new do |t|
68
+ t.input = test['input']
69
+ t.output = test['output']
70
+ t.ws_security = test['ws-security']
71
+ end
72
+ end
73
+
74
+ data
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,54 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class TestSuiteResult
5
+
6
+ def initialize
7
+ @success = false
8
+ @broken_tests = []
9
+ yield self if block_given?
10
+ end
11
+
12
+ attr_accessor :model, :test_results
13
+ attr_reader :total_failures, :total_success, :broken_tests
14
+
15
+ def calculate_totals
16
+ @total_failures = @total_success = 0
17
+ @broken_tests.clear
18
+ return if @test_results.nil?
19
+
20
+ @test_results.each do |res|
21
+ next if res.status.nil?
22
+ if res.status.error?
23
+ @total_failures += 1
24
+ @broken_tests << res
25
+ end
26
+ @total_success += 1 if res.status.success?
27
+ end
28
+
29
+ @success = @total_failures == 0
30
+ end
31
+
32
+ def success?
33
+ @success
34
+ end
35
+
36
+ def error?
37
+ !success?
38
+ end
39
+
40
+ def total_tests
41
+ (@test_results.nil?) ? 0 : @test_results.size
42
+ end
43
+
44
+ def to_hash
45
+ { :model => ((@model) ? @model.to_hash : @model),
46
+ :test_results => ((@test_results) ? @test_results.map {|t| t.to_hash } : @test_results),
47
+ :total_failures => @total_failures, :total_success => @total_success,
48
+ :broken_tests => @broken_tests }
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,34 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class TextOperator
5
+
6
+ def initialize(opt = {})
7
+ if block_given?
8
+ yield self
9
+ else
10
+ _load_properties opt
11
+ end
12
+ end
13
+
14
+ attr_accessor :contains, :not_contains, :equals, :regex
15
+
16
+ def to_hash
17
+ Hash.new({
18
+ :contains => @contains, :not_contains => @not_contains,
19
+ :equals => @equals, :regex => @regex
20
+ })
21
+ end
22
+
23
+ private
24
+ def _load_properties(opt)
25
+ @contains = opt[:contains]
26
+ @not_contains = opt[:not_contains]
27
+ @equals = opt[:equals]
28
+ @regex = opt[:regex]
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,48 @@
1
+ module Theotokos
2
+ module Model
3
+
4
+ class WsConfig
5
+
6
+ def initialize
7
+ yield self if block_given?
8
+ end
9
+
10
+ attr_accessor :env_namespace, :namespaces, :ssl_verify_mode, :ssl_version,
11
+ :ssl_cert_file, :ssl_cert_key_file, :ssl_ca_cert_file, :ssl_cert_key_password
12
+
13
+ def self.ws_attributes
14
+ %W(env_namespace namespaces ssl_verify_mode ssl_version ssl_cert_file ssl_cert_key_file
15
+ ssl_ca_cert_file ssl_cert_key_password)
16
+ end
17
+
18
+ def self.load_ws_config
19
+ return WsConfig.new unless File.exist? ENV['ws.config.path']
20
+
21
+ data = YAML.load_file ENV['ws.config.path']
22
+ profile = ((ENV['profile'] == 'default' || ENV['profile'].nil?) ? '' : "#{ENV['profile']}.")
23
+
24
+ WsConfig.new do |c|
25
+ c.env_namespace = data['request.env.namespace']
26
+
27
+ if data['request.namespaces']
28
+ namespaces = {}
29
+ data['request.namespaces'].to_s.split(',').each do |namespace|
30
+ tokens = namespace.split '='
31
+ namespaces[tokens[0].strip] = tokens[1].strip
32
+ end
33
+ c.namespaces = namespaces
34
+ end
35
+
36
+ c.ssl_verify_mode = data["#{profile}ssl.verify.mode"].to_sym if data["#{profile}ssl.verify.mode"]
37
+ c.ssl_version = data["#{profile}ssl.version"].to_sym if data["#{profile}ssl.version"]
38
+ c.ssl_cert_file = data["#{profile}ssl.cert.file"]
39
+ c.ssl_cert_key_file = data["#{profile}ssl.cert.key.file"]
40
+ c.ssl_ca_cert_file = data["#{profile}ssl.ca.cert.file"]
41
+ c.ssl_cert_key_password = data["#{profile}ssl.cert.key.password"]
42
+ end
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,58 @@
1
+ module Net
2
+
3
+ class SoapNet
4
+
5
+ def self.send_request(options)
6
+ logger = AppLogger.create_logger self
7
+ client = _savon_client options[:wsdl], options[:ws_config], options[:ws_security]
8
+ service = options[:service].to_s.gsub(/(.)([A-Z])/,'\1_\2').downcase # snake_case
9
+ xml = success = nil
10
+
11
+ begin
12
+ logger.debug "Send request to service '#{service}'"
13
+ response = client.call service.to_sym, :message => options[:params]
14
+ xml = Nokogiri::XML(response.xml, nil, "UTF-8").to_xml
15
+ success = true
16
+ rescue Exception => ex
17
+ return { :success => false, :xml => Nokogiri::XML(ex.http.body, nil, "UTF-8").to_xml } if ex.instance_of? Savon::SOAPFault
18
+
19
+ xml = Nokogiri::XML::Builder.new do |xml|
20
+ xml.error do
21
+ xml.message ex.to_s
22
+ xml.backtrace ex.backtrace.join("\n ")
23
+ end
24
+ end.to_xml
25
+ success = false
26
+ end
27
+
28
+ logger.debug "Success on request? #{success}"
29
+ { :success => success, :xml => xml }
30
+ end
31
+
32
+ def self._savon_client(wsdl_url, ws_config, ws_security)
33
+ logger = AppLogger.create_logger self
34
+ logger.debug "Prepare web service app client"
35
+
36
+ params = {}
37
+ params[:env_namespace] = ws_config.env_namespace if ws_config.env_namespace
38
+ params[:namespaces] = ws_config.namespaces if ws_config.namespaces
39
+
40
+ params[:ssl_verify_mode] = ws_config.ssl_verify_mode if ws_config.ssl_verify_mode
41
+ params[:ssl_version] = ws_config.ssl_version if ws_config.ssl_version
42
+ params[:ssl_cert_file] = ws_config.ssl_cert_file if ws_config.ssl_cert_file
43
+ params[:ssl_cert_key_file] = ws_config.ssl_cert_key_file if ws_config.ssl_cert_key_file
44
+ params[:ssl_ca_cert_file] = ws_config.ssl_ca_cert_file if ws_config.ssl_ca_cert_file
45
+ params[:ssl_cert_key_password] = ws_config.ssl_cert_key_password if ws_config.ssl_cert_key_password
46
+
47
+ logger.debug "Client config params for requesting service: #{params}"
48
+ logger.debug "WS-Security params: #{ws_security}" if (!ws_security.nil? && !ws_security.empty?)
49
+
50
+ Savon.client(params) do
51
+ wsdl wsdl_url
52
+ wsse_auth ws_security['login'], ws_security['password'], :digest if (!ws_security.nil? && !ws_security.empty?)
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,68 @@
1
+ module Report
2
+
3
+ class ChartFactory
4
+
5
+ def self.success_failure_chart(opt)
6
+ total = opt[:total_success].to_i + opt[:total_failures].to_f
7
+ success = ((opt[:total_success].to_i * 100) / total).to_f.round 2
8
+ failures = ((opt[:total_failures].to_i * 100) / total).to_f.round 2
9
+
10
+ str = "[{ value: #{success}, color: \"#1A0B9C\", highlight: \"#1E0CC0\", label: \"Success (%)\"},"
11
+ str << "{ value : #{failures}, color : \"#BF1717\", highlight: \"#D71515\", label: \"Failures (%)\"}]"
12
+
13
+ ChartFactory._template :id => opt[:id], :data => str, :type => :pie
14
+ end
15
+
16
+ def self.totals_tags_chart(opt)
17
+ stats = opt[:stats]
18
+ str = <<-eos
19
+ {
20
+ labels: ["#{stats.keys.join('","')}"],
21
+ datasets: [{
22
+ fillColor: "rgba(151,187,205,0.5)",
23
+ strokeColor: "rgba(151,187,205,0.8)",
24
+ highlightFill: "rgba(151,187,205,0.75)",
25
+ highlightStroke: "rgba(151,187,205,1)",
26
+ data: [#{stats.map {|k, v| stats[k][:total] }.join(',')}]
27
+ }]
28
+ }
29
+ eos
30
+ ChartFactory._template :id => opt[:id], :data => str, :type => :bar
31
+ end
32
+
33
+ def self.stats_tags_chart(opt)
34
+ stats = opt[:stats]
35
+ str = <<-eos
36
+ {
37
+ labels: ["#{stats.keys.join('","')}"],
38
+ datasets: [{
39
+ fillColor: "rgba(220,220,220,0.5)",
40
+ strokeColor: "rgba(220,220,220,0.8)",
41
+ highlightFill: "rgba(220,220,220,0.75)",
42
+ highlightStroke: "rgba(220,220,220,1)",
43
+ data: [#{stats.keys.map {|k| 100 }.join(',')}]
44
+ },
45
+ {
46
+ fillColor: "rgba(151,187,205,0.5)",
47
+ strokeColor: "rgba(151,187,205,0.8)",
48
+ highlightFill: "rgba(151,187,205,0.75)",
49
+ highlightStroke: "rgba(151,187,205,1)",
50
+ data: [#{stats.map {|k, v| stats[k][:stat] }.join(',')}]
51
+ }]
52
+ }
53
+ eos
54
+ ChartFactory._template :id => opt[:id], :data => str, :type => :bar
55
+ end
56
+
57
+ def self._template(opt)
58
+ <<-eos
59
+ var data = #{opt[:data]};
60
+
61
+ var chart = document.getElementById("#{opt[:id]}").getContext("2d");
62
+ new Chart(chart).#{opt[:type].to_s.capitalize}(data, {});
63
+ eos
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,94 @@
1
+ module Report
2
+
3
+ class Console < Reporter
4
+
5
+ def print(object)
6
+ case object.class.name
7
+ when Theotokos::Model::TestResult.name then _print_test_result object
8
+ when Theotokos::Model::TestSuiteResult.name then _print_test_suite_result object
9
+ when Theotokos::Model::TestAppResult.name then _print_test_app_result object
10
+ else puts "Console printing is not supported for objects of type #{object.class.name}"
11
+ end
12
+ end
13
+
14
+ private
15
+ def _print_test_result(test)
16
+ @output = ''
17
+ _append "Test case: ##{test.name}"
18
+ _append "Test description: #{test.description}"
19
+ _append "Tags: #{test.tags.join(', ')}" if test.tags
20
+ _append "Test expectations."
21
+
22
+ if test.test_expectation && !test.status.nil?
23
+ if test.test_expectation['file']
24
+ file = test.test_expectation['file']
25
+ _append " => File '#{file}'\n#{File.read(Helper.format_ws_output_path file)}"
26
+ _append " => Status: #{test.status.test_file_status ? 'Passed' : 'Failed'}\n"
27
+ end
28
+ puts
29
+ if test.test_expectation['text']
30
+ exp = test.test_expectation['text']
31
+ _append " => Text\n"
32
+
33
+ exp.each do |k, v|
34
+ _append "#{k}: #{v}"
35
+ if test.status.test_text_status.nil?
36
+ _append "Status: Not performed"
37
+ else
38
+ status = test.status.test_text_status[k.to_sym]
39
+ _append "Status: #{status ? 'Passed' : 'Failed'}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ if test.error
46
+ backtrace = ((test.error[:backtrace].instance_of? Array) ? test.error[:backtrace].join("\n") : test.error[:backtrace])
47
+ _append "\n - Error message: #{test.error[:message]}"
48
+ _append "\n - Error detail:\n#{backtrace}"
49
+ else
50
+ _append "\n- Found output."
51
+ _append (test.test_actual) ? File.read(test.test_actual) : ''
52
+ end
53
+
54
+ _append "\n- Test case status: #{((test.status.nil?) ? 'Skipped' : (test.status.success? ? 'Success' : 'Fail'))}"
55
+ _append "\n------\n\n"
56
+
57
+ @output
58
+ end
59
+
60
+ def _print_test_suite_result(suite)
61
+ @output = ''
62
+ _append "-" * 100
63
+ _append "Total test success: #{suite.total_success}"
64
+ _append "Total test failures: #{suite.total_failures}"
65
+
66
+ @output
67
+ end
68
+
69
+ def _print_test_app_result(app)
70
+ @output = ''
71
+ _append "*" * 100
72
+ _append "Total test suites success: #{app.total_success}"
73
+ _append "Total test suites failures: #{app.total_failures}\n"
74
+
75
+ if app.error?
76
+ _append "*" * 100
77
+ _append "- Broken tests"
78
+ app.broken_suites.each do |suite|
79
+ _append "Test suite: #{suite.model.source}\nTest cases: ##{suite.broken_tests.map {|t| t.name }.join(', #')}"
80
+ end
81
+ end
82
+
83
+ @output
84
+ end
85
+
86
+ def _append(text)
87
+ @output << "\n" unless @output.empty?
88
+ @output << text
89
+ puts text unless ENV['ENVIRONMENT'] == 'test'
90
+ end
91
+
92
+ end
93
+
94
+ end