[DRE-commits] [coderay] 05/14: restore tests and rake_tasks v1.1.2
Daisuke Higuchi
dai at moszumanska.debian.org
Sun Oct 22 15:26:56 UTC 2017
This is an automated email from the git hooks/post-receive script.
dai pushed a commit to branch master
in repository coderay.
commit 710636716e6ccab751f41785cad31e9b7a3efc1c
Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
Date: Mon Oct 23 00:01:36 2017 +0900
restore tests and rake_tasks v1.1.2
---
.../0000-restore_tests_and_rake_tasks_v1.1.2.patch | 4573 ++++++++++++++++++++
debian/patches/series | 1 +
2 files changed, 4574 insertions(+)
diff --git a/debian/patches/0000-restore_tests_and_rake_tasks_v1.1.2.patch b/debian/patches/0000-restore_tests_and_rake_tasks_v1.1.2.patch
new file mode 100644
index 0000000..59fe03b
--- /dev/null
+++ b/debian/patches/0000-restore_tests_and_rake_tasks_v1.1.2.patch
@@ -0,0 +1,4573 @@
+Description: restore tests and rake_tasks v1.1.2
+Author: HIGUCHI Daisuke (VDR dai) <dai at debian.org>
+Origin: vendor
+Forwarded: not-needed
+Last-Update: 2017-10-22
+
+diff --git a/Rakefile b/Rakefile
+new file mode 100644
+index 0000000..c9b1e8a
+--- /dev/null
++++ b/Rakefile
+@@ -0,0 +1,37 @@
++require 'bundler/gem_tasks'
++
++$:.unshift File.dirname(__FILE__) unless $:.include? '.'
++
++ROOT = '.'
++LIB_ROOT = File.join ROOT, 'lib'
++
++task :default => :test
++
++if File.directory? 'rake_tasks'
++
++ # load rake tasks from subfolder
++ for task_file in Dir['rake_tasks/*.rake'].sort
++ load task_file
++ end
++
++else
++
++ # fallback tasks when rake_tasks folder is not present (eg. in the distribution package)
++ desc 'Run CodeRay tests (basic)'
++ task :test do
++ ruby './test/functional/suite.rb'
++ ruby './test/functional/for_redcloth.rb'
++ end
++
++ gem 'rdoc' if defined? gem
++ require 'rdoc/task'
++ desc 'Generate documentation for CodeRay'
++ Rake::RDocTask.new :doc do |rd|
++ rd.title = 'CodeRay Documentation'
++ rd.main = 'README_INDEX.rdoc'
++ rd.rdoc_files.add Dir['lib']
++ rd.rdoc_files.add rd.main
++ rd.rdoc_dir = 'doc'
++ end
++
++end
+diff --git a/rake_tasks/benchmark.rake b/rake_tasks/benchmark.rake
+new file mode 100644
+index 0000000..8edeffb
+--- /dev/null
++++ b/rake_tasks/benchmark.rake
+@@ -0,0 +1,6 @@
++desc 'Do a benchmark'
++task :benchmark do
++ ruby 'bench/bench.rb ruby html'
++end
++
++task :bench => :benchmark
+diff --git a/rake_tasks/code_statistics.rb b/rake_tasks/code_statistics.rb
+new file mode 100644
+index 0000000..0a2016b
+--- /dev/null
++++ b/rake_tasks/code_statistics.rb
+@@ -0,0 +1,171 @@
++# From rails (http://rubyonrails.com)
++#
++# Improved by murphy
++class CodeStatistics
++
++ TEST_TYPES = /\btest/i
++
++ # Create a new Code Statistic.
++ #
++ # Rakefile Example:
++ #
++ # desc 'Report code statistics (LOC) from the application'
++ # task :stats => :copy_files do
++ # require 'rake_helpers/code_statistics'
++ # CodeStatistics.new(
++ # ["Main", "lib"],
++ # ["Tests", "test"],
++ # ["Demos", "demo"]
++ # ).to_s
++ # end
++ def initialize(*pairs)
++ @pairs = pairs
++ @statistics = calculate_statistics
++ @total = if pairs.empty? then nil else calculate_total end
++ end
++
++ # Print a textual table viewing the stats
++ #
++ # Intended for console output.
++ def print
++ print_header
++ @pairs.each { |name, path| print_line name, @statistics[name] }
++ print_splitter
++
++ if @total
++ print_line 'Total', @total
++ print_splitter
++ end
++
++ print_code_test_stats
++ end
++
++private
++
++ DEFAULT_FILE_PATTERN = /\.rb$/
++
++ def calculate_statistics
++ @pairs.inject({}) do |stats, (name, path, pattern, is_ruby_code)|
++ pattern ||= DEFAULT_FILE_PATTERN
++ path = File.join path, '*.rb'
++ stats[name] = calculate_directory_statistics path, pattern, is_ruby_code
++ stats
++ end
++ end
++
++ def calculate_directory_statistics directory, pattern = DEFAULT_FILE_PATTERN, is_ruby_code = true
++ is_ruby_code = true if is_ruby_code.nil?
++ stats = Hash.new 0
++
++ Dir[directory].each do |file_name|
++ p "Scanning #{file_name}..." if $VERBOSE
++ next unless file_name =~ pattern
++
++ lines = codelines = classes = modules = methods = 0
++ empty_lines = comment_lines = 0
++ in_comment_block = false
++
++ File.readlines(file_name).each do |line|
++ lines += 1
++ if line[/^\s*$/]
++ empty_lines += 1
++ elsif is_ruby_code
++ case line
++ when /^=end\b/
++ comment_lines += 1
++ in_comment_block = false
++ when in_comment_block
++ comment_lines += 1
++ when /^\s*class\b/
++ classes += 1
++ when /^\s*module\b/
++ modules += 1
++ when /^\s*def\b/
++ methods += 1
++ when /^\s*#/
++ comment_lines += 1
++ when /^=begin\b/
++ in_comment_block = false
++ comment_lines += 1
++ when /^__END__$/
++ in_comment_block = true
++ end
++ end
++ end
++
++ codelines = lines - comment_lines - empty_lines
++
++ stats[:lines] += lines
++ stats[:comments] += comment_lines
++ stats[:codelines] += codelines
++ stats[:classes] += classes
++ stats[:modules] += modules
++ stats[:methods] += methods
++ stats[:files] += 1
++ end
++
++ stats
++ end
++
++ def calculate_total
++ total = Hash.new 0
++ @statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
++ total
++ end
++
++ def calculate_code
++ code_loc = 0
++ @statistics.each { |k, v| code_loc += v[:codelines] unless k[TEST_TYPES] }
++ code_loc
++ end
++
++ def calculate_tests
++ test_loc = 0
++ @statistics.each { |k, v| test_loc += v[:codelines] if k[TEST_TYPES] }
++ test_loc
++ end
++
++ def print_header
++ print_splitter
++ puts "| T=Test Name | Files | Lines | LOC | Comments | Classes | Modules | Methods | M/C | LOC/M |"
++ print_splitter
++ end
++
++ def print_splitter
++ puts "+---------------------------+-------+-------+-------+----------+---------+---------+---------+-----+-------+"
++ end
++
++ def print_line name, statistics
++ m_over_c = (statistics[:methods] / (statistics[:classes] + statistics[:modules])) rescue m_over_c = 0
++ loc_over_m = (statistics[:codelines] / statistics[:methods]) - 2 rescue loc_over_m = 0
++
++ if name[TEST_TYPES]
++ name = "T #{name}"
++ else
++ name = " #{name}"
++ end
++
++ line = "| %-25s | %5d | %5d | %5d | %8d | %7d | %7d | %7d | %3d | %5d |" % (
++ [name, *statistics.values_at(:files, :lines, :codelines, :comments, :classes, :modules, :methods)] +
++ [m_over_c, loc_over_m] )
++
++ puts line
++ end
++
++ def print_code_test_stats
++ code = calculate_code
++ tests = calculate_tests
++
++ puts " Code LOC = #{code} Test LOC = #{tests} Code:Test Ratio = [1 : #{sprintf("%.2f", tests.to_f/code)}]"
++ puts ""
++ end
++
++end
++
++# Run a test script.
++if $0 == __FILE__
++ $VERBOSE = true
++ CodeStatistics.new(
++ ['This dir', File.dirname(__FILE__)]
++ ).print
++end
+diff --git a/rake_tasks/documentation.rake b/rake_tasks/documentation.rake
+new file mode 100644
+index 0000000..4f7cef7
+--- /dev/null
++++ b/rake_tasks/documentation.rake
+@@ -0,0 +1,23 @@
++begin
++ if RUBY_VERSION >= '1.8.7'
++ gem 'rdoc' if defined? gem
++ require 'rdoc/task'
++ else
++ require 'rake/rdoctask'
++ end
++rescue LoadError
++ warn 'Please gem install rdoc.'
++end
++
++desc 'Generate documentation for CodeRay'
++Rake::RDocTask.new :doc do |rd|
++ rd.main = 'lib/README'
++ rd.title = 'CodeRay Documentation'
++
++ rd.options << '--line-numbers' << '--tab-width' << '2'
++
++ rd.main = 'README_INDEX.rdoc'
++ rd.rdoc_files.add 'README_INDEX.rdoc'
++ rd.rdoc_files.add Dir['lib']
++ rd.rdoc_dir = 'doc'
++end if defined? Rake::RDocTask
+diff --git a/rake_tasks/generator.rake b/rake_tasks/generator.rake
+new file mode 100644
+index 0000000..284adcb
+--- /dev/null
++++ b/rake_tasks/generator.rake
+@@ -0,0 +1,72 @@
++namespace :generate do
++ desc 'generates a new scanner NAME=lang [ALT=alternative,plugin,ids] [EXT=file,extensions] [BASE=base lang]'
++ task :scanner do
++ raise 'I need a scanner name; use NAME=lang' unless scanner_class_name = ENV['NAME']
++ raise "Invalid lang: #{scanner_class_name}; use NAME=lang." unless /\A\w+\z/ === scanner_class_name
++ require 'active_support/all'
++ lang = scanner_class_name.underscore
++ class_name = scanner_class_name.camelize
++
++ def scanner_file_for_lang lang
++ File.join(LIB_ROOT, 'coderay', 'scanners', lang + '.rb')
++ end
++
++ scanner_file = scanner_file_for_lang lang
++ if File.exist? scanner_file
++ print "#{scanner_file} already exists. Overwrite? [y|N] "
++ exit unless $stdin.gets.chomp.downcase == 'y'
++ end
++
++ base_lang = ENV.fetch('BASE', 'json')
++ base_scanner_file = scanner_file_for_lang(base_lang)
++ puts "Reading base scanner #{base_scanner_file}..."
++ base_scanner = File.read base_scanner_file
++ puts "Writing new scanner #{scanner_file}..."
++ File.open(scanner_file, 'w') do |file|
++ file.write base_scanner.
++ sub(/class \w+ < Scanner/, "class #{class_name} < Scanner").
++ sub('# Scanner for JSON (JavaScript Object Notation).', "# A scanner for #{scanner_class_name}.").
++ sub(/register_for :\w+/, "register_for :#{lang}").
++ sub(/file_extension '\S+'/, "file_extension '#{ENV.fetch('EXT', lang).split(',').first}'")
++ end
++
++ test_dir = File.join(ROOT, 'test', 'scanners', lang)
++ unless File.exist? test_dir
++ puts "Creating test folder #{test_dir}..."
++ sh "mkdir #{test_dir}"
++ end
++ test_suite_file = File.join(test_dir, 'suite.rb')
++ unless File.exist? test_suite_file
++ puts "Creating test suite file #{test_suite_file}..."
++ base_suite = File.read File.join(test_dir, '..', 'ruby', 'suite.rb')
++ File.open(test_suite_file, 'w') do |file|
++ file.write base_suite.sub(/class Ruby/, "class #{class_name}")
++ end
++ end
++
++ if extensions = ENV['EXT']
++ file_type_file = File.join(LIB_ROOT, 'coderay', 'helpers', 'filetype.rb')
++ puts "Not automated. Remember to add your extensions to #{file_type_file}:"
++ for ext in extensions.split(',')
++ puts " '#{ext}' => :#{lang},"
++ end
++ end
++
++ if alternative_ids = ENV['ALT'] && alternative_ids != lang
++ map_file = File.join(LIB_ROOT, 'coderay', 'scanners', '_map.rb')
++ puts "Not automated. Remember to add your alternative plugin ids to #{map_file}:"
++ for id in alternative_ids.split(',')
++ puts " :#{id} => :#{lang},"
++ end
++ end
++
++ print 'Add to git? [Y|n] '
++ answer = $stdin.gets.chomp.downcase
++ if answer.empty? || answer == 'y'
++ sh "git add #{scanner_file}"
++ cd File.join('test', 'scanners') do
++ sh "git add #{lang}"
++ end
++ end
++ end
++end
+diff --git a/rake_tasks/statistic.rake b/rake_tasks/statistic.rake
+new file mode 100644
+index 0000000..d30e9b1
+--- /dev/null
++++ b/rake_tasks/statistic.rake
+@@ -0,0 +1,19 @@
++desc 'Report code statistics (LOC) from the application'
++task :stats do
++ require './rake_tasks/code_statistics'
++ CodeStatistics.new(
++ ['Main', 'lib', /coderay.rb$/],
++ ['CodeRay', 'lib/coderay/'],
++ [' Scanners', 'lib/coderay/scanners/**'],
++ [' Encoders', 'lib/coderay/encoders/**'],
++ [' Helpers', 'lib/coderay/helpers/**'],
++ [' Styles', 'lib/coderay/styles/**'],
++ ['Executable', 'bin', /coderay$/],
++ ['Executable Tests', 'test/executable/**'],
++ ['Functional Tests', 'test/functional/**'],
++ ['Scanner Tests', 'test/scanners/**', /suite\.rb$/],
++ ['Unit Tests', 'test/unit/**'],
++ # [' Test Data', 'test/scanners/**', /\.in\./, false],
++ ['Demos', 'sample/**']
++ ).print
++end
+diff --git a/rake_tasks/test.rake b/rake_tasks/test.rake
+new file mode 100644
+index 0000000..1a23a5b
+--- /dev/null
++++ b/rake_tasks/test.rake
+@@ -0,0 +1,82 @@
++namespace :test do
++ desc 'run functional tests'
++ task :functional do
++ ruby './test/functional/suite.rb'
++ ruby './test/functional/for_redcloth.rb' unless (''.chop! rescue true)
++ end
++
++ desc 'run unit tests'
++ task :units do
++ ruby './test/unit/suite.rb'
++ end
++
++ scanner_suite = 'test/scanners/suite.rb'
++ desc 'run all scanner tests'
++ task :scanners => :update_scanner_suite do
++ ruby scanner_suite
++ end
++
++ desc 'update scanner test suite from GitHub'
++ task :update_scanner_suite do
++ if File.exist? scanner_suite
++ Dir.chdir File.dirname(scanner_suite) do
++ if File.directory? '.git'
++ puts 'Updating scanner test suite...'
++ sh 'git pull'
++ elsif File.directory? '.svn'
++ raise <<-ERROR
++Found the deprecated Subversion scanner test suite in ./#{File.dirname(scanner_suite)}.
++Please rename or remove it and run again to use the GitHub repository:
++
++ mv test/scanners test/scanners-old
++ ERROR
++ else
++ raise 'No scanner test suite found.'
++ end
++ end
++ else
++ puts 'Downloading scanner test suite...'
++ sh 'git clone https://github.com/rubychan/coderay-scanner-tests.git test/scanners/'
++ end
++ end
++
++ namespace :scanner do
++ Dir['./test/scanners/*'].each do |scanner|
++ next unless File.directory? scanner
++ lang = File.basename(scanner)
++ desc "run all scanner tests for #{lang}"
++ task lang => :update_scanner_suite do
++ ruby "./test/scanners/suite.rb #{lang}"
++ end
++ end
++ end
++
++ desc 'clean test output files'
++ task :clean do
++ for file in Dir['test/scanners/**/*.actual.*']
++ rm file
++ end
++ for file in Dir['test/scanners/**/*.debug.diff']
++ rm file
++ end
++ for file in Dir['test/scanners/**/*.debug.diff.html']
++ rm file
++ end
++ for file in Dir['test/scanners/**/*.expected.html']
++ rm file
++ end
++ end
++
++ desc 'test the CodeRay executable'
++ task :exe do
++ if RUBY_VERSION >= '1.8.7'
++ ruby './test/executable/suite.rb'
++ else
++ puts
++ puts "Can't run executable tests because shoulda-context requires Ruby 1.8.7+."
++ puts "Skipping."
++ end
++ end
++end
++
++task :test => %w(test:functional test:units test:exe)
+diff --git a/test/executable/source.py b/test/executable/source.py
+new file mode 100644
+index 0000000..1bb2c00
+--- /dev/null
++++ b/test/executable/source.py
+@@ -0,0 +1 @@
++class ClassName(): pass
+\ No newline at end of file
+diff --git a/test/executable/source.rb b/test/executable/source.rb
+new file mode 100644
+index 0000000..226f15f
+--- /dev/null
++++ b/test/executable/source.rb
+@@ -0,0 +1 @@
++class ClassName; end
+\ No newline at end of file
+diff --git a/test/executable/source_with_comments.rb b/test/executable/source_with_comments.rb
+new file mode 100644
+index 0000000..ec79358
+--- /dev/null
++++ b/test/executable/source_with_comments.rb
+@@ -0,0 +1,3 @@
++# a class
++class ClassName
++end
+diff --git a/test/executable/suite.rb b/test/executable/suite.rb
+new file mode 100644
+index 0000000..997405c
+--- /dev/null
++++ b/test/executable/suite.rb
+@@ -0,0 +1,226 @@
++require 'test/unit'
++require 'rubygems' unless defined? Gem
++require 'shoulda-context'
++
++require 'pathname'
++require 'json'
++
++$:.unshift File.expand_path('../../../lib', __FILE__)
++require 'coderay'
++
++puts "Running CodeRay #{CodeRay::VERSION} executable tests..."
++
++class TestCodeRayExecutable < Test::Unit::TestCase
++
++ ROOT_DIR = Pathname.new(File.dirname(__FILE__)) + '..' + '..'
++ EXECUTABLE = ROOT_DIR + 'bin' + 'coderay'
++ RUBY_COMMAND = 'ruby'
++ EXE_COMMAND =
++ if RUBY_PLATFORM === 'java' && `ruby --ng -e '' 2> /dev/null` && $?.success?
++ # use Nailgun
++ "#{RUBY_COMMAND}--ng -I%s %s"
++ else
++ "#{RUBY_COMMAND} -I%s %s"
++ end % [ROOT_DIR + 'lib', EXECUTABLE]
++
++ def coderay args, options = {}
++ if options[:fake_tty]
++ command = "#{EXE_COMMAND} #{args} --tty"
++ else
++ command = "#{EXE_COMMAND} #{args}"
++ end
++
++ puts command if $DEBUG
++
++ if options[:input]
++ output = IO.popen "#{command} 2>&1", "r+" do |io|
++ io.write options[:input]
++ io.close_write
++ io.read
++ end
++ else
++ output = `#{command} 2>&1`
++ end
++
++ if output[EXECUTABLE.to_s]
++ raise output
++ else
++ output
++ end
++ end
++
++ context 'a simple call with no arguments' do
++ should 'work' do
++ assert_nothing_raised { coderay('') }
++ end
++ should 'print version and help' do
++ assert_match(/CodeRay #{CodeRay::VERSION}/, coderay(''))
++ assert_match(/usage:/, coderay(''))
++ end
++ end
++
++ context 'version' do
++ should 'be printed with -v' do
++ assert_match(/\ACodeRay #{CodeRay::VERSION}\Z/, coderay('-v'))
++ end
++ should 'be printed with --version' do
++ assert_match(/\ACodeRay #{CodeRay::VERSION}\Z/, coderay('--version'))
++ end
++ end
++
++ context 'help' do
++ should 'be printed with -h' do
++ assert_match(/^usage:/, coderay('-h'))
++ end
++ should 'be printed with --help' do
++ assert_match(/^usage:/, coderay('--help'))
++ end
++ should 'be printed with subcommand help' do
++ assert_match(/^usage:/, coderay('help'))
++ end
++ end
++
++ context 'commands' do
++ should 'be printed with subcommand commands' do
++ assert_match(/^ +help/, coderay('commands'))
++ assert_match(/^ +version/, coderay('commands'))
++ end
++ end
++
++ context 'highlighting a file to the terminal' do
++ source_file = ROOT_DIR + 'test/executable/source.py'
++
++ source = File.read source_file
++
++ ansi_seq = /\e\[[0-9;]+m/
++
++ should 'not throw an error' do
++ assert_nothing_raised { coderay(source_file, :fake_tty => true) }
++ end
++ should 'output its contents to stdout' do
++ target = coderay(source_file, :fake_tty => true)
++ assert_equal source, target.chomp.gsub(ansi_seq, '')
++ end
++ should 'output ANSI-colored text' do
++ target = coderay(source_file, :fake_tty => true)
++ assert_not_equal source, target.chomp
++ assert_equal 6, target.scan(ansi_seq).size
++ end
++ end
++
++ context 'highlighting a file into a pipe (source.rb -html > source.rb.html)' do
++ source_file = ROOT_DIR + 'test/executable/source.rb'
++ target_file = "#{source_file}.html"
++ command = "#{source_file} -html > #{target_file}"
++
++ source = File.read source_file
++
++ pre = %r{<td class="code"><pre>(.*?)</pre>}m
++ tag = /<[^>]*>/
++
++ should 'not throw an error' do
++ assert_nothing_raised { coderay(command) }
++ end
++ should 'output its contents to the pipe' do
++ coderay(command)
++ target = File.read(target_file)
++ if target = target[pre, 1]
++ assert_equal source, target.gsub(tag, '').strip
++ else
++ flunk "target code has no <pre> tag: #{target}"
++ end
++ end
++ should 'output valid HTML' do
++ coderay(command)
++ target = File.read(target_file)
++ assert_not_equal source, target[pre, 1]
++ assert_equal 6, target[pre, 1].scan(tag).size
++ assert_match %r{\A<!DOCTYPE html>\n<html>\n<head>}, target
++ end
++ end
++
++ context 'highlighting a file into another file (source.rb source.rb.json)' do
++ source_file = ROOT_DIR + 'test/executable/source.rb'
++ target_file = "#{source_file}.json"
++ command = "#{source_file} #{target_file}"
++
++ source = File.read source_file
++
++ text = /"text":"([^"]*)"/
++
++ should 'not throw an error' do
++ assert_nothing_raised { coderay(command) }
++ end
++ should 'output its contents to the file' do
++ coderay(command)
++ target = File.read(target_file)
++ assert_equal source, target.scan(text).join
++ end
++ should 'output JSON' do
++ coderay(command)
++ target = File.read(target_file)
++ assert_not_equal source, target
++ assert_equal 6, target.scan(text).size
++ end
++ end
++
++ context 'highlighting a file without explicit input type (source.py)' do
++ source_file = ROOT_DIR + 'test/executable/source.py'
++ command = "#{source_file} -html"
++
++ source = File.read source_file
++
++ pre = %r{<td class="code"><pre>(.*?)</pre>}m
++ tag_class = /<span class="([^>"]*)"?[^>]*>/
++
++ should 'respect the file extension and highlight the input as Python' do
++ target = coderay(command)
++ assert_equal %w(keyword class keyword), target[pre, 1].scan(tag_class).flatten
++ end
++ end
++
++ context 'highlighting a file with explicit input type (-ruby source.py)' do
++ source_file = ROOT_DIR + 'test/executable/source.py'
++ command = "-ruby #{source_file} -html"
++
++ source = File.read source_file
++
++ pre = %r{<td class="code"><pre>(.*?)</pre>}m
++ tag_class = /<span class="([^>"]*)"?[^>]*>/
++
++ should 'ignore the file extension and highlight the input as Ruby' do
++ target = coderay(command)
++ assert_equal %w(keyword class), target[pre, 1].scan(tag_class).flatten
++ end
++ end
++
++ context 'highlighting a file with explicit input and output type (-ruby source.py -span)' do
++ source_file = ROOT_DIR + 'test/executable/source.py'
++ command = "-ruby #{source_file} -span"
++
++ source = File.read source_file
++
++ span_tags = /<\/?span[^>]*>/
++
++ should 'just respect the output type and include span tags' do
++ target = coderay(command)
++ assert_equal source, target.chomp.gsub(span_tags, '')
++ end
++ end
++
++ context 'the LOC counter' do
++ source_file = ROOT_DIR + 'test/executable/source_with_comments.rb'
++ command = "-ruby -loc"
++
++ should 'work' do
++ output = coderay(command, :input => <<-CODE)
++# test
++=begin
++=end
++test
++ CODE
++ assert_equal "1\n", output
++ end
++ end
++
++end
+diff --git a/test/functional/basic.rb b/test/functional/basic.rb
+new file mode 100644
+index 0000000..752d4ba
+--- /dev/null
++++ b/test/functional/basic.rb
+@@ -0,0 +1,318 @@
++# encoding: utf-8
++require 'test/unit'
++require File.expand_path('../../lib/assert_warning', __FILE__)
++
++$:.unshift File.expand_path('../../../lib', __FILE__)
++require 'coderay'
++
++class BasicTest < Test::Unit::TestCase
++
++ def test_version
++ assert_nothing_raised do
++ assert_match(/\A\d\.\d\.\d?\z/, CodeRay::VERSION)
++ end
++ end
++
++ def with_empty_load_path
++ old_load_path = $:.dup
++ $:.clear
++ yield
++ ensure
++ $:.replace old_load_path
++ end
++
++ def test_autoload
++ with_empty_load_path do
++ assert_nothing_raised do
++ CodeRay::Scanners::Java::BuiltinTypes
++ end
++ end
++ end
++
++ RUBY_TEST_CODE = 'puts "Hello, World!"'
++
++ RUBY_TEST_TOKENS = [
++ ['puts', :ident],
++ [' ', :space],
++ [:begin_group, :string],
++ ['"', :delimiter],
++ ['Hello, World!', :content],
++ ['"', :delimiter],
++ [:end_group, :string]
++ ].flatten
++ def test_simple_scan
++ assert_nothing_raised do
++ assert_equal RUBY_TEST_TOKENS, CodeRay.scan(RUBY_TEST_CODE, :ruby).tokens
++ end
++ end
++
++ RUBY_TEST_HTML = 'puts <span class="string"><span class="delimiter">"</span>' +
++ '<span class="content">Hello, World!</span><span class="delimiter">"</span></span>'
++ def test_simple_highlight
++ assert_nothing_raised do
++ assert_equal RUBY_TEST_HTML, CodeRay.scan(RUBY_TEST_CODE, :ruby).html
++ end
++ end
++
++ def test_scan_file
++ CodeRay.scan_file __FILE__
++ end
++
++ def test_encode
++ assert_equal 1, CodeRay.encode('test', :python, :count)
++ end
++
++ def test_encode_tokens
++ assert_equal 1, CodeRay.encode_tokens(CodeRay::Tokens['test', :string], :count)
++ end
++
++ def test_encode_file
++ assert_equal File.read(__FILE__), CodeRay.encode_file(__FILE__, :text)
++ end
++
++ def test_highlight
++ assert_match '<pre>test</pre>', CodeRay.highlight('test', :python)
++ end
++
++ def test_highlight_file
++ assert_match "require <span class=\"string\"><span class=\"delimiter\">'</span><span class=\"content\">test/unit</span><span class=\"delimiter\">'</span></span>\n", CodeRay.highlight_file(__FILE__)
++ end
++
++ def test_duo
++ assert_equal(RUBY_TEST_CODE,
++ CodeRay::Duo[:plain, :text].highlight(RUBY_TEST_CODE))
++ assert_equal(RUBY_TEST_CODE,
++ CodeRay::Duo[:plain => :text].highlight(RUBY_TEST_CODE))
++ end
++
++ def test_duo_stream
++ assert_equal(RUBY_TEST_CODE,
++ CodeRay::Duo[:plain, :text].highlight(RUBY_TEST_CODE, :stream => true))
++ end
++
++ def test_comment_filter
++ assert_equal <<-EXPECTED, CodeRay.scan(<<-INPUT, :ruby).comment_filter.text
++#!/usr/bin/env ruby
++
++code
++
++more code
++ EXPECTED
++#!/usr/bin/env ruby
++=begin
++A multi-line comment.
++=end
++code
++# A single-line comment.
++more code # and another comment, in-line.
++ INPUT
++ end
++
++ def test_lines_of_code
++ assert_equal 2, CodeRay.scan(<<-INPUT, :ruby).lines_of_code
++#!/usr/bin/env ruby
++=begin
++A multi-line comment.
++=end
++code
++# A single-line comment.
++more code # and another comment, in-line.
++ INPUT
++ rHTML = <<-RHTML
++<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
++ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
++
++<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
++<head>
++ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
++ <title><%= controller.controller_name.titleize %>: <%= controller.action_name %></title>
++ <%= stylesheet_link_tag 'scaffold' %>
++</head>
++<body>
++
++<p style="color: green"><%= flash[:notice] %></p>
++
++<div id="main">
++ <%= yield %>
++</div>
++
++</body>
++</html>
++ RHTML
++ assert_equal 0, CodeRay.scan(rHTML, :html).lines_of_code
++ assert_equal 0, CodeRay.scan(rHTML, :php).lines_of_code
++ assert_equal 0, CodeRay.scan(rHTML, :yaml).lines_of_code
++ assert_equal 4, CodeRay.scan(rHTML, :erb).lines_of_code
++ end
++
++ def test_list_of_encoders
++ assert_kind_of(Array, CodeRay::Encoders.list)
++ assert CodeRay::Encoders.list.include?(:count)
++ end
++
++ def test_list_of_scanners
++ assert_kind_of(Array, CodeRay::Scanners.list)
++ assert CodeRay::Scanners.list.include?(:text)
++ end
++
++ def test_token_kinds
++ assert_kind_of Hash, CodeRay::TokenKinds
++ for kind, css_class in CodeRay::TokenKinds
++ assert_kind_of Symbol, kind
++ if css_class != false
++ assert_kind_of String, css_class, "TokenKinds[%p] == %p" % [kind, css_class]
++ end
++ end
++ assert_equal 'reserved', CodeRay::TokenKinds[:reserved]
++ assert_equal false, CodeRay::TokenKinds[:shibboleet]
++ end
++
++ class Milk < CodeRay::Encoders::Encoder
++ FILE_EXTENSION = 'cocoa'
++ end
++
++ class HoneyBee < CodeRay::Encoders::Encoder
++ end
++
++ def test_encoder_file_extension
++ assert_nothing_raised do
++ assert_equal 'html', CodeRay::Encoders::Page::FILE_EXTENSION
++ assert_equal 'cocoa', Milk::FILE_EXTENSION
++ assert_equal 'cocoa', Milk.new.file_extension
++ assert_equal 'honeybee', HoneyBee::FILE_EXTENSION
++ assert_equal 'honeybee', HoneyBee.new.file_extension
++ end
++ assert_raise NameError do
++ HoneyBee::MISSING_CONSTANT
++ end
++ end
++
++ def test_encoder_tokens
++ encoder = CodeRay::Encoders::Encoder.new
++ encoder.send :setup, {}
++ assert_raise(ArgumentError) { encoder.token :strange, '' }
++ encoder.token 'test', :debug
++ end
++
++ def test_encoder_deprecated_interface
++ encoder = CodeRay::Encoders::Encoder.new
++ encoder.send :setup, {}
++ assert_warning 'Using old Tokens#<< interface.' do
++ encoder << ['test', :content]
++ end
++ assert_raise ArgumentError do
++ encoder << [:strange, :input]
++ end
++ assert_raise ArgumentError do
++ encoder.encode_tokens [['test', :token]]
++ end
++ end
++
++ def encoder_token_interface_deprecation_warning_given
++ CodeRay::Encoders::Encoder.send :class_variable_get, :@@CODERAY_TOKEN_INTERFACE_DEPRECATION_WARNING_GIVEN
++ end
++
++ def test_scanner_file_extension
++ assert_equal 'rb', CodeRay::Scanners::Ruby.file_extension
++ assert_equal 'rb', CodeRay::Scanners::Ruby.new.file_extension
++ assert_equal 'java', CodeRay::Scanners::Java.file_extension
++ assert_equal 'java', CodeRay::Scanners::Java.new.file_extension
++ end
++
++ def test_scanner_lang
++ assert_equal :ruby, CodeRay::Scanners::Ruby.lang
++ assert_equal :ruby, CodeRay::Scanners::Ruby.new.lang
++ assert_equal :java, CodeRay::Scanners::Java.lang
++ assert_equal :java, CodeRay::Scanners::Java.new.lang
++ end
++
++ def test_scanner_tokenize
++ assert_equal ['foo', :plain], CodeRay::Scanners::Plain.new.tokenize('foo')
++ assert_equal [['foo', :plain], ['bar', :plain]], CodeRay::Scanners::Plain.new.tokenize(['foo', 'bar'])
++ CodeRay::Scanners::Plain.new.tokenize 42
++ end
++
++ def test_scanner_tokens
++ scanner = CodeRay::Scanners::Plain.new
++ scanner.tokenize('foo')
++ assert_equal ['foo', :plain], scanner.tokens
++ scanner.string = ''
++ assert_equal ['', :plain], scanner.tokens
++ end
++
++ def test_scanner_line_and_column
++ scanner = CodeRay::Scanners::Plain.new "foo\nbär+quux"
++ assert_equal 0, scanner.pos
++ assert_equal 1, scanner.line
++ assert_equal 1, scanner.column
++ scanner.scan(/foo/)
++ assert_equal 3, scanner.pos
++ assert_equal 1, scanner.line
++ assert_equal 4, scanner.column
++ scanner.scan(/\n/)
++ assert_equal 4, scanner.pos
++ assert_equal 2, scanner.line
++ assert_equal 1, scanner.column
++ scanner.scan(/b/)
++ assert_equal 5, scanner.pos
++ assert_equal 2, scanner.line
++ assert_equal 2, scanner.column
++ scanner.scan(/a/)
++ assert_equal 5, scanner.pos
++ assert_equal 2, scanner.line
++ assert_equal 2, scanner.column
++ scanner.scan(/ä/)
++ assert_equal 7, scanner.pos
++ assert_equal 2, scanner.line
++ assert_equal 4, scanner.column
++ scanner.scan(/r/)
++ assert_equal 8, scanner.pos
++ assert_equal 2, scanner.line
++ assert_equal 5, scanner.column
++ end
++
++ def test_scanner_use_subclasses
++ assert_raise NotImplementedError do
++ CodeRay::Scanners::Scanner.new
++ end
++ end
++
++ class InvalidScanner < CodeRay::Scanners::Scanner
++ end
++
++ def test_scanner_scan_tokens
++ assert_raise NotImplementedError do
++ InvalidScanner.new.tokenize ''
++ end
++ end
++
++ class RaisingScanner < CodeRay::Scanners::Scanner
++ def scan_tokens encoder, options
++ raise_inspect 'message', [], :initial
++ end
++ end
++
++ def test_scanner_raise_inspect
++ assert_raise CodeRay::Scanners::Scanner::ScanError do
++ RaisingScanner.new.tokenize ''
++ end
++ end
++
++ def test_scan_a_frozen_string
++ assert_nothing_raised do
++ CodeRay.scan RUBY_VERSION, :ruby
++ CodeRay.scan RUBY_VERSION, :plain
++ end
++ end
++
++ def test_scan_a_non_string
++ assert_nothing_raised do
++ CodeRay.scan 42, :ruby
++ CodeRay.scan nil, :ruby
++ CodeRay.scan self, :ruby
++ CodeRay.encode ENV.to_hash, :ruby, :page
++ CodeRay.highlight CodeRay, :plain
++ end
++ end
++
++end
+diff --git a/test/functional/examples.rb b/test/functional/examples.rb
+new file mode 100644
+index 0000000..985ef87
+--- /dev/null
++++ b/test/functional/examples.rb
+@@ -0,0 +1,129 @@
++require 'test/unit'
++
++$:.unshift File.expand_path('../../../lib', __FILE__)
++require 'coderay'
++
++class ExamplesTest < Test::Unit::TestCase
++
++ def test_examples
++ # output as HTML div (using inline CSS styles)
++ div = CodeRay.scan('puts "Hello, world!"', :ruby).div
++ assert_equal <<-DIV, div
++<div class="CodeRay">
++ <div class="code"><pre>puts <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">Hello, world!</span><span style="color:#710">"</span></span></pre></div>
++</div>
++ DIV
++
++ # ...with line numbers
++ div = CodeRay.scan(<<-CODE.chomp, :ruby).div(:line_numbers => :table)
++5.times do
++ puts 'Hello, world!'
++end
++ CODE
++ assert_equal <<-DIV, div
++<table class="CodeRay"><tr>
++ <td class="line-numbers"><pre><a href="#n1" name="n1">1</a>
++<a href="#n2" name="n2">2</a>
++<a href="#n3" name="n3">3</a>
++</pre></td>
++ <td class="code"><pre><span style="color:#00D">5</span>.times <span style="color:#080;font-weight:bold">do</span>
++ puts <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">'</span><span style="color:#D20">Hello, world!</span><span style="color:#710">'</span></span>
++<span style="color:#080;font-weight:bold">end</span></pre></td>
++</tr></table>
++ DIV
++
++ # output as standalone HTML page (using CSS classes)
++ page = CodeRay.scan('puts "Hello, world!"', :ruby).page
++ assert_match <<-PAGE, page
++<body>
++
++<table class="CodeRay"><tr>
++ <td class="line-numbers"><pre><a href="#n1" name="n1">1</a>
++</pre></td>
++ <td class="code"><pre>puts <span class="string"><span class="delimiter">"</span><span class="content">Hello, world!</span><span class="delimiter">"</span></span></pre></td>
++</tr></table>
++
++</body>
++ PAGE
++
++ # keep scanned tokens for later use
++ tokens = CodeRay.scan('{ "just": "an", "example": 42 }', :json)
++ assert_kind_of CodeRay::TokensProxy, tokens
++
++ assert_equal ["{", :operator, " ", :space, :begin_group, :key,
++ "\"", :delimiter, "just", :content, "\"", :delimiter,
++ :end_group, :key, ":", :operator, " ", :space,
++ :begin_group, :string, "\"", :delimiter, "an", :content,
++ "\"", :delimiter, :end_group, :string, ",", :operator,
++ " ", :space, :begin_group, :key, "\"", :delimiter,
++ "example", :content, "\"", :delimiter, :end_group, :key,
++ ":", :operator, " ", :space, "42", :integer,
++ " ", :space, "}", :operator], tokens.tokens
++
++ # produce a token statistic
++ assert_equal <<-STATISTIC, tokens.statistic
++
++Code Statistics
++
++Tokens 26
++ Non-Whitespace 15
++Bytes Total 31
++
++Token Types (7):
++ type count ratio size (average)
++-------------------------------------------------------------
++ TOTAL 26 100.00 % 1.2
++ delimiter 6 23.08 % 1.0
++ operator 5 19.23 % 1.0
++ space 5 19.23 % 1.0
++ key 4 15.38 % 0.0
++ :begin_group 3 11.54 % 0.0
++ :end_group 3 11.54 % 0.0
++ content 3 11.54 % 4.3
++ string 2 7.69 % 0.0
++ integer 1 3.85 % 2.0
++
++ STATISTIC
++
++ # count the tokens
++ assert_equal 26, tokens.count
++
++ # produce a HTML div, but with CSS classes
++ div = tokens.div(:css => :class)
++ assert_equal <<-DIV, div
++<div class="CodeRay">
++ <div class="code"><pre>{ <span class="key"><span class="delimiter">"</span><span class="content">just</span><span class="delimiter">"</span></span>: <span class="string"><span class="delimiter">"</span><span class="content">an</span><span class="delimiter">"</span></span>, <span class="key"><span class="delimiter">"</span><span class="content">example</span><span class="delimiter">"</span></span>: <span class="integer">42</span> }</pre></div>
++</div>
++ DIV
++
++ # highlight a file (HTML div); guess the file type base on the extension
++ assert_equal :ruby, CodeRay::FileType[__FILE__]
++
++ # get a new scanner for Python
++ python_scanner = CodeRay.scanner :python
++ assert_kind_of CodeRay::Scanners::Python, python_scanner
++
++ # get a new encoder for terminal
++ terminal_encoder = CodeRay.encoder :term
++ assert_kind_of CodeRay::Encoders::Terminal, terminal_encoder
++
++ # scanning into tokens
++ tokens = python_scanner.tokenize 'import this; # The Zen of Python'
++ assert_equal ["import", :keyword, " ", :space, "this", :include,
++ ";", :operator, " ", :space, "# The Zen of Python", :comment], tokens
++
++ # format the tokens
++ term = terminal_encoder.encode_tokens(tokens)
++ assert_equal "\e[32mimport\e[0m \e[31mthis\e[0m; \e[1;30m# The Zen of Python\e[0m", term
++
++ # re-using scanner and encoder
++ ruby_highlighter = CodeRay::Duo[:ruby, :div]
++ div = ruby_highlighter.encode('puts "Hello, world!"')
++ assert_equal <<-DIV, div
++<div class="CodeRay">
++ <div class="code"><pre>puts <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">Hello, world!</span><span style="color:#710">"</span></span></pre></div>
++</div>
++ DIV
++ end
++
++end
+diff --git a/test/functional/for_redcloth.rb b/test/functional/for_redcloth.rb
+new file mode 100644
+index 0000000..9fd244e
+--- /dev/null
++++ b/test/functional/for_redcloth.rb
+@@ -0,0 +1,78 @@
++require 'test/unit'
++
++$:.unshift File.expand_path('../../../lib', __FILE__)
++require 'coderay'
++
++begin
++ require 'rubygems' unless defined? Gem
++ gem 'RedCloth', '>= 4.0.3' rescue nil
++ require 'redcloth'
++rescue LoadError
++ warn 'RedCloth not found - skipping for_redcloth tests.'
++ undef RedCloth if defined? RedCloth
++end
++
++class BasicTest < Test::Unit::TestCase
++
++ def test_for_redcloth
++ require 'coderay/for_redcloth'
++ assert_equal "<p><span lang=\"ruby\" class=\"CodeRay\">puts <span style=\"background-color:hsla(0,100%,50%,0.05)\"><span style=\"color:#710\">"</span><span style=\"color:#D20\">Hello, World!</span><span style=\"color:#710\">"</span></span></span></p>",
++ RedCloth.new('@[ruby]puts "Hello, World!"@').to_html
++ assert_equal <<-BLOCKCODE.chomp,
++<div lang="ruby" class="CodeRay">
++ <div class="code"><pre>puts <span style="background-color:hsla(0,100%,50%,0.05)"><span style="color:#710">"</span><span style="color:#D20">Hello, World!</span><span style="color:#710">"</span></span></pre></div>
++</div>
++ BLOCKCODE
++ RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html
++ end
++
++ def test_for_redcloth_no_lang
++ require 'coderay/for_redcloth'
++ assert_equal "<p><code>puts \"Hello, World!\"</code></p>",
++ RedCloth.new('@puts "Hello, World!"@').to_html
++ assert_equal <<-BLOCKCODE.chomp,
++<pre><code>puts \"Hello, World!\"</code></pre>
++ BLOCKCODE
++ RedCloth.new('bc. puts "Hello, World!"').to_html
++ end
++
++ def test_for_redcloth_style
++ require 'coderay/for_redcloth'
++ assert_equal <<-BLOCKCODE.chomp,
++<pre style=\"color: red;\"><code style=\"color: red;\">puts \"Hello, World!\"</code></pre>
++ BLOCKCODE
++ RedCloth.new('bc{color: red}. puts "Hello, World!"').to_html
++ end
++
++ def test_for_redcloth_escapes
++ require 'coderay/for_redcloth'
++ assert_equal '<p><span lang="ruby" class="CodeRay">></span></p>',
++ RedCloth.new('@[ruby]>@').to_html
++ assert_equal <<-BLOCKCODE.chomp,
++<div lang="ruby" class="CodeRay">
++ <div class="code"><pre>&</pre></div>
++</div>
++ BLOCKCODE
++ RedCloth.new('bc[ruby]. &').to_html
++ end
++
++ def test_for_redcloth_escapes2
++ require 'coderay/for_redcloth'
++ assert_equal "<p><span lang=\"c\" class=\"CodeRay\"><span style=\"color:#579\">#include</span> <span style=\"color:#B44;font-weight:bold\"><test.h></span></span></p>",
++ RedCloth.new('@[c]#include <test.h>@').to_html
++ end
++
++ # See http://jgarber.lighthouseapp.com/projects/13054/tickets/124-code-markup-does-not-allow-brackets.
++ def test_for_redcloth_false_positive
++ require 'coderay/for_redcloth'
++ assert_equal '<p><code>[project]_dff.skjd</code></p>',
++ RedCloth.new('@[project]_dff.skjd@').to_html
++ # false positive, but expected behavior / known issue
++ assert_equal "<p><span lang=\"ruby\" class=\"CodeRay\">_dff.skjd</span></p>",
++ RedCloth.new('@[ruby]_dff.skjd@').to_html
++ assert_equal <<-BLOCKCODE.chomp, RedCloth.new('bc. [project]_dff.skjd').to_html
++<pre><code>[project]_dff.skjd</code></pre>
++ BLOCKCODE
++ end
++
++end if defined? RedCloth
+\ No newline at end of file
+diff --git a/test/functional/suite.rb b/test/functional/suite.rb
+new file mode 100644
+index 0000000..ec23eec
+--- /dev/null
++++ b/test/functional/suite.rb
+@@ -0,0 +1,15 @@
++require 'test/unit'
++
++$VERBOSE = $CODERAY_DEBUG = true
++$:.unshift File.expand_path('../../../lib', __FILE__)
++require 'coderay'
++
++mydir = File.dirname(__FILE__)
++suite = Dir[File.join(mydir, '*.rb')].
++ map { |tc| File.basename(tc).sub(/\.rb$/, '') } - %w'suite for_redcloth'
++
++puts "Running basic CodeRay #{CodeRay::VERSION} tests: #{suite.join(', ')}"
++
++for test_case in suite
++ load File.join(mydir, test_case + '.rb')
++end
+diff --git a/test/lib/README b/test/lib/README
+new file mode 100644
+index 0000000..7c41648
+--- /dev/null
++++ b/test/lib/README
+@@ -0,0 +1,2 @@
++Contents:
++- test/unit: We need the old Test::Unit for the scanner test suite to work with Ruby 1.9.
+diff --git a/test/lib/assert_warning.rb b/test/lib/assert_warning.rb
+new file mode 100644
+index 0000000..828b464
+--- /dev/null
++++ b/test/lib/assert_warning.rb
+@@ -0,0 +1,15 @@
++class Test::Unit::TestCase
++
++ def assert_warning expected_warning
++ require 'stringio'
++ oldstderr = $stderr
++ $stderr = StringIO.new
++ yield
++ $stderr.rewind
++ given_warning = $stderr.read.chomp
++ assert_equal expected_warning, given_warning
++ ensure
++ $stderr = oldstderr
++ end
++
++end
+diff --git a/test/lib/test/unit.rb b/test/lib/test/unit.rb
+new file mode 100644
+index 0000000..b71f644
+--- /dev/null
++++ b/test/lib/test/unit.rb
+@@ -0,0 +1,280 @@
++require 'test/unit/testcase'
++require 'test/unit/autorunner'
++
++module Test # :nodoc:
++ #
++ # = Test::Unit - Ruby Unit Testing Framework
++ #
++ # == Introduction
++ #
++ # Unit testing is making waves all over the place, largely due to the
++ # fact that it is a core practice of XP. While XP is great, unit testing
++ # has been around for a long time and has always been a good idea. One
++ # of the keys to good unit testing, though, is not just writing tests,
++ # but having tests. What's the difference? Well, if you just _write_ a
++ # test and throw it away, you have no guarantee that something won't
++ # change later which breaks your code. If, on the other hand, you _have_
++ # tests (obviously you have to write them first), and run them as often
++ # as possible, you slowly build up a wall of things that cannot break
++ # without you immediately knowing about it. This is when unit testing
++ # hits its peak usefulness.
++ #
++ # Enter Test::Unit, a framework for unit testing in Ruby, helping you to
++ # design, debug and evaluate your code by making it easy to write and
++ # have tests for it.
++ #
++ #
++ # == Notes
++ #
++ # Test::Unit has grown out of and superceded Lapidary.
++ #
++ #
++ # == Feedback
++ #
++ # I like (and do my best to practice) XP, so I value early releases,
++ # user feedback, and clean, simple, expressive code. There is always
++ # room for improvement in everything I do, and Test::Unit is no
++ # exception. Please, let me know what you think of Test::Unit as it
++ # stands, and what you'd like to see expanded/changed/improved/etc. If
++ # you find a bug, let me know ASAP; one good way to let me know what the
++ # bug is is to submit a new test that catches it :-) Also, I'd love to
++ # hear about any successes you have with Test::Unit, and any
++ # documentation you might add will be greatly appreciated. My contact
++ # info is below.
++ #
++ #
++ # == Contact Information
++ #
++ # A lot of discussion happens about Ruby in general on the ruby-talk
++ # mailing list (http://www.ruby-lang.org/en/ml.html), and you can ask
++ # any questions you might have there. I monitor the list, as do many
++ # other helpful Rubyists, and you're sure to get a quick answer. Of
++ # course, you're also welcome to email me (Nathaniel Talbott) directly
++ # at mailto:testunit at talbott.ws, and I'll do my best to help you out.
++ #
++ #
++ # == Credits
++ #
++ # I'd like to thank...
++ #
++ # Matz, for a great language!
++ #
++ # Masaki Suketa, for his work on RubyUnit, which filled a vital need in
++ # the Ruby world for a very long time. I'm also grateful for his help in
++ # polishing Test::Unit and getting the RubyUnit compatibility layer
++ # right. His graciousness in allowing Test::Unit to supercede RubyUnit
++ # continues to be a challenge to me to be more willing to defer my own
++ # rights.
++ #
++ # Ken McKinlay, for his interest and work on unit testing, and for his
++ # willingness to dialog about it. He was also a great help in pointing
++ # out some of the holes in the RubyUnit compatibility layer.
++ #
++ # Dave Thomas, for the original idea that led to the extremely simple
++ # "require 'test/unit'", plus his code to improve it even more by
++ # allowing the selection of tests from the command-line. Also, without
++ # RDoc, the documentation for Test::Unit would stink a lot more than it
++ # does now.
++ #
++ # Everyone who's helped out with bug reports, feature ideas,
++ # encouragement to continue, etc. It's a real privilege to be a part of
++ # the Ruby community.
++ #
++ # The guys at RoleModel Software, for putting up with me repeating, "But
++ # this would be so much easier in Ruby!" whenever we're coding in Java.
++ #
++ # My Creator, for giving me life, and giving it more abundantly.
++ #
++ #
++ # == License
++ #
++ # Test::Unit is copyright (c) 2000-2003 Nathaniel Talbott. It is free
++ # software, and is distributed under the Ruby license. See the COPYING
++ # file in the standard Ruby distribution for details.
++ #
++ #
++ # == Warranty
++ #
++ # This software is provided "as is" and without any express or
++ # implied warranties, including, without limitation, the implied
++ # warranties of merchantibility and fitness for a particular
++ # purpose.
++ #
++ #
++ # == Author
++ #
++ # Nathaniel Talbott.
++ # Copyright (c) 2000-2003, Nathaniel Talbott
++ #
++ # ----
++ #
++ # = Usage
++ #
++ # The general idea behind unit testing is that you write a _test_
++ # _method_ that makes certain _assertions_ about your code, working
++ # against a _test_ _fixture_. A bunch of these _test_ _methods_ are
++ # bundled up into a _test_ _suite_ and can be run any time the
++ # developer wants. The results of a run are gathered in a _test_
++ # _result_ and displayed to the user through some UI. So, lets break
++ # this down and see how Test::Unit provides each of these necessary
++ # pieces.
++ #
++ #
++ # == Assertions
++ #
++ # These are the heart of the framework. Think of an assertion as a
++ # statement of expected outcome, i.e. "I assert that x should be equal
++ # to y". If, when the assertion is executed, it turns out to be
++ # correct, nothing happens, and life is good. If, on the other hand,
++ # your assertion turns out to be false, an error is propagated with
++ # pertinent information so that you can go back and make your
++ # assertion succeed, and, once again, life is good. For an explanation
++ # of the current assertions, see Test::Unit::Assertions.
++ #
++ #
++ # == Test Method & Test Fixture
++ #
++ # Obviously, these assertions have to be called within a context that
++ # knows about them and can do something meaningful with their
++ # pass/fail value. Also, it's handy to collect a bunch of related
++ # tests, each test represented by a method, into a common test class
++ # that knows how to run them. The tests will be in a separate class
++ # from the code they're testing for a couple of reasons. First of all,
++ # it allows your code to stay uncluttered with test code, making it
++ # easier to maintain. Second, it allows the tests to be stripped out
++ # for deployment, since they're really there for you, the developer,
++ # and your users don't need them. Third, and most importantly, it
++ # allows you to set up a common test fixture for your tests to run
++ # against.
++ #
++ # What's a test fixture? Well, tests do not live in a vacuum; rather,
++ # they're run against the code they are testing. Often, a collection
++ # of tests will run against a common set of data, also called a
++ # fixture. If they're all bundled into the same test class, they can
++ # all share the setting up and tearing down of that data, eliminating
++ # unnecessary duplication and making it much easier to add related
++ # tests.
++ #
++ # Test::Unit::TestCase wraps up a collection of test methods together
++ # and allows you to easily set up and tear down the same test fixture
++ # for each test. This is done by overriding #setup and/or #teardown,
++ # which will be called before and after each test method that is
++ # run. The TestCase also knows how to collect the results of your
++ # assertions into a Test::Unit::TestResult, which can then be reported
++ # back to you... but I'm getting ahead of myself. To write a test,
++ # follow these steps:
++ #
++ # * Make sure Test::Unit is in your library path.
++ # * require 'test/unit' in your test script.
++ # * Create a class that subclasses Test::Unit::TestCase.
++ # * Add a method that begins with "test" to your class.
++ # * Make assertions in your test method.
++ # * Optionally define #setup and/or #teardown to set up and/or tear
++ # down your common test fixture.
++ # * You can now run your test as you would any other Ruby
++ # script... try it and see!
++ #
++ # A really simple test might look like this (#setup and #teardown are
++ # commented out to indicate that they are completely optional):
++ #
++ # require 'test/unit'
++ #
++ # class TC_MyTest < Test::Unit::TestCase
++ # # def setup
++ # # end
++ #
++ # # def teardown
++ # # end
++ #
++ # def test_fail
++ # assert(false, 'Assertion was false.')
++ # end
++ # end
++ #
++ #
++ # == Test Runners
++ #
++ # So, now you have this great test class, but you still need a way to
++ # run it and view any failures that occur during the run. This is
++ # where Test::Unit::UI::Console::TestRunner (and others, such as
++ # Test::Unit::UI::GTK::TestRunner) comes into play. The console test
++ # runner is automatically invoked for you if you require 'test/unit'
++ # and simply run the file. To use another runner, or to manually
++ # invoke a runner, simply call its run class method and pass in an
++ # object that responds to the suite message with a
++ # Test::Unit::TestSuite. This can be as simple as passing in your
++ # TestCase class (which has a class suite method). It might look
++ # something like this:
++ #
++ # require 'test/unit/ui/console/testrunner'
++ # Test::Unit::UI::Console::TestRunner.run(TC_MyTest)
++ #
++ #
++ # == Test Suite
++ #
++ # As more and more unit tests accumulate for a given project, it
++ # becomes a real drag running them one at a time, and it also
++ # introduces the potential to overlook a failing test because you
++ # forget to run it. Suddenly it becomes very handy that the
++ # TestRunners can take any object that returns a Test::Unit::TestSuite
++ # in response to a suite method. The TestSuite can, in turn, contain
++ # other TestSuites or individual tests (typically created by a
++ # TestCase). In other words, you can easily wrap up a group of
++ # TestCases and TestSuites like this:
++ #
++ # require 'test/unit/testsuite'
++ # require 'tc_myfirsttests'
++ # require 'tc_moretestsbyme'
++ # require 'ts_anothersetoftests'
++ #
++ # class TS_MyTests
++ # def self.suite
++ # suite = Test::Unit::TestSuite.new
++ # suite << TC_MyFirstTests.suite
++ # suite << TC_MoreTestsByMe.suite
++ # suite << TS_AnotherSetOfTests.suite
++ # return suite
++ # end
++ # end
++ # Test::Unit::UI::Console::TestRunner.run(TS_MyTests)
++ #
++ # Now, this is a bit cumbersome, so Test::Unit does a little bit more
++ # for you, by wrapping these up automatically when you require
++ # 'test/unit'. What does this mean? It means you could write the above
++ # test case like this instead:
++ #
++ # require 'test/unit'
++ # require 'tc_myfirsttests'
++ # require 'tc_moretestsbyme'
++ # require 'ts_anothersetoftests'
++ #
++ # Test::Unit is smart enough to find all the test cases existing in
++ # the ObjectSpace and wrap them up into a suite for you. It then runs
++ # the dynamic suite using the console TestRunner.
++ #
++ #
++ # == Questions?
++ #
++ # I'd really like to get feedback from all levels of Ruby
++ # practitioners about typos, grammatical errors, unclear statements,
++ # missing points, etc., in this document (or any other).
++ #
++
++ module Unit
++ # If set to false Test::Unit will not automatically run at exit.
++ def self.run=(flag)
++ @run = flag
++ end
++
++ # Automatically run tests at exit?
++ def self.run?
++ @run ||= false
++ end
++ end
++end
++
++at_exit do
++ unless $! || Test::Unit.run?
++ exit Test::Unit::AutoRunner.run
++ end
++end
+diff --git a/test/lib/test/unit/assertionfailederror.rb b/test/lib/test/unit/assertionfailederror.rb
+new file mode 100644
+index 0000000..a21e4b5
+--- /dev/null
++++ b/test/lib/test/unit/assertionfailederror.rb
+@@ -0,0 +1,14 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++module Test
++ module Unit
++
++ # Thrown by Test::Unit::Assertions when an assertion fails.
++ class AssertionFailedError < StandardError
++ end
++ end
++end
+diff --git a/test/lib/test/unit/assertions.rb b/test/lib/test/unit/assertions.rb
+new file mode 100644
+index 0000000..aa97799
+--- /dev/null
++++ b/test/lib/test/unit/assertions.rb
+@@ -0,0 +1,622 @@
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit/assertionfailederror'
++require 'test/unit/util/backtracefilter'
++
++module Test
++ module Unit
++
++ ##
++ # Test::Unit::Assertions contains the standard Test::Unit assertions.
++ # Assertions is included in Test::Unit::TestCase.
++ #
++ # To include it in your own code and use its functionality, you simply
++ # need to rescue Test::Unit::AssertionFailedError. Additionally you may
++ # override add_assertion to get notified whenever an assertion is made.
++ #
++ # Notes:
++ # * The message to each assertion, if given, will be propagated with the
++ # failure.
++ # * It is easy to add your own assertions based on assert_block().
++ #
++ # = Example Custom Assertion
++ #
++ # def deny(boolean, message = nil)
++ # message = build_message message, '<?> is not false or nil.', boolean
++ # assert_block message do
++ # not boolean
++ # end
++ # end
++
++ module Assertions
++
++ ##
++ # The assertion upon which all other assertions are based. Passes if the
++ # block yields true.
++ #
++ # Example:
++ # assert_block "Couldn't do the thing" do
++ # do_the_thing
++ # end
++
++ public
++ def assert_block(message="assert_block failed.") # :yields:
++ _wrap_assertion do
++ if (! yield)
++ raise AssertionFailedError.new(message.to_s)
++ end
++ end
++ end
++
++ ##
++ # Asserts that +boolean+ is not false or nil.
++ #
++ # Example:
++ # assert [1, 2].include?(5)
++
++ public
++ def assert(boolean, message=nil)
++ _wrap_assertion do
++ assert_block("assert should not be called with a block.") { !block_given? }
++ assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
++ end
++ end
++
++ ##
++ # Passes if +expected+ == +actual.
++ #
++ # Note that the ordering of arguments is important, since a helpful
++ # error message is generated when this one fails that tells you the
++ # values of expected and actual.
++ #
++ # Example:
++ # assert_equal 'MY STRING', 'my string'.upcase
++
++ public
++ def assert_equal(expected, actual, message=nil)
++ full_message = build_message(message, <<EOT, expected, actual)
++<?> expected but was
++<?>.
++EOT
++ assert_block(full_message) { expected == actual }
++ end
++
++ private
++ def _check_exception_class(args) # :nodoc:
++ args.partition do |klass|
++ next if klass.instance_of?(Module)
++ assert(Exception >= klass, "Should expect a class of exception, #{klass}")
++ true
++ end
++ end
++
++ private
++ def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
++ exceptions.include?(actual_exception.class) or
++ modules.any? {|mod| actual_exception.is_a?(mod)}
++ end
++
++ ##
++ # Passes if the block raises one of the given exceptions.
++ #
++ # Example:
++ # assert_raise RuntimeError, LoadError do
++ # raise 'Boom!!!'
++ # end
++
++ public
++ def assert_raise(*args)
++ _wrap_assertion do
++ if Module === args.last
++ message = ""
++ else
++ message = args.pop
++ end
++ exceptions, modules = _check_exception_class(args)
++ expected = args.size == 1 ? args.first : args
++ actual_exception = nil
++ full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
++ assert_block(full_message) do
++ begin
++ yield
++ rescue Exception => actual_exception
++ break
++ end
++ false
++ end
++ full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
++ assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
++ actual_exception
++ end
++ end
++
++ ##
++ # Alias of assert_raise.
++ #
++ # Will be deprecated in 1.9, and removed in 2.0.
++
++ public
++ def assert_raises(*args, &block)
++ assert_raise(*args, &block)
++ end
++
++ ##
++ # Passes if +object+ .instance_of? +klass+
++ #
++ # Example:
++ # assert_instance_of String, 'foo'
++
++ public
++ def assert_instance_of(klass, object, message="")
++ _wrap_assertion do
++ assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
++ full_message = build_message(message, <<EOT, object, klass, object.class)
++<?> expected to be an instance of
++<?> but was
++<?>.
++EOT
++ assert_block(full_message){object.instance_of?(klass)}
++ end
++ end
++
++ ##
++ # Passes if +object+ is nil.
++ #
++ # Example:
++ # assert_nil [1, 2].uniq!
++
++ public
++ def assert_nil(object, message="")
++ assert_equal(nil, object, message)
++ end
++
++ ##
++ # Passes if +object+ .kind_of? +klass+
++ #
++ # Example:
++ # assert_kind_of Object, 'foo'
++
++ public
++ def assert_kind_of(klass, object, message="")
++ _wrap_assertion do
++ assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
++ full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
++ assert_block(full_message){object.kind_of?(klass)}
++ end
++ end
++
++ ##
++ # Passes if +object+ .respond_to? +method+
++ #
++ # Example:
++ # assert_respond_to 'bugbear', :slice
++
++ public
++ def assert_respond_to(object, method, message="")
++ _wrap_assertion do
++ full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
++
++ assert_block(full_message) do
++ method.kind_of?(Symbol) || method.respond_to?(:to_str)
++ end
++ full_message = build_message(message, <<EOT, object, object.class, method)
++<?>
++of type <?>
++expected to respond_to\\?<?>.
++EOT
++ assert_block(full_message) { object.respond_to?(method) }
++ end
++ end
++
++ ##
++ # Passes if +string+ =~ +pattern+.
++ #
++ # Example:
++ # assert_match(/\d+/, 'five, 6, seven')
++
++ public
++ def assert_match(pattern, string, message="")
++ _wrap_assertion do
++ pattern = case(pattern)
++ when String
++ Regexp.new(Regexp.escape(pattern))
++ else
++ pattern
++ end
++ full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
++ assert_block(full_message) { string =~ pattern }
++ end
++ end
++
++ ##
++ # Passes if +actual+ .equal? +expected+ (i.e. they are the same
++ # instance).
++ #
++ # Example:
++ # o = Object.new
++ # assert_same o, o
++
++ public
++ def assert_same(expected, actual, message="")
++ full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
++<?>
++with id <?> expected to be equal\\? to
++<?>
++with id <?>.
++EOT
++ assert_block(full_message) { actual.equal?(expected) }
++ end
++
++ ##
++ # Compares the +object1+ with +object2+ using +operator+.
++ #
++ # Passes if object1.__send__(operator, object2) is true.
++ #
++ # Example:
++ # assert_operator 5, :>=, 4
++
++ public
++ def assert_operator(object1, operator, object2, message="")
++ _wrap_assertion do
++ full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
++ assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
++ full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
++<?> expected to be
++?
++<?>.
++EOT
++ assert_block(full_message) { object1.__send__(operator, object2) }
++ end
++ end
++
++ ##
++ # Passes if block does not raise an exception.
++ #
++ # Example:
++ # assert_nothing_raised do
++ # [1, 2].uniq
++ # end
++
++ public
++ def assert_nothing_raised(*args)
++ _wrap_assertion do
++ if Module === args.last
++ message = ""
++ else
++ message = args.pop
++ end
++ exceptions, modules = _check_exception_class(args)
++ begin
++ yield
++ rescue Exception => e
++ if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
++ _expected_exception?(e, exceptions, modules))
++ assert_block(build_message(message, "Exception raised:\n?", e)){false}
++ else
++ raise
++ end
++ end
++ nil
++ end
++ end
++
++ ##
++ # Flunk always fails.
++ #
++ # Example:
++ # flunk 'Not done testing yet.'
++
++ public
++ def flunk(message="Flunked")
++ assert_block(build_message(message)){false}
++ end
++
++ ##
++ # Passes if ! +actual+ .equal? +expected+
++ #
++ # Example:
++ # assert_not_same Object.new, Object.new
++
++ public
++ def assert_not_same(expected, actual, message="")
++ full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
++<?>
++with id <?> expected to not be equal\\? to
++<?>
++with id <?>.
++EOT
++ assert_block(full_message) { !actual.equal?(expected) }
++ end
++
++ ##
++ # Passes if +expected+ != +actual+
++ #
++ # Example:
++ # assert_not_equal 'some string', 5
++
++ public
++ def assert_not_equal(expected, actual, message="")
++ full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
++ assert_block(full_message) { expected != actual }
++ end
++
++ ##
++ # Passes if ! +object+ .nil?
++ #
++ # Example:
++ # assert_not_nil '1 two 3'.sub!(/two/, '2')
++
++ public
++ def assert_not_nil(object, message="")
++ full_message = build_message(message, "<?> expected to not be nil.", object)
++ assert_block(full_message){!object.nil?}
++ end
++
++ ##
++ # Passes if +regexp+ !~ +string+
++ #
++ # Example:
++ # assert_no_match(/two/, 'one 2 three')
++
++ public
++ def assert_no_match(regexp, string, message="")
++ _wrap_assertion do
++ assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
++ full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
++ assert_block(full_message) { regexp !~ string }
++ end
++ end
++
++ UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
++ ThreadError => /^uncaught throw \`(.+)\' in thread /} #`
++
++ ##
++ # Passes if the block throws +expected_symbol+
++ #
++ # Example:
++ # assert_throws :done do
++ # throw :done
++ # end
++
++ public
++ def assert_throws(expected_symbol, message="", &proc)
++ _wrap_assertion do
++ assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
++ assert_block("Should have passed a block to assert_throws."){block_given?}
++ caught = true
++ begin
++ catch(expected_symbol) do
++ proc.call
++ caught = false
++ end
++ full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
++ assert_block(full_message){caught}
++ rescue NameError, ThreadError => error
++ if UncaughtThrow[error.class] !~ error.message
++ raise error
++ end
++ full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
++ flunk(full_message)
++ end
++ end
++ end
++
++ ##
++ # Passes if block does not throw anything.
++ #
++ # Example:
++ # assert_nothing_thrown do
++ # [1, 2].uniq
++ # end
++
++ public
++ def assert_nothing_thrown(message="", &proc)
++ _wrap_assertion do
++ assert(block_given?, "Should have passed a block to assert_nothing_thrown")
++ begin
++ proc.call
++ rescue NameError, ThreadError => error
++ if UncaughtThrow[error.class] !~ error.message
++ raise error
++ end
++ full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
++ flunk(full_message)
++ end
++ assert(true, "Expected nothing to be thrown")
++ end
++ end
++
++ ##
++ # Passes if +expected_float+ and +actual_float+ are equal
++ # within +delta+ tolerance.
++ #
++ # Example:
++ # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
++
++ public
++ def assert_in_delta(expected_float, actual_float, delta, message="")
++ _wrap_assertion do
++ {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
++ assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
++ end
++ assert_operator(delta, :>=, 0.0, "The delta should not be negative")
++ full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
++<?> and
++<?> expected to be within
++<?> of each other.
++EOT
++ assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
++ end
++ end
++
++ ##
++ # Passes if the method send returns a true value.
++ #
++ # +send_array+ is composed of:
++ # * A receiver
++ # * A method
++ # * Arguments to the method
++ #
++ # Example:
++ # assert_send [[1, 2], :include?, 4]
++
++ public
++ def assert_send(send_array, message="")
++ _wrap_assertion do
++ assert_instance_of(Array, send_array, "assert_send requires an array of send information")
++ assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
++ full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
++<?> expected to respond to
++<?(?)> with a true value.
++EOT
++ assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
++ end
++ end
++
++ ##
++ # Builds a failure message. +head+ is added before the +template+ and
++ # +arguments+ replaces the '?'s positionally in the template.
++
++ public
++ def build_message(head, template=nil, *arguments)
++ template &&= template.chomp
++ return AssertionMessage.new(head, template, arguments)
++ end
++
++ private
++ def _wrap_assertion
++ @_assertion_wrapped ||= false
++ unless (@_assertion_wrapped)
++ @_assertion_wrapped = true
++ begin
++ add_assertion
++ return yield
++ ensure
++ @_assertion_wrapped = false
++ end
++ else
++ return yield
++ end
++ end
++
++ ##
++ # Called whenever an assertion is made. Define this in classes that
++ # include Test::Unit::Assertions to record assertion counts.
++
++ private
++ def add_assertion
++ end
++
++ ##
++ # Select whether or not to use the pretty-printer. If this option is set
++ # to false before any assertions are made, pp.rb will not be required.
++
++ public
++ def self.use_pp=(value)
++ AssertionMessage.use_pp = value
++ end
++
++ # :stopdoc:
++
++ class AssertionMessage
++ @use_pp = true
++ class << self
++ attr_accessor :use_pp
++ end
++
++ class Literal
++ def initialize(value)
++ @value = value
++ end
++
++ def inspect
++ @value.to_s
++ end
++ end
++
++ class Template
++ def self.create(string)
++ parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
++ self.new(parts)
++ end
++
++ attr_reader :count
++
++ def initialize(parts)
++ @parts = parts
++ @count = parts.find_all{|e| e == '?'}.size
++ end
++
++ def result(parameters)
++ raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
++ params = parameters.dup
++ @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
++ end
++ end
++
++ def self.literal(value)
++ Literal.new(value)
++ end
++
++ include Util::BacktraceFilter
++
++ def initialize(head, template_string, parameters)
++ @head = head
++ @template_string = template_string
++ @parameters = parameters
++ end
++
++ def convert(object)
++ case object
++ when Exception
++ <<EOM.chop
++Class: <#{convert(object.class)}>
++Message: <#{convert(object.message)}>
++---Backtrace---
++#{filter_backtrace(object.backtrace).join("\n")}
++---------------
++EOM
++ else
++ if(self.class.use_pp)
++ begin
++ require 'pp'
++ rescue LoadError
++ self.class.use_pp = false
++ return object.inspect
++ end unless(defined?(PP))
++ PP.pp(object, '').chomp
++ else
++ object.inspect
++ end
++ end
++ end
++
++ def template
++ @template ||= Template.create(@template_string)
++ end
++
++ def add_period(string)
++ (string =~ /\.\Z/ ? string : string + '.')
++ end
++
++ def to_s
++ message_parts = []
++ if (@head)
++ head = @head.to_s
++ unless(head.empty?)
++ message_parts << add_period(head)
++ end
++ end
++ tail = template.result(@parameters.collect{|e| convert(e)})
++ message_parts << tail unless(tail.empty?)
++ message_parts.join("\n")
++ end
++ end
++
++ # :startdoc:
++
++ end
++ end
++end
+diff --git a/test/lib/test/unit/autorunner.rb b/test/lib/test/unit/autorunner.rb
+new file mode 100644
+index 0000000..0dfc01c
+--- /dev/null
++++ b/test/lib/test/unit/autorunner.rb
+@@ -0,0 +1,219 @@
++require 'test/unit/ui/testrunnerutilities'
++require 'optparse'
++
++module Test
++ module Unit
++ class AutoRunner
++ def self.run(force_standalone=false, default_dir=nil, argv=ARGV, &block)
++ r = new(force_standalone || standalone?, &block)
++ r.base = default_dir
++ r.process_args(argv)
++ r.run
++ end
++
++ def self.standalone?
++ return false unless("-e" == $0)
++ ObjectSpace.each_object(Class) do |klass|
++ return false if(klass < TestCase)
++ end
++ true
++ end
++
++ RUNNERS = {
++ :console => proc do |r|
++ require 'test/unit/ui/console/testrunner'
++ Test::Unit::UI::Console::TestRunner
++ end,
++ :gtk => proc do |r|
++ require 'test/unit/ui/gtk/testrunner'
++ Test::Unit::UI::GTK::TestRunner
++ end,
++ :gtk2 => proc do |r|
++ require 'test/unit/ui/gtk2/testrunner'
++ Test::Unit::UI::GTK2::TestRunner
++ end,
++ :fox => proc do |r|
++ require 'test/unit/ui/fox/testrunner'
++ Test::Unit::UI::Fox::TestRunner
++ end,
++ :tk => proc do |r|
++ require 'test/unit/ui/tk/testrunner'
++ Test::Unit::UI::Tk::TestRunner
++ end,
++ }
++
++ OUTPUT_LEVELS = [
++ [:silent, UI::SILENT],
++ [:progress, UI::PROGRESS_ONLY],
++ [:normal, UI::NORMAL],
++ [:verbose, UI::VERBOSE],
++ ]
++
++ COLLECTORS = {
++ :objectspace => proc do |r|
++ require 'test/unit/collector/objectspace'
++ c = Collector::ObjectSpace.new
++ c.filter = r.filters
++ c.collect($0.sub(/\.rb\Z/, ''))
++ end,
++ :dir => proc do |r|
++ require 'test/unit/collector/dir'
++ c = Collector::Dir.new
++ c.filter = r.filters
++ c.pattern.concat(r.pattern) if(r.pattern)
++ c.exclude.concat(r.exclude) if(r.exclude)
++ c.base = r.base
++ $:.push(r.base) if r.base
++ c.collect(*(r.to_run.empty? ? ['.'] : r.to_run))
++ end,
++ }
++
++ attr_reader :suite
++ attr_accessor :output_level, :filters, :to_run, :pattern, :exclude, :base, :workdir
++ attr_writer :runner, :collector
++
++ def initialize(standalone)
++ Unit.run = true
++ @standalone = standalone
++ @runner = RUNNERS[:console]
++ @collector = COLLECTORS[(standalone ? :dir : :objectspace)]
++ @filters = []
++ @to_run = []
++ @output_level = UI::NORMAL
++ @workdir = nil
++ yield(self) if(block_given?)
++ end
++
++ def process_args(args = ARGV)
++ begin
++ options.order!(args) {|arg| @to_run << arg}
++ rescue OptionParser::ParseError => e
++ puts e
++ puts options
++ $! = nil
++ abort
++ else
++ @filters << proc{false} unless(@filters.empty?)
++ end
++ not @to_run.empty?
++ end
++
++ def options
++ @options ||= OptionParser.new do |o|
++ o.banner = "Test::Unit automatic runner."
++ o.banner << "\nUsage: #{$0} [options] [-- untouched arguments]"
++
++ o.on
++ o.on('-r', '--runner=RUNNER', RUNNERS,
++ "Use the given RUNNER.",
++ "(" + keyword_display(RUNNERS) + ")") do |r|
++ @runner = r
++ end
++
++ if(@standalone)
++ o.on('-b', '--basedir=DIR', "Base directory of test suites.") do |b|
++ @base = b
++ end
++
++ o.on('-w', '--workdir=DIR', "Working directory to run tests.") do |w|
++ @workdir = w
++ end
++
++ o.on('-a', '--add=TORUN', Array,
++ "Add TORUN to the list of things to run;",
++ "can be a file or a directory.") do |a|
++ @to_run.concat(a)
++ end
++
++ @pattern = []
++ o.on('-p', '--pattern=PATTERN', Regexp,
++ "Match files to collect against PATTERN.") do |e|
++ @pattern << e
++ end
++
++ @exclude = []
++ o.on('-x', '--exclude=PATTERN', Regexp,
++ "Ignore files to collect against PATTERN.") do |e|
++ @exclude << e
++ end
++ end
++
++ o.on('-n', '--name=NAME', String,
++ "Runs tests matching NAME.",
++ "(patterns may be used).") do |n|
++ n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
++ case n
++ when Regexp
++ @filters << proc{|t| n =~ t.method_name ? true : nil}
++ else
++ @filters << proc{|t| n == t.method_name ? true : nil}
++ end
++ end
++
++ o.on('-t', '--testcase=TESTCASE', String,
++ "Runs tests in TestCases matching TESTCASE.",
++ "(patterns may be used).") do |n|
++ n = (%r{\A/(.*)/\Z} =~ n ? Regexp.new($1) : n)
++ case n
++ when Regexp
++ @filters << proc{|t| n =~ t.class.name ? true : nil}
++ else
++ @filters << proc{|t| n == t.class.name ? true : nil}
++ end
++ end
++
++ o.on('-I', "--load-path=DIR[#{File::PATH_SEPARATOR}DIR...]",
++ "Appends directory list to $LOAD_PATH.") do |dirs|
++ $LOAD_PATH.concat(dirs.split(File::PATH_SEPARATOR))
++ end
++
++ o.on('-v', '--verbose=[LEVEL]', OUTPUT_LEVELS,
++ "Set the output level (default is verbose).",
++ "(" + keyword_display(OUTPUT_LEVELS) + ")") do |l|
++ @output_level = l || UI::VERBOSE
++ end
++
++ o.on('--',
++ "Stop processing options so that the",
++ "remaining options will be passed to the",
++ "test."){o.terminate}
++
++ o.on('-h', '--help', 'Display this help.'){puts o; exit}
++
++ o.on_tail
++ o.on_tail('Deprecated options:')
++
++ o.on_tail('--console', 'Console runner (use --runner).') do
++ warn("Deprecated option (--console).")
++ @runner = RUNNERS[:console]
++ end
++
++ o.on_tail('--gtk', 'GTK runner (use --runner).') do
++ warn("Deprecated option (--gtk).")
++ @runner = RUNNERS[:gtk]
++ end
++
++ o.on_tail('--fox', 'Fox runner (use --runner).') do
++ warn("Deprecated option (--fox).")
++ @runner = RUNNERS[:fox]
++ end
++
++ o.on_tail
++ end
++ end
++
++ def keyword_display(array)
++ list = array.collect {|e, *| e.to_s}
++ Array === array or list.sort!
++ list.collect {|e| e.sub(/^(.)([A-Za-z]+)(?=\w*$)/, '\\1[\\2]')}.join(", ")
++ end
++
++ def run
++ @suite = @collector[self]
++ result = @runner[self] or return false
++ Dir.chdir(@workdir) if @workdir
++ result.run(@suite, @output_level).passed?
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/collector.rb b/test/lib/test/unit/collector.rb
+new file mode 100644
+index 0000000..9e9e654
+--- /dev/null
++++ b/test/lib/test/unit/collector.rb
+@@ -0,0 +1,43 @@
++module Test
++ module Unit
++ module Collector
++ def initialize
++ @filters = []
++ end
++
++ def filter=(filters)
++ @filters = case(filters)
++ when Proc
++ [filters]
++ when Array
++ filters
++ end
++ end
++
++ def add_suite(destination, suite)
++ to_delete = suite.tests.find_all{|t| !include?(t)}
++ to_delete.each{|t| suite.delete(t)}
++ destination << suite unless(suite.size == 0)
++ end
++
++ def include?(test)
++ return true if(@filters.empty?)
++ @filters.each do |filter|
++ result = filter[test]
++ if(result.nil?)
++ next
++ elsif(!result)
++ return false
++ else
++ return true
++ end
++ end
++ true
++ end
++
++ def sort(suites)
++ suites.sort_by{|s| s.name}
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/collector/dir.rb b/test/lib/test/unit/collector/dir.rb
+new file mode 100644
+index 0000000..97c8d28
+--- /dev/null
++++ b/test/lib/test/unit/collector/dir.rb
+@@ -0,0 +1,107 @@
++require 'test/unit/testsuite'
++require 'test/unit/collector'
++
++module Test
++ module Unit
++ module Collector
++ class Dir
++ include Collector
++
++ attr_reader :pattern, :exclude
++ attr_accessor :base
++
++ def initialize(dir=::Dir, file=::File, object_space=::ObjectSpace, req=nil)
++ super()
++ @dir = dir
++ @file = file
++ @object_space = object_space
++ @req = req
++ @pattern = [/\btest_.*\.rb\Z/m]
++ @exclude = []
++ end
++
++ def collect(*from)
++ basedir = @base
++ $:.push(basedir) if basedir
++ if(from.empty?)
++ recursive_collect('.', find_test_cases)
++ elsif(from.size == 1)
++ recursive_collect(from.first, find_test_cases)
++ else
++ suites = []
++ from.each do |f|
++ suite = recursive_collect(f, find_test_cases)
++ suites << suite unless(suite.tests.empty?)
++ end
++ suite = TestSuite.new("[#{from.join(', ')}]")
++ sort(suites).each{|s| suite << s}
++ suite
++ end
++ ensure
++ $:.delete_at($:.rindex(basedir)) if basedir
++ end
++
++ def find_test_cases(ignore=[])
++ cases = []
++ @object_space.each_object(Class) do |c|
++ cases << c if(c < TestCase && !ignore.include?(c))
++ end
++ ignore.concat(cases)
++ cases
++ end
++
++ def recursive_collect(name, already_gathered)
++ sub_suites = []
++ path = realdir(name)
++ if @file.directory?(path)
++ dir_name = name unless name == '.'
++ @dir.entries(path).each do |e|
++ next if(e == '.' || e == '..')
++ e_name = dir_name ? @file.join(dir_name, e) : e
++ if @file.directory?(realdir(e_name))
++ next if /\ACVS\z/ =~ e
++ sub_suite = recursive_collect(e_name, already_gathered)
++ sub_suites << sub_suite unless(sub_suite.empty?)
++ else
++ next if /~\z/ =~ e_name or /\A\.\#/ =~ e
++ if @pattern and !@pattern.empty?
++ next unless @pattern.any? {|pat| pat =~ e_name}
++ end
++ if @exclude and !@exclude.empty?
++ next if @exclude.any? {|pat| pat =~ e_name}
++ end
++ collect_file(e_name, sub_suites, already_gathered)
++ end
++ end
++ else
++ collect_file(name, sub_suites, already_gathered)
++ end
++ suite = TestSuite.new(@file.basename(name))
++ sort(sub_suites).each{|s| suite << s}
++ suite
++ end
++
++ def collect_file(name, suites, already_gathered)
++ dir = @file.dirname(@file.expand_path(name, @base))
++ $:.unshift(dir)
++ if(@req)
++ @req.require(name)
++ else
++ require(name)
++ end
++ find_test_cases(already_gathered).each{|t| add_suite(suites, t.suite)}
++ ensure
++ $:.delete_at($:.rindex(dir)) if(dir)
++ end
++
++ def realdir(path)
++ if @base
++ @file.join(@base, path)
++ else
++ path
++ end
++ end
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/error.rb b/test/lib/test/unit/error.rb
+new file mode 100644
+index 0000000..43a813f
+--- /dev/null
++++ b/test/lib/test/unit/error.rb
+@@ -0,0 +1,56 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit/util/backtracefilter'
++
++module Test
++ module Unit
++
++ # Encapsulates an error in a test. Created by
++ # Test::Unit::TestCase when it rescues an exception thrown
++ # during the processing of a test.
++ class Error
++ include Util::BacktraceFilter
++
++ attr_reader(:test_name, :exception)
++
++ SINGLE_CHARACTER = 'E'
++
++ # Creates a new Error with the given test_name and
++ # exception.
++ def initialize(test_name, exception)
++ @test_name = test_name
++ @exception = exception
++ end
++
++ # Returns a single character representation of an error.
++ def single_character_display
++ SINGLE_CHARACTER
++ end
++
++ # Returns the message associated with the error.
++ def message
++ "#{@exception.class.name}: #{@exception.message}"
++ end
++
++ # Returns a brief version of the error description.
++ def short_display
++ "#@test_name: #{message.split("\n")[0]}"
++ end
++
++ # Returns a verbose version of the error description.
++ def long_display
++ backtrace = filter_backtrace(@exception.backtrace).join("\n ")
++ "Error:\n#@test_name:\n#{message}\n #{backtrace}"
++ end
++
++ # Overridden to return long_display.
++ def to_s
++ long_display
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/failure.rb b/test/lib/test/unit/failure.rb
+new file mode 100644
+index 0000000..832c998
+--- /dev/null
++++ b/test/lib/test/unit/failure.rb
+@@ -0,0 +1,51 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++module Test
++ module Unit
++
++ # Encapsulates a test failure. Created by Test::Unit::TestCase
++ # when an assertion fails.
++ class Failure
++ attr_reader :test_name, :location, :message
++
++ SINGLE_CHARACTER = 'F'
++
++ # Creates a new Failure with the given location and
++ # message.
++ def initialize(test_name, location, message)
++ @test_name = test_name
++ @location = location
++ @message = message
++ end
++
++ # Returns a single character representation of a failure.
++ def single_character_display
++ SINGLE_CHARACTER
++ end
++
++ # Returns a brief version of the error description.
++ def short_display
++ "#@test_name: #{@message.split("\n")[0]}"
++ end
++
++ # Returns a verbose version of the error description.
++ def long_display
++ location_display = if(location.size == 1)
++ location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
++ else
++ "\n [#{location.join("\n ")}]"
++ end
++ "Failure:\n#@test_name#{location_display}:\n#@message"
++ end
++
++ # Overridden to return long_display.
++ def to_s
++ long_display
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/testcase.rb b/test/lib/test/unit/testcase.rb
+new file mode 100644
+index 0000000..f53b460
+--- /dev/null
++++ b/test/lib/test/unit/testcase.rb
+@@ -0,0 +1,160 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit/assertions'
++require 'test/unit/failure'
++require 'test/unit/error'
++require 'test/unit/testsuite'
++require 'test/unit/assertionfailederror'
++require 'test/unit/util/backtracefilter'
++
++module Test
++ module Unit
++
++ # Ties everything together. If you subclass and add your own
++ # test methods, it takes care of making them into tests and
++ # wrapping those tests into a suite. It also does the
++ # nitty-gritty of actually running an individual test and
++ # collecting its results into a Test::Unit::TestResult object.
++ class TestCase
++ include Assertions
++ include Util::BacktraceFilter
++
++ attr_reader :method_name
++
++ STARTED = name + "::STARTED"
++ FINISHED = name + "::FINISHED"
++
++ ##
++ # These exceptions are not caught by #run.
++
++ PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, Interrupt,
++ SystemExit]
++
++ # Creates a new instance of the fixture for running the
++ # test represented by test_method_name.
++ def initialize(test_method_name)
++ unless(respond_to?(test_method_name) and
++ (method(test_method_name).arity == 0 ||
++ method(test_method_name).arity == -1))
++ throw :invalid_test
++ end
++ @method_name = test_method_name
++ @test_passed = true
++ end
++
++ # Rolls up all of the test* methods in the fixture into
++ # one suite, creating a new instance of the fixture for
++ # each method.
++ def self.suite
++ method_names = public_instance_methods(true)
++ tests = method_names.delete_if {|method_name| method_name !~ /^test./}
++ suite = TestSuite.new(name)
++ tests.sort.each do
++ |test|
++ catch(:invalid_test) do
++ suite << new(test)
++ end
++ end
++ if (suite.empty?)
++ catch(:invalid_test) do
++ suite << new("default_test")
++ end
++ end
++ return suite
++ end
++
++ # Runs the individual test method represented by this
++ # instance of the fixture, collecting statistics, failures
++ # and errors in result.
++ def run(result)
++ yield(STARTED, name)
++ @_result = result
++ begin
++ setup
++ __send__(@method_name)
++ rescue AssertionFailedError => e
++ add_failure(e.message, e.backtrace)
++ rescue Exception
++ raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
++ add_error($!)
++ ensure
++ begin
++ teardown
++ rescue AssertionFailedError => e
++ add_failure(e.message, e.backtrace)
++ rescue Exception
++ raise if PASSTHROUGH_EXCEPTIONS.include? $!.class
++ add_error($!)
++ end
++ end
++ result.add_run
++ yield(FINISHED, name)
++ end
++
++ # Called before every test method runs. Can be used
++ # to set up fixture information.
++ def setup
++ end
++
++ # Called after every test method runs. Can be used to tear
++ # down fixture information.
++ def teardown
++ end
++
++ def default_test
++ flunk("No tests were specified")
++ end
++
++ # Returns whether this individual test passed or
++ # not. Primarily for use in teardown so that artifacts
++ # can be left behind if the test fails.
++ def passed?
++ return @test_passed
++ end
++ private :passed?
++
++ def size
++ 1
++ end
++
++ def add_assertion
++ @_result.add_assertion
++ end
++ private :add_assertion
++
++ def add_failure(message, all_locations=caller())
++ @test_passed = false
++ @_result.add_failure(Failure.new(name, filter_backtrace(all_locations), message))
++ end
++ private :add_failure
++
++ def add_error(exception)
++ @test_passed = false
++ @_result.add_error(Error.new(name, exception))
++ end
++ private :add_error
++
++ # Returns a human-readable name for the specific test that
++ # this instance of TestCase represents.
++ def name
++ "#{@method_name}(#{self.class.name})"
++ end
++
++ # Overridden to return #name.
++ def to_s
++ name
++ end
++
++ # It's handy to be able to compare TestCase instances.
++ def ==(other)
++ return false unless(other.kind_of?(self.class))
++ return false unless(@method_name == other.method_name)
++ self.class == other.class
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/testresult.rb b/test/lib/test/unit/testresult.rb
+new file mode 100644
+index 0000000..e3a472e
+--- /dev/null
++++ b/test/lib/test/unit/testresult.rb
+@@ -0,0 +1,80 @@
++#--
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit/util/observable'
++
++module Test
++ module Unit
++
++ # Collects Test::Unit::Failure and Test::Unit::Error so that
++ # they can be displayed to the user. To this end, observers
++ # can be added to it, allowing the dynamic updating of, say, a
++ # UI.
++ class TestResult
++ include Util::Observable
++
++ CHANGED = "CHANGED"
++ FAULT = "FAULT"
++
++ attr_reader(:run_count, :assertion_count)
++
++ # Constructs a new, empty TestResult.
++ def initialize
++ @run_count, @assertion_count = 0, 0
++ @failures, @errors = Array.new, Array.new
++ end
++
++ # Records a test run.
++ def add_run
++ @run_count += 1
++ notify_listeners(CHANGED, self)
++ end
++
++ # Records a Test::Unit::Failure.
++ def add_failure(failure)
++ @failures << failure
++ notify_listeners(FAULT, failure)
++ notify_listeners(CHANGED, self)
++ end
++
++ # Records a Test::Unit::Error.
++ def add_error(error)
++ @errors << error
++ notify_listeners(FAULT, error)
++ notify_listeners(CHANGED, self)
++ end
++
++ # Records an individual assertion.
++ def add_assertion
++ @assertion_count += 1
++ notify_listeners(CHANGED, self)
++ end
++
++ # Returns a string contain the recorded runs, assertions,
++ # failures and errors in this TestResult.
++ def to_s
++ "#{run_count} tests, #{assertion_count} assertions, #{failure_count} failures, #{error_count} errors"
++ end
++
++ # Returns whether or not this TestResult represents
++ # successful completion.
++ def passed?
++ return @failures.empty? && @errors.empty?
++ end
++
++ # Returns the number of failures this TestResult has
++ # recorded.
++ def failure_count
++ return @failures.size
++ end
++
++ # Returns the number of errors this TestResult has
++ # recorded.
++ def error_count
++ return @errors.size
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/testsuite.rb b/test/lib/test/unit/testsuite.rb
+new file mode 100644
+index 0000000..6fea976
+--- /dev/null
++++ b/test/lib/test/unit/testsuite.rb
+@@ -0,0 +1,76 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++module Test
++ module Unit
++
++ # A collection of tests which can be #run.
++ #
++ # Note: It is easy to confuse a TestSuite instance with
++ # something that has a static suite method; I know because _I_
++ # have trouble keeping them straight. Think of something that
++ # has a suite method as simply providing a way to get a
++ # meaningful TestSuite instance.
++ class TestSuite
++ attr_reader :name, :tests
++
++ STARTED = name + "::STARTED"
++ FINISHED = name + "::FINISHED"
++
++ # Creates a new TestSuite with the given name.
++ def initialize(name="Unnamed TestSuite")
++ @name = name
++ @tests = []
++ end
++
++ # Runs the tests and/or suites contained in this
++ # TestSuite.
++ def run(result, &progress_block)
++ yield(STARTED, name)
++ @tests.each do |test|
++ test.run(result, &progress_block)
++ end
++ yield(FINISHED, name)
++ end
++
++ # Adds the test to the suite.
++ def <<(test)
++ @tests << test
++ self
++ end
++
++ def delete(test)
++ @tests.delete(test)
++ end
++
++ # Retuns the rolled up number of tests in this suite;
++ # i.e. if the suite contains other suites, it counts the
++ # tests within those suites, not the suites themselves.
++ def size
++ total_size = 0
++ @tests.each { |test| total_size += test.size }
++ total_size
++ end
++
++ def empty?
++ tests.empty?
++ end
++
++ # Overridden to return the name given the suite at
++ # creation.
++ def to_s
++ @name
++ end
++
++ # It's handy to be able to compare TestSuite instances.
++ def ==(other)
++ return false unless(other.kind_of?(self.class))
++ return false unless(@name == other.name)
++ @tests == other.tests
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/ui/console/testrunner.rb b/test/lib/test/unit/ui/console/testrunner.rb
+new file mode 100644
+index 0000000..6b600e3
+--- /dev/null
++++ b/test/lib/test/unit/ui/console/testrunner.rb
+@@ -0,0 +1,127 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit/ui/testrunnermediator'
++require 'test/unit/ui/testrunnerutilities'
++
++module Test
++ module Unit
++ module UI
++ module Console
++
++ # Runs a Test::Unit::TestSuite on the console.
++ class TestRunner
++ extend TestRunnerUtilities
++
++ # Creates a new TestRunner for running the passed
++ # suite. If quiet_mode is true, the output while
++ # running is limited to progress dots, errors and
++ # failures, and the final result. io specifies
++ # where runner output should go to; defaults to
++ # STDOUT.
++ def initialize(suite, output_level=NORMAL, io=STDOUT)
++ if (suite.respond_to?(:suite))
++ @suite = suite.suite
++ else
++ @suite = suite
++ end
++ @output_level = output_level
++ @io = io
++ @already_outputted = false
++ @faults = []
++ end
++
++ # Begins the test run.
++ def start
++ setup_mediator
++ attach_to_mediator
++ return start_mediator
++ end
++
++ private
++ def setup_mediator
++ @mediator = create_mediator(@suite)
++ suite_name = @suite.to_s
++ if ( @suite.kind_of?(Module) )
++ suite_name = @suite.name
++ end
++ output("Loaded suite #{suite_name}")
++ end
++
++ def create_mediator(suite)
++ return TestRunnerMediator.new(suite)
++ end
++
++ def attach_to_mediator
++ @mediator.add_listener(TestResult::FAULT, &method(:add_fault))
++ @mediator.add_listener(TestRunnerMediator::STARTED, &method(:started))
++ @mediator.add_listener(TestRunnerMediator::FINISHED, &method(:finished))
++ @mediator.add_listener(TestCase::STARTED, &method(:test_started))
++ @mediator.add_listener(TestCase::FINISHED, &method(:test_finished))
++ end
++
++ def start_mediator
++ return @mediator.run_suite
++ end
++
++ def add_fault(fault)
++ @faults << fault
++ output_single(fault.single_character_display, PROGRESS_ONLY)
++ @already_outputted = true
++ end
++
++ def started(result)
++ @result = result
++ output("Started")
++ end
++
++ def finished(elapsed_time)
++ nl
++ output("Finished in #{elapsed_time} seconds.")
++ @faults.each_with_index do |fault, index|
++ nl
++ output("%3d) %s" % [index + 1, fault.long_display])
++ end
++ nl
++ output(@result)
++ end
++
++ def test_started(name)
++ output_single(name + ": ", VERBOSE)
++ end
++
++ def test_finished(name)
++ output_single(".", PROGRESS_ONLY) unless (@already_outputted)
++ nl(VERBOSE)
++ @already_outputted = false
++ end
++
++ def nl(level=NORMAL)
++ output("", level)
++ end
++
++ def output(something, level=NORMAL)
++ @io.puts(something) if (output?(level))
++ @io.flush
++ end
++
++ def output_single(something, level=NORMAL)
++ @io.write(something) if (output?(level))
++ @io.flush
++ end
++
++ def output?(level)
++ level <= @output_level
++ end
++ end
++ end
++ end
++ end
++end
++
++if __FILE__ == $0
++ Test::Unit::UI::Console::TestRunner.start_command_line_test
++end
+diff --git a/test/lib/test/unit/ui/testrunnermediator.rb b/test/lib/test/unit/ui/testrunnermediator.rb
+new file mode 100644
+index 0000000..d34510d
+--- /dev/null
++++ b/test/lib/test/unit/ui/testrunnermediator.rb
+@@ -0,0 +1,68 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit'
++require 'test/unit/util/observable'
++require 'test/unit/testresult'
++
++module Test
++ module Unit
++ module UI
++
++ # Provides an interface to write any given UI against,
++ # hopefully making it easy to write new UIs.
++ class TestRunnerMediator
++ RESET = name + "::RESET"
++ STARTED = name + "::STARTED"
++ FINISHED = name + "::FINISHED"
++
++ include Util::Observable
++
++ # Creates a new TestRunnerMediator initialized to run
++ # the passed suite.
++ def initialize(suite)
++ @suite = suite
++ end
++
++ # Runs the suite the TestRunnerMediator was created
++ # with.
++ def run_suite
++ Unit.run = true
++ begin_time = Time.now
++ notify_listeners(RESET, @suite.size)
++ result = create_result
++ notify_listeners(STARTED, result)
++ result_listener = result.add_listener(TestResult::CHANGED) do |updated_result|
++ notify_listeners(TestResult::CHANGED, updated_result)
++ end
++
++ fault_listener = result.add_listener(TestResult::FAULT) do |fault|
++ notify_listeners(TestResult::FAULT, fault)
++ end
++
++ @suite.run(result) do |channel, value|
++ notify_listeners(channel, value)
++ end
++
++ result.remove_listener(TestResult::FAULT, fault_listener)
++ result.remove_listener(TestResult::CHANGED, result_listener)
++ end_time = Time.now
++ elapsed_time = end_time - begin_time
++ notify_listeners(FINISHED, elapsed_time) #"Finished in #{elapsed_time} seconds.")
++ return result
++ end
++
++ private
++ # A factory method to create the result the mediator
++ # should run with. Can be overridden by subclasses if
++ # one wants to use a different result.
++ def create_result
++ return TestResult.new
++ end
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/ui/testrunnerutilities.rb b/test/lib/test/unit/ui/testrunnerutilities.rb
+new file mode 100644
+index 0000000..70b885b
+--- /dev/null
++++ b/test/lib/test/unit/ui/testrunnerutilities.rb
+@@ -0,0 +1,46 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++module Test
++ module Unit
++ module UI
++
++ SILENT = 0
++ PROGRESS_ONLY = 1
++ NORMAL = 2
++ VERBOSE = 3
++
++ # Provides some utilities common to most, if not all,
++ # TestRunners.
++ #
++ #--
++ #
++ # Perhaps there ought to be a TestRunner superclass? There
++ # seems to be a decent amount of shared code between test
++ # runners.
++
++ module TestRunnerUtilities
++
++ # Creates a new TestRunner and runs the suite.
++ def run(suite, output_level=NORMAL)
++ return new(suite, output_level).start
++ end
++
++ # Takes care of the ARGV parsing and suite
++ # determination necessary for running one of the
++ # TestRunners from the command line.
++ def start_command_line_test
++ if ARGV.empty?
++ puts "You should supply the name of a test suite file to the runner"
++ exit
++ end
++ require ARGV[0].gsub(/.+::/, '')
++ new(eval(ARGV[0])).start
++ end
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/util/backtracefilter.rb b/test/lib/test/unit/util/backtracefilter.rb
+new file mode 100644
+index 0000000..7ebec2d
+--- /dev/null
++++ b/test/lib/test/unit/util/backtracefilter.rb
+@@ -0,0 +1,40 @@
++module Test
++ module Unit
++ module Util
++ module BacktraceFilter
++ TESTUNIT_FILE_SEPARATORS = %r{[\\/:]}
++ TESTUNIT_PREFIX = __FILE__.split(TESTUNIT_FILE_SEPARATORS)[0..-3]
++ TESTUNIT_RB_FILE = /\.rb\Z/
++
++ def filter_backtrace(backtrace, prefix=nil)
++ return ["No backtrace"] unless(backtrace)
++ split_p = if(prefix)
++ prefix.split(TESTUNIT_FILE_SEPARATORS)
++ else
++ TESTUNIT_PREFIX
++ end
++ match = proc do |e|
++ split_e = e.split(TESTUNIT_FILE_SEPARATORS)[0, split_p.size]
++ next false unless(split_e[0..-2] == split_p[0..-2])
++ split_e[-1].sub(TESTUNIT_RB_FILE, '') == split_p[-1]
++ end
++ return backtrace unless(backtrace.detect(&match))
++ found_prefix = false
++ new_backtrace = backtrace.reverse.reject do |e|
++ if(match[e])
++ found_prefix = true
++ true
++ elsif(found_prefix)
++ false
++ else
++ true
++ end
++ end.reverse
++ new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace)
++ new_backtrace = new_backtrace.reject(&match)
++ new_backtrace.empty? ? backtrace : new_backtrace
++ end
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/util/observable.rb b/test/lib/test/unit/util/observable.rb
+new file mode 100644
+index 0000000..3567d34
+--- /dev/null
++++ b/test/lib/test/unit/util/observable.rb
+@@ -0,0 +1,90 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++require 'test/unit/util/procwrapper'
++
++module Test
++ module Unit
++ module Util
++
++ # This is a utility class that allows anything mixing
++ # it in to notify a set of listeners about interesting
++ # events.
++ module Observable
++ # We use this for defaults since nil might mean something
++ NOTHING = "NOTHING/#{__id__}"
++
++ # Adds the passed proc as a listener on the
++ # channel indicated by channel_name. listener_key
++ # is used to remove the listener later; if none is
++ # specified, the proc itself is used.
++ #
++ # Whatever is used as the listener_key is
++ # returned, making it very easy to use the proc
++ # itself as the listener_key:
++ #
++ # listener = add_listener("Channel") { ... }
++ # remove_listener("Channel", listener)
++ def add_listener(channel_name, listener_key=NOTHING, &listener) # :yields: value
++ unless(block_given?)
++ raise ArgumentError.new("No callback was passed as a listener")
++ end
++
++ key = listener_key
++ if (listener_key == NOTHING)
++ listener_key = listener
++ key = ProcWrapper.new(listener)
++ end
++
++ channels[channel_name] ||= {}
++ channels[channel_name][key] = listener
++ return listener_key
++ end
++
++ # Removes the listener indicated by listener_key
++ # from the channel indicated by
++ # channel_name. Returns the registered proc, or
++ # nil if none was found.
++ def remove_listener(channel_name, listener_key)
++ channel = channels[channel_name]
++ return nil unless (channel)
++ key = listener_key
++ if (listener_key.instance_of?(Proc))
++ key = ProcWrapper.new(listener_key)
++ end
++ if (channel.has_key?(key))
++ return channel.delete(key)
++ end
++ return nil
++ end
++
++ # Calls all the procs registered on the channel
++ # indicated by channel_name. If value is
++ # specified, it is passed in to the procs,
++ # otherwise they are called with no arguments.
++ #
++ #--
++ #
++ # Perhaps this should be private? Would it ever
++ # make sense for an external class to call this
++ # method directly?
++ def notify_listeners(channel_name, *arguments)
++ channel = channels[channel_name]
++ return 0 unless (channel)
++ listeners = channel.values
++ listeners.each { |listener| listener.call(*arguments) }
++ return listeners.size
++ end
++
++ private
++ def channels
++ @channels ||= {}
++ return @channels
++ end
++ end
++ end
++ end
++end
+diff --git a/test/lib/test/unit/util/procwrapper.rb b/test/lib/test/unit/util/procwrapper.rb
+new file mode 100644
+index 0000000..ad72521
+--- /dev/null
++++ b/test/lib/test/unit/util/procwrapper.rb
+@@ -0,0 +1,48 @@
++#--
++#
++# Author:: Nathaniel Talbott.
++# Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
++# License:: Ruby license.
++
++module Test
++ module Unit
++ module Util
++
++ # Allows the storage of a Proc passed through '&' in a
++ # hash.
++ #
++ # Note: this may be inefficient, since the hash being
++ # used is not necessarily very good. In Observable,
++ # efficiency is not too important, since the hash is
++ # only accessed when adding and removing listeners,
++ # not when notifying.
++
++ class ProcWrapper
++
++ # Creates a new wrapper for a_proc.
++ def initialize(a_proc)
++ @a_proc = a_proc
++ @hash = a_proc.inspect.sub(/^(#<#{a_proc.class}:)/){''}.sub(/(>)$/){''}.hex
++ end
++
++ def hash
++ return @hash
++ end
++
++ def ==(other)
++ case(other)
++ when ProcWrapper
++ return @a_proc == other.to_proc
++ else
++ return super
++ end
++ end
++ alias :eql? :==
++
++ def to_proc
++ return @a_proc
++ end
++ end
++ end
++ end
++end
+diff --git a/test/unit/comment_filter.rb b/test/unit/comment_filter.rb
+new file mode 100644
+index 0000000..e255d07
+--- /dev/null
++++ b/test/unit/comment_filter.rb
+@@ -0,0 +1,53 @@
++require 'test/unit'
++require 'coderay'
++
++class CommentFilterTest < Test::Unit::TestCase
++
++ def test_filtering_comments
++ tokens = CodeRay.scan <<-RUBY, :ruby
++#!/usr/bin/env ruby
++# a minimal Ruby program
++puts "Hello world!"
++ RUBY
++ assert_equal <<-RUBY_FILTERED, tokens.comment_filter.text
++#!/usr/bin/env ruby
++
++puts "Hello world!"
++ RUBY_FILTERED
++ end
++
++ def test_filtering_docstrings
++ tokens = CodeRay.scan <<-PYTHON, :python
++'''
++Assuming this is file mymodule.py then this string, being the
++first statement in the file will become the mymodule modules
++docstring when the file is imported
++'''
++
++class Myclass():
++ """
++ The class's docstring
++ """
++
++ def mymethod(self):
++ '''The method's docstring'''
++
++def myfunction():
++ """The function's docstring"""
++ PYTHON
++ assert_equal <<-PYTHON_FILTERED.chomp, tokens.comment_filter.text
++
++
++class Myclass():
++
++
++ def mymethod(self):
++
++
++def myfunction():
++
++
++PYTHON_FILTERED
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/count.rb b/test/unit/count.rb
+new file mode 100644
+index 0000000..448e8f1
+--- /dev/null
++++ b/test/unit/count.rb
+@@ -0,0 +1,15 @@
++require 'test/unit'
++require 'coderay'
++
++class CountTest < Test::Unit::TestCase
++
++ def test_count
++ tokens = CodeRay.scan <<-RUBY.strip, :ruby
++#!/usr/bin/env ruby
++# a minimal Ruby program
++puts "Hello world!"
++ RUBY
++ assert_equal 11, tokens.encode(:count)
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/debug.rb b/test/unit/debug.rb
+new file mode 100644
+index 0000000..88baf56
+--- /dev/null
++++ b/test/unit/debug.rb
+@@ -0,0 +1,77 @@
++require 'test/unit'
++require 'coderay'
++
++class DebugEncoderTest < Test::Unit::TestCase
++
++ def test_creation
++ debug = nil
++ assert_nothing_raised do
++ debug = CodeRay.encoder :debug
++ end
++ assert CodeRay::Encoders::Debug < CodeRay::Encoders::Encoder
++ assert_kind_of CodeRay::Encoders::Encoder, debug
++ end
++
++ TEST_INPUT = CodeRay::Tokens[
++ ['10', :integer],
++ ['(\\)', :operator],
++ [:begin_group, :string],
++ ['test', :content],
++ [:end_group, :string],
++ [:begin_line, :head],
++ ["\n", :space],
++ ["\n \t", :space],
++ [" \n", :space],
++ ["[]", :method],
++ [:end_line, :head],
++ ].flatten
++ TEST_OUTPUT = <<-'DEBUG'.chomp
++integer(10)operator((\\\))string<content(test)>head[
++
++
++method([])]
++ DEBUG
++
++ def test_filtering_text_tokens
++ assert_equal TEST_OUTPUT, CodeRay::Encoders::Debug.new.encode_tokens(TEST_INPUT)
++ assert_equal TEST_OUTPUT, TEST_INPUT.debug
++ end
++
++end
++
++class DebugScannerTest < Test::Unit::TestCase
++
++ def test_creation
++ assert CodeRay::Scanners::Debug < CodeRay::Scanners::Scanner
++ debug = nil
++ assert_nothing_raised do
++ debug = CodeRay.scanner :debug
++ end
++ assert_kind_of CodeRay::Scanners::Scanner, debug
++ end
++
++ TEST_INPUT = <<-'DEBUG'.chomp
++integer(10)operator((\\\))string<content(test)>test[
++
++
++method([])]
++ DEBUG
++ TEST_OUTPUT = CodeRay::Tokens[
++ ['10', :integer],
++ ['(\\)', :operator],
++ [:begin_group, :string],
++ ['test', :content],
++ [:end_group, :string],
++ [:begin_line, :unknown],
++ ["\n\n \t \n", :space],
++ ["[]", :method],
++ [:end_line, :unknown],
++ ].flatten
++
++ def test_filtering_text_tokens
++ assert_equal TEST_OUTPUT, CodeRay::Scanners::Debug.new.tokenize(TEST_INPUT)
++ assert_kind_of CodeRay::TokensProxy, CodeRay.scan(TEST_INPUT, :debug)
++ assert_equal TEST_OUTPUT, CodeRay.scan(TEST_INPUT, :debug).tokens
++ end
++
++end
+diff --git a/test/unit/duo.rb b/test/unit/duo.rb
+new file mode 100644
+index 0000000..05c26a5
+--- /dev/null
++++ b/test/unit/duo.rb
+@@ -0,0 +1,35 @@
++require 'test/unit'
++require 'yaml'
++require 'coderay'
++
++class DuoTest < Test::Unit::TestCase
++
++ def test_two_arguments
++ duo = CodeRay::Duo[:ruby, :html]
++ assert_kind_of CodeRay::Scanners[:ruby], duo.scanner
++ assert_kind_of CodeRay::Encoders[:html], duo.encoder
++ end
++
++ def test_two_hash
++ duo = CodeRay::Duo[:ruby => :html]
++ assert_kind_of CodeRay::Scanners[:ruby], duo.scanner
++ assert_kind_of CodeRay::Encoders[:html], duo.encoder
++ end
++
++ def test_call
++ duo = CodeRay::Duo[:python => :yml]
++ yaml = [["def", :keyword],
++ [" ", :space],
++ ["test", :method],
++ [":", :operator],
++ [" ", :space],
++ [:begin_group, :string],
++ ["\"", :delimiter],
++ ["pass", :content],
++ ["\"", :delimiter],
++ [:end_group, :string]]
++
++ assert_equal yaml, YAML.load(duo.call('def test: "pass"'))
++ end
++
++end
+diff --git a/test/unit/file_type.rb b/test/unit/file_type.rb
+new file mode 100644
+index 0000000..263517b
+--- /dev/null
++++ b/test/unit/file_type.rb
+@@ -0,0 +1,116 @@
++require 'test/unit'
++require File.expand_path('../../lib/assert_warning', __FILE__)
++
++require 'coderay/helpers/file_type'
++
++class FileTypeTests < Test::Unit::TestCase
++
++ include CodeRay
++
++ def test_fetch
++ assert_raise FileType::UnknownFileType do
++ FileType.fetch ''
++ end
++
++ assert_throws :not_found do
++ FileType.fetch '.' do
++ throw :not_found
++ end
++ end
++
++ assert_equal :default, FileType.fetch('c', :default)
++ end
++
++ def test_block_supersedes_default_warning
++ assert_warning 'Block supersedes default value argument; use either.' do
++ FileType.fetch('c', :default) { }
++ end
++ end
++
++ def test_ruby
++ assert_equal :ruby, FileType[__FILE__]
++ assert_equal :ruby, FileType['test.rb']
++ assert_equal :ruby, FileType['test.java.rb']
++ assert_equal :java, FileType['test.rb.java']
++ assert_equal :ruby, FileType['C:\\Program Files\\x\\y\\c\\test.rbw']
++ assert_equal :ruby, FileType['/usr/bin/something/Rakefile']
++ assert_equal :ruby, FileType['~/myapp/gem/Rantfile']
++ assert_equal :ruby, FileType['./lib/tasks\repository.rake']
++ assert_not_equal :ruby, FileType['test_rb']
++ assert_not_equal :ruby, FileType['Makefile']
++ assert_not_equal :ruby, FileType['set.rb/set']
++ assert_not_equal :ruby, FileType['~/projects/blabla/rb']
++ end
++
++ def test_c
++ assert_equal :c, FileType['test.c']
++ assert_equal :c, FileType['C:\\Program Files\\x\\y\\c\\test.h']
++ assert_not_equal :c, FileType['test_c']
++ assert_not_equal :c, FileType['Makefile']
++ assert_not_equal :c, FileType['set.h/set']
++ assert_not_equal :c, FileType['~/projects/blabla/c']
++ end
++
++ def test_cpp
++ assert_equal :cpp, FileType['test.c++']
++ assert_equal :cpp, FileType['test.cxx']
++ assert_equal :cpp, FileType['test.hh']
++ assert_equal :cpp, FileType['test.hpp']
++ assert_equal :cpp, FileType['test.cu']
++ assert_equal :cpp, FileType['test.C']
++ assert_not_equal :cpp, FileType['test.c']
++ assert_not_equal :cpp, FileType['test.h']
++ end
++
++ def test_html
++ assert_equal :html, FileType['test.htm']
++ assert_equal :html, FileType['test.xhtml']
++ assert_equal :html, FileType['test.html.xhtml']
++ assert_equal :erb, FileType['_form.rhtml']
++ assert_equal :erb, FileType['_form.html.erb']
++ end
++
++ def test_yaml
++ assert_equal :yaml, FileType['test.yml']
++ assert_equal :yaml, FileType['test.yaml']
++ assert_equal :yaml, FileType['my.html.yaml']
++ assert_not_equal :yaml, FileType['YAML']
++ end
++
++ def test_pathname
++ require 'pathname'
++ pn = Pathname.new 'test.rb'
++ assert_equal :ruby, FileType[pn]
++ dir = Pathname.new '/etc/var/blubb'
++ assert_equal :ruby, FileType[dir + pn]
++ assert_equal :cpp, FileType[dir + 'test.cpp']
++ end
++
++ def test_no_shebang
++ dir = './test'
++ if File.directory? dir
++ Dir.chdir dir do
++ assert_equal :c, FileType['test.c']
++ end
++ end
++ end
++
++ def test_shebang_empty_file
++ require 'tmpdir'
++ tmpfile = File.join(Dir.tmpdir, 'bla')
++ File.open(tmpfile, 'w') { } # touch
++ assert_equal nil, FileType[tmpfile, true]
++ end
++
++ def test_shebang_no_file
++ assert_equal nil, FileType['i do not exist', true]
++ end
++
++ def test_shebang
++ require 'tmpdir'
++ tmpfile = File.join(Dir.tmpdir, 'bla')
++ File.open(tmpfile, 'w') { |f| f.puts '#!/usr/bin/env ruby' }
++ assert_equal :ruby, FileType[tmpfile, true]
++ end
++
++end
+diff --git a/test/unit/filter.rb b/test/unit/filter.rb
+new file mode 100644
+index 0000000..25dff77
+--- /dev/null
++++ b/test/unit/filter.rb
+@@ -0,0 +1,38 @@
++require 'test/unit'
++require 'coderay'
++
++class FilterTest < Test::Unit::TestCase
++
++ def test_creation
++ filter = nil
++ assert_nothing_raised do
++ filter = CodeRay.encoder :filter
++ end
++ assert CodeRay::Encoders::Filter < CodeRay::Encoders::Encoder
++ assert_kind_of CodeRay::Encoders::Encoder, filter
++ end
++
++ def test_filtering_text_tokens
++ tokens = CodeRay::Tokens.new
++ 10.times do |i|
++ tokens.text_token i.to_s, :index
++ end
++ assert_equal tokens, CodeRay::Encoders::Filter.new.encode_tokens(tokens)
++ assert_equal tokens, tokens.filter
++ end
++
++ def test_filtering_block_tokens
++ tokens = CodeRay::Tokens.new
++ 10.times do |i|
++ tokens.begin_group :index
++ tokens.text_token i.to_s, :content
++ tokens.end_group :index
++ tokens.begin_line :index
++ tokens.text_token i.to_s, :content
++ tokens.end_line :index
++ end
++ assert_equal tokens, CodeRay::Encoders::Filter.new.encode_tokens(tokens)
++ assert_equal tokens, tokens.filter
++ end
++
++end
+diff --git a/test/unit/html.rb b/test/unit/html.rb
+new file mode 100644
+index 0000000..0072635
+--- /dev/null
++++ b/test/unit/html.rb
+@@ -0,0 +1,103 @@
++require 'test/unit'
++require 'coderay'
++
++class HtmlTest < Test::Unit::TestCase
++
++ def test_break_lines_option
++ snippets = {}
++
++ snippets[:ruby] = {}
++
++ snippets[:ruby][:in] = <<-RUBY
++ruby_inside = <<-RUBY_INSIDE
++This is tricky,
++isn't it?
++RUBY_INSIDE
++ RUBY
++
++ snippets[:ruby][:expected_with_option_off] = <<-HTML_OPT_INDEPENDENT_LINES_OFF
++ruby_inside = <span class=\"string\"><span class=\"delimiter\"><<-RUBY_INSIDE</span></span><span class=\"string\"><span class=\"content\">
++This is tricky,
++isn't it?</span><span class=\"delimiter\">
++RUBY_INSIDE</span></span>
++ HTML_OPT_INDEPENDENT_LINES_OFF
++
++ snippets[:ruby][:expected_with_option_on] = <<-HTML_OPT_INDEPENDENT_LINES_ON
++ruby_inside = <span class=\"string\"><span class=\"delimiter\"><<-RUBY_INSIDE</span></span><span class=\"string\"><span class=\"content\"></span></span>
++<span class=\"string\"><span class=\"content\">This is tricky,</span></span>
++<span class=\"string\"><span class=\"content\">isn't it?</span><span class=\"delimiter\"></span></span>
++<span class=\"string\"><span class=\"delimiter\">RUBY_INSIDE</span></span>
++ HTML_OPT_INDEPENDENT_LINES_ON
++
++ snippets[:java] = {}
++
++ snippets[:java][:in] = <<-JAVA
++import java.lang.*;
++
++/**
++ * This is some multiline javadoc
++ * used to test the
++ */
++public class Test {
++ public static final String MESSAGE = "My message\
++ To the world";
++
++ static void main() {
++ /*
++ * Another multiline
++ * comment
++ */
++ System.out.println(MESSAGE);
++ }
++}
++ JAVA
++
++ snippets[:java][:expected_with_option_off] = <<-HTML_OPT_INDEPENDENT_LINES_OFF
++<span class=\"keyword\">import</span> <span class=\"include\">java.lang</span>.*;
++
++<span class=\"comment\">/**
++ * This is some multiline javadoc
++ * used to test the
++ */</span>
++<span class=\"directive\">public</span> <span class=\"type\">class</span> <span class=\"class\">Test</span> {
++ <span class=\"directive\">public</span> <span class=\"directive\">static</span> <span class=\"directive\">final</span> <span class=\"predefined-type\">String</span> MESSAGE = <span class=\"string\"><span class=\"delimiter\">"</span><span class=\"content\">My message To the world</span><span class=\"delimiter\">"</span></span>;
++
++ <span class=\"directive\">static</span> <span class=\"type\">void</span> main() {
++ <span class=\"comment\">/*
++ * Another multiline
++ * comment
++ */</span>
++ <span class=\"predefined-type\">System</span>.out.println(MESSAGE);
++ }
++}
++ HTML_OPT_INDEPENDENT_LINES_OFF
++
++ snippets[:java][:expected_with_option_on] = <<-HTML_OPT_INDEPENDENT_LINES_ON
++<span class=\"keyword\">import</span> <span class=\"include\">java.lang</span>.*;
++
++<span class=\"comment\">/**</span>
++<span class=\"comment\"> * This is some multiline javadoc</span>
++<span class=\"comment\"> * used to test the</span>
++<span class=\"comment\"> */</span>
++<span class=\"directive\">public</span> <span class=\"type\">class</span> <span class=\"class\">Test</span> {
++ <span class=\"directive\">public</span> <span class=\"directive\">static</span> <span class=\"directive\">final</span> <span class=\"predefined-type\">String</span> MESSAGE = <span class=\"string\"><span class=\"delimiter\">"</span><span class=\"content\">My message To the world</span><span class=\"delimiter\">"</span></span>;
++
++ <span class=\"directive\">static</span> <span class=\"type\">void</span> main() {
++ <span class=\"comment\">/*</span>
++<span class=\"comment\"> * Another multiline</span>
++<span class=\"comment\"> * comment</span>
++<span class=\"comment\"> */</span>
++ <span class=\"predefined-type\">System</span>.out.println(MESSAGE);
++ }
++}
++ HTML_OPT_INDEPENDENT_LINES_ON
++
++ for lang, code in snippets
++ tokens = CodeRay.scan code[:in], lang
++
++ assert_equal code[:expected_with_option_off], tokens.html
++ assert_equal code[:expected_with_option_off], tokens.html(:break_lines => false)
++ assert_equal code[:expected_with_option_on], tokens.html(:break_lines => true)
++ end
++ end
++end
+diff --git a/test/unit/json_encoder.rb b/test/unit/json_encoder.rb
+new file mode 100644
+index 0000000..4e44a64
+--- /dev/null
++++ b/test/unit/json_encoder.rb
+@@ -0,0 +1,28 @@
++require 'test/unit'
++require 'coderay'
++
++class JSONEncoderTest < Test::Unit::TestCase
++
++ def test_json_output
++ old_load_paths = $:.dup
++ begin
++ $:.delete '.'
++ $:.delete File.dirname(__FILE__)
++ json = CodeRay.scan('puts "Hello world!"', :ruby).json
++ assert_equal [
++ {"type"=>"text", "text"=>"puts", "kind"=>"ident"},
++ {"type"=>"text", "text"=>" ", "kind"=>"space"},
++ {"type"=>"block", "action"=>"open", "kind"=>"string"},
++ {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"},
++ {"type"=>"text", "text"=>"Hello world!", "kind"=>"content"},
++ {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"},
++ {"type"=>"block", "action"=>"close", "kind"=>"string"},
++ ], JSON.load(json)
++ ensure
++ for path in old_load_paths - $:
++ $: << path
++ end
++ end
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/lines_of_code.rb b/test/unit/lines_of_code.rb
+new file mode 100644
+index 0000000..e2c0caf
+--- /dev/null
++++ b/test/unit/lines_of_code.rb
+@@ -0,0 +1,52 @@
++require 'test/unit'
++require 'coderay'
++$VERBOSE = true
++
++require File.expand_path('../../lib/assert_warning', __FILE__)
++
++class LinesOfCodeTest < Test::Unit::TestCase
++
++ def test_creation
++ assert CodeRay::Encoders::LinesOfCode < CodeRay::Encoders::Encoder
++ filter = nil
++ assert_nothing_raised do
++ filter = CodeRay.encoder :loc
++ end
++ assert_kind_of CodeRay::Encoders::LinesOfCode, filter
++ assert_nothing_raised do
++ filter = CodeRay.encoder :lines_of_code
++ end
++ assert_kind_of CodeRay::Encoders::LinesOfCode, filter
++ end
++
++ def test_lines_of_code
++ tokens = CodeRay.scan <<-RUBY, :ruby
++#!/usr/bin/env ruby
++
++# a minimal Ruby program
++puts "Hello world!"
++ RUBY
++ assert_equal 1, CodeRay::Encoders::LinesOfCode.new.encode_tokens(tokens)
++ assert_equal 1, tokens.lines_of_code
++ assert_equal 1, tokens.loc
++ end
++
++ class ScannerMockup
++ KINDS_NOT_LOC = [:space]
++ end
++
++ def test_filtering_block_tokens
++ tokens = CodeRay::Tokens.new
++ tokens.concat ["Hello\n", :world]
++ tokens.concat ["\n", :space]
++ tokens.concat ["Hello\n", :comment]
++
++ assert_warning 'Tokens have no associated scanner, counting all nonempty lines.' do
++ assert_equal 1, tokens.lines_of_code
++ end
++
++ tokens.scanner = ScannerMockup.new
++ assert_equal 2, tokens.lines_of_code
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/null.rb b/test/unit/null.rb
+new file mode 100644
+index 0000000..d3a9b0d
+--- /dev/null
++++ b/test/unit/null.rb
+@@ -0,0 +1,14 @@
++require 'test/unit'
++require 'coderay'
++
++class NullTest < Test::Unit::TestCase
++
++ def test_null
++ ruby = <<-RUBY
++puts "Hello world!"
++ RUBY
++ tokens = CodeRay.scan ruby, :ruby
++ assert_equal '', tokens.encode(:null)
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/plugin.rb b/test/unit/plugin.rb
+new file mode 100755
+index 0000000..41eec51
+--- /dev/null
++++ b/test/unit/plugin.rb
+@@ -0,0 +1,69 @@
++require 'test/unit'
++require 'pathname'
++
++$:.unshift File.expand_path('../../../lib', __FILE__)
++require 'coderay'
++
++class PluginScannerTest < Test::Unit::TestCase
++
++ module Plugins
++ extend CodeRay::PluginHost
++ plugin_path File.dirname(__FILE__), 'plugins'
++ class Plugin
++ extend CodeRay::Plugin
++ plugin_host Plugins
++ end
++ end
++
++ module PluginsWithDefault
++ extend CodeRay::PluginHost
++ plugin_path File.dirname(__FILE__), 'plugins_with_default'
++ class Plugin
++ extend CodeRay::Plugin
++ plugin_host PluginsWithDefault
++ end
++ default :default_plugin
++ end
++
++ def test_load
++ require Pathname.new(__FILE__).realpath.dirname + 'plugins' + 'user_defined' + 'user_plugin'
++ assert_equal 'UserPlugin', Plugins.load(:user_plugin).name
++ end
++
++ def test_load_all
++ assert_instance_of Symbol, Plugins.load_all.first
++ assert_operator Plugins.all_plugins.first, :<, Plugins::Plugin
++ assert_equal 'The Example', Plugins.all_plugins.map { |plugin| plugin.title }.sort.first
++ end
++
++ def test_default
++ assert_nothing_raised do
++ assert_operator PluginsWithDefault[:gargamel], :<, PluginsWithDefault::Plugin
++ end
++ assert_equal PluginsWithDefault::Default, PluginsWithDefault.default
++ end
++
++ def test_plugin_not_found
++ assert_raise CodeRay::PluginHost::PluginNotFound do
++ Plugins[:thestral]
++ end
++ assert_raise ArgumentError do
++ Plugins[14]
++ end
++ assert_raise ArgumentError do
++ Plugins['test/test']
++ end
++ assert_raise CodeRay::PluginHost::PluginNotFound do
++ PluginsWithDefault[:example_without_register_for]
++ end
++ end
++
++ def test_autoload_constants
++ assert_operator Plugins::Example, :<, Plugins::Plugin
++ end
++
++ def test_title
++ assert_equal 'The Example', Plugins::Example.title
++ end
++
++end
+diff --git a/test/unit/plugins/example.rb b/test/unit/plugins/example.rb
+new file mode 100644
+index 0000000..af1aeba
+--- /dev/null
++++ b/test/unit/plugins/example.rb
+@@ -0,0 +1,6 @@
++class Example < PluginScannerTest::Plugins::Plugin
++
++ register_for :example
++ title 'The Example'
++
++end
+diff --git a/test/unit/plugins/user_defined/user_plugin.rb b/test/unit/plugins/user_defined/user_plugin.rb
+new file mode 100644
+index 0000000..f47c934
+--- /dev/null
++++ b/test/unit/plugins/user_defined/user_plugin.rb
+@@ -0,0 +1,5 @@
++class UserPlugin < PluginScannerTest::Plugins::Plugin
++
++ register_for :user_plugin
++
++end
+diff --git a/test/unit/plugins_with_default/default_plugin.rb b/test/unit/plugins_with_default/default_plugin.rb
+new file mode 100644
+index 0000000..ae9e4c5
+--- /dev/null
++++ b/test/unit/plugins_with_default/default_plugin.rb
+@@ -0,0 +1,5 @@
++class DefaultPlugin < PluginScannerTest::PluginsWithDefault::Plugin
++
++ register_for :default_plugin
++
++end
+diff --git a/test/unit/plugins_with_default/example_without_register_for.rb b/test/unit/plugins_with_default/example_without_register_for.rb
+new file mode 100644
+index 0000000..083baf6
+--- /dev/null
++++ b/test/unit/plugins_with_default/example_without_register_for.rb
+@@ -0,0 +1,5 @@
++class ExampleWithoutRegisterFor < PluginScannerTest::PluginsWithDefault::Plugin
++
++ register_for :wrong_id
++
++end
+diff --git a/test/unit/statistic.rb b/test/unit/statistic.rb
+new file mode 100644
+index 0000000..1326dca
+--- /dev/null
++++ b/test/unit/statistic.rb
+@@ -0,0 +1,59 @@
++require 'test/unit'
++require 'coderay'
++
++class StatisticEncoderTest < Test::Unit::TestCase
++
++ def test_creation
++ assert CodeRay::Encoders::Statistic < CodeRay::Encoders::Encoder
++ stats = nil
++ assert_nothing_raised do
++ stats = CodeRay.encoder :statistic
++ end
++ assert_kind_of CodeRay::Encoders::Encoder, stats
++ end
++
++ TEST_INPUT = CodeRay::Tokens[
++ ['10', :integer],
++ ['(\\)', :operator],
++ [:begin_group, :string],
++ ['test', :content],
++ [:end_group, :string],
++ [:begin_line, :test],
++ ["\n", :space],
++ ["\n \t", :space],
++ [" \n", :space],
++ ["[]", :method],
++ [:end_line, :test],
++ ].flatten
++ TEST_OUTPUT = <<-'DEBUG'
++
++Code Statistics
++
++Tokens 11
++ Non-Whitespace 4
++Bytes Total 20
++
++Token Types (7):
++ type count ratio size (average)
++-------------------------------------------------------------
++ TOTAL 11 100.00 % 1.8
++ space 3 27.27 % 3.0
++ string 2 18.18 % 0.0
++ test 2 18.18 % 0.0
++ :begin_group 1 9.09 % 0.0
++ :begin_line 1 9.09 % 0.0
++ :end_group 1 9.09 % 0.0
++ :end_line 1 9.09 % 0.0
++ content 1 9.09 % 4.0
++ integer 1 9.09 % 2.0
++ method 1 9.09 % 2.0
++ operator 1 9.09 % 3.0
++
++ DEBUG
++
++ def test_filtering_text_tokens
++ assert_equal TEST_OUTPUT, CodeRay::Encoders::Statistic.new.encode_tokens(TEST_INPUT)
++ assert_equal TEST_OUTPUT, TEST_INPUT.statistic
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/suite.rb b/test/unit/suite.rb
+new file mode 100755
+index 0000000..417dfed
+--- /dev/null
++++ b/test/unit/suite.rb
+@@ -0,0 +1,16 @@
++require 'test/unit'
++require 'rubygems'
++
++$VERBOSE = $CODERAY_DEBUG = true
++$:.unshift 'lib'
++
++mydir = File.dirname(__FILE__)
++suite = Dir[File.join(mydir, '*.rb')].
++ map { |tc| File.basename(tc).sub(/\.rb$/, '') } - %w'suite vhdl'
++
++puts "Running CodeRay unit tests: #{suite.join(', ')}"
++
++helpers = %w(file_type word_list tokens)
++for test_case in helpers + (suite - helpers)
++ load File.join(mydir, test_case + '.rb')
++end
+diff --git a/test/unit/text.rb b/test/unit/text.rb
+new file mode 100644
+index 0000000..db086f5
+--- /dev/null
++++ b/test/unit/text.rb
+@@ -0,0 +1,14 @@
++require 'test/unit'
++require 'coderay'
++
++class TextTest < Test::Unit::TestCase
++
++ def test_count
++ ruby = <<-RUBY
++puts "Hello world!"
++ RUBY
++ tokens = CodeRay.scan ruby, :ruby
++ assert_equal ruby, tokens.encode(:text)
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/token_kind_filter.rb b/test/unit/token_kind_filter.rb
+new file mode 100644
+index 0000000..13bae52
+--- /dev/null
++++ b/test/unit/token_kind_filter.rb
+@@ -0,0 +1,50 @@
++require 'test/unit'
++require 'coderay'
++
++class TokenKindFilterTest < Test::Unit::TestCase
++
++ def test_creation
++ assert CodeRay::Encoders::TokenKindFilter < CodeRay::Encoders::Encoder
++ assert CodeRay::Encoders::TokenKindFilter < CodeRay::Encoders::Filter
++ filter = nil
++ assert_nothing_raised do
++ filter = CodeRay.encoder :token_kind_filter
++ end
++ assert_instance_of CodeRay::Encoders::TokenKindFilter, filter
++ end
++
++ def test_filtering_text_tokens
++ tokens = CodeRay::Tokens.new
++ for i in 1..10
++ tokens.text_token i.to_s, :index
++ tokens.text_token ' ', :space if i < 10
++ end
++ assert_equal 10, CodeRay::Encoders::TokenKindFilter.new.encode_tokens(tokens, :exclude => :space).count
++ assert_equal 10, tokens.token_kind_filter(:exclude => :space).count
++ assert_equal 9, CodeRay::Encoders::TokenKindFilter.new.encode_tokens(tokens, :include => :space).count
++ assert_equal 9, tokens.token_kind_filter(:include => :space).count
++ assert_equal 0, CodeRay::Encoders::TokenKindFilter.new.encode_tokens(tokens, :exclude => :all).count
++ assert_equal 0, tokens.token_kind_filter(:exclude => :all).count
++ end
++
++ def test_filtering_block_tokens
++ tokens = CodeRay::Tokens.new
++ 10.times do |i|
++ tokens.begin_group :index
++ tokens.text_token i.to_s, :content
++ tokens.end_group :index
++ tokens.begin_group :naught if i == 5
++ tokens.end_group :naught if i == 7
++ tokens.begin_line :blubb
++ tokens.text_token i.to_s, :content
++ tokens.end_line :blubb
++ end
++ assert_equal 16, CodeRay::Encoders::TokenKindFilter.new.encode_tokens(tokens, :include => :blubb).count
++ assert_equal 16, tokens.token_kind_filter(:include => :blubb).count
++ assert_equal 24, CodeRay::Encoders::TokenKindFilter.new.encode_tokens(tokens, :include => [:blubb, :content]).count
++ assert_equal 24, tokens.token_kind_filter(:include => [:blubb, :content]).count
++ assert_equal 32, CodeRay::Encoders::TokenKindFilter.new.encode_tokens(tokens, :exclude => :index).count
++ assert_equal 32, tokens.token_kind_filter(:exclude => :index).count
++ end
++
++end
+diff --git a/test/unit/tokens.rb b/test/unit/tokens.rb
+new file mode 100644
+index 0000000..73b0fd5
+--- /dev/null
++++ b/test/unit/tokens.rb
+@@ -0,0 +1,77 @@
++require 'test/unit'
++require 'coderay'
++
++class TokensTest < Test::Unit::TestCase
++
++ def test_creation
++ assert CodeRay::Tokens < Array
++ tokens = nil
++ assert_nothing_raised do
++ tokens = CodeRay::Tokens.new
++ end
++ assert_kind_of Array, tokens
++ end
++
++ def test_adding_tokens
++ tokens = make_tokens
++ assert_equal tokens.size, 8
++ assert_equal tokens.count, 4
++ end
++
++ def test_to_s
++ assert_equal 'string()', make_tokens.to_s
++ end
++
++ def test_encode_with_nonsense
++ assert_raise NoMethodError do
++ make_tokens.nonsense
++ end
++ end
++
++ def test_split_into_parts
++ parts_4_3 = [
++ ["stri", :type],
++ ["ng", :type, :begin_group, :operator, "(", :content, :end_group, :operator],
++ [:begin_group, :operator, ")", :content, :end_group, :operator]
++ ]
++ assert_equal parts_4_3, make_tokens.split_into_parts(4, 3)
++ assert_equal [make_tokens.to_a], make_tokens.split_into_parts
++
++ parts_7_0_1 = [
++ ["string", :type, :begin_group, :operator, "(", :content, :end_group, :operator],
++ [],
++ [:begin_group, :operator, ")", :content, :end_group, :operator]
++ ]
++ assert_equal parts_7_0_1, make_tokens.split_into_parts(7, 0, 1)
++
++ line = CodeRay::Tokens[:begin_line, :head, '...', :plain]
++ line_parts = [
++ [:begin_line, :head, ".", :plain, :end_line, :head],
++ [:begin_line, :head, "..", :plain]
++ ]
++ assert_equal line_parts, line.split_into_parts(1)
++
++ assert_raise ArgumentError do
++ CodeRay::Tokens[:bullshit, :input].split_into_parts
++ end
++ assert_raise ArgumentError do
++ CodeRay::Tokens[42, 43].split_into_parts
++ end
++ end
++
++ def test_encode
++ assert_match(/\A\[\{(?:"type":"text"|"text":"string"|"kind":"type"|,){5}\},/, make_tokens.encode(:json))
++ end
++
++ def make_tokens
++ tokens = CodeRay::Tokens.new
++ assert_nothing_raised do
++ tokens.text_token 'string', :type
++ tokens.begin_group :operator
++ tokens.text_token '()', :content
++ tokens.end_group :operator
++ end
++ tokens
++ end
++
++end
+\ No newline at end of file
+diff --git a/test/unit/word_list.rb b/test/unit/word_list.rb
+new file mode 100644
+index 0000000..40d5a26
+--- /dev/null
++++ b/test/unit/word_list.rb
+@@ -0,0 +1,64 @@
++require 'test/unit'
++require 'coderay/helpers/word_list'
++
++class WordListTest < Test::Unit::TestCase
++
++ include CodeRay
++
++ # define word arrays
++ RESERVED_WORDS = %w[
++ asm break case continue default do else
++ ...
++ ]
++
++ PREDEFINED_TYPES = %w[
++ int long short char void
++ ...
++ ]
++
++ PREDEFINED_CONSTANTS = %w[
++ EOF NULL ...
++ ]
++
++ # make a WordList
++ IDENT_KIND = WordList.new(:ident).
++ add(RESERVED_WORDS, :reserved).
++ add(PREDEFINED_TYPES, :predefined_type).
++ add(PREDEFINED_CONSTANTS, :predefined_constant)
++
++ def test_word_list_example
++ assert_equal :predefined_type, IDENT_KIND['void']
++ # assert_equal :predefined_constant, IDENT_KIND['...'] # not specified
++ end
++
++ def test_word_list
++ list = WordList.new(:ident).add(['foobar'], :reserved)
++ assert_equal :reserved, list['foobar']
++ assert_equal :ident, list['FooBar']
++ assert_equal 1, list.size
++ end
++
++ def test_case_ignoring_word_list
++ list = WordList::CaseIgnoring.new(:ident).add(['foobar'], :reserved)
++ assert_equal :ident, list['foo']
++ assert_equal :reserved, list['foobar']
++ assert_equal :reserved, list['FooBar']
++ assert_equal 1, list.size
++
++ list = WordList::CaseIgnoring.new(:ident).add(['FooBar'], :reserved)
++ assert_equal :ident, list['foo']
++ assert_equal :reserved, list['foobar']
++ assert_equal :reserved, list['FooBar']
++ assert_equal 1, list.size
++ end
++
++ def test_dup
++ list = WordList.new(:ident).add(['foobar'], :reserved)
++ assert_equal :reserved, list['foobar']
++ list2 = list.dup
++ list2.add(%w[foobar], :keyword)
++ assert_equal :keyword, list2['foobar']
++ assert_equal :reserved, list['foobar']
++ end
++
++end
diff --git a/debian/patches/series b/debian/patches/series
index 7d4702b..191475a 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
+0000-restore_tests_and_rake_tasks_v1.1.2.patch
0001-Remove-rubygems-depends.patch
0002-Add-lack-file-for-UnitTest.patch
0003-Add-Encoding.default_external.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/coderay.git
More information about the Pkg-ruby-extras-commits
mailing list