#!/usr/bin/env ruby #-- # Copyright (C) 2002, 2004 Matt Armstrong. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN # NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # require 'tests/testbase' require 'rmail/parser/multipart' class TestRMailParserMultipart < TestBase # FIXME: TODO # - test \n -vs- \r\n -vs \r end of line characters def parse_multipart(filename, boundary, chunk_size, expected_results) assembled = nil data_as_file(filename) { |f| parser = RMail::Parser::MultipartReader.new(f, boundary) parser.chunk_size = chunk_size results = [] loop { chunk = parser.read(nil) puts "test: got part #{chunk.inspect}" if $DEBUG delimiter = parser.delimiter puts "test: got delimiter #{delimiter.inspect}" if $DEBUG if chunk assembled ||= '' assembled << chunk end if delimiter assembled ||= '' assembled << delimiter end results << [ chunk, parser.preamble?, parser.epilogue?, delimiter ] unless parser.next_part break end } if expected_results != results puts "\nfailure for chunks size #{chunk_size.to_s}" pp expected_results pp results end assert_equal(expected_results, results, "\nfile #{filename}\nchunk_size #{chunk_size}\n") } filedata = data_as_file(filename) { |f| f.read(nil) } filedata = nil if filedata.empty? assert_equal(filedata, assembled, "data loss while reassembling file data") end def for_all_chunk_sizes(filename, boundary, expected_results) size = File.stat(data_filename(filename)).size (size + 10).downto(1) { |chunk_size| parse_multipart(filename, boundary, chunk_size, expected_results) } end def test_multipart_data_01 for_all_chunk_sizes('multipart/data.1', 'aa', [ [ "preamble", true, false, "\n--aa\n" ], [ "part1", false, false, "\n--aa--\n" ], [ "epilogue\n", false, true, nil ] ]) end def test_multipart_data_02 for_all_chunk_sizes('multipart/data.2', 'aa', [ [ nil, true, false, "\n--aa\n" ], [ nil, false, false, "\n--aa--\n" ], [ "\n", false, true, nil ] ]) end def test_multipart_data_03 for_all_chunk_sizes('multipart/data.3', 'aa', [ [ nil, true, false, "--aa\n" ], [ nil, false, false, "--aa--\n" ], [ "", false, true, nil ] ]) end def test_multipart_data_04 for_all_chunk_sizes('multipart/data.4', 'aa', [ [ "preamble", true, false, "\n--aa--\n" ], [ "epilogue\n", false, true, nil ] ]) end def test_multipart_data_05 for_all_chunk_sizes('multipart/data.5', 'aa', [ [ nil, true, false, "--aa--\n" ], [ "", false, true, nil ] ]) end def test_multipart_data_06 for_all_chunk_sizes('multipart/data.6', 'aa', [ [ nil, true, false, "\n--aa--\n" ], [ "", false, true, nil ] ]) end def test_multipart_data_07 for_all_chunk_sizes('multipart/data.7', 'aa', [ [ "preamble\n", true, false, "\n--aa--\n" ], [ "", false, true, nil ] ]) end def test_multipart_data_08 for_all_chunk_sizes('multipart/data.8', 'aa', [ [ "preamble", true, false, "\n--aa\n" ], [ "part1", false, false, "\n--aa--\n" ], [ "epilogue", false, true, nil ] ]) end def test_multipart_data_09 for_all_chunk_sizes('multipart/data.9', 'aa', [ [ nil, true, false, "\n--aa\n" ], [ nil, false, false, "\n--aa--" ], [ "", false, true, nil ] ]) end def test_multipart_data_10 for_all_chunk_sizes('multipart/data.10', 'aa', [ [ nil, true, false, "--aa--" ], [ "", false, true, nil ] ]) end def test_multipart_data_11 for_all_chunk_sizes('multipart/data.11', 'aa', [ [ "preamble", true, false, "\n--aa\t\n" ], [ "part1", false, false, "\n--aa \n" ], [ "part2", false, false, "\n--aa \t \t\n" ], [ "part3", false, false, "\n--aa-- \n" ], [ "epilogue\n", false, true, nil ] ]) end def test_multipart_data_12 # The following from RFC2046 indicates that a delimiter existing # as the prefix of a line is sufficient for the line to be # considered a delimiter -- even if there is stuff after the # boundary: # # NOTE TO IMPLEMENTORS: Boundary string comparisons must # compare the boundary value with the beginning of each # candidate line. An exact match of the entire candidate line # is not required; it is sufficient that the boundary appear in # its entirety following the CRLF. # # However, messages in the field do not seem to comply with this # (namely, Eudora), so we parse more strictly. for_all_chunk_sizes('multipart/data.12', 'aa', [[ "preamble\n--aaZ\npart1\n--aa notignored\npart2\n--aa \t \tnotignored\npart3\n--aa--notignored\nepilogue\n", true, false, nil ]]) end def test_multipart_data_13 for_all_chunk_sizes('multipart/data.13', 'aa', [ [ "preamble", true, false, "\n--aa\n" ], [ "part1\n", false, false, nil ] ]) end def test_multipart_data_14 for_all_chunk_sizes('multipart/data.14', 'aa', [ [ "preamble", true, false, "\n--aa\n" ], [ "part1", false, false, nil ] ]) end def test_multipart_data_15 for_all_chunk_sizes('multipart/data.15', 'aa', [ [ "preamble\nline1\nline2\n", true, false, nil ] ]) end def test_multipart_data_16 for_all_chunk_sizes('multipart/data.16', 'aa', [ [ "preamble\nline1\nline2", true, false, nil ] ]) end def test_multipart_data_17 for_all_chunk_sizes('multipart/data.17', 'aa', [ [ nil, true, false, nil ] ]) end def test_s_new data_as_file('multipart/data.1') { |f| p = RMail::Parser::MultipartReader.new(f, "foo") assert_kind_of(RMail::Parser::MultipartReader, p) } end end