polytrix 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-todo.yml +14 -5
  3. data/Gemfile +2 -1
  4. data/README.md +139 -177
  5. data/Rakefile +5 -12
  6. data/bin/polytrix +0 -1
  7. data/features/bootstrapping.feature +0 -3
  8. data/features/cloning.feature +0 -3
  9. data/features/show.feature +38 -0
  10. data/features/states.feature +12 -13
  11. data/features/step_definitions/sdk_steps.rb +0 -4
  12. data/lib/polytrix/challenge.rb +135 -53
  13. data/lib/polytrix/challenge_result.rb +0 -2
  14. data/lib/polytrix/challenge_runner.rb +28 -18
  15. data/lib/polytrix/cli.rb +53 -69
  16. data/lib/polytrix/color.rb +2 -2
  17. data/lib/polytrix/command/action.rb +4 -3
  18. data/lib/polytrix/command/list.rb +39 -28
  19. data/lib/polytrix/command/report.rb +9 -86
  20. data/lib/polytrix/command/reports/code2doc.rb +72 -0
  21. data/lib/polytrix/command/reports/dashboard.rb +125 -0
  22. data/lib/polytrix/command/show.rb +148 -0
  23. data/lib/polytrix/command.rb +37 -104
  24. data/lib/polytrix/configuration.rb +14 -18
  25. data/lib/polytrix/{core/hashie.rb → dash.rb} +4 -3
  26. data/lib/polytrix/documentation/code_segmenter.rb +8 -8
  27. data/lib/polytrix/documentation/comment_styles.rb +1 -1
  28. data/lib/polytrix/documentation/helpers/code_helper.rb +9 -0
  29. data/lib/polytrix/documentation_generator.rb +11 -14
  30. data/lib/polytrix/error.rb +104 -97
  31. data/lib/polytrix/executor.rb +33 -0
  32. data/lib/polytrix/{runners → executors}/buff_shellout_executor.rb +1 -1
  33. data/lib/polytrix/executors/linux_challenge_executor.rb +29 -0
  34. data/lib/polytrix/executors/mixlib_shellout_executor.rb +55 -0
  35. data/lib/polytrix/{runners/windows_challenge_runner.rb → executors/windows_challenge_executor.rb} +4 -11
  36. data/lib/polytrix/{core/implementor.rb → implementor.rb} +10 -6
  37. data/lib/polytrix/manifest.rb +2 -31
  38. data/lib/polytrix/{reports → reporters}/hash_reporter.rb +6 -2
  39. data/lib/polytrix/{reports → reporters}/json_reporter.rb +2 -2
  40. data/lib/polytrix/{reports → reporters}/markdown_reporter.rb +7 -2
  41. data/lib/polytrix/{reports → reporters}/yaml_reporter.rb +2 -2
  42. data/lib/polytrix/reporters.rb +27 -0
  43. data/lib/polytrix/result.rb +6 -5
  44. data/lib/polytrix/spies/file_system_spy.rb +15 -0
  45. data/lib/polytrix/spies.rb +61 -0
  46. data/lib/polytrix/state_file.rb +1 -20
  47. data/lib/polytrix/util.rb +157 -62
  48. data/lib/polytrix/validation.rb +41 -2
  49. data/lib/polytrix/validator.rb +9 -4
  50. data/lib/polytrix/version.rb +1 -1
  51. data/lib/polytrix.rb +110 -105
  52. data/polytrix.gemspec +7 -2
  53. data/polytrix.yml +16 -13
  54. data/resources/assets/pygments/autumn.css +58 -0
  55. data/resources/assets/pygments/borland.css +46 -0
  56. data/resources/assets/pygments/bw.css +34 -0
  57. data/resources/assets/pygments/colorful.css +61 -0
  58. data/resources/assets/pygments/default.css +62 -0
  59. data/resources/assets/pygments/emacs.css +61 -0
  60. data/resources/assets/pygments/friendly.css +61 -0
  61. data/resources/assets/pygments/fruity.css +69 -0
  62. data/resources/assets/pygments/github.css +61 -0
  63. data/resources/assets/pygments/manni.css +61 -0
  64. data/resources/assets/pygments/monokai.css +64 -0
  65. data/resources/assets/pygments/murphy.css +61 -0
  66. data/resources/assets/pygments/native.css +69 -0
  67. data/resources/assets/pygments/pastie.css +60 -0
  68. data/resources/assets/pygments/perldoc.css +58 -0
  69. data/resources/assets/pygments/tango.css +69 -0
  70. data/resources/assets/pygments/trac.css +59 -0
  71. data/resources/assets/pygments/vim.css +69 -0
  72. data/resources/assets/pygments/vs.css +33 -0
  73. data/resources/assets/pygments/zenburn.css +1 -0
  74. data/resources/assets/style.css +41 -0
  75. data/resources/templates/dashboard/files/dashboard.html.tt +82 -0
  76. data/resources/templates/dashboard/templates/_test_report.html.tt +87 -0
  77. data/samples/bootstrap.sh +2 -0
  78. data/samples/clone.sh +2 -0
  79. data/samples/code2doc.sh +4 -0
  80. data/samples/docs/samples/code2doc/java/katas-hello_world-java.md +17 -0
  81. data/samples/docs/samples/code2doc/java/katas-quine-java.md +35 -0
  82. data/samples/docs/samples/code2doc/python/katas-hello_world-python.md +5 -0
  83. data/samples/docs/samples/code2doc/python/katas-quine-python.md +6 -0
  84. data/samples/docs/samples/code2doc/ruby/katas-hello_world-ruby.md +11 -0
  85. data/samples/exec.sh +2 -0
  86. data/samples/polytrix.rb +2 -2
  87. data/samples/polytrix.yml +5 -2
  88. data/samples/show.sh +4 -0
  89. data/samples/test.sh +2 -0
  90. data/samples/tests/polytrix/validators.rb +2 -2
  91. data/samples/verify.sh +3 -0
  92. data/scripts/wrapper +4 -7
  93. data/spec/fabricators/challenge_fabricator.rb +2 -9
  94. data/spec/fabricators/implementor_fabricator.rb +0 -8
  95. data/spec/fabricators/manifest_fabricator.rb +2 -9
  96. data/spec/fabricators/validator_fabricator.rb +2 -4
  97. data/spec/polytrix/challenge_runner_spec.rb +20 -0
  98. data/spec/polytrix/documentation/helpers/code_helper_spec.rb +7 -7
  99. data/spec/polytrix/file_finder_spec.rb +5 -5
  100. data/spec/polytrix/manifest_spec.rb +0 -21
  101. data/spec/polytrix/result_spec.rb +14 -14
  102. data/spec/polytrix/validator_registry_spec.rb +4 -4
  103. data/spec/polytrix/validator_spec.rb +9 -9
  104. data/spec/polytrix_spec.rb +1 -25
  105. data/spec/spec_helper.rb +8 -1
  106. metadata +130 -38
  107. data/features/execution.feature +0 -53
  108. data/features/fixtures/spec/polytrix_spec.rb +0 -7
  109. data/lib/polytrix/cli/report.rb +0 -84
  110. data/lib/polytrix/command/rundoc.rb +0 -27
  111. data/lib/polytrix/core/file_system_helper.rb +0 -75
  112. data/lib/polytrix/core/manifest_section.rb +0 -4
  113. data/lib/polytrix/core/string_helpers.rb +0 -15
  114. data/lib/polytrix/documentation/view_helper.rb +0 -21
  115. data/lib/polytrix/rspec/documentation_formatter.rb +0 -66
  116. data/lib/polytrix/rspec/yaml_report.rb +0 -51
  117. data/lib/polytrix/rspec.rb +0 -56
  118. data/lib/polytrix/runners/executor.rb +0 -34
  119. data/lib/polytrix/runners/linux_challenge_runner.rb +0 -23
  120. data/lib/polytrix/runners/middleware/change_directory.rb +0 -20
  121. data/lib/polytrix/runners/middleware/feature_executor.rb +0 -24
  122. data/lib/polytrix/runners/middleware/setup_env_vars.rb +0 -42
  123. data/lib/polytrix/runners/mixlib_shellout_executor.rb +0 -83
  124. data/lib/polytrix/validations.rb +0 -23
  125. data/samples/scripts/wrapper +0 -7
  126. data/spec/polytrix/middleware/feature_executor_spec.rb +0 -48
  127. data/spec/polytrix/validations_spec.rb +0 -16
