"Fossies" - the Fresh Open Source Software Archive

Member "asciidoctor-2.0.10/test/test_helper.rb" (1 Jun 2019, 13722 Bytes) of package /linux/www/asciidoctor-2.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "test_helper.rb": 2.0.5_vs_2.0.6.

    1 # frozen_string_literal: true
    2 ASCIIDOCTOR_TEST_DIR = File.absolute_path __dir__
    3 ASCIIDOCTOR_LIB_DIR = ENV['ASCIIDOCTOR_LIB_DIR'] || (File.join ASCIIDOCTOR_TEST_DIR, '../lib')
    4 
    5 require 'simplecov' if ENV['COVERAGE'] == 'true'
    6 
    7 require File.join ASCIIDOCTOR_LIB_DIR, 'asciidoctor'
    8 Dir.chdir Asciidoctor::ROOT_DIR
    9 
   10 require 'nokogiri'
   11 proc do
   12   old_verbose, $VERBOSE = $VERBOSE, nil
   13   require 'rouge'
   14   Rouge::Lexer.disable_debug!
   15   $VERBOSE = old_verbose
   16 end.call
   17 require 'socket'
   18 require 'tempfile'
   19 require 'tmpdir'
   20 
   21 autoload :FileUtils, 'fileutils'
   22 autoload :Open3, 'open3'
   23 autoload :Pathname,  'pathname'
   24 
   25 RE_XMLNS_ATTRIBUTE = / xmlns="[^"]+"/
   26 RE_DOCTYPE = /\s*<!DOCTYPE (.*)/
   27 
   28 require 'minitest/autorun'
   29 
   30 # Minitest 4 doesn't have Minitest::Test
   31 Minitest::Test = MiniTest::Unit::TestCase unless defined? Minitest::Test
   32 
   33 class Minitest::Test
   34   def jruby?
   35     RUBY_ENGINE == 'jruby'
   36   end
   37 
   38   def windows?
   39     RbConfig::CONFIG['host_os'] =~ /win|ming/
   40   end
   41 
   42   def disk_root
   43     %(#{windows? ? (Asciidoctor::ROOT_DIR.partition '/')[0] : ''}/)
   44   end
   45 
   46   def empty_document options = {}
   47     options[:parse] ? (Asciidoctor::Document.new [], options).parse : (Asciidoctor::Document.new [], options)
   48   end
   49 
   50   def empty_safe_document options = {}
   51     Asciidoctor::Document.new [], (options.merge safe: :safe)
   52   end
   53 
   54   def sample_doc_path name
   55     unless (name = name.to_s).include? '.'
   56       %w(adoc asciidoc txt).each do |ext|
   57         if File.exist? fixture_path %(#{name}.#{ext})
   58           name = %(#{name}.#{ext})
   59           break
   60         end
   61       end
   62     end
   63     fixture_path name
   64   end
   65 
   66   def bindir
   67     File.join Asciidoctor::ROOT_DIR, 'bin'
   68   end
   69 
   70   def asciidoctor_cmd use_ruby = true, ruby_opts = nil
   71     executable = File.join bindir, 'asciidoctor'
   72     if use_ruby
   73       ruby = File.join RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name']
   74       ruby = %(#{ruby} #{ruby_opts}) if ruby_opts
   75       %(#{ruby} #{executable})
   76     else
   77       executable
   78     end
   79   end
   80 
   81   def testdir
   82     ASCIIDOCTOR_TEST_DIR
   83   end
   84 
   85   def fixturedir
   86     File.join testdir, 'fixtures'
   87   end
   88 
   89   def fixture_path name
   90     File.join fixturedir, name
   91   end
   92 
   93   def example_document name, opts = {}
   94     document_from_string (File.read (sample_doc_path name), mode: Asciidoctor::FILE_READ_MODE), opts
   95   end
   96 
   97   def xmlnodes_at_css css, content, count = nil
   98     xmlnodes_at_path :css, css, content, count
   99   end
  100 
  101   def xmlnodes_at_xpath xpath, content, count = nil
  102     xmlnodes_at_path :xpath, xpath, content, count
  103   end
  104 
  105   def xmlnodes_at_path type, path, content, count = nil
  106     doc = xmldoc_from_string content
  107     case type
  108     when :xpath
  109       namespaces = (doc.respond_to? :root) ? doc.root.namespaces : {}
  110       results = doc.xpath %(#{path.sub '/', './'}), namespaces
  111     when :css
  112       results = doc.css path
  113     end
  114     count == 1 ? results.first : results
  115   end
  116 
  117   # Generate an xpath attribute matcher that matches a name in the class attribute
  118   def contains_class name
  119     %(contains(concat(' ', normalize-space(@class), ' '), ' #{name} '))
  120   end
  121 
  122   def assert_css css, content, count = nil
  123     assert_path :css, css, content, count
  124   end
  125 
  126   def assert_xpath xpath, content, count = nil
  127     assert_path :xpath, xpath, content, count
  128   end
  129 
  130   def assert_path type, path, content, count = nil
  131     case type
  132     when :xpath
  133       type_name = 'XPath'
  134     when :css
  135       type_name = 'CSS'
  136     end
  137 
  138     results = xmlnodes_at_path type, path, content
  139 
  140     if count == true || count == false
  141       if count == results
  142         assert true
  143       else
  144         flunk %(#{type_name} #{path} yielded #{results} rather than #{count} for:\n#{content})
  145       end
  146     elsif count && results.size != count
  147       flunk %(#{type_name} #{path} yielded #{results.size} elements rather than #{count} for:\n#{content})
  148     elsif count.nil? && results.empty?
  149       flunk %(#{type_name} #{path} not found in:\n#{content})
  150     else
  151       assert true
  152     end
  153   end
  154 
  155   def assert_include expected, actual
  156     assert_includes actual, expected
  157   end
  158 
  159   def refute_include not_expected, actual
  160     refute_includes actual, not_expected
  161   end
  162 
  163   def assert_message logger, severity, expected_message, kind = String, idx = nil
  164     unless idx
  165       assert_equal 1, logger.messages.size
  166       idx = 0
  167     end
  168     message = logger.messages[idx]
  169     assert_equal severity, message[:severity]
  170     assert_kind_of kind, message[:message]
  171     if kind == String
  172       actual_message = message[:message]
  173     else
  174       refute_nil message[:message][:source_location]
  175       actual_message = message[:message].inspect
  176     end
  177     if expected_message.start_with? '~'
  178       assert_includes actual_message, expected_message[1..-1]
  179     else
  180       assert_equal expected_message, actual_message
  181     end
  182   end
  183 
  184   def assert_messages logger, expected_messages
  185     assert_equal expected_messages.size, logger.messages.size
  186     expected_messages.each_with_index do |expected_message_details, idx|
  187       severity, expected_message, kind = expected_message_details
  188       assert_message logger, severity, expected_message, (kind || String), idx
  189     end
  190   end
  191 
  192   def xmldoc_from_string content
  193     if (content.start_with? '<?xml ') || RE_XMLNS_ATTRIBUTE =~ content
  194       Nokogiri::XML::Document.parse content
  195     elsif !(doctype_match = content.match RE_DOCTYPE)
  196       Nokogiri::HTML::DocumentFragment.parse content
  197     elsif doctype_match[1].start_with? 'html'
  198       Nokogiri::HTML::Document.parse content
  199     else
  200       Nokogiri::XML::Document.parse content
  201     end
  202   end
  203 
  204   def document_from_string src, opts = {}
  205     assign_default_test_options opts
  206     opts[:parse] ? (Asciidoctor::Document.new src.lines, opts).parse : (Asciidoctor::Document.new src.lines, opts)
  207   end
  208 
  209   def block_from_string src, opts = {}
  210     (document_from_string src, (opts.merge standalone: false)).blocks.first
  211   end
  212 
  213   def convert_string src, opts = {}
  214     keep_namespaces = opts.delete :keep_namespaces
  215     if keep_namespaces
  216       (document_from_string src, opts).convert
  217     else
  218       # this is required because nokogiri is easily confused by namespaces
  219       result = (document_from_string src, opts).convert
  220       result ? (result.sub RE_XMLNS_ATTRIBUTE, '') : result
  221     end
  222   end
  223 
  224   def convert_string_to_embedded src, opts = {}
  225     (document_from_string src, (opts.merge standalone: false)).convert
  226   end
  227 
  228   def convert_inline_string src, opts = {}
  229     (document_from_string src, (opts.merge doctype: :inline)).convert
  230   end
  231 
  232   def parse_header_metadata source, doc = nil
  233     reader = Asciidoctor::Reader.new source.split Asciidoctor::LF
  234     [(Asciidoctor::Parser.parse_header_metadata reader, doc), reader]
  235   end
  236 
  237   def assign_default_test_options opts
  238     opts[:standalone] = true unless opts.key? :standalone
  239     opts[:parse] = true unless opts.key? :parse
  240     if opts[:standalone]
  241       # don't embed stylesheet unless test requests the default behavior
  242       if opts.key? :linkcss_default
  243         opts.delete :linkcss_default
  244       else
  245         opts[:attributes] ||= {}
  246         opts[:attributes]['linkcss'] = ''
  247       end
  248     end
  249     if (template_dir = ENV['TEMPLATE_DIR'])
  250       opts[:template_dir] = template_dir unless opts.key? :template_dir
  251     end
  252     nil
  253   end
  254 
  255   # Decode the numeric character reference, such as 8212, to a Unicode glyph
  256   # so it may be used in an XPath expression.
  257   #
  258   # Examples
  259   #
  260   #   decode_char 60
  261   #   # => "<"
  262   #
  263   # Returns the decoded String that corresponds to the numeric character reference
  264   def decode_char number
  265     [number].pack 'U1'
  266   end
  267 
  268   def invoke_cli_with_filenames argv = [], filenames = [], &block
  269     filepaths = []
  270 
  271     filenames.each do |filename|
  272       if filenames.nil? || (Pathname.new filename).absolute?
  273         filepaths << filename
  274       else
  275         filepaths << (fixture_path filename)
  276       end
  277     end
  278 
  279     invoker = Asciidoctor::Cli::Invoker.new argv + filepaths
  280     invoker.invoke!(&block)
  281     invoker
  282   end
  283 
  284   def invoke_cli_to_buffer argv = [], filename = 'sample.adoc', &block
  285     invoke_cli argv, filename, [StringIO.new, StringIO.new], &block
  286   end
  287 
  288   def invoke_cli argv = [], filename = 'sample.adoc', buffers = nil, &block
  289     if filename.nil? || filename == '-' || (Pathname.new filename).absolute?
  290       filepath = filename
  291     else
  292       filepath = fixture_path filename
  293     end
  294     invoker = Asciidoctor::Cli::Invoker.new argv + [filepath]
  295     invoker.redirect_streams(*buffers) if buffers
  296     invoker.invoke!(&block)
  297     invoker
  298   end
  299 
  300   def redirect_streams
  301     old_stdout, $stdout = $stdout, StringIO.new
  302     old_stderr, $stderr = $stderr, StringIO.new
  303     old_logger = Asciidoctor::LoggerManager.logger
  304     old_logger_level = old_logger.level
  305     new_logger = (Asciidoctor::LoggerManager.logger = Asciidoctor::Logger.new $stderr)
  306     new_logger.level = old_logger_level
  307     yield $stdout, $stderr
  308   ensure
  309     $stdout, $stderr = old_stdout, old_stderr
  310     Asciidoctor::LoggerManager.logger = old_logger
  311   end
  312 
  313   def resolve_localhost
  314     Socket.ip_address_list.find(&:ipv4?).ip_address
  315   end
  316 
  317   def using_memory_logger level = nil
  318     old_logger = Asciidoctor::LoggerManager.logger
  319     memory_logger = Asciidoctor::MemoryLogger.new
  320     memory_logger.level = level if level
  321     begin
  322       Asciidoctor::LoggerManager.logger = memory_logger
  323       yield memory_logger
  324     ensure
  325       Asciidoctor::LoggerManager.logger = old_logger
  326     end
  327   end
  328 
  329   def in_verbose_mode
  330     begin
  331       old_logger_level, Asciidoctor::LoggerManager.logger.level = Asciidoctor::LoggerManager.logger.level, Logger::Severity::DEBUG
  332       yield
  333     ensure
  334       Asciidoctor::LoggerManager.logger.level = old_logger_level
  335     end
  336   end
  337 
  338   def run_command *args, &block
  339     if Hash === (env = args[0])
  340       cmd = args[1]
  341     else
  342       cmd, env = env, nil
  343     end
  344     opts = { err: [:child, :out] }
  345     if env
  346       # NOTE remove workaround once https://github.com/jruby/jruby/issues/3428 is resolved
  347       if jruby?
  348         begin
  349           old_env, env = ENV, (ENV.merge env)
  350           env.each {|key, val| env.delete key if val.nil? } if env.value? nil
  351           ENV.replace env
  352           IO.popen cmd, opts, &block
  353         ensure
  354           ENV.replace old_env
  355         end
  356       elsif env.value? nil
  357         env = env.inject(ENV.to_h) do |acc, (key, val)|
  358           val.nil? ? (acc.delete key) : (acc[key] = val)
  359           acc
  360         end
  361         IO.popen env, cmd, (opts.merge unsetenv_others: true), &block
  362       else
  363         IO.popen env, cmd, opts, &block
  364       end
  365     else
  366       IO.popen cmd, opts, &block
  367     end
  368   end
  369 
  370   def using_test_webserver host = resolve_localhost, port = 9876
  371     base_dir = testdir
  372     server = TCPServer.new host, port
  373     server_thread = Thread.start do
  374       while (session = server.accept)
  375         request = session.gets
  376         if /^GET (\S+) HTTP\/1\.1$/ =~ request.chomp
  377           resource = (resource = $1) == '' ? '.' : resource
  378         else
  379           session.print %(HTTP/1.1 405 Method Not Allowed\r\nContent-Type: text/plain\r\n\r\n)
  380           session.print %(405 - Method not allowed\n)
  381           session.close
  382           next
  383         end
  384         if resource == '/name/asciidoctor'
  385           session.print %(HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n)
  386           session.print %({"name": "asciidoctor"}\n)
  387         elsif File.file?(resource_file = (File.join base_dir, resource))
  388           mimetype = if (ext = File.extname(resource_file)[1..-1])
  389             ext == 'adoc' ? 'text/plain' : %(image/#{ext})
  390           else
  391             'text/plain'
  392           end
  393           session.print %(HTTP/1.1 200 OK\r\nContent-Type: #{mimetype}\r\n\r\n)
  394           File.open resource_file, Asciidoctor::FILE_READ_MODE do |fd|
  395             until fd.eof? do
  396               buffer = fd.read 256
  397               session.write buffer
  398             end
  399           end
  400         else
  401           session.print %(HTTP/1.1 404 File Not Found\r\nContent-Type: text/plain\r\n\r\n)
  402           session.print %(404 - Resource not found.\n)
  403         end
  404         session.close
  405       end
  406     end
  407     begin
  408       yield
  409     ensure
  410       server_thread.exit
  411       server_thread.value
  412       server.close
  413     end
  414   end
  415 end
  416 
  417 ###
  418 #
  419 # Context goodness provided by @citrusbyte's contest.
  420 # See https://github.com/citrusbyte/contest
  421 #
  422 ###
  423 
  424 # Contest adds +teardown+, +test+ and +context+ as class methods, and the
  425 # instance methods +setup+ and +teardown+ now iterate on the corresponding
  426 # blocks. Note that all setup and teardown blocks must be defined with the
  427 # block syntax. Adding setup or teardown instance methods defeats the purpose
  428 # of this library.
  429 class Minitest::Test
  430   class << self
  431     def setup &block
  432       define_method :setup do
  433         super(&block)
  434         instance_eval(&block)
  435       end
  436     end
  437 
  438     def teardown &block
  439       define_method :teardown do
  440         instance_eval(&block)
  441         super(&block)
  442       end
  443     end
  444 
  445     def context *name, &block
  446       subclass = Class.new self
  447       remove_tests subclass
  448       subclass.class_eval(&block) if block_given?
  449       const_set (context_name name.join(' ')), subclass
  450     end
  451 
  452     def test name, &block
  453       define_method (test_name name), &block
  454     end
  455 
  456     def remove_tests subclass
  457       subclass.public_instance_methods.each do |m|
  458         subclass.send :undef_method, m if m.to_s.start_with? 'test_'
  459       end
  460     end
  461 
  462     alias should test
  463     alias describe context
  464 
  465     private
  466 
  467     def context_name name
  468       %(Test#{(sanitize_name name).gsub(/(^| )(\w)/) { $2.upcase }}).to_sym
  469     end
  470 
  471     def test_name name
  472       %(test_#{((sanitize_name name).gsub %r/\s+/, '_')}).to_sym
  473     end
  474 
  475     def sanitize_name name
  476       (name.gsub %r/\W+/, ' ').strip
  477     end
  478   end
  479 end
  480 
  481 def context *name, &block
  482   Minitest::Test.context name, &block
  483 end