Skip to content

Commit

Permalink
Added unittests to replicate issue jstedfast#395
Browse files Browse the repository at this point in the history
  • Loading branch information
Luigi Grilli committed May 15, 2018
1 parent c188903 commit e63020d
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 72 deletions.
86 changes: 44 additions & 42 deletions MimeKit/MimeParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public partial class MimeParser : IEnumerable<MimeMessage>
const int PadSize = 4;

// I/O buffering
readonly byte[] input = new byte[ReadAheadSize + BlockSize + PadSize];
byte[] input = new byte[ReadAheadSize + BlockSize + PadSize];
const int inputStart = ReadAheadSize;
int inputIndex = ReadAheadSize;
int inputEnd = ReadAheadSize;
Expand All @@ -135,8 +135,8 @@ public partial class MimeParser : IEnumerable<MimeMessage>
long headerOffset;
int headerIndex;

readonly List<Boundary> bounds;
readonly List<Header> headers;
readonly List<Boundary> bounds = new List<Boundary>();
readonly List<Header> headers = new List<Header>();

MimeParserState state;
MimeFormat format;
Expand Down Expand Up @@ -217,45 +217,42 @@ public MimeParser (ParserOptions options, Stream stream, bool persistent = false
{
}

/// <summary>
/// Initializes a new instance of the <see cref="MimeKit.MimeParser"/> class.
/// </summary>
/// <remarks>
/// <para>Creates a new <see cref="MimeParser"/> that will parse the specified stream.</para>
/// <para>If <paramref name="persistent"/> is <c>true</c> and <paramref name="stream"/> is seekable, then
/// the <see cref="MimeParser"/> will not copy the content of <see cref="MimePart"/>s into memory. Instead,
/// it will use a <see cref="MimeKit.IO.BoundStream"/> to reference a substream of <paramref name="stream"/>.
/// This has the potential to not only save memory usage, but also improve <see cref="MimeParser"/>
/// performance.</para>
/// <para>It should be noted, however, that disposing <paramref name="stream"/> will make it impossible
/// for <see cref="MimeContent"/> to read the content.</para>
/// </remarks>
/// <param name="options">The parser options.</param>
/// <param name="stream">The stream to parse.</param>
/// <param name="format">The format of the stream.</param>
/// <param name="persistent"><c>true</c> if the stream is persistent; otherwise <c>false</c>.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="stream"/> is <c>null</c>.</para>
/// </exception>
public MimeParser (ParserOptions options, Stream stream, MimeFormat format, bool persistent = false)
{
bounds = new List<Boundary> ();
headers = new List<Header> ();

SetStream (options, stream, format, persistent);
}

/// <summary>
/// Gets a value indicating whether the parser has reached the end of the input stream.
/// </summary>
/// <remarks>
/// Gets a value indicating whether the parser has reached the end of the input stream.
/// </remarks>
/// <value><c>true</c> if this parser has reached the end of the input stream;
/// otherwise, <c>false</c>.</value>
public bool IsEndOfStream {
/// <summary>
/// Initializes a new instance of the <see cref="MimeKit.MimeParser"/> class.
/// </summary>
/// <remarks>
/// <para>Creates a new <see cref="MimeParser"/> that will parse the specified stream.</para>
/// <para>If <paramref name="persistent"/> is <c>true</c> and <paramref name="stream"/> is seekable, then
/// the <see cref="MimeParser"/> will not copy the content of <see cref="MimePart"/>s into memory. Instead,
/// it will use a <see cref="MimeKit.IO.BoundStream"/> to reference a substream of <paramref name="stream"/>.
/// This has the potential to not only save memory usage, but also improve <see cref="MimeParser"/>
/// performance.</para>
/// <para>It should be noted, however, that disposing <paramref name="stream"/> will make it impossible
/// for <see cref="MimeContent"/> to read the content.</para>
/// </remarks>
/// <param name="options">The parser options.</param>
/// <param name="stream">The stream to parse.</param>
/// <param name="format">The format of the stream.</param>
/// <param name="persistent"><c>true</c> if the stream is persistent; otherwise <c>false</c>.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="options"/> is <c>null</c>.</para>
/// <para>-or-</para>
/// <para><paramref name="stream"/> is <c>null</c>.</para>
/// </exception>
public MimeParser(ParserOptions options, Stream stream, MimeFormat format, bool persistent = false)
{
SetStream(options, stream, format, persistent);
}

/// <summary>
/// Gets a value indicating whether the parser has reached the end of the input stream.
/// </summary>
/// <remarks>
/// Gets a value indicating whether the parser has reached the end of the input stream.
/// </remarks>
/// <value><c>true</c> if this parser has reached the end of the input stream;
/// otherwise, <c>false</c>.</value>
public bool IsEndOfStream {
get { return state == MimeParserState.Eos; }
}

Expand Down Expand Up @@ -423,6 +420,11 @@ public void SetStream (Stream stream, bool persistent = false)
SetStream (ParserOptions.Default, stream, MimeFormat.Default, persistent);
}

internal void SetBlockSize(int size)
{
input = new byte[ReadAheadSize + size + PadSize];
}

#if DEBUG
static string ConvertToCString (byte[] buffer, int startIndex, int length)
{
Expand Down
73 changes: 43 additions & 30 deletions UnitTests/MimeParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -601,40 +601,53 @@ static void AssertJwzMboxResults (string actual, Stream output)
} while (true);
}

