2012-01-27 18:29:02 +00:00
|
|
|
class SimpleTest
|
2015-12-07 21:49:41 +00:00
|
|
|
@@json_schema_identification = nil
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
EXIT_CODE_ALIASES = {
|
|
|
|
:success => 0,
|
|
|
|
:warning => 1,
|
|
|
|
:error => 2,
|
2012-01-27 18:29:02 +00:00
|
|
|
}
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def self.instantiate class_name
|
|
|
|
file_name = class_name_to_file_name class_name
|
|
|
|
content = IO.readlines(file_name).join("")
|
|
|
|
|
2015-02-03 06:58:01 +00:00
|
|
|
if ! %r{class\s+.*?\s+<\s+Test}.match(content)
|
2012-01-31 17:59:27 +00:00
|
|
|
content = %Q!
|
|
|
|
class ::#{class_name} < SimpleTest
|
|
|
|
def initialize
|
|
|
|
super
|
|
|
|
|
|
|
|
#{content}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
!
|
|
|
|
else
|
|
|
|
content.gsub!(/class\s+/, 'class ::')
|
|
|
|
end
|
|
|
|
|
|
|
|
eval content, nil, file_name, 5
|
2012-01-27 18:29:02 +00:00
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
constantize(class_name).new
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def initialize
|
|
|
|
@commands = []
|
|
|
|
@tmp_num = 0
|
|
|
|
@tmp_num_mutex = Mutex.new
|
|
|
|
@blocks = {
|
|
|
|
:setup => [],
|
|
|
|
:tests => [],
|
|
|
|
:cleanup => [],
|
|
|
|
}
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def commands
|
|
|
|
@commands
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def describe description
|
|
|
|
@description = description
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def setup &block
|
|
|
|
@blocks[:setup] << block
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def cleanup &block
|
|
|
|
@blocks[:cleanup] << block
|
|
|
|
end
|
|
|
|
|
|
|
|
def tmp_name_prefix
|
|
|
|
[ "/tmp/mkvtoolnix-auto-test-#{self.class.name}", $$.to_s, Thread.current[:number] ].join("-") + "-"
|
|
|
|
end
|
|
|
|
|
|
|
|
def tmp_name
|
|
|
|
@tmp_num_mutex.lock
|
|
|
|
@tmp_num ||= 0
|
|
|
|
@tmp_num += 1
|
|
|
|
result = self.tmp_name_prefix + @tmp_num.to_s
|
|
|
|
@tmp_num_mutex.unlock
|
2012-01-27 18:29:02 +00:00
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def tmp
|
|
|
|
@tmp ||= tmp_name
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2015-12-29 13:00:13 +00:00
|
|
|
def clean_tmp
|
|
|
|
File.unlink(@tmp) if File.exists?(@tmp) && (ENV["KEEP_TMPFILES"] != "1")
|
|
|
|
@tmp = nil
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def hash_file name
|
2012-01-27 18:29:02 +00:00
|
|
|
md5 name
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def hash_tmp erase = true
|
|
|
|
output = hash_file @tmp
|
2012-01-27 18:29:02 +00:00
|
|
|
|
2015-12-29 13:00:13 +00:00
|
|
|
clean_tmp if erase
|
2012-01-27 18:29:02 +00:00
|
|
|
|
|
|
|
output
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def unlink_tmp_files
|
2012-01-27 18:29:02 +00:00
|
|
|
return if ENV["KEEP_TMPFILES"] == "1"
|
2015-02-03 06:58:01 +00:00
|
|
|
re = %r{^#{self.tmp_name_prefix}}
|
2012-01-27 18:29:02 +00:00
|
|
|
Dir.entries("/tmp").each do |entry|
|
|
|
|
file = "/tmp/#{entry}"
|
|
|
|
File.unlink(file) if re.match(file) and File.exists?(file)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def test name, &block
|
|
|
|
@blocks[:tests] << { :name => name, :block => block }
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2016-04-09 16:08:02 +00:00
|
|
|
def exit_code_string exit_code
|
|
|
|
return exit_code == 0 ? 'ok' \
|
|
|
|
: exit_code == 1 ? 'warning' \
|
|
|
|
: exit_code == 2 ? 'error' \
|
|
|
|
: "unknown(#{exit_code})"
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def test_merge file, *args
|
2016-04-09 16:08:02 +00:00
|
|
|
options = args.extract_options!
|
|
|
|
full_command_line = [ options[:args], file ].flatten.join(' ')
|
|
|
|
options[:name] ||= full_command_line
|
|
|
|
options[:result_type] ||= :hash
|
2012-01-31 17:59:27 +00:00
|
|
|
@blocks[:tests] << {
|
2012-01-27 18:29:02 +00:00
|
|
|
:name => full_command_line,
|
|
|
|
:block => lambda {
|
2016-04-09 16:08:02 +00:00
|
|
|
output = options[:output] || tmp
|
|
|
|
_, exit_code = *merge(full_command_line, :exit_code => options[:exit_code], :output => output)
|
|
|
|
result = options[:exit_code] == :error ? 'error' \
|
|
|
|
: options[:result_type] == :hash ? hash_file(output) \
|
|
|
|
: exit_code_string(exit_code)
|
2015-12-29 13:00:13 +00:00
|
|
|
|
|
|
|
clean_tmp unless options[:keep_tmp]
|
|
|
|
|
|
|
|
result
|
2012-01-27 18:29:02 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def test_identify file, *args
|
2012-01-31 13:55:00 +00:00
|
|
|
options = args.extract_options!
|
2017-01-22 09:53:11 +00:00
|
|
|
options[:format] = :json if options[:format].nil?
|
|
|
|
full_command_line = [ "--identification-format", options[:format].to_s, "--identify", options[:args], file ].flatten.join(' ')
|
2012-01-31 13:55:00 +00:00
|
|
|
options[:name] ||= full_command_line
|
2012-01-31 17:59:27 +00:00
|
|
|
@blocks[:tests] << {
|
2012-01-31 13:55:00 +00:00
|
|
|
:name => full_command_line,
|
|
|
|
:block => lambda {
|
2017-04-15 16:46:43 +00:00
|
|
|
sys "../src/mkvmerge #{full_command_line} --engage no_variable_data > #{tmp}", :exit_code => options[:exit_code]
|
2017-01-22 09:53:11 +00:00
|
|
|
|
|
|
|
text = IO.readlines(tmp).reject { |line| %r{^\s*"identification_format_version":\s*\d+}.match(line) }.join('')
|
|
|
|
File.open(tmp, 'w') { |tmp_file| tmp_file.puts text }
|
|
|
|
|
2012-05-06 17:27:06 +00:00
|
|
|
if options[:filter]
|
|
|
|
text = options[:filter].call(IO.readlines(tmp).join(''))
|
2015-11-03 19:40:13 +00:00
|
|
|
File.open(tmp, 'w') { |tmp_file| tmp_file.puts text }
|
2012-05-06 17:27:06 +00:00
|
|
|
end
|
2012-02-06 18:15:48 +00:00
|
|
|
options[:keep_tmp] ? hash_file(tmp) : hash_tmp
|
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2014-12-16 15:51:20 +00:00
|
|
|
def test_info file, *args
|
|
|
|
options = args.extract_options!
|
|
|
|
full_command_line = [ options[:args], file ].flatten.join(' ')
|
|
|
|
options[:name] ||= full_command_line
|
|
|
|
@blocks[:tests] << {
|
|
|
|
:name => full_command_line,
|
|
|
|
:block => lambda {
|
|
|
|
output = options[:output] || tmp
|
|
|
|
info full_command_line, :exit_code => options[:exit_code], :output => output
|
|
|
|
options[:keep_tmp] ? hash_file(output) : hash_tmp
|
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-03-04 16:52:50 +00:00
|
|
|
def test_merge_unsupported file, *args
|
|
|
|
options = args.extract_options!
|
|
|
|
full_command_line = [ options[:args], file ].flatten.join(' ')
|
|
|
|
options[:name] ||= full_command_line
|
|
|
|
@blocks[:tests] << {
|
|
|
|
:name => full_command_line,
|
|
|
|
:block => lambda {
|
|
|
|
sys "../src/mkvmerge --identify-verbose #{full_command_line} > #{tmp}", :exit_code => 3
|
2015-02-03 06:58:01 +00:00
|
|
|
%r{unsupported container}.match(IO.readlines(tmp).first || '') ? :ok : :bad
|
2012-03-04 16:52:50 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-02-06 18:15:48 +00:00
|
|
|
def test_ui_locale locale, *args
|
2013-10-26 12:06:04 +00:00
|
|
|
describe "mkvmerge / UI locale: #{locale}"
|
|
|
|
|
2012-02-06 18:15:48 +00:00
|
|
|
@blocks[:tests] << {
|
|
|
|
:name => "mkvmerge UI locale #{locale}",
|
|
|
|
:block => lambda {
|
|
|
|
sys "../src/mkvmerge -o /dev/null --ui-language #{locale} data/avi/v.avi | head -n 2 | tail -n 1 > #{tmp}-#{locale}"
|
2013-10-26 13:47:25 +00:00
|
|
|
result = hash_file "#{tmp}-#{locale}"
|
|
|
|
self.error 'Locale #{locale} not supported by MKVToolNix' if result == 'f54ee70a6ad9bfc5f61de5ba5ca5a3c8'
|
|
|
|
result
|
2012-02-06 18:15:48 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
@blocks[:tests] << {
|
|
|
|
:name => "mkvinfo UI locale #{locale}",
|
|
|
|
:block => lambda {
|
|
|
|
sys "../src/mkvinfo --ui-language #{locale} data/mkv/complex.mkv | head -n 2 > #{tmp}-#{locale}"
|
2013-10-26 13:47:25 +00:00
|
|
|
result = hash_file "#{tmp}-#{locale}"
|
|
|
|
self.error 'Locale #{locale} not supported by MKVToolNix' if result == 'f54ee70a6ad9bfc5f61de5ba5ca5a3c8'
|
|
|
|
result
|
2012-01-31 13:55:00 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def description
|
|
|
|
@description || fail("Class #{self.class.name} misses its description")
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def run_test
|
2015-11-03 19:40:13 +00:00
|
|
|
@blocks[:setup].each(&:call)
|
2012-01-27 18:29:02 +00:00
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
results = @blocks[:tests].collect do |test|
|
2012-01-27 18:29:02 +00:00
|
|
|
result = nil
|
|
|
|
begin
|
|
|
|
result = test[:block].call
|
|
|
|
rescue RuntimeError => ex
|
2012-01-31 17:59:27 +00:00
|
|
|
show_message "Test case '#{self.class.name}', sub-test '#{test[:name]}': #{ex}"
|
2017-10-07 13:00:00 +00:00
|
|
|
result = :failed
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2015-11-03 19:40:13 +00:00
|
|
|
@blocks[:cleanup].each(&:call)
|
2012-01-27 18:29:02 +00:00
|
|
|
|
2012-01-31 15:55:31 +00:00
|
|
|
unlink_tmp_files
|
|
|
|
|
2012-01-27 18:29:02 +00:00
|
|
|
results.join '-'
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def merge *args
|
2012-01-27 18:29:02 +00:00
|
|
|
options = args.extract_options!
|
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
|
|
|
output = options[:output] || self.tmp
|
|
|
|
command = "../src/mkvmerge --engage no_variable_data -o #{output} #{args.first}"
|
2017-08-12 07:59:23 +00:00
|
|
|
self.sys command, :exit_code => options[:exit_code], :no_result => options[:no_result]
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2012-09-02 10:26:25 +00:00
|
|
|
def identify *args
|
|
|
|
options = args.extract_options!
|
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
2015-12-07 21:49:41 +00:00
|
|
|
verbose = !options[:verbose].nil? ? options[:verbose] : true
|
|
|
|
format = options[:format] ? options[:format].to_s.downcase.gsub(/_/, '-') : verbose ? 'verbose-text' : 'text'
|
|
|
|
|
|
|
|
command = "../src/mkvmerge --identify --identification-format #{format} --engage no_variable_data #{args.first}"
|
|
|
|
|
2017-08-12 07:59:23 +00:00
|
|
|
self.sys command, :exit_code => options[:exit_code], :no_result => options[:no_result]
|
2012-09-02 10:26:25 +00:00
|
|
|
end
|
|
|
|
|
2016-03-27 13:00:12 +00:00
|
|
|
def identify_json *args
|
|
|
|
options = args.extract_options!
|
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
|
|
|
command = "../src/mkvmerge --identify --identification-format json --engage no_variable_data #{args.first}"
|
|
|
|
|
2017-08-12 07:59:23 +00:00
|
|
|
output, _ = self.sys(command, :exit_code => options[:exit_code], :no_result => options[:no_result])
|
2016-03-27 13:00:12 +00:00
|
|
|
|
|
|
|
return JSON.load(output.join(''))
|
|
|
|
end
|
|
|
|
|
2012-03-08 08:37:28 +00:00
|
|
|
def info *args
|
|
|
|
options = args.extract_options!
|
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
|
|
|
output = options[:output] || self.tmp
|
2015-02-03 06:58:01 +00:00
|
|
|
output = "> #{output}" unless %r{^[>\|]}.match(output)
|
2012-04-08 08:19:17 +00:00
|
|
|
output = '' if options[:output] == :return
|
2012-03-08 08:37:28 +00:00
|
|
|
command = "../src/mkvinfo --engage no_variable_data --ui-language en_US #{args.first} #{output}"
|
2017-08-12 07:59:23 +00:00
|
|
|
self.sys command, :exit_code => options[:exit_code], :no_result => options[:no_result]
|
2012-03-08 08:37:28 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def extract *args
|
2012-01-31 15:55:31 +00:00
|
|
|
options = args.extract_options!
|
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
|
|
|
mode = options[:mode] || :tracks
|
|
|
|
command = "../src/mkvextract --engage no_variable_data #{mode} #{args.first} " + options.keys.select { |key| key.is_a?(Numeric) }.sort.collect { |key| "#{key}:#{options[key]}" }.join(' ')
|
|
|
|
|
2017-08-12 07:59:23 +00:00
|
|
|
self.sys command, :exit_code => options[:exit_code], :no_result => options[:no_result]
|
2012-01-31 15:55:31 +00:00
|
|
|
end
|
|
|
|
|
2015-02-23 19:37:31 +00:00
|
|
|
def propedit file_name, *args
|
2012-09-02 10:26:25 +00:00
|
|
|
options = args.extract_options!
|
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
2015-02-23 19:37:31 +00:00
|
|
|
command = "../src/mkvpropedit --engage no_variable_data #{file_name} #{args.first}"
|
2017-08-12 07:59:23 +00:00
|
|
|
*result = self.sys command, :exit_code => options[:exit_code], :no_result => options[:no_result]
|
2015-02-23 19:37:31 +00:00
|
|
|
|
2016-05-04 10:48:14 +00:00
|
|
|
self.sys "../src/tools/ebml_validator -M #{file_name}", dont_record_command: true if FileTest.exists?("../src/tools/ebml_validator")
|
2015-02-23 19:37:31 +00:00
|
|
|
|
|
|
|
return *result
|
2012-09-02 10:26:25 +00:00
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def sys *args
|
2012-01-31 13:23:17 +00:00
|
|
|
options = args.extract_options!
|
2012-01-31 17:59:27 +00:00
|
|
|
options[:exit_code] = EXIT_CODE_ALIASES[ options[:exit_code] ] || options[:exit_code] || 0
|
2012-01-27 18:29:02 +00:00
|
|
|
fail ArgumentError if args.empty?
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
command = args.shift
|
2017-08-12 07:59:23 +00:00
|
|
|
@commands << { :command => command, :no_result => options[:no_result] } unless options[:dont_record_command]
|
2012-03-26 07:28:42 +00:00
|
|
|
|
2015-02-03 06:58:01 +00:00
|
|
|
if !%r{>}.match command
|
2012-03-26 07:28:42 +00:00
|
|
|
temp_file = Tempfile.new('mkvtoolnix-test-output')
|
|
|
|
temp_file.close
|
|
|
|
command << " >#{temp_file.path} 2>&1 "
|
|
|
|
end
|
2012-01-27 18:29:02 +00:00
|
|
|
|
2013-02-16 14:28:19 +00:00
|
|
|
puts "COMMAND #{command}" if ENV['DEBUG']
|
2012-03-26 07:28:42 +00:00
|
|
|
|
2013-12-18 21:20:17 +00:00
|
|
|
exit_code = 0
|
|
|
|
if !system(command)
|
|
|
|
exit_code = $? >> 8
|
|
|
|
self.error "system command failed: #{command} (#{exit_code})" if options[:exit_code] != exit_code
|
|
|
|
end
|
|
|
|
|
|
|
|
return IO.readlines(temp_file.path), exit_code if temp_file
|
|
|
|
return exit_code
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|
|
|
|
|
2017-08-12 07:59:23 +00:00
|
|
|
def cp source, target, *args
|
|
|
|
options = args.extract_options!
|
|
|
|
options[:no_result] = true unless options.key?(:no_result)
|
|
|
|
|
|
|
|
sys "cp '#{source}' '#{target}'", options
|
|
|
|
end
|
|
|
|
|
2012-01-31 17:59:27 +00:00
|
|
|
def error reason
|
2012-01-27 18:29:02 +00:00
|
|
|
show_message " Failed. Reason: #{reason}"
|
|
|
|
raise "test failed"
|
|
|
|
end
|
2015-12-07 21:49:41 +00:00
|
|
|
|
|
|
|
def json_schema_identification
|
|
|
|
return @@json_schema_identification if @@json_schema_identification
|
|
|
|
|
|
|
|
require "json_schema"
|
|
|
|
|
|
|
|
json_store = JsonSchema::DocumentStore.new
|
|
|
|
parser = JsonSchema::Parser.new
|
|
|
|
expander = JsonSchema::ReferenceExpander.new
|
2017-06-22 18:04:40 +00:00
|
|
|
version = IO.readlines("../src/merge/id_result.h").detect { |line| /#define +ID_JSON_FORMAT_VERSION\b/.match line }.gsub(/.* .* /, '').chop
|
|
|
|
schema = parser.parse JSON.load(File.read("../doc/json-schema/mkvmerge-identification-output-schema-v#{version}.json"))
|
2015-12-07 21:49:41 +00:00
|
|
|
|
|
|
|
expander.expand(schema, store: json_store)
|
|
|
|
json_store.add_schema schema
|
|
|
|
|
|
|
|
@@json_schema_identification = schema
|
|
|
|
end
|
2016-07-07 17:36:30 +00:00
|
|
|
|
|
|
|
def json_summarize_tracks json
|
|
|
|
basics = %w{id type codec}
|
|
|
|
properties = %w{language number audio_channels audio_sampling_frequency pixel_dimensions}
|
|
|
|
|
|
|
|
json["tracks"].
|
|
|
|
map do |t|
|
|
|
|
(basics.map { |b| t[b] } +
|
|
|
|
properties.map { |p| t["properties"][p] }).
|
|
|
|
reject(&:nil?).
|
|
|
|
join("+").
|
|
|
|
gsub(%r{[:/+-]+}, "_")
|
|
|
|
end.
|
|
|
|
join("/")
|
|
|
|
end
|
2012-01-27 18:29:02 +00:00
|
|
|
end
|