# frozen_string_literal: true ASCIIDOCTOR_TEST_DIR = File.absolute_path __dir__ ASCIIDOCTOR_LIB_DIR = ENV['ASCIIDOCTOR_LIB_DIR'] || (File.join ASCIIDOCTOR_TEST_DIR, '../lib') require 'simplecov' if ENV['COVERAGE'] == 'true' require File.join ASCIIDOCTOR_LIB_DIR, 'asciidoctor' Dir.chdir Asciidoctor::ROOT_DIR require 'nokogiri' # NOTE rouge has all sorts of warnings we don't want to see, so silence them proc do old_verbose, $VERBOSE = $VERBOSE, nil require 'rouge' $VERBOSE = old_verbose end.call require 'socket' require 'tempfile' require 'tmpdir' autoload :FileUtils, 'fileutils' autoload :Pathname, 'pathname' RE_XMLNS_ATTRIBUTE = / xmlns="[^"]+"/ RE_DOCTYPE = /\s* "<" # # Returns the decoded String that corresponds to the numeric character reference def decode_char number [number].pack 'U1' end def invoke_cli_with_filenames argv = [], filenames = [], &block filepaths = [] filenames.each do |filename| if filenames.nil? || (Pathname.new filename).absolute? filepaths << filename else filepaths << (fixture_path filename) end end invoker = Asciidoctor::Cli::Invoker.new argv + filepaths invoker.invoke!(&block) invoker end def invoke_cli_to_buffer argv = [], filename = 'sample.adoc', &block invoke_cli argv, filename, [StringIO.new, StringIO.new], &block end def invoke_cli argv = [], filename = 'sample.adoc', buffers = nil, &block if filename.nil? || filename == '-' || (Pathname.new filename).absolute? filepath = filename else filepath = fixture_path filename end invoker = Asciidoctor::Cli::Invoker.new argv + [filepath] invoker.redirect_streams(*buffers) if buffers invoker.invoke!(&block) invoker end def redirect_streams old_stdout, $stdout = $stdout, StringIO.new old_stderr, $stderr = $stderr, StringIO.new old_logger = Asciidoctor::LoggerManager.logger old_logger_level = old_logger.level new_logger = (Asciidoctor::LoggerManager.logger = Asciidoctor::Logger.new $stderr) new_logger.level = old_logger_level yield $stdout, $stderr ensure $stdout, $stderr = old_stdout, old_stderr Asciidoctor::LoggerManager.logger = old_logger end def resolve_localhost Socket.ip_address_list.find(&:ipv4?).ip_address end def using_memory_logger level = nil old_logger = Asciidoctor::LoggerManager.logger memory_logger = Asciidoctor::MemoryLogger.new memory_logger.level = level if level begin Asciidoctor::LoggerManager.logger = memory_logger yield memory_logger ensure Asciidoctor::LoggerManager.logger = old_logger end end def in_verbose_mode begin old_logger_level, Asciidoctor::LoggerManager.logger.level = Asciidoctor::LoggerManager.logger.level, Logger::Severity::DEBUG yield ensure Asciidoctor::LoggerManager.logger.level = old_logger_level end end def asciidoctor_cmd ruby_args = nil [Gem.ruby, *ruby_args, (File.join bindir, 'asciidoctor')] end # NOTE run_command fails on JRuby 9.1 for Windows with the following error: # Java::JavaLang::ClassCastException at org.jruby.util.ShellLauncher.getModifiedEnv(ShellLauncher.java:271) def run_command cmd, *args, &block if Array === cmd args.unshift(*cmd) cmd = args.shift end kw_args = Hash === args[-1] ? args.pop : {} env = kw_args[:env] (env ||= {})['RUBYOPT'] = nil unless kw_args[:use_bundler] # JRuby 9.1 on Windows doesn't support popen options; therefore, test cannot capture / assert on stderr opts = jruby_9_1_windows? ? {} : { err: [:child, :out] } if env # NOTE while JRuby 9.2.10.0 implements support for unsetenv_others, it doesn't work in child #if jruby? && (Gem::Version.new JRUBY_VERSION) < (Gem::Version.new '9.2.10.0') if jruby? begin old_env, env = ENV.merge, (ENV.merge env) env.each {|key, val| env.delete key if val.nil? } if env.value? nil ENV.replace env popen [cmd, *args, opts], &block ensure ENV.replace old_env end elsif env.value? nil env = env.each_with_object ENV.to_h do |(key, val), accum| val.nil? ? (accum.delete key) : (accum[key] = val) end popen [env, cmd, *args, (opts.merge unsetenv_others: true)], &block else popen [env, cmd, *args, opts], &block end else popen [cmd, *args, opts], &block end end def popen args, &block # When block is passed to IO.popen, JRuby for Windows does not return value of block as return value if jruby? && windows? result = nil IO.popen args do |io| result = yield io end result else IO.popen args, &block end end def using_test_webserver host = resolve_localhost, port = 9876 base_dir = testdir server = TCPServer.new host, port server_thread = Thread.start do Thread.current[:requests] = requests = [] while (session = server.accept) requests << (request = session.gets) if /^GET (\S+) HTTP\/1\.1$/ =~ request.chomp resource = (resource = $1) == '' ? '.' : resource else session.print %(HTTP/1.1 405 Method Not Allowed\r\nContent-Type: text/plain\r\n\r\n) session.print %(405 - Method not allowed\n) session.close next end if resource == '/name/asciidoctor' session.print %(HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n) session.print %({"name": "asciidoctor"}\n) elsif File.file? resource_file = (File.join base_dir, resource) if (ext = File.extname(resource_file)[1..-1]) mimetype = ext == 'adoc' ? 'text/plain' : %(image/#{ext}) else mimetype = 'text/plain' end session.print %(HTTP/1.1 200 OK\r\nContent-Type: #{mimetype}\r\n\r\n) File.open resource_file, Asciidoctor::FILE_READ_MODE do |fd| session.write fd.read 256 until fd.eof? end else session.print %(HTTP/1.1 404 File Not Found\r\nContent-Type: text/plain\r\n\r\n) session.print %(404 - Resource not found.\n) end session.close end end begin yield %(http://#{host}:#{port}), server_thread ensure server_thread.exit server_thread.value server.close end end end ### # # Context goodness provided by @citrusbyte's contest. # See https://github.com/citrusbyte/contest # ### # Contest adds +teardown+, +test+ and +context+ as class methods, and the # instance methods +setup+ and +teardown+ now iterate on the corresponding # blocks. Note that all setup and teardown blocks must be defined with the # block syntax. Adding setup or teardown instance methods defeats the purpose # of this library. class Minitest::Test class << self def setup &block define_method :setup do super(&block) instance_eval(&block) end end def teardown &block define_method :teardown do instance_eval(&block) super(&block) end end def context name, opts = {}, &block if opts.key? :if return unless opts[:if] elsif opts.key? :unless return if opts[:unless] end subclass = Class.new self remove_tests subclass subclass.class_eval(&block) if block_given? const_set (context_name name), subclass end def test name, opts = {}, &block if opts.key? :if return unless opts[:if] elsif opts.key? :unless return if opts[:unless] end define_method (test_name name), &block end def remove_tests subclass subclass.public_instance_methods.each do |m| subclass.send :undef_method, m if m.to_s.start_with? 'test_' end end alias should test alias describe context private def context_name name %(Test#{(sanitize_name name).gsub(/(^| )(\w)/) { $2.upcase }}).to_sym end def test_name name %(test_#{(sanitize_name name).gsub %r/\s+/, '_'}).to_sym end def sanitize_name name (name.gsub %r/\W+/, ' ').strip end end end def context name, &block Minitest::Test.context name, &block end