@@ -1,52 +1,63 @@
1
+ require 'polytrix/reporters'
1
2
  module Polytrix
2
3
  module Command
3
4
  class List < Polytrix::Command::Base
4
- def call
5
- # Logging.mdc['command'] = 'list'
5
+ include Polytrix::Reporters
6
6
 
7
+ def call
7
8
  setup
8
- tests = parse_subcommand(args.first)
9
-
10
- table = [
11
- [
12
- colorize('Suite', :green), colorize('Scenario', :green),
13
- colorize('Implementor', :green), colorize('Status', :green)
14
- ]
15
- ]
9
+ @reporter = Polytrix::Reporters.reporter(options[:format], shell)
10
+ tests = parse_subcommand(args.pop)
11
+
12
+ table = [header_row]
16
13
  table += tests.map do | challenge |
17
- [
18
- color_pad(challenge.suite),
19
- color_pad(challenge.name),
20
- color_pad(challenge.implementor.name),
21
- format_last_action(challenge)
22
- ]
14
+ row(challenge)
23
15
  end
24
- shell.print_table table
16
+ print_table(table)
25
17
  end
26
18
 
27
19
  private
28
20
 
21
+ def header_row
22
+ row = []
23
+ row << colorize('Test ID', :green)
24
+ row << colorize('Suite', :green)
25
+ row << colorize('Scenario', :green)
26
+ row << colorize('Implementor', :green)
27
+ row << colorize('Status', :green)
28
+ row << colorize('Source', :green) if options[:source]
29
+ row
30
+ end
31
+
32
+ def row(challenge)
33
+ row = []
34
+ row << color_pad(challenge.slug)
35
+ row << color_pad(challenge.suite)
36
+ row << color_pad(challenge.name)
37
+ row << color_pad(challenge.implementor.name)
38
+ row << format_status(challenge)
39
+ if options[:source]
40
+ source_file = challenge.absolute_source_file ? relativize(challenge.absolute_source_file, Dir.pwd) : colorize('<No code sample>', :red)
41
+ row << source_file
42
+ end
43
+ row
44
+ end
45
+
29
46
  def print_table(*args)
