omnitest 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +0 -0
  4. data/.groc.json +7 -0
  5. data/.rspec +6 -0
  6. data/.rubocop.yml +5 -0
  7. data/.rubocop_todo.yml +47 -0
  8. data/.travis.yml +12 -0
  9. data/.yardopts +3 -0
  10. data/Gemfile +26 -0
  11. data/README.md +341 -0
  12. data/Rakefile +33 -0
  13. data/appveyor.yml +9 -0
  14. data/bin/omnidoc +5 -0
  15. data/bin/omnitask +5 -0
  16. data/bin/omnitest +5 -0
  17. data/bower.json +21 -0
  18. data/doc-src/index.md.tt +341 -0
  19. data/doc-src/project_sets.md.tt +31 -0
  20. data/doc-src/usage/crosstask.md.tt +86 -0
  21. data/doc-src/usage/omnitest.md.tt +87 -0
  22. data/features/bootstrapping.feature +25 -0
  23. data/features/cloning.feature +32 -0
  24. data/features/fixtures/configs/omnitest_sample.yaml +11 -0
  25. data/features/fixtures/configs/skeptic_empty.yaml +12 -0
  26. data/features/fixtures/configs/skeptic_hello_world.yaml +10 -0
  27. data/features/show.feature +38 -0
  28. data/features/states.feature +40 -0
  29. data/features/step_definitions/sdk_steps.rb +22 -0
  30. data/features/support/env.rb +9 -0
  31. data/lib/omnitest.rb +211 -0
  32. data/lib/omnitest/cli.rb +297 -0
  33. data/lib/omnitest/command.rb +103 -0
  34. data/lib/omnitest/command/generate.rb +29 -0
  35. data/lib/omnitest/command/generators/code2doc.rb +79 -0
  36. data/lib/omnitest/command/generators/dashboard.rb +148 -0
  37. data/lib/omnitest/command/generators/documentation.rb +119 -0
  38. data/lib/omnitest/command/list.rb +62 -0
  39. data/lib/omnitest/command/project_action.rb +26 -0
  40. data/lib/omnitest/command/scenario_action.rb +20 -0
  41. data/lib/omnitest/command/show.rb +148 -0
  42. data/lib/omnitest/command/task.rb +27 -0
  43. data/lib/omnitest/command/test.rb +41 -0
  44. data/lib/omnitest/configuration.rb +53 -0
  45. data/lib/omnitest/documentation_generator.rb +68 -0
  46. data/lib/omnitest/project.rb +100 -0
  47. data/lib/omnitest/project_logger.rb +273 -0
  48. data/lib/omnitest/project_set.rb +47 -0
  49. data/lib/omnitest/reporters.rb +27 -0
  50. data/lib/omnitest/reporters/hash_reporter.rb +32 -0
  51. data/lib/omnitest/reporters/json_reporter.rb +12 -0
  52. data/lib/omnitest/reporters/markdown_reporter.rb +26 -0
  53. data/lib/omnitest/reporters/yaml_reporter.rb +12 -0
  54. data/lib/omnitest/run_action.rb +44 -0
  55. data/lib/omnitest/version.rb +3 -0
  56. data/lib/omnitest/workflow.rb +5 -0
  57. data/mkdocs.yml +8 -0
  58. data/omnitest.gemspec +39 -0
  59. data/omnitest.yaml +5 -0
  60. data/resources/assets/angular/angular.min.js +217 -0
  61. data/resources/assets/angular/angular.min.js.map +8 -0
  62. data/resources/assets/angular/json-formatter.min.css +6 -0
  63. data/resources/assets/angular/json-formatter.min.js +7 -0
  64. data/resources/assets/angular/ng-table.map +1 -0
  65. data/resources/assets/angular/ng-table.min.css +3 -0
  66. data/resources/assets/angular/ng-table.min.js +3 -0
  67. data/resources/assets/angular/ui-bootstrap-tpls.min.js +10 -0
  68. data/resources/assets/bootstrap/bootstrap.min.css +9 -0
  69. data/resources/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  70. data/resources/assets/fonts/glyphicons-halflings-regular.svg +229 -0
  71. data/resources/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  72. data/resources/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  73. data/resources/assets/pygments/autumn.css +58 -0
  74. data/resources/assets/pygments/borland.css +46 -0
  75. data/resources/assets/pygments/bw.css +34 -0
  76. data/resources/assets/pygments/colorful.css +61 -0
  77. data/resources/assets/pygments/default.css +62 -0
  78. data/resources/assets/pygments/emacs.css +61 -0
  79. data/resources/assets/pygments/friendly.css +61 -0
  80. data/resources/assets/pygments/fruity.css +69 -0
  81. data/resources/assets/pygments/github.css +61 -0
  82. data/resources/assets/pygments/manni.css +61 -0
  83. data/resources/assets/pygments/monokai.css +64 -0
  84. data/resources/assets/pygments/murphy.css +61 -0
  85. data/resources/assets/pygments/native.css +69 -0
  86. data/resources/assets/pygments/pastie.css +60 -0
  87. data/resources/assets/pygments/perldoc.css +58 -0
  88. data/resources/assets/pygments/tango.css +69 -0
  89. data/resources/assets/pygments/trac.css +59 -0
  90. data/resources/assets/pygments/vim.css +69 -0
  91. data/resources/assets/pygments/vs.css +33 -0
  92. data/resources/assets/pygments/zenburn.css +1 -0
  93. data/resources/assets/style.css +56 -0
  94. data/resources/code_sample.tt +2 -0
  95. data/resources/generators/dashboard/files/dashboard.html.tt +51 -0
  96. data/resources/generators/dashboard/files/dashboard.js +26 -0
  97. data/resources/generators/dashboard/templates/_test_report.html.haml +91 -0
  98. data/resources/generators/todo/templates/todo.md.tt +6 -0
  99. data/resources/generators/todo/todo_template.rb +1 -0
  100. data/samples/.gitignore +2 -0
  101. data/samples/_markdown.md +5 -0
  102. data/samples/bootstrap.sh +2 -0
  103. data/samples/clone.sh +2 -0
  104. data/samples/code2doc.sh +5 -0
  105. data/samples/default_bootstrap.rb +7 -0
  106. data/samples/detect.sh +2 -0
  107. data/samples/exec.sh +2 -0
  108. data/samples/omnitest.yaml +24 -0
  109. data/samples/omnitest_simple.yaml +8 -0
  110. data/samples/scripts/bootstrap +3 -0
  111. data/samples/show.sh +4 -0
  112. data/samples/skeptic.yaml +13 -0
  113. data/samples/skeptic_simple.yaml +9 -0
  114. data/samples/test.sh +2 -0
  115. data/samples/tests/omnitest/validators.rb +23 -0
  116. data/samples/verify.sh +3 -0
  117. data/scripts/bootstrap.ps1 +7 -0
  118. data/scripts/run_script.sh +4 -0
  119. data/skeptic.yaml +26 -0
  120. data/spec/fabricators/project_fabricator.rb +19 -0
  121. data/spec/fabricators/scenario_fabricator.rb +6 -0
  122. data/spec/fabricators/test_manifest_fabricator.rb +41 -0
  123. data/spec/fabricators/validator_fabricator.rb +12 -0
  124. data/spec/fixtures/factorial.py +18 -0
  125. data/spec/fixtures/omnitest.yaml +11 -0
  126. data/spec/fixtures/skeptic.yaml +16 -0
  127. data/spec/fixtures/src-doc/_scenario.md.erb +1 -0
  128. data/spec/fixtures/src-doc/quine.md.erb +20 -0
  129. data/spec/omnitest/cli_spec.rb +38 -0
  130. data/spec/omnitest/configuration_spec.rb +25 -0
  131. data/spec/omnitest/documentation_generator_spec.rb +59 -0
  132. data/spec/omnitest/file_finder_spec.rb +21 -0
  133. data/spec/omnitest/project_spec.rb +65 -0
  134. data/spec/omnitest_spec.rb +13 -0
  135. data/spec/spec_helper.rb +32 -0
  136. data/spec/thor_spy.rb +66 -0
  137. data/tests/omnitest/bootstrap_validations.rb +7 -0
  138. data/tests/omnitest/show_validations.rb +22 -0
  139. data/yard_macros.rb +25 -0
  140. metadata +470 -0
