require File.join(File.dirname(__FILE__), 'external_test_helper.rb') require 'ext_ind' require 'fileutils' require 'ext_arr' class ExtIndTest < Test::Unit::TestCase include Benchmark include External include TestArray attr_reader :index, :tempfile def setup # cls represents an array @cls = ExtInd @tempfile = Tempfile.new("indextest") @tempfile << array.pack(format) @tempfile.pos = 0 @index = ExtInd.new(@tempfile) end def array [1,2,3,4,5] end def framed_array [[1],[2],[3],[4],[5]] end def format "I*" end def teardown @tempfile.close unless @tempfile.closed? end # # readme doc test # def test_readme_doc_for_ext_ind ea = ExtArr.new assert_equal ExtInd, ea.index.class index = ea.index assert_equal 'I*', index.format assert_equal 2, index.frame index << [1,2] index << [3,4] assert_equal [[1,2],[3,4]], index.to_a Tempfile.open('test_readme_doc_for_ext_ind') do |file| file << [1,2,3].pack("IQS") file << [4,5,6].pack("IQS") file << [7,8,9].pack("IQS") file.flush index = ExtInd.new(file, :format => "IQS") assert_equal [4,5,6], index[1] assert_equal [[1,2,3],[4,5,6],[7,8,9]], index.to_a end end # # setup tests # def test_setup assert_equal ExtInd, @cls assert_equal 0, index.pos assert_equal 5, index.length assert_equal 4, index.frame_size assert_equal 8 * 2**20, index.buffer_size assert_equal [0], index.nil_value assert !index.cached? assert_nil index.cache assert_equal({:format => "I", :buffer_size => 8 * 2**20, :nil_value => [0], :cached => false}, index.options) tempfile.pos = 0 assert_equal array.pack(format), tempfile.read assert_equal tempfile.path, index.io.path end # # class read tests # def test_read_returns_the_index_file_in_frame assert_equal framed_array, ExtInd.read(tempfile.path) tempfile.pos = tempfile.length tempfile << [6].pack("I") tempfile.flush tempfile.pos = 0 assert_equal [1,2,3,4,5,6].pack("I*"), tempfile.read assert_equal [[1,2],[3,4],[5,6]], ExtInd.read(tempfile.path, :format => 'II') end # # class directive size tests # def test_directive_size_returns_the_number_of_bytes_to_pack_a_directive # @ | Moves to absolute position # not implemented assert_nil ExtInd.directive_size('@') # A | ASCII string (space padded, count is width) assert_equal 1, ["a"].pack("A").length assert_equal 1, ExtInd.directive_size('A') # a | ASCII string (null padded, count is width) assert_equal 1, ["a"].pack("a").length assert_equal 1, ExtInd.directive_size('a') # B | Bit string (descending bit order) assert_equal 1, ['a'].pack("B").length assert_equal 1, ExtInd.directive_size('B') # b | Bit string (ascending bit order) assert_equal 1, ['a'].pack("b").length assert_equal 1, ExtInd.directive_size('b') # C | Unsigned char assert_equal 1, [1].pack("C").length assert_equal 1, ExtInd.directive_size('C') # c | Char assert_equal 1, [1].pack("c").length assert_equal 1, ExtInd.directive_size('c') # D, d | Double-precision float, native format assert_equal 8, [1].pack("D").length assert_equal 8, ExtInd.directive_size('D') assert_equal 8, [1].pack("d").length assert_equal 8, ExtInd.directive_size('d') # E | Double-precision float, little-endian byte order assert_equal 8, [1].pack("E").length assert_equal 8, ExtInd.directive_size('E') # e | Single-precision float, little-endian byte order assert_equal 4, [1].pack("e").length assert_equal 4, ExtInd.directive_size('e') # F, f | Single-precision float, native format assert_equal 4, [1].pack("F").length assert_equal 4, ExtInd.directive_size('F') assert_equal 4, [1].pack("f").length assert_equal 4, ExtInd.directive_size('f') # G | Double-precision float, network (big-endian) byte order assert_equal 8, [1].pack("G").length assert_equal 8, ExtInd.directive_size('G') # g | Single-precision float, network (big-endian) byte order assert_equal 4, [1].pack("g").length assert_equal 4, ExtInd.directive_size('g') # H | Hex string (high nibble first) assert_equal 1, ['a'].pack("H").length assert_equal 1, ExtInd.directive_size('H') # h | Hex string (low nibble first) assert_equal 1, ['a'].pack("h").length assert_equal 1, ExtInd.directive_size('h') # I | Unsigned integer assert_equal 4, [1].pack("I").length assert_equal 4, ExtInd.directive_size('I') # i | Integer assert_equal 4, [1].pack("i").length assert_equal 4, ExtInd.directive_size('i') # L | Unsigned long assert_equal 4, [1].pack("L").length assert_equal 4, ExtInd.directive_size('L') # l | Long assert_equal 4, [1].pack("l").length assert_equal 4, ExtInd.directive_size('l') # M | Quoted printable, MIME encoding (see RFC2045) assert_equal 3, ['a'].pack("M").length assert_equal 3, ExtInd.directive_size('M') # m | Base64 encoded string assert_equal 5, ['a'].pack("m").length assert_equal 5, ExtInd.directive_size('m') # N | Long, network (big-endian) byte order assert_equal 4, [1].pack("N").length assert_equal 4, ExtInd.directive_size('N') # n | Short, network (big-endian) byte-order assert_equal 2, [1].pack("n").length assert_equal 2, ExtInd.directive_size('n') # P | Pointer to a structure (fixed-length string) assert_equal 4, ['a'].pack("P").length assert_equal 4, ExtInd.directive_size('P') # p | Pointer to a null-terminated string assert_equal 4, ['a'].pack("p").length assert_equal 4, ExtInd.directive_size('p') # Q, q | 64-bit number assert_equal 8, [1].pack("Q").length assert_equal 8, ExtInd.directive_size('Q') assert_equal 8, [1].pack("q").length assert_equal 8, ExtInd.directive_size('q') # S | Unsigned short assert_equal 2, [1].pack("S").length assert_equal 2, ExtInd.directive_size('S') # s | Short assert_equal 2, [1].pack("s").length assert_equal 2, ExtInd.directive_size('s') # U | UTF-8 assert_equal 1, [1].pack("U").length assert_equal 1, ExtInd.directive_size('U') # u | UU-encoded string assert_equal 6, ['a'].pack("u").length assert_equal 6, ExtInd.directive_size('u') # V | Long, little-endian byte order assert_equal 4, [1].pack("V").length assert_equal 4, ExtInd.directive_size('V') # v | Short, little-endian byte order assert_equal 2, [1].pack("v").length assert_equal 2, ExtInd.directive_size('v') # w | BER-compressed integer\fnm # not implemented assert_equal 1, [1].pack("w").length assert_equal 1, ExtInd.directive_size('w') # X | Back up a byte # not implemented assert_nil ExtInd.directive_size('X') # x | Null byte assert_equal 1, [nil].pack("x").length assert_equal 1, ExtInd.directive_size('x') # Z | Same as ``a'', except that null is added with * assert_equal 1, ['a'].pack("Z").length assert_equal 1, ExtInd.directive_size('Z') end # # initialize tests # def test_index_initialized_to_single_int_format_by_default index = @cls.new assert_equal 'I*', index.format assert_equal 1, index.frame assert_equal 4, index.frame_size assert_equal [0], index.nil_value assert !index.cached? assert_nil index.cache end def test_initialize_calculates_frame_and_frame_size_from_format { 'I' => [1, 4], 'II' => [2, 8], 'IQS' => [3, 14] }.each_pair do |format, expected| index = @cls.new(nil, :format => format) assert_equal expected, [index.frame, index.frame_size] assert_equal Array.new(expected.first, 0), index.nil_value end end def test_format_with_unknown_directive_raises_error assert_raise(ArgumentError) { @cls.new(nil, :format => 'x') } end def test_default_nil_value_is_calculated_according_to_frame index = @cls.new(nil, :format => "I") assert_equal [0], index.nil_value index = @cls.new(nil, :format => "II") assert_equal [0, 0], index.nil_value end def test_nil_value_can_be_provided_in_options index = @cls.new(nil, :nil_value => [8]) assert_equal [8], index.nil_value index = @cls.new(nil, :format => "II", :nil_value => [8,9]) assert_equal [8,9], index.nil_value end def test_nil_value_option_raises_error_if_out_of_frame assert_raise(ArgumentError) { @cls.new(nil, :nil_value => [8, 9]) } assert_raise(ArgumentError) { @cls.new(nil, :format => 'II', :nil_value => [0]) } end # # buffer_size test # def test_index_and_io_chunk_and_gap_size_are_calculated_relative_to_buffer_size index = @cls.new(nil, :buffer_size => 40000) assert_equal 40000, index.buffer_size assert_equal 4, index.frame_size assert_equal 10000, index.default_blksize assert_equal 40000, index.io.default_blksize index.buffer_size = 80000 assert_equal 20000, index.default_blksize assert_equal 80000, index.io.default_blksize end def test_buffer_size_is_io_default_blksize index = @cls.new index.io.default_blksize = 1000 assert_equal 1000, index.io.default_blksize assert_equal 1000, index.buffer_size end # # default_blksize test # def test_default_blksize_sets_io_default_blksize index = @cls.new assert_equal 4, index.frame_size index.default_blksize = 10000 assert_equal 10000, index.default_blksize assert_equal 40000, index.io.default_blksize end # # nil_value tests # def test_nil_value_documentation i = @cls.new assert_equal [0], i.nil_value assert_equal "\000\000\000\000", i.nil_value(false) end # # length test # def test_length_returns_io_length_divided_by_frame_size assert_equal 20, tempfile.length assert_equal 5, index.length tempfile.length = 4 assert_equal 1, index.length tempfile.length = 0 assert_equal 0, index.length end # # pos test # def test_pos_returns_io_pos_divided_by_frame_size assert_equal 0, index.io.pos assert_equal 0, index.pos index.io.pos = 4 assert_equal 1, index.pos index.io.pos = 20 assert_equal 5, index.pos end # # pos= test # def test_pos_set_documentation i = @cls[[1],[2],[3]] assert_equal 3, i.length i.pos = 2 assert_equal 2, i.pos i.pos = -1 assert_equal 2, i.pos end def test_pos_set_sets_io_pos_to_index_value_of_input_times_frame_size index.pos = 1 assert_equal 1, index.pos assert_equal 4, index.io.pos index.pos = -1 assert_equal 4, index.pos assert_equal 16, index.io.pos end def test_positions_can_be_set_beyond_the_index_length index.pos = 10 assert_equal 10, index.pos end def test_pos_set_raises_error_if_out_of_bounds assert_raise(ArgumentError) { index.pos = -6 } end # # readbytes test # def test_readbytes_documentation i = @cls[[1],[2],[3]] assert_equal [1,2,3], i.readbytes.unpack("I*") assert_equal [1], i.readbytes(1,0).unpack("I*") assert_equal [2,3], i.readbytes(10,1).unpack("I*") i.pos = 3 assert_equal "", i.readbytes assert_equal nil, i.readbytes(1) end def test_readbytes_returns_bytestring_for_n_and_pos assert_equal array.pack(format), index.readbytes(5,0) assert_equal array.pack(format), index.readbytes(5,-5) assert_equal [2,3].pack(format), index.readbytes(2,1) assert_equal array.pack(format), index.readbytes(10,0) assert_equal array.pack(format), index.readbytes(10,-5) index.pos = 0 assert_equal array.pack(format), index.readbytes index.pos = 3 assert_equal [4,5].pack(format), index.readbytes index.pos = 3 assert_equal [4].pack(format), index.readbytes(1) end def test_readbytes_returns_nil_if_n_is_specified_and_no_entries_can_be_read assert_nil index.readbytes(1,5) end def test_readbytes_returns_empty_string_if_n_is_nil_and_no_entries_can_be_read assert_equal "", index.readbytes(nil, 5) end def test_readbytes_raises_error_if_position_is_out_of_bounds assert_raise(ArgumentError) { index.readbytes(1,-6) } end def test_readbytes_behavior_is_like_io_behavior tempfile.pos = 20 assert_equal "", tempfile.read(nil) assert_nil tempfile.read(1) end # # unpack tests # def test_unpack_documentation assert_equal "I*", index.format assert_equal [1], index.unpack( [1].pack('I*') ) assert_equal [[1], [2], [3]], index.unpack( [1,2,3].pack('I*') ) assert_equal [], index.unpack("") end def test_unpack_unpacks_string_into_frames_using_format assert_equal [[1],[2],[3],[4],[5]], index.unpack(array.pack(format)) assert_equal [1], index.unpack([1].pack(format)) assert_equal [], index.unpack("") end # # read tests # def test_read_documentation i = @cls[[1],[2],[3]] assert_equal 0, i.pos assert_equal [[1],[2],[3]], i.read assert_equal [1], i.read(1,0) assert_equal [[2],[3]], i.read(10,1) i.pos = 3 assert_equal [], i.read assert_equal nil, i.read(1) end def test_read_returns_unpacked_array_for_n_and_pos assert_equal framed_array, index.read(5,0) assert_equal framed_array, index.read(5,-5) assert_equal [[2],[3]], index.read(2,1) assert_equal framed_array, index.read(10,0) assert_equal framed_array, index.read(10,-5) index.pos = 0 assert_equal framed_array, index.read index.pos = 3 assert_equal [[4],[5]], index.read index.pos = 3 assert_equal [4], index.read(1) end def test_read_returns_nil_if_n_is_specified_and_no_entries_can_be_read assert_nil index.read(1,5) end def test_read_returns_empty_array_if_n_is_nil_and_no_entries_can_be_read assert_equal [], index.read(nil, 5) end def test_read_raises_error_if_position_is_out_of_bounds assert_raise(ArgumentError) { index.read(1,-6) } end # # test unframed_write # def test_documentation i = @cls[] i.unframed_write([2,3], 1) i.pos = 0 i.unframed_write([1]) assert_equal [[1],[2],[3]], i.read(3, 0) end def test_unframed_write_unframed_writes_packed_array_to_io_at_pos_and_adjusts_io_length index = @cls.new index.unframed_write([1,2,3]) assert_equal 12, index.io.length assert_equal 12, index.io.pos index.io.pos = 0 assert_equal [1,2,3].pack("I*"), index.io.read index.unframed_write([-2], 1) assert_equal 12, index.io.length assert_equal 8, index.io.pos index.io.pos = 0 assert_equal [1,-2,3].pack("I*"), index.io.read end def test_unframed_write_pads_with_nil_value_if_position_is_past_length index = @cls.new nil, :nil_value => [8] assert_equal 0, index.length index.unframed_write([1,2,3], 2) index.io.pos = 0 assert_equal [8,8,1,2,3], index.io.read.unpack("I*") end def test_unframed_write_unframed_writes_nothing_with_empty_array assert_equal 20, index.io.length index.unframed_write([]) index.pos = 0 assert_equal 20, index.io.length index.unframed_write([], 0) index.pos = 0 assert_equal 20, index.io.length end def test_unframed_write_raises_error_if_array_is_not_in_frame index = @cls.new(nil, :format => "II") assert_raise(ArgumentError) { index.unframed_write([1]) } assert_raise(ArgumentError) { index.unframed_write([1,2,3]) } end # # mixed formats test # def test_read_handles_mixed_formats index = @cls.new tempfile, :format => "IQS" tempfile.pos = 0 a = [1,2,3].pack("IQS") b = [4,5,6].pack("IQS") c = [7,8,9].pack("IQS") tempfile << a + b + c index.pos=0 assert_equal [[1,2,3],[4,5,6],[7,8,9]], index.read index.pos=1 assert_equal [4,5,6], index.read(1) end def test_unframed_write_handles_mixed_formats index = @cls.new tempfile, :format => "IQS" a = [1,2,3].pack("IQS") b = [4,5,6].pack("IQS") c = [7,8,9].pack("IQS") d = [-4,-5,-6].pack("IQS") index.unframed_write([1,2,3,4,5,6,7,8,9]) tempfile.pos=0 assert_equal a+b+c, tempfile.read index.pos=1 index.unframed_write([-4,-5,-6]) tempfile.pos=0 assert_equal a+d+c, tempfile.read end # # numeric format range tests # unless defined?(SHRT_MIN) SHRT_MIN = -32768 SHRT_MAX = 32767 USHRT_MIN = 0 USHRT_MAX = 65535 LONG_MIN = -2147483648 LONG_MAX = 2147483647 ULONG_MIN = 0 ULONG_MAX = 4294967295 LLONG_MIN = -9223372036854775808 LLONG_MAX = 9223372036854775807 ULLONG_MIN = 0 ULLONG_MAX = 18446744073709551615 end def test_read_and_unframed_write_handles_full_numeric_range_for_numeric_formats # S handles an unsigned short i = @cls.new tempfile, :format => 'S' i.unframed_write([USHRT_MIN], 0) assert_equal [USHRT_MIN], i.read(1,0) i.unframed_write([USHRT_MAX], 0) assert_equal [USHRT_MAX], i.read(1,0) i.unframed_write([USHRT_MIN-1], 0) assert_equal [USHRT_MAX], i.read(1,0) # s handles an signed short i = @cls.new tempfile, :format => 's' i.unframed_write([SHRT_MIN], 0) assert_equal [SHRT_MIN], i.read(1,0) i.unframed_write([SHRT_MAX], 0) assert_equal [SHRT_MAX], i.read(1,0) i.unframed_write([SHRT_MIN], 0) assert_equal [SHRT_MIN], i.read(1,0) i.unframed_write([SHRT_MIN-1], 0) assert_equal [SHRT_MAX], i.read(1,0) # I,L handle an unsigned long ['I', 'L'].each do |format| i = @cls.new tempfile, :format => format i.unframed_write([ULONG_MIN], 0) assert_equal [ULONG_MIN], i.read(1,0) i.unframed_write([ULONG_MAX], 0) assert_equal [ULONG_MAX], i.read(1,0) i.unframed_write([ULONG_MIN-1], 0) assert_equal [ULONG_MAX], i.read(1,0) end # i,l handle an signed long ['i', 'l'].each do |format| i = @cls.new tempfile, :format => format i.unframed_write([LONG_MIN], 0) assert_equal [LONG_MIN], i.read(1,0) i.unframed_write([LONG_MAX], 0) assert_equal [LONG_MAX], i.read(1,0) i.unframed_write([LONG_MIN], 0) assert_equal [LONG_MIN], i.read(1,0) i.unframed_write([LONG_MIN-1], 0) assert_equal [LONG_MAX], i.read(1,0) end # Q handles an unsigned long long i = @cls.new tempfile, :format => 'Q' i.unframed_write([ULLONG_MIN], 0) assert_equal [ULLONG_MIN], i.read(1,0) i.unframed_write([ULLONG_MAX], 0) assert_equal [ULLONG_MAX], i.read(1,0) i.unframed_write([ULLONG_MIN-1], 0) assert_equal [ULLONG_MAX], i.read(1,0) # q handles an signed long long i = @cls.new tempfile, :format => 'q' i.unframed_write([LLONG_MIN], 0) assert_equal [LLONG_MIN], i.read(1,0) i.unframed_write([LLONG_MAX], 0) assert_equal [LLONG_MAX], i.read(1,0) i.unframed_write([LLONG_MIN], 0) assert_equal [LLONG_MIN], i.read(1,0) i.unframed_write([LLONG_MIN-1], 0) assert_equal [LLONG_MAX], i.read(1,0) end def test_read_and_unframed_write_cycle_numerics_beyond_natural_range # S handles an unsigned short i = @cls.new tempfile, :format => 'S' i.unframed_write([-USHRT_MAX], 0) assert_equal [1], i.read(1,0) i.unframed_write([USHRT_MIN-1], 0) assert_equal [USHRT_MAX], i.read(1,0) # s handles an signed short i = @cls.new tempfile, :format => 's' i.unframed_write([SHRT_MIN], 0) assert_equal [SHRT_MIN], i.read(1,0) i.unframed_write([SHRT_MIN-1], 0) assert_equal [SHRT_MAX], i.read(1,0) # I,L handle an unsigned long ['I', 'L'].each do |format| i = @cls.new tempfile, :format => format i.unframed_write([-ULONG_MAX], 0) assert_equal [1], i.read(1,0) i.unframed_write([ULONG_MIN-1], 0) assert_equal [ULONG_MAX], i.read(1,0) end # i,l handle an signed long ['i', 'l'].each do |format| i = @cls.new tempfile, :format => format i.unframed_write([LONG_MIN], 0) assert_equal [LONG_MIN], i.read(1,0) i.unframed_write([LONG_MIN-1], 0) assert_equal [LONG_MAX], i.read(1,0) end # Q handles an unsigned long long i = @cls.new tempfile, :format => 'Q' i.unframed_write([-ULLONG_MAX], 0) assert_equal [1], i.read(1,0) i.unframed_write([ULLONG_MIN-1], 0) assert_equal [ULLONG_MAX], i.read(1,0) # q handles an signed long long i = @cls.new tempfile, :format => 'q' i.unframed_write([LLONG_MIN], 0) assert_equal [LLONG_MIN], i.read(1,0) i.unframed_write([LLONG_MIN-1], 0) assert_equal [LLONG_MAX], i.read(1,0) end def test_numerics_cycle_up_to_the_unsigned_max_in_either_sign # S,s,I,i,L,l all can cycle up to the size of an ULONG ['S','s','I','i','L','l'].each do |format| i = @cls.new tempfile, :format => format assert_raise(RangeError) { i.unframed_write([-(ULONG_MAX+1)]) } assert_raise(RangeError) { i.unframed_write([(ULONG_MAX+1)]) } end # Q,q can cycle up to the size of an ULLONG ['Q', 'q'].each do |format| i = @cls.new tempfile, :format => format assert_raise(RangeError) { i.unframed_write([-(ULLONG_MAX+1)]) } assert_raise(RangeError) { i.unframed_write([(ULLONG_MAX+1)]) } end end ############################# # Array method documentation ############################# def test_AREF_doc io = StringIO.new [1,2,3,4,5].pack("I*") i = ExtInd.new(io, :format => 'I') assert_equal [3], i[2] assert_equal nil, i[6] assert_equal [[2],[3]], i[1,2] assert_equal [[2],[3],[4]], i[1..3] assert_equal [[5]], i[4..7] assert_equal nil, i[6..10] assert_equal [[3],[4],[5]], i[-3,3] assert_equal nil, i[5] assert_equal [], i[5,1] assert_equal [], i[5..10] end def test_ASET_doc io = StringIO.new "" i = ExtInd.new(io, :format => 'I') assert_equal [0], i.nil_value i[4] = [4] assert_equal [[0], [0], [0], [0], [4]], i.to_a i[0, 3] = [ [1], [2], [3] ] assert_equal [[1], [2], [3], [0], [4]], i.to_a i[1..2] = [ [5], [6] ] assert_equal [[1], [5], [6], [0], [4]], i.to_a i[0, 2] = [[7]] assert_equal [[7], [6], [0], [4]], i.to_a i[0..2] = [[8]] assert_equal [[8], [4]], i.to_a i[-1] = [9] assert_equal [[8], [9]], i.to_a i[1..-1] = nil assert_equal [[8]], i.to_a end ############################# # Modified Array methods tests ############################# def test_01_square_brackets # Changes: results returned in frame a = @cls[ 5, 4, 3, 2, 1 ] assert_instance_of(@cls, a) assert_equal(5, a.length) #5.times { |i| assert_equal(5-i, a[i]) } 5.times { |i| assert_equal([5-i], a[i]) } assert_nil(a[6]) end def test_PLUS # '+' # Changes: strings not allowed in ExtInd # replace 'cat' with 4, 'dog' with 5 assert_equal(@cls[], @cls[] + @cls[]) assert_equal(@cls[1], @cls[1] + @cls[]) assert_equal(@cls[1], @cls[] + @cls[1]) assert_equal(@cls[1, 1], @cls[1] + @cls[1]) #assert_equal(@cls['cat', 'dog', 1, 2, 3], %w(cat dog) + (1..3).to_a) assert_equal(@cls[4, 5, 1, 2, 3], @cls[4,5] + @cls[*(1..3).to_a]) # Additional: # check addition of Array to ExtInd (can't add ExtInd to Array) assert_equal(@cls[4, 5, 1, 2, 3], @cls[4,5] + [[1],[2],[3]]) assert_raise(TypeError) { [4,5] + @cls[*(1..3).to_a] } # check result is distinct from factors a = @cls[1] b = @cls[2] c = a + b assert_equal [[1],[2]], c.to_a a.concat [[1]] b.concat [[2]] c.concat [[3]] assert_equal [[1],[1]], a.to_a assert_equal [[2],[2]], b.to_a assert_equal [[1],[2],[3]], c.to_a end def test_LSHIFT # '<<' # Changes: inputs must be in frame and can't take # strings. And ExtInd can't accept itself as an entry a = @cls[] #a << 1 a << [1] assert_equal(@cls[1], a) #a << 2 << 3 a << [2] << [3] assert_equal(@cls[1, 2, 3], a) #a << nil << 'cat' #assert_equal(@cls[1, 2, 3, nil, 'cat'], a) #a << a #assert_equal(@cls[1, 2, 3, nil, 'cat', a], a) end def test_CMP # '<=>' # Changes: strings not allowed in ExtInd # replace 'cat' with 4, 'dog' with 5 assert_equal(-1, 4 <=> 5) assert_equal(0, @cls[] <=> @cls[]) assert_equal(0, @cls[1] <=> @cls[1]) #assert_equal(0, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'cat']) assert_equal(0, @cls[1, 2, 3] <=> @cls[1, 2, 3]) assert_equal(-1, @cls[] <=> @cls[1]) assert_equal(1, @cls[1] <=> @cls[]) #assert_equal(-1, @cls[1, 2, 3] <=> @cls[1, 2, 3, 'cat']) assert_equal(-1, @cls[1, 2, 3] <=> @cls[1, 2, 3, 4]) #assert_equal(1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3]) assert_equal(1, @cls[1, 2, 3, 4] <=> @cls[1, 2, 3]) #assert_equal(-1, @cls[1, 2, 3, 'cat'] <=> @cls[1, 2, 3, 'dog']) assert_equal(-1, @cls[1, 2, 3, 4] <=> @cls[1, 2, 3, 5]) #assert_equal(1, @cls[1, 2, 3, 'dog'] <=> @cls[1, 2, 3, 'cat']) assert_equal(1, @cls[1, 2, 3, 5] <=> @cls[1, 2, 3, 4]) end def test_AREF # '[]' # Changes: results returned in frame a = @cls[*(1..100).to_a] #assert_equal(1, a[0]) assert_equal([1], a[0]) #assert_equal(100, a[99]) assert_equal([100], a[99]) assert_nil(a[100]) #assert_equal(100, a[-1]) assert_equal([100], a[-1]) #assert_equal(99, a[-2]) assert_equal([99], a[-2]) #assert_equal(1, a[-100]) assert_equal([1], a[-100]) assert_nil(a[-101]) assert_nil(a[-101,0]) assert_nil(a[-101,1]) assert_nil(a[-101,-1]) assert_nil(a[10,-1]) # assert_equal(@cls[1], a[0,1]) assert_equal([[1]], a[0,1]) #assert_equal(@cls[100], a[99,1]) assert_equal([[100]], a[99,1]) #assert_equal(@cls[], a[100,1]) assert_equal([], a[100,1]) #assert_equal(@cls[100], a[99,100]) assert_equal([[100]], a[99,100]) #assert_equal(@cls[100], a[-1,1]) assert_equal([[100]], a[-1,1]) #assert_equal(@cls[99], a[-2,1]) assert_equal([[99]], a[-2,1]) #assert_equal(@cls[], a[-100,0]) assert_equal([], a[-100,0]) #assert_equal(@cls[1], a[-100,1]) assert_equal([[1]], a[-100,1]) assert_equal(@cls[10, 11, 12], a[9, 3]) assert_equal(@cls[10, 11, 12], a[-91, 3]) # assert_equal(@cls[1], a[0..0]) assert_equal([[1]], a[0..0]) # assert_equal(@cls[100], a[99..99]) assert_equal([[100]], a[99..99]) # assert_equal(@cls[], a[100..100]) assert_equal([], a[100..100]) # assert_equal(@cls[100], a[99..200]) assert_equal([[100]], a[99..200]) # assert_equal(@cls[100], a[-1..-1]) assert_equal([[100]], a[-1..-1]) # assert_equal(@cls[99], a[-2..-2]) assert_equal([[99]], a[-2..-2]) assert_equal(@cls[10, 11, 12], a[9..11]) assert_equal(@cls[10, 11, 12], a[-91..-89]) assert_nil(a[10, -3]) # Ruby 1.8 feature change: # Array#[size..x] returns [] instead of nil. #assert_nil(a[10..7]) assert_equal [], a[10..7] assert_raise(TypeError) {a['cat']} end def test_ASET # '[]=' # Changes: values and results specified in frame # added mirror tests to ensure testing using array # and index inputs # -- pair -- a = @cls[*(0..99).to_a] #assert_equal(0, a[0] = 0) assert_equal([0], a[0] = [0]) assert_equal(@cls[0] + @cls[*(1..99).to_a], a) a = @cls[*(0..99).to_a] b = @cls[0] assert_equal(b, a[0] = b) assert_equal(@cls[0] + @cls[*(1..99).to_a], a) # -- pair -- a = @cls[*(0..99).to_a] #assert_equal(0, a[10,10] = 0) assert_equal([[0]], a[10,10] = [[0]]) assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] b = @cls[0] assert_equal(b, a[10,10] = b) assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) # -- pair -- a = @cls[*(0..99).to_a] #assert_equal(0, a[-1] = 0) assert_equal([0], a[-1] = [0]) assert_equal(@cls[*(0..98).to_a] + @cls[0], a) a = @cls[*(0..99).to_a] b = @cls[0] assert_equal(b, a[-1] = b) assert_equal(@cls[*(0..98).to_a] + @cls[0], a) # -- pair -- a = @cls[*(0..99).to_a] #assert_equal(0, a[-10, 10] = 0) assert_equal([[0]], a[-10, 10] = [[0]]) assert_equal(@cls[*(0..89).to_a] + @cls[0], a) a = @cls[*(0..99).to_a] b = @cls[0] assert_equal(b, a[-10, 10] = b) assert_equal(@cls[*(0..89).to_a] + @cls[0], a) # -- pair -- a = @cls[*(0..99).to_a] #assert_equal(0, a[0,1000] = 0) assert_equal([[0]], a[0,1000] = [[0]]) assert_equal(@cls[0] , a) a = @cls[*(0..99).to_a] b = @cls[0] assert_equal(b, a[0,1000] = b) assert_equal(@cls[0] , a) # -- pair -- a = @cls[*(0..99).to_a] #assert_equal(0, a[10..19] = 0) assert_equal([[0]], a[10..19] = [[0]]) assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] b = @cls[0] assert_equal(b, a[10..19] = b) assert_equal(@cls[*(0..9).to_a] + @cls[0] + @cls[*(20..99).to_a], a) # -- pair -- # Changes: cannot take strings, # replace a,b,c with 1001, 1002, 10003 #b = @cls[*%w( a b c )] b = @cls[1001, 1002, 10003] c = [[1001],[1002],[10003]] a = @cls[*(0..99).to_a] assert_equal(b, a[0,1] = b) assert_equal(b + @cls[*(1..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(c, a[0,1] = c) assert_equal(b + @cls[*(1..99).to_a], a) # -- pair -- a = @cls[*(0..99).to_a] assert_equal(b, a[10,10] = b) assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(c, a[10,10] = c) assert_equal(@cls[*(0..9).to_a] + c + @cls[*(20..99).to_a], a) # -- pair -- a = @cls[*(0..99).to_a] assert_equal(b, a[-1, 1] = b) assert_equal(@cls[*(0..98).to_a] + b, a) a = @cls[*(0..99).to_a] assert_equal(c, a[-1, 1] = c) assert_equal(@cls[*(0..98).to_a] + c, a) # -- pair -- a = @cls[*(0..99).to_a] assert_equal(b, a[-10, 10] = b) assert_equal(@cls[*(0..89).to_a] + b, a) a = @cls[*(0..99).to_a] assert_equal(c, a[-10, 10] = c) assert_equal(@cls[*(0..89).to_a] + c, a) # -- pair -- a = @cls[*(0..99).to_a] assert_equal(b, a[0,1000] = b) assert_equal(b , a) a = @cls[*(0..99).to_a] assert_equal(c, a[0,1000] = c) assert_equal(c , a.to_a) # -- pair -- a = @cls[*(0..99).to_a] assert_equal(b, a[10..19] = b) assert_equal(@cls[*(0..9).to_a] + b + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(c, a[10..19] = c) assert_equal(@cls[*(0..9).to_a] + c + @cls[*(20..99).to_a], a) # Ruby 1.8 feature change: # assigning nil does not remove elements. =begin a = @cls[*(0..99).to_a] assert_equal(nil, a[0,1] = nil) assert_equal(@cls[*(1..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[10,10] = nil) assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[-1, 1] = nil) assert_equal(@cls[*(0..98).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[-10, 10] = nil) assert_equal(@cls[*(0..89).to_a], a) a = @cls[*(0..99).to_a] assert_equal(nil, a[0,1000] = nil) assert_equal(@cls[] , a) a = @cls[*(0..99).to_a] assert_equal(nil, a[10..19] = nil) assert_equal(@cls[*(0..9).to_a] + @cls[*(20..99).to_a], a) =end # Changes: should have @cls in definition a = @cls[1, 2, 3] a[1, 0] = a #assert_equal([1, 1, 2, 3, 2, 3], a) assert_equal(@cls[1, 1, 2, 3, 2, 3], a) a = @cls[1, 2, 3] a[-1, 0] = a #assert_equal([1, 2, 1, 2, 3, 3], a) assert_equal(@cls[1, 2, 1, 2, 3, 3], a) # Additional: # -- test self insertions -- a = @cls[1, 2, 3] a[1, 3] = a assert_equal(@cls[1,1,2,3], a) a = @cls[1, 2, 3] a[3, 3] = a assert_equal(@cls[1,2,3,1,2,3], a) a = @cls[1, 2, 3] a[4, 3] = a assert_equal(@cls[1,2,3,0,1,2,3], a) # -- test insertions where padding is necessary -- # -- pair -- a = @cls[1,2,3, {:nil_value => [8]}] b = @cls[1001, 1002, 10003, {:nil_value => [8]}] assert_equal(b, a[4, 3] = b) assert_equal(@cls[1,2,3,8,1001,1002,10003, {:nil_value => [8]}], a.to_a) a = @cls[1,2,3, {:nil_value => [8]}] c = [[1001], [1002], [10003]] assert_equal(c, a[4, 3] = c) assert_equal(@cls[1,2,3,8,1001,1002,10003, {:nil_value => [8]}], a) # -- pair -- a = @cls[1,2,3, {:nil_value => [8]}] b = @cls[1001, 1002, 10003, {:nil_value => [8]}] assert_equal(b, a[4, 1] = b) assert_equal(@cls[1,2,3,8,1001,1002,10003, {:nil_value => [8]}], a) a = @cls[1,2,3, {:nil_value => [8]}] c = [[1001], [1002], [10003]] assert_equal(c, a[4, 1] = c) assert_equal(@cls[1,2,3,8,1001,1002,10003, {:nil_value => [8]}], a) # -- test insertions with nils -- # -- pair -- a = @cls[1,2,3] b = @cls[1001, nil, nil, 10003] assert_equal(b, a[1, 3] = b) assert_equal(@cls[1,1001,0,0,10003], a) a = @cls[1,2,3] c = [[1001], nil, nil, [10003]] assert_equal(c, a[1, 3] = c) assert_equal(@cls[1,1001,0,0,10003], a) # -- insert beyond end of index, with inconsistent range -- # first check the array behavior, then assert the same with ExtInd a = (0..5).to_a assert_equal([11,12,13], a[11..12] = [11,12,13]) assert_equal((0..5).to_a + [nil,nil,nil,nil,nil] + (11..13).to_a, a) # -- pair -- a = @cls[*(0..5).to_a] b = @cls[11,12,13] assert_equal(b, a[11..12] = b) assert_equal(@cls[*(0..5).to_a] + @cls[0,0,0,0,0] + b, a) a = @cls[*(0..5).to_a] c = [[11],[12],[13]] assert_equal(c, a[11..12] = c) assert_equal(@cls[*(0..5).to_a] + @cls[0,0,0,0,0] + c, a) end def test_at # Chagnes: values must be in frame a = @cls[*(0..99).to_a] # assert_equal(0, a.at(0)) assert_equal([0], a.at(0)) # assert_equal(10, a.at(10)) assert_equal([10], a.at(10)) # assert_equal(99, a.at(99)) assert_equal([99], a.at(99)) assert_equal(nil, a.at(100)) # assert_equal(99, a.at(-1)) assert_equal([99], a.at(-1)) # assert_equal(0, a.at(-100)) assert_equal([0], a.at(-100)) assert_equal(nil, a.at(-101)) assert_raise(TypeError) { a.at('cat') } end def test_concat # Changes: ExtInd does not support Array/ExtInd nesting assert_equal(@cls[1, 2, 3, 4], @cls[1, 2].concat(@cls[3, 4])) assert_equal(@cls[1, 2, 3, 4], @cls[].concat(@cls[1, 2, 3, 4])) assert_equal(@cls[1, 2, 3, 4], @cls[1, 2, 3, 4].concat(@cls[])) assert_equal(@cls[], @cls[].concat(@cls[])) #assert_equal(@cls[@cls[1, 2], @cls[3, 4]], @cls[@cls[1, 2]].concat(@cls[@cls[3, 4]])) # Changes: should have @cls in definition a = @cls[1, 2, 3] a.concat(a) #assert_equal([1, 2, 3, 1, 2, 3], a) assert_equal(@cls[1, 2, 3, 1, 2, 3], a) end def test_each # Changes: cannot take strings, # replace (ant bat cat dog) with [1,2,3,4] #a = @cls[*%w( ant bat cat dog )] a = @cls[*(1..4).to_a] i = 0 a.each { |e| assert_equal(a[i], e) i += 1 } assert_equal(4, i) a = @cls[] i = 0 a.each { |e| assert_equal(a[i], e) i += 1 } assert_equal(0, i) assert_equal(a, a.each {}) end def test_each_index # Changes: cannot take strings, # replace (ant bat cat dog) with [1,2,3,4] #a = @cls[*%w( ant bat cat dog )] a = @cls[*(1..4).to_a] i = 0 a.each_index { |ind| assert_equal(i, ind) i += 1 } assert_equal(4, i) a = @cls[] i = 0 a.each_index { |ind| assert_equal(i, ind) i += 1 } assert_equal(0, i) assert_equal(a, a.each_index {}) end def test_eql? assert(@cls[].eql?(@cls[])) assert(@cls[1].eql?(@cls[1])) assert(@cls[1, 1, 2, 2].eql?(@cls[1, 1, 2, 2])) # Changes: all values are treated according to the format # so these floats are converted to ints and the ExtInds # are equal #assert(!@cls[1.0, 1.0, 2.0, 2.0].eql?(@cls[1, 1, 2, 2])) assert(@cls[1.0, 1.0, 2.0, 2.0].eql?(@cls[1, 1, 2, 2])) end def test_first # Changes: must be in frame #assert_equal(3, @cls[3, 4, 5].first) assert_equal([3], @cls[3, 4, 5].first) assert_equal(nil, @cls[].first) end def test_last # Changes: must be in frame assert_equal(nil, @cls[].last) # assert_equal(1, @cls[1].last) assert_equal([1], @cls[1].last) # assert_equal(99, @cls[*(3..99).to_a].last) assert_equal([99], @cls[*(3..99).to_a].last) end def test_to_a a = @cls[ 1, 2, 3 ] # Changes: can't do this comparison by object id #a_id = a.__id__ #assert_equal(a, a.to_a) assert_equal [[1],[2],[3]], a.to_a #assert_equal(a_id, a.to_a.__id__) end ############################# # Additional Array methods tests ############################# # # ASET tests # def test_ASET_raises_error_if_input_is_not_in_frame a = @cls.new assert_raise(ArgumentError) { a[0] = 1 } assert_raise(ArgumentError) { a[0,1] = [1] } assert_raise(ArgumentError) { a[0,1] = [[1,2]] } end def test_ASET_raises_error_if_input_is_index_with_different_attributes a = @cls.new(nil, :format => "I") b = @cls.new(nil, :format => "II") assert_raise(ArgumentError) { a[0,1] = b } end ####################### # Benchmark tests ####################### # # benchmarks # def index_bm_test(mode, length=20, array=nil, &block) benchmark_test(length) do |x| ['I', 'IIIIIIIIII'].each do |format| unless array array = [] 1.upto(10000) {|i| array << i } end Tempfile.open('benchmark') do |file| file << array.pack('I*') begin index = @cls.new(file, :format => format) yield(x, format, index) ensure index.close if index end end end yield(x, "array reference", array) end array end def test_element_reference_speed_for_index n = 100 index_bm_test('r') do |x, type, index| puts type x.report("#{n}kx [index]") { (n*1000).times { index[1000] } } x.report("#{n}kx [range]") { (n*1000).times { index[1000..1000] } } x.report("#{n}kx [s,1]") { (n*1000).times { index[1000, 1] } } x.report("#{n}kx [s,10]") { (n*1000).times { index[1000, 10] } } x.report("#{n}kx [s,100]") { (n*1000).times { index[1000, 100] } } puts end end def test_element_assignment_speed_for_index index_bm_test('r+') do |x, type, index| puts type n = 10 obj = Array.new(index.respond_to?(:frame) ? index.frame : 1, 0) x.report("#{n}kx [index]=") do (n*1000).times { index[1000] = obj} end x.report("#{n}kx [range]=") do (n*1000).times { index[1000..1000] = [obj] } end x.report("#{n}kx [s,1]=") do (n*1000).times { index[1000,1] = [obj] } end puts end end end class Hold def btest_each_speed indexbm_test('r') do |x, type, index| x.report("10x #{type} - cs100k") { 10.times { index.each {|e|} } } #x.report("10x #{type} - cs100") { 10.times { index.each(0,index.length, 100) {|e|} } } end end def btest_push_speed indexbm_test('r+') do |x, type, index| obj = Array.new(index.frame, 0) x.report("10kx #{type} index=") do 10000.times { index << obj} end end end def btest_sort_speed benchmark_test(20) do |x| n = 1 unsorted, sorted = sort_arrays(n*10**6) x.report("#{n}M array sort") do unsorted.sort end index = setup_index({:default_blksize => 100000}, unsorted) x.report("#{n}M index sort") do index.sort.close end index.close index = setup_index({:frame => 2, :default_blksize => 100000}, unsorted) x.report("#{n}M frame with block") do index.sort {|a, b| b <=> a }.close end index.close sindex = setup_sindex({:default_blksize => 100000}, unsorted) x.report("#{n}M sindex sort") do sindex.sort.close end sindex.close # cannot finish... not sure why # sindex = setup_sindex({:frame => 2, :default_blksize => 100000}, unsorted) # x.report("#{n}M frame with block") do # sindex.sort {|a, b| b <=> a }.close # end # sindex.close end end end