require 'fileutils' module IMWTest module Random STRING_CHARS = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + [' ',' ',' ',' ',' '] unless defined?(STRING_CHARS) TEXT_CHARS = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + [' ',' ',' ',' ',' ',"\n"] unless defined?(TEXT_CHARS) FILENAME_CHARS = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["-","_",' '] unless defined?(FILENAME_CHARS) FILENAME_MAX_LENGTH = 9 unless defined?(FILENAME_MAX_LENGTH) TEXT_MAX_LENGTH = 1024 unless defined?(TEXT_MAX_LENGTH) EXTENSIONS = [ [/\.csv$/ , :csv_file], [/\.xml$/ , :xml_file], [/\.html$/ , :html_file], [/\.tar\.gz$/ , :targz_file], [/\.tar\.bz2$/ , :tarbz2_file], [/\.bz2$/ , :bz2_file], [/\.gz$/ , :gz_file], [/\.tar$/ , :tar_file], [/\.rar$/ , :rar_file], [/\.zip$/ , :zip_file] ] unless defined?(EXTENSIONS) # Return a random filename. Optional +length+ to set the maximum # length of the filename returned. def self.basename options = {} length = (options[:length] or FILENAME_MAX_LENGTH) filename = (1..length).map { |i| FILENAME_CHARS.random }.join # filenames beginning with hyphens suck while (filename[0,1] == '-') do filename[0] = FILENAME_CHARS.random end filename end # Return a random string of text up. Control the length with # optional +length+ and also the presence of +newlines+. def self.text options = {} length = (options[:length] or TEXT_MAX_LENGTH) char_pool = options[:newlines] ? TEXT_CHARS : STRING_CHARS (1..length).map { |i| char_pool.random }.join end # Create a random file by matching the extension of the given # +filename+ or a text file if no match is found. def self.file filename match = EXTENSIONS.find { |regex,func| regex.match filename } match ? self.send(match.last,filename) : self.text_file(filename) end # Create a random text file at +filename+ containing a maximum of # +length+ characters. def self.text_file filename, options = {} File.open(filename,'w') { |f| f.write text(:newlines => true) } end # Create a comma-separated value file containing random text at # +filename+ with the maximum +num_rows+, the given +num_columns+, # and the maximum +entry_length+. def self.csv_file(filename,num_rows = 500, num_columns = 9, entry_length = 9) f = File.open(filename,'w') rand(num_rows).times do # rows num_columns.times do # columns f.write(text(:length => entry_length)) # entry f.write ',' end f.write(text(:length => entry_length)) # last entry f.write("\n") end f.close end # Create an XML file at +filename+ of the maximum +length+. # # At the present moment, this file contains random text in a very # boring single-element XML tree. Randomizing the tree has not # been implemented. def self.xml_file filename, options = {} options = options.reverse_merge({:max_depth => 5, :starting_depth => 1, :depth => nil, :pretty_print => true}) File.open(filename,'w') do |file| file.write "\n" file.write "" + text + "" file.close end end # Create an HTML file at +filename+ of the maximum +length+. # # At the present moment, this file contains random text in a very # boring bare-bones HTML with a single element body. Randomizing # the tree has not been implemented. def self.html_file(filename, title_length = 100, body_length = 5000) f = File.open(filename,'w') f.write "" + string(title_length) + "" + string(body_length) + "" f.close end # Create a tar archive at the given +filename+ containing random # files. def self.tar_file filename tmpd = File.dirname(filename) + '/dir' directory_with_files(tmpd) FileUtils.cd(tmpd) {|dir| system("tar -cf file.tar *") } FileUtils.cp(tmpd + "/file.tar",filename) FileUtils.rm_rf(tmpd) end # Create a tar.gz archive at the given +filename+ containing # random files. def self.targz_file filename tar = File.dirname(filename) + "/file.tar" targz = tar + ".gz" tar_file tar system("gzip #{tar}") FileUtils.cp(targz,filename) FileUtils.rm(targz) end # Create a tar.bz2 archive at the given +filename+ containing # random files. def self.tarbz2_file filename tar = File.dirname(filename) + "/file.tar" tarbz2 = tar + ".bz2" tar_file tar system("bzip2 #{tar}") FileUtils.cp(tarbz2,filename) FileUtils.rm(tarbz2) end # Create a .bz2 file at the given +filename+. def self.bz2_file filename text_path = File.dirname(filename) + "/fake_file" text_file(text_path) system("bzip2 #{text_path}") FileUtils.mv(text_path + ".bz2", filename) end # Create a .gz file at the given +filename+. def self.gz_file filename text_path = File.dirname(filename) + "/fake_file" text_file(text_path) system("gzip #{text_path}") FileUtils.mv(text_path + ".gz", filename) end # Create a compressed rar archive at the given +filename+ # containing random files. def self.rar_file filename tmpd = File.dirname(filename) + '/dir' directory_with_files(tmpd) FileUtils.cd(tmpd) {|dir| system("rar a -o+ -inul file.rar *") } FileUtils.cp(tmpd + "/file.rar",filename) FileUtils.rm_rf(tmpd) end # Create a compressed zip archive at the given +filename+ # containing random files. def self.zip_file filename tmpd = File.dirname(filename) + '/dir' directory_with_files(tmpd) FileUtils.cd(tmpd) {|dir| system("zip -qqr file.zip *") } FileUtils.cp(tmpd + "/file.zip",filename) FileUtils.rm_rf(tmpd) end # Creates +directory+ and fills it with random files containing # random data. # # Options (with their default values in parentheses) include: # # :extensions ([txt,csv,dat,xml]):: extensions to use. If an extension is known (see IMWTest::Random::EXTENSIONS) then appropriately formatted random data will be used If an extension is not known, it will be treated as text. The extension +dir+ will create a directory which will itself be filled with random files in the same way as its parent. # :max_depth (3):: maximum depth to nest directories # :starting_depth (1):: the default depth the parent directory is assumed to have # :num_files (10):: the maximum number of files per directory # :force (false):: force overwriting of existing directories def self.directory_with_files(directory,options = {}) directory = File.expand_path(directory) options = options.reverse_merge({:extensions => ['txt','csv','dat'],:max_depth => 3,:force => false,:starting_depth => 1, :num_files => 3}) depth = options[:starting_depth] if File.exist?(directory) then if options[:force] then FileUtils.rm_rf(directory) else raise "#{directory} already exists" end end FileUtils.mkdir_p(directory) (rand(options[:num_files]) + 2).times do ext = options[:extensions].random name = self.basename if ext == 'dir' then if depth <= options[:max_depth] then newd = directory + '/' + name FileUtils.mkdir(newd) directory_with_files(newd,options.merge({:starting_depth => (depth + 1)})) else next end else file(directory + '/' + name + '.' + ext) end end end end end