@@ -0,0 +1,27 @@
1
+ require 'benchmark'
2
+
3
+ module Omnitest
4
+ module Command
5
+ class Task < Omnitest::Command::Base
6
+ include RunAction
7
+
8
+ # Invoke the command.
9
+ def call
10
+ banner "Starting Omnitest (v#{Omnitest::VERSION})"
11
+ elapsed = Benchmark.measure do
12
+ setup
13
+ task = args.shift
14
+ project_regex = args.shift
15
+ projects = Omnitest.filter_projects(project_regex)
16
+ if options[:exec]
17
+ run_action(projects, :execute, options[:concurrency])
18
+ else
19
+ run_action(projects, task, options[:concurrency])
20
+ end
21
+ end
22
+ # Need task summary...
23
+ banner "Omnitest is finished. #{Core::Util.duration(elapsed.real)}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ require 'omnitest/command'
2
+
3
+ require 'benchmark'
4
+
5
+ module Omnitest
6
+ module Command
7
+ # Command to test one or more instances.
8
+ class Test < Omnitest::Command::Base
9
+ include RunAction
10
+
11
+ # Invoke the command.
12
+ def call
13
+ banner "Starting Omnitest (v#{Omnitest::VERSION})"
14
+ scenarios = nil
15
+ elapsed = Benchmark.measure do
16
+ setup
17
+ scenarios = parse_subcommand(args.shift, args.shift)
18
+
19
+ run_action(scenarios, :test, options[:concurrency])
20
+ end
21
+ banner "Omnitest is finished. #{Core::Util.duration(elapsed.real)}"
22
+ test_summary(scenarios)
23
+ end
24
+
25
+ def test_summary(scenarios)
26
+ # TODO: Need an actual test summary
27
+ failed_scenarios = scenarios.select do | s |
28
+ !s.status_description.match(/Fully Verified|<Not Found>/)
29
+ end
30
+
31
+ shell.say
32
+ failed_scenarios.each do | scenario |
33
+ shell.say_status scenario.status_description, scenario.slug
34
+ end
35
+ status_line = "#{scenarios.size} scenarios, #{failed_scenarios.size} failures" # , x pending
36
+ shell.say status_line
37
+ abort unless failed_scenarios.empty?
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+
2
+ require 'rspec/support'
3
+ require 'rspec/expectations'
4
+
5
+ module Omnitest
6
+ RESOURCES_DIR = File.expand_path '../../../resources', __FILE__
7
+
8
+ class Configuration < Omnitest::Core::Dash
9
+ extend Forwardable
10
+ field :dry_run, Object, default: false
11
+ field :log_root, Pathname, default: '.omnitest/logs'
12
+ field :log_level, Symbol, default: :info
13
+ field :travis, Object, default: false
14
+ field :concurrency, Integer
15
+
16
+ # TODO: This should probably be configurable, or tied to Thor color options.
17
+ if RSpec.respond_to?(:configuration)
18
+ RSpec.configuration.color = true
19
+ else
20
+ RSpec::Expectations.configuration.color = true
21
+ end
22
+
23
+ def skeptic
24
+ Skeptic.configuration
25
+ end
26
+
27
+ def default_logger
28
+ @default_logger ||= ProjectLogger.new(stdout: $stdout, level: Core::Util.to_logger_level(log_level))
29
+ end
30
+
31
+ def project_set
32
+ @project_set ||= load_project_set('omnitest.yaml')
33
+ end
34
+
35
+ def project_set=(project_set_data)
36
+ if project_set_data.is_a? Skeptic::TestManifest
37
+ @project_set = project_set_data
38
+ else
39
+ @project_set = ProjectSet.from_yaml project_set_data
40
+ end
41
+ @project_set
42
+ rescue Errno::ENOENT => e
43
+ raise UserError, "Could not load test manifest: #{e.message}"
44
+ end
45
+
46
+ def clear
47
+ skeptic.clear
48
+ super
49
+ end
50
+
51
+ alias_method :load_project_set, :project_set=
52
+ end
53
+ end
@@ -0,0 +1,68 @@
1
+ require 'tilt' # padrino-helpers wants you to pre-require tilt/erubis
2
+ require 'erubis'
3
+ require 'padrino-helpers'
4
+
5
+ module Omnitest
6
+ class DocumentationGenerator
7
+ [
8
+ Padrino::Helpers::OutputHelpers,
9
+ Padrino::Helpers::AssetTagHelpers,
10
+ Padrino::Helpers::TagHelpers,
11
+ Omnitest::Psychic::Code2Doc::CodeHelper
12
+ ].each do | helper|
13
+ include helper
14
+ end
15
+
16
+ attr_reader :scenario
17
+
18
+ def initialize(template_file = nil, scenario = nil)
19
+ @scenario = scenario
20
+ @template_file = template_file
21
+ end
22
+
23
+ def process(scenarios)
24
+ return nil unless File.readable? @template_file
25
+
26
+ @scenarios = scenarios
27
+ erb = ERB.new File.read(@template_file)
28
+ @result = erb.result(binding) || ''
29
+ end
30
+
31
+ def save(target_file)
32
+ fail 'No results to write, please call process before save' if @result.nil? || @result.empty?
33
+
34
+ FileUtils.mkdir_p File.dirname(target_file)
35
+ File.open(target_file, 'wb') do |f|
36
+ f.write @result
37
+ end
38
+ end
39
+
40
+ def code2doc(source_file, language = nil)
41
+ source_code = File.read(source_file)
42
+ segmenter_language ||= infer_language(source_file)
43
+
44
+ buffer = StringIO.new
45
+ segmenter_options = {
46
+ language: language
47
+ }
48
+ segmenter = Omnitest::Psychic::Code2Doc::CodeSegmenter.new(segmenter_options)
49
+ segments = segmenter.segment source_code
50
+ segments.each do |comment, code|
51
+ comment = comment.join("\n")
52
+ code = code.join("\n")
53
+ code = code_block(code, language) unless code.empty?
54
+ next if comment.empty? && code.empty?
55
+ code = "\n#{code}\n" if !comment.empty? && !code.empty? # Markdown needs separation
56
+ buffer.puts [comment, code].join("\n")
57
+ end
58
+ buffer.string
59
+ end
60
+
61
+ private
62
+
63
+ def infer_language(source_file)
64
+ language, comment_style = Psychic::Code2Doc::CommentStyles.infer File.extname(source_file)
65
+ segmenter_language = comment_style[:language] || language
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,100 @@
1
+ module Omnitest
2
+ class Project < Omnitest::Core::Dash
3
+ include Omnitest::Core::Logging
4
+ include Omnitest::Core::FileSystem
5
+
6
+ class GitOptions < Omnitest::Core::Dash
7
+ required_field :repo, String
8
+ field :branch, String
9
+ field :to, String
10
+
11
+ def initialize(data)
12
+ data = { repo: data } if data.is_a? String
13
+ super
14
+ end
15
+ end
16
+
17
+ field :name, String
18
+ field :basedir, Pathname
19
+ field :language, String
20
+ field :git, GitOptions
21
+
22
+ alias_method :cwd, :basedir
23
+
24
+ attr_accessor :psychic, :skeptic
25
+
26
+ def psychic
27
+ @psychic ||= Omnitest::Psychic.new(name: name, cwd: basedir, logger: logger, travis: Omnitest.configuration.travis)
28
+ end
29
+
30
+ def skeptic
31
+ @skeptic ||= Omnitest::Skeptic.new(psychic)
32
+ end
33
+
34
+ def execute(*args)
35
+ psychic.execute(*args)
36
+ end
37
+
38
+ def basedir
39
+ self[:basedir] ||= "projects/#{name}"
40
+ end
41
+
42
+ def logger
43
+ @logger ||= Omnitest.new_logger(self)
44
+ end
45
+
46
+ def clone
47
+ if git.nil? || git.repo.nil?
48
+ logger.info 'Skipping clone because there are no git options'
49
+ return
50
+ end
51
+ branch = git.branch ||= 'master'
52
+ target_dir = git.to ||= basedir
53
+ target_dir = Omnitest::Core::FileSystem.relativize(target_dir, Omnitest.basedir)
54
+ if File.exist? target_dir
55
+ logger.info "Skipping clone because #{target_dir} already exists"
56
+ else
57
+ clone_cmd = "git clone #{git.repo} -b #{branch} #{target_dir}"
58
+ logger.info "Cloning: #{clone_cmd}"
59
+ Omnitest.psychic.execute(clone_cmd)
60
+ end
61
+ end
62
+
63
+ def task(task_name, opts = { fail_if_missing: true })
64
+ banner_msg = opts[:custom_banner] || "Running task #{task_name} for #{name}"
65
+ banner banner_msg
66
+ fail "Project #{name} has not been cloned" unless cloned?
67
+ psychic.task(task_name).execute
68
+ rescue Omnitest::Psychic::TaskNotImplementedError => e
69
+ if opts[:fail_if_missing]
70
+ logger.error("Could not run task #{task_name} for #{name}: #{e.message}")
71
+ raise ActionFailed.new("Failed to run task #{task_name} for #{name}: #{e.message}", e)
72
+ else
73
+ logger.warn "Skipping #{task_name} for #{name}, no #{task_name} task exists"
74
+ end
75
+ end
76
+
77
+ def workflow(workflow_name)
78
+ workflow_definition = Omnitest.configuration.project_set.workflows[workflow_name]
79
+ fail UserError, "Workflow '#{workflow_name}' is not defined" if workflow_definition.nil?
80
+
81
+ workflow = psychic.workflow(workflow_name) do
82
+ workflow_definition.tasks.each do | task_name |
83
+ task task_name
84
+ end
85
+ end
86
+
87
+ workflow.execute
88
+ rescue Psychic::TaskNotImplementedError => e
89
+ raise UserError, "Cannot run workflow '#{workflow_name}' for project '#{name}': #{e.message}"
90
+ end
91
+
92
+ def bootstrap
93
+ task('bootstrap', custom_banner: "Bootstrapping #{name}", fail_if_missing: false)
94
+ end
95
+
96
+ def cloned?
97
+ File.directory? basedir
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,273 @@
1
+ require 'fileutils'
2
+ require 'logger'
3
+
4
+ module Omnitest
5
+ class ProjectLogger
6
+ include ::Logger::Severity
7
+
8
+ # @return [IO] the log device
9
+ attr_reader :logdev
10
+
11
+ # Constructs a new logger.
12
+ #
13
+ # @param options [Hash] configuration for a new logger
14
+ # @option options [Symbol] :color color to use when when outputting
15
+ # messages
16
+ # @option options [Integer] :level the logging severity threshold
17
+ # (default: `Omnitest::DEFAULT_LOG_LEVEL`)
18
+ # @option options [String,IO] :logdev filepath String or IO object to be
19
+ # used for logging (default: `nil`)
20
+ # @option options [String] :progname program name to include in log
21
+ # messages (default: `"Omnitest"`)
22
+ # @option options [IO] :stdout a standard out IO object to use
23
+ # (default: `$stdout`)
24
+ def initialize(options = {})
25
+ color = options[:color]
26
+
27
+ @loggers = []
28
+ @loggers << @logdev = logdev_logger(options[:logdev]) if options[:logdev]
29
+ @loggers << stdout_logger(options[:stdout], color) if options[:stdout]
30
+ @loggers << stdout_logger($stdout, color) if @loggers.empty?
31
+
32
+ self.progname = options[:progname] || 'Omnitest'
33
+ self.level = options[:level] || default_log_level
34
+ end
35
+
36
+ class << self
37
+ private
38
+
39
+ # @api private
40
+ # @!macro delegate_to_first_logger
41
+ # @method $1()
42
+ def delegate_to_first_logger(meth)
43
+ define_method(meth) { |*args| @loggers.first.public_send(meth, *args) }
44
+ end
45
+
46
+ # @api private
47
+ # @!macro delegate_to_all_loggers
48
+ # @method $1()
49
+ def delegate_to_all_loggers(meth)
50
+ define_method(meth) do |*args|
51
+ result = nil
52
+ @loggers.each { |l| result = l.public_send(meth, *args) }
53
+ result
54
+ end
55
+ end
56
+ end
57
+
58
+ # @return [Integer] the logging severity threshold
59
+ # @see http://is.gd/Okuy5p
60
+ delegate_to_first_logger :level
61
+
62
+ # Sets the logging severity threshold.
63
+ #
64
+ # @param level [Integer] the logging severity threshold
65
+ # @see http://is.gd/H1VBFH
66
+ delegate_to_all_loggers :level=
67
+
68
+ # @return [String] program name to include in log messages
69
+ # @see http://is.gd/5uHGK0
70
+ delegate_to_first_logger :progname
71
+
72
+ # Sets the program name to include in log messages.
73
+ #
74
+ # @param progname [String] the program name to include in log messages
75
+ # @see http://is.gd/f2U5Xj
76
+ delegate_to_all_loggers :progname=
77
+
78
+ # @return [String] the date format being used
79
+ # @see http://is.gd/btmFWJ
80
+ delegate_to_first_logger :datetime_format
81
+
82
+ # Sets the date format being used.
83
+ #
84
+ # @param format [String] the date format
85
+ # @see http://is.gd/M36ml8
86
+ delegate_to_all_loggers :datetime_format=
87
+
88
+ # Log a message if the given severity is high enough.
89
+ #
90
+ # @see http://is.gd/5opBW0
91
+ delegate_to_all_loggers :add
92
+
93
+ # Dump one or more messages to info.
94
+ #
95
+ # @param message [#to_s] the message to log
96
+ # @see http://is.gd/BCp5KV
97
+ delegate_to_all_loggers :<<
98
+
99
+ # Log a message with severity of banner (high level).
100
+ #
101
+ # @param message_or_progname [#to_s] the message to log. In the block
102
+ # form, this is the progname to use in the log message.
103
+ # @yield evaluates to the message to log. This is not evaluated unless the
104
+ # logger's level is sufficient to log the message. This allows you to
105
+ # create potentially expensive logging messages that are only called when
106
+ # the logger is configured to show them.
107
+ # @return [nil,true] when the given severity is not high enough (for this
108
+ # particular logger), log no message, and return true
109
+ # @see http://is.gd/pYUCYU
110
+ delegate_to_all_loggers :banner
111
+
112
+ # Log a message with severity of debug.
113
+ #
114
+ # @param message_or_progname [#to_s] the message to log. In the block
115
+ # form, this is the progname to use in the log message.
116
+ # @yield evaluates to the message to log. This is not evaluated unless the
117
+ # logger's level is sufficient to log the message. This allows you to
118
+ # create potentially expensive logging messages that are only called when
119
+ # the logger is configured to show them.
120
+ # @return [nil,true] when the given severity is not high enough (for this
121
+ # particular logger), log no message, and return true
122
+ # @see http://is.gd/Re97Zp
123
+ delegate_to_all_loggers :debug
124
+
125
+ # @return [true,false] whether or not the current severity level
126
+ # allows for the printing of debug messages
127
+ # @see http://is.gd/Iq08xB
128
+ delegate_to_first_logger :debug?
129
+
130
+ # Log a message with severity of info.
131
+ #
132
+ # @param message_or_progname [#to_s] the message to log. In the block
133
+ # form, this is the progname to use in the log message.
134
+ # @yield evaluates to the message to log. This is not evaluated unless the
135
+ # logger's level is sufficient to log the message. This allows you to
136
+ # create potentially expensive logging messages that are only called when
137
+ # the logger is configured to show them.
138
+ # @return [nil,true] when the given severity is not high enough (for this
139
+ # particular logger), log no message, and return true
140
+ # @see http://is.gd/pYUCYU
141
+ delegate_to_all_loggers :info
142
+
143
+ # @return [true,false] whether or not the current severity level
144
+ # allows for the printing of info messages
145
+ # @see http://is.gd/lBtJkT
146
+ delegate_to_first_logger :info?
147
+
148
+ # Log a message with severity of error.
149
+ #
150
+ # @param message_or_progname [#to_s] the message to log. In the block
151
+ # form, this is the progname to use in the log message.
152
+ # @yield evaluates to the message to log. This is not evaluated unless the
153
+ # logger's level is sufficient to log the message. This allows you to
154
+ # create potentially expensive logging messages that are only called when
155
+ # the logger is configured to show them.
156
+ # @return [nil,true] when the given severity is not high enough (for this
157
+ # particular logger), log no message, and return true
158
+ # @see http://is.gd/mLwYMl
159
+ delegate_to_all_loggers :error
160
+
161
+ # @return [true,false] whether or not the current severity level
162
+ # allows for the printing of error messages
163
+ # @see http://is.gd/QY19JL
164
+ delegate_to_first_logger :error?
165
+
166
+ # Log a message with severity of warn.
167
+ #
168
+ # @param message_or_progname [#to_s] the message to log. In the block
169
+ # form, this is the progname to use in the log message.
170
+ # @yield evaluates to the message to log. This is not evaluated unless the
171
+ # logger's level is sufficient to log the message. This allows you to
172
+ # create potentially expensive logging messages that are only called when
173
+ # the logger is configured to show them.
174
+ # @return [nil,true] when the given severity is not high enough (for this
175
+ # particular logger), log no message, and return true
176
+ # @see http://is.gd/PX9AIS
177
+ delegate_to_all_loggers :warn
178
+
179
+ # @return [true,false] whether or not the current severity level
180
+ # allows for the printing of warn messages
181
+ # @see http://is.gd/Gdr4lD
182
+ delegate_to_first_logger :warn?
183
+
184
+ # Log a message with severity of fatal.
185
+ #
186
+ # @param message_or_progname [#to_s] the message to log. In the block
187
+ # form, this is the progname to use in the log message.
188
+ # @yield evaluates to the message to log. This is not evaluated unless the
189
+ # logger's level is sufficient to log the message. This allows you to
190
+ # create potentially expensive logging messages that are only called when
191
+ # the logger is configured to show them.
192
+ # @return [nil,true] when the given severity is not high enough (for this
193
+ # particular logger), log no message, and return true
194
+ # @see http://is.gd/5ElFPK
195
+ delegate_to_all_loggers :fatal
196
+
197
+ # @return [true,false] whether or not the current severity level
198
+ # allows for the printing of fatal messages
199
+ # @see http://is.gd/7PgwRl
200
+ delegate_to_first_logger :fatal?
201
+
202
+ # Log a message with severity of unknown.
203
+ #
204
+ # @param message_or_progname [#to_s] the message to log. In the block
205
+ # form, this is the progname to use in the log message.
206
+ # @yield evaluates to the message to log. This is not evaluated unless the
207
+ # logger's level is sufficient to log the message. This allows you to
208
+ # create potentially expensive logging messages that are only called when
209
+ # the logger is configured to show them.
210
+ # @return [nil,true] when the given severity is not high enough (for this
211
+ # particular logger), log no message, and return true
212
+ # @see http://is.gd/Y4hqpf
213
+ delegate_to_all_loggers :unknown
214
+
215
+ # Close the logging devices.
216
+ #
217
+ # @see http://is.gd/b13cVn
218
+ delegate_to_all_loggers :close
219
+
220
+ private
221
+
222
+ # @return [Integer] the default logger level
223
+ # @api private
224
+ def default_log_level
225
+ Omnitest::Core::Util.to_logger_level(Omnitest.configuration.log_level)
226
+ end
227
+
228
+ # Construct a new standard out logger.
229
+ #
230
+ # @param stdout [IO] the IO object that represents stdout (or similar)
231
+ # @param color [Symbol] color to use when outputing messages
232
+ # @return [StdoutLogger] a new logger
233
+ # @api private
234
+ def stdout_logger(stdout, color)
235
+ logger = Omnitest::Core::StdoutLogger.new(stdout)
236
+ if Omnitest.tty?
237
+ logger.formatter = proc do |_severity, _datetime, _progname, msg|
238
+ Core::Color.colorize("#{msg}", color).concat("\n")
239
+ end
240
+ else
241
+ logger.formatter = proc do |_severity, _datetime, _progname, msg|
242
+ msg.concat("\n")
243
+ end
244
+ end
245
+ logger
246
+ end
247
+
248
+ # Construct a new logdev logger.
249
+ #
250
+ # @param filepath_or_logdev [String,IO] a filepath String or IO object
251
+ # @return [LogdevLogger] a new logger
252
+ # @api private
253
+ def logdev_logger(filepath_or_logdev)
254
+ Omnitest::Core::LogdevLogger.new(resolve_logdev(filepath_or_logdev))
255
+ end
256
+
257
+ # Return an IO object from a filepath String or the IO object itself.
258
+ #
259
+ # @param filepath_or_logdev [String,IO] a filepath String or IO object
260
+ # @return [IO] an IO object
261
+ # @api private
262
+ def resolve_logdev(filepath_or_logdev)
263
+ if filepath_or_logdev.is_a? String
264
+ FileUtils.mkdir_p(File.dirname(filepath_or_logdev))
265
+ file = File.open(File.expand_path(filepath_or_logdev), 'ab')
266
+ file.sync = true
267
+ file
268
+ else
269
+ filepath_or_logdev
270
+ end
271
+ end
272
+ end
273
+ end