null+****@clear*****
null+****@clear*****
2012年 3月 6日 (火) 16:10:00 JST
Kouhei Sutou 2012-03-06 16:10:00 +0900 (Tue, 06 Mar 2012)
New Revision: e087ca7e87174d441b4d54b659a2232d0982cfee
Log:
Move to lib/groonga/tester.rb
Copied files:
lib/groonga/tester.rb
(from bin/groonga-test)
Modified files:
bin/groonga-test
Modified: bin/groonga-test (+1 -565)
===================================================================
--- bin/groonga-test 2012-03-06 16:06:25 +0900 (044c447)
+++ bin/groonga-test 2012-03-06 16:10:00 +0900 (afc2bf6)
@@ -15,570 +15,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-require "English"
-require "optparse"
-require "pathname"
-require "fileutils"
-require "tempfile"
-require "json"
-require "shellwords"
-
-class GroongaTester
- VERSION = "1.0.0"
-
- class << self
- def run(argv=nil)
- argv ||= ARGV.dup
- tester = new
- catch do |tag|
- parser = create_option_parser(tester, tag)
- targets = parser.parse!(argv)
- tester.run(*targets)
- end
- end
-
- private
- def create_option_parser(tester, tag)
- parser = OptionParser.new
- parser.banner += " TEST_FILE_OR_DIRECTORY..."
-
- parser.on("--groonga=COMMAND",
- "Use COMMAND as groonga command",
- "(#{tester.groonga})") do |command|
- tester.groonga = command
- end
-
- parser.on("--groonga-suggest-create-dataset=COMMAND",
- "Use COMMAND as groonga_suggest_create_dataset command",
- "(#{tester.groonga_suggest_create_dataset})") do |command|
- tester.groonga_suggest_create_dataset = command
- end
-
- parser.on("--base-directory=DIRECTORY",
- "Use DIRECTORY as a base directory of relative path",
- "(#{tester.base_directory})") do |directory|
- tester.base_directory = directory
- end
-
- parser.on("--diff=DIFF",
- "Use DIFF as diff command",
- "(#{tester.diff})") do |diff|
- tester.diff = diff
- tester.diff_options.clear
- end
-
- diff_option_is_specified = false
- parser.on("--diff-option=OPTION",
- "Use OPTION as diff command",
- "(#{tester.diff_options.join(' ')})") do |option|
- tester.diff_options.clear if diff_option_is_specified
- tester.diff_options << option
- diff_option_is_specified = true
- end
-
- parser.on("--version",
- "Show version and exit") do
- puts(GroongaTester::VERSION)
- throw(tag, true)
- end
-
- parser
- end
- end
-
- attr_accessor :groonga, :groonga_suggest_create_dataset
- attr_accessor :base_directory, :diff, :diff_options
- def initialize
- @groonga = "groonga"
- @groonga_suggest_create_dataset = "groonga-suggest-create-dataset"
- @base_directory = "."
- detect_suitable_diff
- end
-
- def run(*targets)
- succeeded = true
- return succeeded if targets.empty?
-
- reporter = Reporter.new(self)
- reporter.start
- targets.each do |target|
- target_path = Pathname(target)
- next unless target_path.exist?
- if target_path.directory?
- Dir.glob(target_path + "**" + "*.test") do |target_file|
- succeeded = false unless run_test(Pathname(target_file), reporter)
- end
- else
- succeeded = false unless run_test(target_path, reporter)
- end
- end
- reporter.finish
- succeeded
- end
-
- private
- def run_test(test_script_path, reporter)
- runner = Runner.new(self, test_script_path)
- runner.run(reporter)
- end
-
- def detect_suitable_diff
- if command_exist?("cut-diff")
- @diff = "cut-diff"
- @diff_options = ["--context-lines", "10"]
- else
- @diff = "diff"
- @diff_options = ["-u"]
- end
- end
-
- def command_exist?(name)
- ENV["PATH"].split(File::PATH_SEPARATOR).each do |path|
- absolute_path = File.join(path, name)
- return true if File.executable?(absolute_path)
- end
- false
- end
-
- class Runner
- MAX_N_COLUMNS = 79
-
- def initialize(tester, test_script_path)
- @tester = tester
- @test_script_path = test_script_path
- @max_n_columns = MAX_N_COLUMNS
- end
-
- def run(reporter)
- succeeded = true
-
- reporter.start_test(@test_script_path)
- actual_result = run_groonga_script
- actual_result = normalize_result(actual_result)
- expected_result = read_expected_result
- if expected_result
- if actual_result == expected_result
- reporter.pass_test
- remove_reject_file
- else
- reporter.fail_test(expected_result, actual_result)
- output_reject_file(actual_result)
- succeeded = false
- end
- else
- reporter.no_check_test(actual_result)
- output_actual_file(actual_result)
- end
- reporter.finish_test
-
- succeeded
- end
-
- private
- def run_groonga_script
- create_temporary_directory do |directory_path|
- run_groonga(File.join(directory_path, "db")) do |io|
- context = Executer::Context.new
- context.base_directory =****@teste*****_directory
- executer = Executer.new(io, context)
- executer.execute(@test_script_path)
- end
- end
- end
-
- def create_temporary_directory
- path = "tmp"
- FileUtils.rm_rf(path)
- FileUtils.mkdir_p(path)
- begin
- yield path
- ensure
- FileUtils.rm_rf(path)
- end
- end
-
- def run_groonga(db_path)
- IO.popen([@tester.groonga, "-n", db_path], "r+") do |io|
- begin
- yield io
- ensure
- io.close unless io.closed?
- end
- end
- end
-
- def normalize_result(result)
- normalized_result = ""
- result.each do |tag, content, options|
- case tag
- when :input
- normalized_result << content
- when :output
- case options[:format]
- when "json"
- status, *values = JSON.parse(content)
- normalized_status = normalize_status(status)
- normalized_output_content = [normalized_status, *values]
- normalized_output = JSON.generate(normalized_output_content)
- if normalized_output.bytesize > @max_n_columns
- normalized_output = JSON.pretty_generate(normalized_output_content)
- end
- normalized_output.force_encoding("ASCII-8BIT")
- normalized_result << "#{normalized_output}\n"
- else
- normalized_result << "#{content}\n".force_encoding("ASCII-8BIT")
- end
- when :error
- normalized_result << "#{content}\n".force_encoding("ASCII-8BIT")
- end
- end
- normalized_result
- end
-
- def normalize_status(status)
- return_code, started_time, elapsed_time, *rest = status
- if return_code.zero?
- [0, 0.0, 0.0]
- else
- message, bactrace = rest
- [[return_code, 0.0, 0.0], message]
- end
- end
-
- def have_extension?
- not @test_script_path.extname.empty?
- end
-
- def related_file_path(extension)
- path = Pathname(@test_script_path.to_s.gsub(/\.[^.]+\z/, ".#{extension}"))
- return nil if @test_script_path == path
- path
- end
-
- def read_expected_result
- return nil unless have_extension?
- result_path = related_file_path("expected")
- return nil if result_path.nil?
- return nil unless result_path.exist?
- result_path.open("r:ascii-8bit") do |result_file|
- result_file.read
- end
- end
-
- def remove_reject_file
- return unless have_extension?
- reject_path = related_file_path("reject")
- return if reject_path.nil?
- FileUtils.rm_rf(reject_path.to_s)
- end
-
- def output_reject_file(actual_result)
- output_actual_result(actual_result, "reject")
- end
-
- def output_actual_file(actual_result)
- output_actual_result(actual_result, "actual")
- end
-
- def output_actual_result(actual_result, suffix)
- result_path = related_file_path(suffix)
- return if result_path.nil?
- result_path.open("w:ascii-8bit") do |result_file|
- result_file.print(actual_result)
- end
- end
- end
-
- class Executer
- class Context
- attr_accessor :logging, :base_directory, :result
- def initialize
- @logging = true
- @base_directory = "."
- @n_nested = 0
- @result = []
- end
-
- def execute
- @n_nested += 1
- yield
- ensure
- @n_nested -= 1
- end
-
- def top_level?
- @n_nested == 1
- end
- end
-
- class Error < StandardError
- end
-
- class NotExist < Error
- attr_reader :path
- def initialize(path)
- @path = path
- super("<#{path}> doesn't exist.")
- end
- end
-
- def initialize(groonga, context=nil)
- @groonga = groonga
- @loading = false
- @pending_command = ""
- @current_command_name = nil
- @output_format = nil
- @context = context || Context.new
- end
-
- def execute(script_path)
- unless script_path.exist?
- raise NotExist.new(script_path)
- end
-
- @context.execute do
- script_path.open("r:ascii-8bit") do |script_file|
- script_file.each_line do |line|
- begin
- if @loading
- execute_line_on_loading(line)
- else
- execute_line_with_continuation_line_support(line)
- end
- rescue Error
- line_info = "#{script_path}:#{script_file.lineno}:#{line.chomp}"
- log_error("#{line_info}: #{$!.message}")
- raise unles****@conte*****_level?
- end
- end
- end
- end
-
- @context.result
- end
-
- private
- def execute_line_on_loading(line)
- log_input(line)
- @groonga.print(line)
- @groonga.flush
- if /\]$/ =~ line
- current_result = read_output
- unless current_result.empty?
- @loading = false
- log_output(current_result)
- end
- end
- end
-
- def execute_line_with_continuation_line_support(line)
- if /\\$/ =~ line
- @pending_command << $PREMATCH
- else
- if @pending_command.empty?
- execute_line(line)
- else
- @pending_command << line
- execute_line(@pending_command)
- @pending_command = ""
- end
- end
- end
-
- def execute_line(line)
- case line
- when /\A\s*\z/
- # do nothing
- when /\A\s*\#/
- comment_content = $POSTMATCH
- execute_comment(comment_content)
- else
- execute_command(line)
- end
- end
-
- def execute_comment(content)
- case content.strip
- when "disable-logging"
- @context.logging = false
- when "enable-logging"
- @context.logging = true
- when /\Ainclude\s+/
- path = $POSTMATCH.strip
- return if path.empty?
- execute_script(path)
- end
- end
-
- def execute_script(path)
- executer = self.class.new(@groonga, @context)
- script_path = Pathname(path)
- if script_path.relative?
- script_path = Pathname(@context.base_directory) + script_path
- end
- executer.execute(script_path)
- end
-
- def execute_command(line)
- extract_command_info(line)
- @loading = true if @current_command == "load"
- log_input(line)
- @groonga.print(line)
- @groonga.flush
- unless @loading
- log_output(read_output)
- end
- end
-
- def extract_command_info(line)
- words = Shellwords.split(line)
- @current_command = words.shift
- if @current_command == "dump"
- @output_format = "groonga-command"
- else
- @output_format = "json"
- words.each_with_index do |word, i|
- if /\A--output_format(?:=(.+))?\z/ =~ word
- @output_format = $1 || words[i + 1]
- break
- end
- end
- end
- end
-
- def read_output
- output = ""
- first_timeout = 1
- timeout = first_timeout
- while IO.select([@groonga], [], [], timeout)
- break if****@groon*****?
- output << @groonga.readpartial(65535)
- timeout = 0
- end
- output
- end
-
- def log(tag, content, options={})
- return unles****@conte*****
- return if content.empty?
- log_force(tag, content, options)
- end
-
- def log_force(tag, content, options)
- @context.result << [tag, content, options]
- end
-
- def log_input(content)
- log(:input, content)
- end
-
- def log_output(content)
- log(:output, content,
- :command => @current_command,
- :format => @output_format)
- end
-
- def log_error(content)
- log_force(:error, content)
- end
- end
-
- class Reporter
- def initialize(tester)
- @tester = tester
- @term_width = guess_term_width
- @current_column = 0
- @output = STDOUT
- @n_tests = 0
- @n_passed_tests = 0
- @failed_tests = []
- end
-
- def start
- end
-
- def start_test(test_script_path)
- @test_name = test_script_path.basename
- print(" #{@test_name}")
- @output.flush
- end
-
- def pass_test
- report_test_result("pass")
- @n_passed_tests += 1
- end
-
- def fail_test(expected, actual)
- report_test_result("fail")
- puts("=" * @term_width)
- report_diff(expected, actual)
- puts("=" * @term_width)
- @failed_tests << @test_name
- end
-
- def no_check_test(result)
- report_test_result("not checked")
- puts(result)
- end
-
- def finish_test
- @n_tests += 1
- end
-
- def finish
- puts
- puts("#{@n_tests} tests, " +
- "#{@n_passed_tests} passes, " +
- "#{@failed_tests.size} failures.")
- if @n_tests.zero?
- pass_ratio = 0
- else
- pass_ratio = (@n_passed_tests / @n_tests.to_f) * 100
- end
- puts("%.4g%% passed." % pass_ratio)
- end
-
- private
- def print(message)
- @current_column += message.to_s.size
- @output.print(message)
- end
-
- def puts(*messages)
- @current_column = 0
- @output.puts(*messages)
- end
-
- def report_test_result(label)
- message = " [#{label}]"
- message = message.rjust(@term_width - @current_column) if @term_width > 0
- puts(message)
- end
-
- def report_diff(expected, actual)
- create_temporary_file("expected", expected) do |expected_file|
- create_temporary_file("actual", actual) do |actual_file|
- diff_options =****@teste*****_options.dup
- diff_options.concat(["--label", "(actual)", actual_file.path,
- "--label", "(expected)", expected_file.path])
- system(@tester.diff, *diff_options)
- end
- end
- end
-
- def create_temporary_file(key, content)
- file = Tempfile.new("groonga-test-#{key}")
- file.print(content)
- file.close
- yield file
- end
-
- def guess_term_width
- Integer(ENV["COLUMNS"] || ENV["TERM_WIDTH"] || 79)
- rescue ArgumentError
- 0
- end
- end
-end
+require "groonga/tester"
exit(GroongaTester.run)
Copied: lib/groonga/tester.rb (+0 -2) 99%
===================================================================
--- bin/groonga-test 2012-03-06 16:06:25 +0900 (044c447)
+++ lib/groonga/tester.rb 2012-03-06 16:10:00 +0900 (e4b8504)
@@ -580,5 +580,3 @@ class GroongaTester
end
end
end
-
-exit(GroongaTester.run)