30
- shell.print_table(*args)
47
+ @reporter.print_table(*args)
31
48
  end
32
49
 
33
50
  def colorize(string, *args)
34
- shell.set_color(string, *args)
51
+ return string unless @reporter.respond_to? :set_color
52
+ @reporter.set_color(string, *args)
35
53
  end
36
54
 
37
55
  def color_pad(string)
38
56
  string + colorize('', :white)
39
57
  end
40
58
 
41
- def format_last_action(challenge)
42
- case challenge.last_action
43
- when 'clone' then colorize('Cloned', :cyan)
44
- when 'bootstrap' then colorize('Bootstrapped', :magenta)
45
- when 'exec' then colorize('Executed', :blue)
46
- when 'verify' then colorize("Verified (x#{challenge.validations.count})", :yellow)
47
- when nil then colorize('<Not Found>', :red)
48
- else colorize("<Unknown (#{challenge.last_action})>", :white)
49
- end
59
+ def format_status(challenge)
60
+ colorize(challenge.status_description, challenge.status_color)
50
61
  end
51
62
  end
52
63
  end
@@ -1,94 +1,17 @@
1
1
  module Polytrix
2
- module Reports
3
- # autoload :TextReporter, 'polytrix/cli/reports/text_reporter'
4
- autoload :MarkdownReporter, 'polytrix/cli/reports/markdown_reporter'
5
- # autoload :HTMLReporter, 'polytrix/cli/reports/html_reporter'
6
- autoload :JSONReporter, 'polytrix/cli/reports/json_reporter'
7
- autoload :YAMLReporter, 'polytrix/cli/reports/yaml_reporter'
8
- end
9
2
  module Command
10
- class Report < Polytrix::Command::Base
11
- def call
12
- fail StandardError, 'Report command not yet implemented - work in progress'
13
- # setup
14
- # @tests = parse_subcommand(args.first)
15
- # tests_by_implementor = @tests.group_by(&:implementor)
16
-
17
- # table = [
18
- # [
19
- # colorize('SDK', :green), colorize('Passed', :green),
20
- # colorize('Failed', :red), colorize('Pending', :yellow),
21
- # colorize('Skipped', :cyan)
22
- # ]
23
- # ]
24
- # load_results.each do |sdk, sdk_summary|
25
- # table << [sdk, sdk_summary[:passed], sdk_summary[:failed], sdk_summary[:pending], sdk_summary[:skipped]]
26
- # end
27
- # shell.print_table table
28
- end
29
-
30
- private
31
-
32
- def count(results, state)
33
- results.count do |r|
34
- result.last_action.to_s == state.to_s
35
- end
36
- end
37
-
38
- def load_results
39
- result_stats = Hash.new do |hash, sdk|
40
- hash[sdk] = { passed: 0, failed: 0, pending: 0, skipped: 0 }
41
- end
42
- Polytrix.manifest.suites.reduce(result_stats) do |hash, (suite_name, suite)|
43
- suite.samples.each do |sample, suite_results|
44
- Polytrix.implementors.map(&:name).each do |sdk|
45
- result = Result.new(suite_results[sdk])
46
- result.validations << Validation.new(validated_by: 'polytrix', result: 'skipped')
47
- hash[sdk][result.status.to_sym] += 1
48
- end
49
- end
50
- hash
51
- end
52
- result_stats
53
- end
54
-
55
- def reporter
56
- @reporter ||= case options[:format]
57
- when 'text'
58
- self
59
- when 'markdown'
60
- Polytrix::CLI::Reports::MarkdownReporter.new
61
- when 'json'
62
- Polytrix::CLI::Reports::JSONReporter.new
63
- when 'yaml'
64
- Polytrix::CLI::Reports::YAMLReporter.new
65
- else
66
- fail "Unknown report format #{options[:format]}"
67
- end
68
- end
69
-
70
- def print_table(*args)
71
- shell.print_table(*args)
72
- end
3
+ class Report < Thor
4
+ namespace :report
73
5
 
