1require 'tempfile' 2require 'fileutils' 3require 'yaml' 4require 'uconv' 5 6$KCODE = "u" 7 8module TomoeTestUtils 9 def self.included(base) 10 base.class_eval do 11 include Base 12 include Path 13 include Config 14 include Dictionary 15 include Unicode 16 include Assertions 17 end 18 end 19 20 module Base 21 def setup 22 super 23 end 24 25 def teardown 26 super 27 end 28 end 29 30 module Path 31 module_function 32 def base_dir 33 File.expand_path(File.dirname(__FILE__)) 34 end 35 36 def tmp_dir 37 File.join(base_dir, "tmp") 38 end 39 40 def top_dir 41 File.expand_path(File.join(base_dir, "..")) 42 end 43 44 def data_dir 45 File.join(top_dir, "data") 46 end 47 48 def test_data_dir 49 File.join(base_dir, "data") 50 end 51 52 def module_dir 53 File.join(top_dir, "module") 54 end 55 56 def recognizer_dir 57 File.join(module_dir, "recognizer", ".libs") 58 end 59 60 def dict_dir 61 File.join(module_dir, "dict", ".libs") 62 end 63 64 def db_dir 65 File.join(top_dir, "db") 66 end 67 68 def db_config_file 69 File.join(db_dir, "config.yml") 70 end 71 72 def test_data_files 73 Dir.glob(File.join(test_data_dir, "*.data")) 74 end 75 76 def dictionary 77 File.join(data_dir, "kanjidic2.xml") 78 end 79 end 80 81 module Config 82 extend Path 83 84 module_function 85 def db_config_for_active_record(type=nil) 86 YAML.load(File.read(db_config_file))[type || ENV["TOMOE_ENV"] || "test"] 87 end 88 89 def db_config(type=nil) 90 config = db_config_for_active_record(type) 91 config.delete("adapter") 92 config.delete("encoding") 93 config["user"] = config.delete("username") if config["username"] 94 config 95 end 96 97 def setup 98 super 99 FileUtils.mkdir_p(tmp_dir) 100 @config_file = make_config_file 101 end 102 103 def teardown 104 super 105 FileUtils.rm_rf(tmp_dir) 106 end 107 108 def dict_module_type 109 ENV["TOMOE_DICT_MODULE"] || "xml" 110 end 111 112 def make_config_file(dict_type=nil) 113 dict_type ||= dict_module_type 114 name ||= "tomoe-#{dict_type}" 115 config_file = Tempfile.new(name) 116 config_file.open 117 config_file.puts(<<-EOC) 118[config] 119use-system-dictionaries = false 120EOC 121 122 config_maker = "make_config_file_for_#{dict_type}" 123 unless respond_to?(config_maker, true) 124 raise "unknown dictionary type: #{dict_type}" 125 end 126 config_file.puts(send(config_maker)) 127 128 config_file.close 129 config_file 130 end 131 132 def make_config_file_for_unihan 133 <<-EOC 134[unihan-dictionary] 135type = unihan 136EOC 137 end 138 139 def est_db 140 File.join(tmp_dir, File.basename(dictionary).sub(/\.xml$/, '')) 141 end 142 143 def ensure_dict_est 144 unless File.exists?(est_db) 145 tmp_est_db = "#{est_db}.tmp" 146 FileUtils.rm_rf(tmp_est_db) 147 xml_dict = Tomoe::DictXML.new("filename" => dictionary, 148 "editable" => false) 149 est_dict = Tomoe::DictEst.new("database" => tmp_est_db, 150 "editable" => true) 151 xml_dict.search(Tomoe::Query.new).each_with_index do |cand, i| 152 est_dict.register(cand.char) 153 end 154 est_dict.flush 155 FileUtils.cp_r(tmp_est_db, est_db) 156 end 157 end 158 159 def ensure_dict_mysql 160 sql_purge("test") 161 xml_dict = Tomoe::DictXML.new("filename" => dictionary, 162 "editable" => false) 163 mysql_dict = Tomoe::DictMySQL.new(db_config("test")) 164 xml_dict.search(Tomoe::Query.new).each_with_index do |cand, i| 165 mysql_dict.register(cand.char) 166 end 167 end 168 169 def make_config_file_for_est 170 dict_basename = File.basename(dictionary).sub(/\.xml$/, '') 171 <<-EOC 172[#{dict_basename}-dictionary] 173type = est 174name = #{dict_basename} 175database = #{est_db} 176EOC 177 end 178 179 def make_config_file_for_xml 180 <<-EOC 181[#{File.basename(dictionary)}-dictionary] 182type = xml 183file = #{dictionary} 184EOC 185 end 186 187 def make_config_file_for_mysql 188 config = <<-EOC 189[mysql-dictionary] 190type = mysql 191EOC 192 db_config.each do |key, value| 193 config << "#{key} = #{value}\n" 194 end 195 config 196 end 197 end 198 199 module Dictionary 200 module_function 201 def make_dict(dict_type=nil, config=nil) 202 dict_type ||= dict_module_type 203 dict_maker = "make_dict_#{dict_type}" 204 unless respond_to?(dict_maker, true) 205 raise "unknown dictionary type: #{dict_type}" 206 end 207 send(dict_maker, config) 208 end 209 210 def make_temporary_dict(original, dict_type=nil, config=nil, &block) 211 dict_type ||= dict_module_type 212 temporary_dict_maker = "make_temporary_dict_#{dict_type}" 213 unless respond_to?(temporary_dict_maker, true) 214 raise "unknown dictionary type: #{dict_type}" 215 end 216 send(temporary_dict_maker, config) do |dict| 217 original.search(Tomoe::Query.new).each do |cand| 218 dict.register(cand.char) 219 end 220 block.call(dict) 221 end 222 end 223 224 def make_dict_unihan(config=nil) 225 check_dict_module_availability("Unihan") 226 Tomoe::DictUnihan.new(config || {}) 227 end 228 229 def make_dict_xml(config=nil) 230 check_dict_module_availability("XML") 231 config ||= {} 232 config = config.dup 233 config["filename"] ||= dictionary 234 Tomoe::DictXML.new(config) 235 end 236 237 def make_temporary_dict_xml(config=nil) 238 check_dict_module_availability("XML") 239 dict = nil 240 begin 241 tmp_dict_dir = File.join(tmp_dir, "dict") 242 FileUtils.mkdir_p(tmp_dict_dir) 243 dict_file = File.join(tmp_dict_dir, "dict.xml") 244 dict = Tomoe::DictXML.new("filename" => dict_file, "editable" => true) 245 yield dict 246 ensure 247 dict.flush if dict 248 FileUtils.rm_rf(tmp_dict_dir) 249 end 250 end 251 252 def make_dict_est(config=nil) 253 check_dict_module_availability("Est") 254 config ||= {} 255 config = config.dup 256 config["database"] ||= dictionary.sub(/\.xml/, '') 257 config["editable"] = true unless config.has_key?("editable") 258 Tomoe::DictEst.new(config) 259 end 260 261 def make_temporary_dict_est(config=nil) 262 check_dict_module_availability("Est") 263 begin 264 tmp_dict_dir = File.join(tmp_dir, "est") 265 yield Tomoe::DictEst.new("database" => tmp_dict_dir, "editable" => true) 266 ensure 267 FileUtils.rm_rf(tmp_dict_dir) 268 end 269 end 270 271 def make_dict_mysql(config=nil) 272 check_dict_module_availability("MySQL") 273 config ||= db_config 274 config = config.dup 275 Tomoe::DictMySQL.new(config) 276 end 277 278 def make_temporary_dict_mysql(config=nil) 279 check_dict_module_availability("MySQL") 280 sql_purge("temp") 281 yield Tomoe::DictMySQL.new(db_config("temp")) 282 end 283 284 def check_dict_module_availability(type) 285 begin 286 Tomoe.const_get("Dict#{type}") 287 rescue NameError 288 raise "Tomoe doesn't support the dictionary type: #{type}" 289 end 290 end 291 292 def sql_migrate(type=nil, version=nil) 293 migrate = File.join(db_dir, "migrate.rb") 294 tomoe_env = ENV["TOMOE_ENV"] 295 ENV["TOMOE_ENV"] = type if type 296 unless `#{migrate} #{version}` 297 message = "failed to migrate" 298 message << " to #{version}" if version 299 raise message 300 end 301 ensure 302 ENV["TOMOE_ENV"] = tomoe_env 303 end 304 305 def sql_purge(type=nil) 306 sql_migrate(type, 0) 307 sql_migrate(type) 308 end 309 end 310 311 module TestData 312 module_function 313 def parse(file) 314 expected = nil 315 writing = Tomoe::Writing.new 316 File.open(file) do |f| 317 expected = f.gets.split 318 f.each do |line| 319 next if /\A\s*\z/ =~ line 320 begin 321 first_point, *rest_points = line.split(/,/) 322 numbered_first_point = numbers_to_point(first_point) 323 writing.move_to(*numbered_first_point) 324 rest_points.each do |point| 325 writing.line_to(*numbers_to_point(point)) 326 end 327 rescue ArgumentError 328 raise "invalid format in #{file} at #{f.lineno}: #{line}" 329 end 330 end 331 end 332 [expected, writing] 333 end 334 335 def numbers_to_point(str) 336 point = str.split.collect {|x| Integer(x)} 337 raise ArgumentError if point.size != 2 338 point 339 end 340 end 341 342 module Unicode 343 module_function 344 def ucs4_to_utf8(ucs4) 345 Uconv.u4tou8([ucs4].pack("I*")) 346 end 347 348 def utf8_to_ucs4(utf8) 349 Uconv.u8tou4(utf8).unpack("I*")[0] 350 end 351 end 352 353 module Assertions 354 def assert_true(actual, *args) 355 assert_equal(true, actual, *args) 356 end 357 358 def assert_false(actual, *args) 359 assert_equal(false, actual, *args) 360 end 361 end 362end 363 364require 'tomoe' 365 366Tomoe::Dict.default_module_dir = TomoeTestUtils::Path.dict_dir 367Tomoe::Recognizer.default_module_dir = TomoeTestUtils::Path.recognizer_dir 368