omnitest 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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