74
- def colorize(string, *args)
75
- shell.set_color(string, *args)
76
- end
6
+ autoload :Dashboard, 'polytrix/command/reports/dashboard'
7
+ register Dashboard, 'dashboard', 'dashboard', 'Create a report dashboard'
8
+ tasks['dashboard'].options = Dashboard.class_options
77
9
 
78
- def color_pad(string)
79
- string + colorize('', :white)
80
- end
10
+ autoload :Code2Doc, 'polytrix/command/reports/code2doc'
11
+ register Code2Doc, 'code2doc', 'code2doc [INSTANCE|REGEXP|all]', 'Generates documenation from sample code for one or more scenarios'
12
+ tasks['code2doc'].options = Code2Doc.class_options
81
13
 
82
- def format_last_action(challenge)
83
- case challenge.last_action
84
- when 'clone' then colorize('Cloned', :cyan)
85
- when 'bootstrap' then colorize('Bootstrapped', :magenta)
86
- when 'exec' then colorize('Executed', :blue)
87
- when 'verify' then colorize("Verified (Level #{challenge.verification_level})", :yellow)
88
- when nil then colorize('<Not Found>', :red)
89
- else colorize("<Unknown (#{challenge.last_action})>", :white)
90
- end
91
- end
14
+ # FIXME: Help shows unwanted usage, e.g. "polytrix polytrix:command:report:code2_doc"
92
15
  end
93
16
  end
94
17
  end