[Test]
public void TestJwzMbox ()
[TestCase(16)]
[TestCase(32)]
[TestCase(64)]
[TestCase(128)]
[TestCase(256)]
[TestCase(512)]
[TestCase(1024)]
[TestCase(2048)]
[TestCase(4096)]
[TestCase(8192)]
public void TestJwzMbox (int blockSize)
{
var options = FormatOptions.Default.Clone ();
var output = new MemoryBlockStream ();
var builder = new StringBuilder ();

options.NewLineFormat = NewLineFormat.Unix;

using (var stream = File.OpenRead (Path.Combine (MboxDataDir, "jwz.mbox.txt"))) {
var parser = new MimeParser (stream, MimeFormat.Mbox);
int count = 0;

while (!parser.IsEndOfStream) {
var message = parser.ParseMessage ();

builder.AppendFormat ("{0}", parser.MboxMarker).Append ('\n');
if (message.From.Count > 0)
builder.AppendFormat ("From: {0}", message.From).Append ('\n');
if (message.To.Count > 0)
builder.AppendFormat ("To: {0}", message.To).Append ('\n');
builder.AppendFormat ("Subject: {0}", message.Subject).Append ('\n');
builder.AppendFormat ("Date: {0}", DateUtils.FormatDate (message.Date)).Append ('\n');
DumpMimeTree (builder, message);
builder.Append ('\n');

var marker = Encoding.UTF8.GetBytes ((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n");
output.Write (marker, 0, marker.Length);
message.WriteTo (options, output);
count++;
}
}

AssertJwzMboxResults (builder.ToString (), output);
var builder = new StringBuilder();
var output = new MemoryBlockStream();

using (var stream = File.OpenRead(Path.Combine(MboxDataDir, "jwz.mbox.txt")))
{
var parser = new MimeParser(stream, MimeFormat.Mbox);
int count = 0;

parser.SetBlockSize(blockSize);

while (!parser.IsEndOfStream)
{
var message = parser.ParseMessage();

builder.AppendFormat("{0}", parser.MboxMarker).Append('\n');
if (message.From.Count > 0)
builder.AppendFormat("From: {0}", message.From).Append('\n');
if (message.To.Count > 0)
builder.AppendFormat("To: {0}", message.To).Append('\n');
builder.AppendFormat("Subject: {0}", message.Subject).Append('\n');
builder.AppendFormat("Date: {0}", DateUtils.FormatDate(message.Date)).Append('\n');
DumpMimeTree(builder, message);
builder.Append('\n');

var marker = Encoding.UTF8.GetBytes((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n");
output.Write(marker, 0, marker.Length);
message.WriteTo(options, output);
count++;
}
}

AssertJwzMboxResults(builder.ToString(), output);
}

[Test]
Expand Down

0 comments on commit e63020d

Please sign in to comment.