@@ -0,0 +1,72 @@
1
+ require 'json'
2
+ require 'polytrix/reporters'
3
+
4
+ module Polytrix
5
+ module Command
6
+ class Report
7
+ class Code2Doc < Thor::Group
8
+ include Polytrix::DefaultLogger
9
+ include Polytrix::Logging
10
+ include Thor::Actions
11
+ include Polytrix::Util::FileSystem
12
+
13
+ class_option :log_level,
14
+ aliases: '-l',
15
+ desc: 'Set the log level (debug, info, warn, error, fatal)'
16
+ class_option :manifest,
17
+ aliases: '-m',
18
+ desc: 'The Polytrix test manifest file location',
19
+ default: 'polytrix.yml'
20
+ class_option :solo,
21
+ desc: 'Enable solo mode - Polytrix will auto-configure a single implementor and its scenarios'
22
+ # , default: 'polytrix.yml'
23
+ class_option :solo_glob,
24
+ desc: 'The globbing pattern to find code samples in solo mode'
25
+ class_option :format,
26
+ aliases: '-f',
27
+ enum: %w(md rst),
28
+ default: 'md',
29
+ desc: 'Target documentation format'
30
+ class_option :target_dir,
31
+ aliases: '-d',
32
+ default: 'docs/',
33
+ desc: 'The target directory where documentation for generated documentation.'
34
+
35
+ class_option :destination, default: 'docs/'
36
+
37
+ def setup
38
+ # HACK: Need to make Command setup/parse_subcommand easily re-usable in Thor::Group actions
39
+ command_options = {
40
+ shell: shell
41
+ }.merge(options)
42
+ command = Polytrix::Command::Base.new(args, options, command_options)
43
+ command.send(:setup)
44
+ @scenarios = command.send(:parse_subcommand, args.pop)
45
+ end
46
+
47
+ def set_destination_root
48
+ self.destination_root = options[:destination]
49
+ end
50
+
51
+ def code2doc
52
+ @scenarios.each do | scenario |
53
+ source_file = scenario.source_file
54
+ if source_file.nil?
55
+ warn "No code sample available for #{scenario.slug}, no documentation will be generated."
56
+ next
57
+ end
58
+
59
+ target_file_name = scenario.slug + ".#{options[:format]}"
60
+
61
+ begin
62
+ doc = Polytrix::DocumentationGenerator.new.code2doc(scenario.absolute_source_file)
63
+ create_file(target_file_name, doc)
64
+ rescue Polytrix::Documentation::CommentStyles::UnknownStyleError
65
+ warn "Could not generated documentation for #{source_file}, because the language couldn't be detected."
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,125 @@
1
+ require 'json'
2
+ require 'polytrix/reporters'
3
+
4
+ module Polytrix
5
+ module Command
6
+ class Report
7
+ class Dashboard < Thor::Group
8
+ include Thor::Actions
9
+ include Polytrix::Util::FileSystem
10
+ module Helpers
11
+ include Polytrix::Util::String
12
+ include Padrino::Helpers::TagHelpers
13
+ include Padrino::Helpers::OutputHelpers
14
+ include Padrino::Helpers::AssetTagHelpers
15
+
16
+ def implementors
17
+ Polytrix.implementors.map do |implementor|
18
+ slugify(implementor.name)
19
+ end
20
+ end
21
+
22
+ def results
23
+ manifest = Polytrix.manifest
24
+ rows = []
25
+ grouped_challenges = manifest.challenges.values.group_by { |challenge| [challenge.suite, challenge.name] }
26
+ grouped_challenges.each do |(suite, name), challenges|
27
+ row = {
28
+ slug_prefix: slugify(suite, name),
29
+ suite: suite,
30
+ scenario: name
31
+ }
32
+ Polytrix.implementors.each do |implementor|
33
+ challenge = challenges.find { |c| c.implementor == implementor }
34
+ row[slugify(implementor.name)] = challenge.status_description
35
+ end
36
+ rows << row
37
+ end
38
+ rows
39
+ end
40
+
41
+ def as_json(table)
42
+ JSON.dump(table)
43
+ end
44
+
45
+ def status(status, msg = nil, _color = :cyan)
46
+ "<strong>#{status}</strong> <em>#{msg}</em>"
47
+ end
48
+
49
+ def bootstrap_color(color)
50
+ bootstrap_classes = {
51
+ green: 'success',
52
+ cyan: 'primary',
53
+ red: 'danger',
54
+ yellow: 'warning'
55
+ }
56
+ bootstrap_classes.key?(color) ? bootstrap_classes[color] : color
57
+ end
58
+ end
59
+
60
+ include Helpers
61
+
62
+ class_option :destination, default: 'reports/'
63
+ class_option :code_style, default: 'github'
64
+
65
+ def self.source_root
66
+ Polytrix::Reporters::TEMPLATE_DIR
67
+ end
68
+
69
+ def report_name
70
+ @report_name ||= self.class.name.downcase.split('::').last
71
+ end
72
+
73
+ def add_framework_to_source_root
74
+ source_paths.map do | path |
75
+ path << "/#{report_name}"
76
+ end
77
+ end
78
+
79
+ def set_destination_root
80
+ self.destination_root = options[:destination]
81
+ end
82
+
83
+ # def load_helpers
84
+ # framework_root = source_paths.first
85
+ # Dir["#{report_name}/helpers/**/*.rb"].each do |helper|
86
+ # load helper
87
+ # end
88
+ # end
89
+
90
+ def setup
91
+ Polytrix.manifest.build_challenges
92
+ test_dir = 'tests/polytrix' # @test_dir.nil? ? nil : File.expand_path(@test_dir)
93
+ return nil unless test_dir && File.directory?(test_dir)
94
+
95
+ $LOAD_PATH.unshift test_dir
96
+ Dir["#{test_dir}/**/*.rb"].each do | file_to_require |
97
+ require relativize(file_to_require, test_dir).to_s.gsub('.rb', '')
98
+ end
99
+ end
100
+
101
+ def copy_assets
102
+ directory Polytrix::Reporters::ASSETS_DIR, 'assets'
103
+ end
104
+
105
+ def copy_base_structure
106
+ directory 'files', '.'
107
+ end
108
+
109
+ def create_test_reports
110
+ Polytrix.manifest.challenges.values.each do |challenge|
111
+ @challenge = challenge
112
+ template 'templates/_test_report.html.tt', "details/#{challenge.slug}.html"
113
+ end
114
+ end
115
+
116
+ def create_spy_reports
117
+ reports = Polytrix::Spies.reports[:dashboard]
118
+ reports.each do | report_class |
119
+ invoke report_class, args, options
120
+ end if reports
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,148 @@
1
+ require 'polytrix/reporters'
2
+
3
+ module Polytrix
4
+ module Command
5
+ class Show < Polytrix::Command::Base
6
+ include Polytrix::Reporters
7
+ include Polytrix::Util::String
8
+ include Polytrix::Util::FileSystem
9
+
10
+ def initialize(cmd_args, cmd_options, options = {})
11
+ @indent_level = 0
12
+ super
13
+ end
14
+
15
+ def call
16
+ setup
17
+ @reporter = Polytrix::Reporters.reporter(options[:format], shell)
18
+ challenges = parse_subcommand(args.pop)
19
+
20
+ challenges.each do | challenge |
21
+ status_color = challenge.status_color.to_sym
22
+ status(challenge.slug, colorize(challenge.status_description, status_color), status_color)
23
+ indent do
24
+ status('Test suite', challenge.suite)
25
+ status('Test scenario', challenge.name)
26
+ status('Implementor', challenge.implementor.name)
27
+ source_file = challenge.absolute_source_file ? relativize(challenge.absolute_source_file, Dir.pwd) : colorize('<No code sample>', :red)
28
+ status('Source', source_file)
29
+ display_source(challenge)
30
+ display_execution_result(challenge)
31
+ display_validations(challenge)
32
+ display_spy_data(challenge)
33
+ end
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def reformat(string)
40
+ return if string.nil? || string.empty?
41
+
42
+ indent do
43
+ string.gsub(/^/, indent)
44
+ end
45
+ end
46
+
47
+ def indent
48
+ if block_given?
49
+ @indent_level += 2
50
+ result = yield
51
+ @indent_level -= 2
52
+ result
53
+ else
54
+ ' ' * @indent_level
55
+ end
56
+ end
57
+
58
+ def display_source(test)
59
+ return if !options[:source] || !test.source?
60
+
61
+ shell.say test.highlighted_code
62
+ end
63
+
64
+ def display_execution_result(test)
65
+ return if test.result.nil? || test.result.execution_result.nil?
66
+
67
+ execution_result = test.result.execution_result
68
+ status 'Execution result'
69
+ indent do
70
+ status('Exit Status', execution_result.exitstatus)
71
+ status 'Stdout'
72
+ say reformat(execution_result.stdout)
73
+ status 'Stderr'
74
+ say reformat(execution_result.stderr)
75
+ end
76
+ end
77
+
78
+ def display_validations(test)
79
+ return if test.validations.nil?
80
+
81
+ status 'Validations'
82
+ indent do
83
+ test.validations.each do | name, validation |
84
+ status(name, indicator(validation))
85
+ indent do
86
+ status 'Error message', validation.error if validation.error
87
+ unless !options[:source] || !validation.error_source?
88
+ status 'Validator source'
89
+ say highlight(validation.error_source, language: 'ruby')
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ def display_spy_data(test)
97
+ return if test.spy_data.nil?
98
+
99
+ status 'Data from spies'
100
+ indent do
101
+ test.spy_data.each do |_spy, data|
102
+ indent do
103
+ data.each_pair do |k, v|
104
+ status(k, v)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def say(msg)
112
+ shell.say msg if msg
113
+ end
114
+
115
+ def status(status, msg = nil, color = :cyan, colwidth = 50)
116
+ msg = yield if block_given?
117
+ shell.say(indent)
118
+ status = shell.set_color("#{status}:", color, true)
119
+ # The built-in say_status is right-aligned, we want left-aligned
120
+ shell.say format("%-#{colwidth}s %s", status, msg).rstrip
121
+ end
122
+
123
+ def print_table(*args)
124
+ @reporter.print_table(*args)
125
+ end
126
+
127
+ def colorize(string, *args)
128
+ return string unless @reporter.respond_to? :set_color
129
+ @reporter.set_color(string, *args)
130
+ end
131
+
132
+ def color_pad(string)
133
+ string + colorize('', :white)
134
+ end
135
+
136
+ def indicator(validation)
137
+ case validation.result
138
+ when :passed
139
+ colorize('✓ Passed', :green)
140
+ when :failed
141
+ colorize('x Failed', :red)
142
+ else
143
+ colorize(validation.result, :yellow)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end