Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 8c55a96

Browse files
committed
Add tests for DeflateStream and GZipStream
1 parent ffdea34 commit 8c55a96

File tree

2 files changed

+223
-20
lines changed

2 files changed

+223
-20
lines changed

src/System.IO.Compression/tests/DeflateStreamTests.cs

Lines changed: 217 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
using System.Reflection;
4+
using System.Collections.Generic;
55
using System.Text;
6+
using System.Threading;
67
using System.Threading.Tasks;
78
using Xunit;
89

@@ -191,20 +192,6 @@ public async Task DecompressFailsWithRealGzStream()
191192
}
192193
}
193194

194-
[Fact]
195-
public void NullBaseStreamThrows()
196-
{
197-
Assert.Throws<ArgumentNullException>(() =>
198-
{
199-
var deflate = new DeflateStream(null, CompressionMode.Decompress);
200-
});
201-
202-
Assert.Throws<ArgumentNullException>(() =>
203-
{
204-
var deflate = new DeflateStream(null, CompressionMode.Compress);
205-
});
206-
}
207-
208195
[Fact]
209196
public void DisposedBaseStreamThrows()
210197
{
@@ -330,6 +317,23 @@ private static void TestCtor(CompressionLevel level, bool? leaveOpen = null)
330317
}
331318
}
332319

320+
[Fact]
321+
public void CtorArgumentValidation()
322+
{
323+
Assert.Throws<ArgumentNullException>(() => new DeflateStream(null, CompressionLevel.Fastest));
324+
Assert.Throws<ArgumentNullException>(() => new DeflateStream(null, CompressionMode.Decompress));
325+
Assert.Throws<ArgumentNullException>(() => new DeflateStream(null, CompressionMode.Compress));
326+
327+
Assert.Throws<ArgumentNullException>(() => new DeflateStream(null, CompressionLevel.Fastest, true));
328+
Assert.Throws<ArgumentNullException>(() => new DeflateStream(null, CompressionMode.Decompress, false));
329+
Assert.Throws<ArgumentNullException>(() => new DeflateStream(null, CompressionMode.Compress, true));
330+
331+
Assert.Throws<ArgumentException>(() => new DeflateStream(new MemoryStream(), (CompressionMode)42));
332+
Assert.Throws<ArgumentException>(() => new DeflateStream(new MemoryStream(), (CompressionMode)43, true));
333+
334+
Assert.Throws<ArgumentException>(() => new DeflateStream(new MemoryStream(new byte[1], writable: false), CompressionLevel.Optimal));
335+
}
336+
333337
[Fact]
334338
public async Task Flush()
335339
{
@@ -353,7 +357,6 @@ public void FlushFailsAfterDispose()
353357
[Fact]
354358
public async Task FlushAsyncFailsAfterDispose()
355359
{
356-
357360
var ms = new MemoryStream();
358361
var ds = new DeflateStream(ms, CompressionMode.Compress);
359362
ds.Dispose();
@@ -376,7 +379,6 @@ public void TestSeekMethodsDecompress()
376379
Assert.Throws<NotSupportedException>(delegate { long value = zip.Position; });
377380
Assert.Throws<NotSupportedException>(delegate { zip.Position = 100L; });
378381
Assert.Throws<NotSupportedException>(delegate { zip.SetLength(100L); });
379-
//Should we try all the enums? doesn't seem necessary
380382
Assert.Throws<NotSupportedException>(delegate { zip.Seek(100L, SeekOrigin.Begin); });
381383
}
382384

@@ -392,8 +394,205 @@ public void TestSeekMethodsCompress()
392394
Assert.Throws<NotSupportedException>(delegate { long value = zip.Position; });
393395
Assert.Throws<NotSupportedException>(delegate { zip.Position = 100L; });
394396
Assert.Throws<NotSupportedException>(delegate { zip.SetLength(100L); });
395-
//Should we try all the enums? doesn't seem necessary
396397
Assert.Throws<NotSupportedException>(delegate { zip.Seek(100L, SeekOrigin.Begin); });
397398
}
399+
400+
[Fact]
401+
public void ReadWriteArgumentValidation()
402+
{
403+
using (var ds = new DeflateStream(new MemoryStream(), CompressionMode.Compress))
404+
{
405+
Assert.Throws<ArgumentNullException>(() => ds.Write(null, 0, 0));
406+
Assert.Throws<ArgumentOutOfRangeException>(() => ds.Write(new byte[1], -1, 0));
407+
Assert.Throws<ArgumentOutOfRangeException>(() => ds.Write(new byte[1], 0, -1));
408+
Assert.Throws<ArgumentException>(() => ds.Write(new byte[1], 0, 2));
409+
Assert.Throws<ArgumentException>(() => ds.Write(new byte[1], 1, 1));
410+
Assert.Throws<InvalidOperationException>(() => ds.Read(new byte[1], 0, 1));
411+
ds.Write(new byte[1], 0, 0);
412+
}
413+
using (var ds = new DeflateStream(new MemoryStream(), CompressionMode.Compress))
414+
{
415+
Assert.Throws<ArgumentNullException>(() => { ds.WriteAsync(null, 0, 0); });
416+
Assert.Throws<ArgumentOutOfRangeException>(() => { ds.WriteAsync(new byte[1], -1, 0); });
417+
Assert.Throws<ArgumentOutOfRangeException>(() => { ds.WriteAsync(new byte[1], 0, -1); });
418+
Assert.Throws<ArgumentException>(() => { ds.WriteAsync(new byte[1], 0, 2); });
419+
Assert.Throws<ArgumentException>(() => { ds.WriteAsync(new byte[1], 1, 1); });
420+
Assert.Throws<InvalidOperationException>(() => { ds.Read(new byte[1], 0, 1); });
421+
}
422+
423+
using (var ds = new DeflateStream(new MemoryStream(), CompressionMode.Decompress))
424+
{
425+
Assert.Throws<ArgumentNullException>(() => ds.Read(null, 0, 0));
426+
Assert.Throws<ArgumentOutOfRangeException>(() => ds.Read(new byte[1], -1, 0));
427+
Assert.Throws<ArgumentOutOfRangeException>(() => ds.Read(new byte[1], 0, -1));
428+
Assert.Throws<ArgumentException>(() => ds.Read(new byte[1], 0, 2));
429+
Assert.Throws<ArgumentException>(() => ds.Read(new byte[1], 1, 1));
430+
Assert.Throws<InvalidOperationException>(() => ds.Write(new byte[1], 0, 1));
431+
432+
var data = new byte[1] { 42 };
433+
Assert.Equal(0, ds.Read(data, 0, 0));
434+
Assert.Equal(42, data[0]);
435+
}
436+
using (var ds = new DeflateStream(new MemoryStream(), CompressionMode.Decompress))
437+
{
438+
Assert.Throws<ArgumentNullException>(() => { ds.ReadAsync(null, 0, 0); });
439+
Assert.Throws<ArgumentOutOfRangeException>(() => { ds.ReadAsync(new byte[1], -1, 0); });
440+
Assert.Throws<ArgumentOutOfRangeException>(() => { ds.ReadAsync(new byte[1], 0, -1); });
441+
Assert.Throws<ArgumentException>(() => { ds.ReadAsync(new byte[1], 0, 2); });
442+
Assert.Throws<ArgumentException>(() => { ds.ReadAsync(new byte[1], 1, 1); });
443+
Assert.Throws<InvalidOperationException>(() => { ds.Write(new byte[1], 0, 1); });
444+
}
445+
}
446+
447+
[Fact]
448+
public void Precancellation()
449+
{
450+
var ms = new MemoryStream();
451+
using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress, leaveOpen: true))
452+
{
453+
Assert.True(ds.WriteAsync(new byte[1], 0, 1, new CancellationToken(true)).IsCanceled);
454+
Assert.True(ds.FlushAsync(new CancellationToken(true)).IsCanceled);
455+
}
456+
using (DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress, leaveOpen: true))
457+
{
458+
Assert.True(ds.ReadAsync(new byte[1], 0, 1, new CancellationToken(true)).IsCanceled);
459+
}
460+
}
461+
462+
[Fact]
463+
public async Task RoundtripCompressDecompress()
464+
{
465+
await RoundtripCompressDecompress(useAsync: false, useGzip: false, chunkSize: 1, totalSize: 10, level: CompressionLevel.Fastest);
466+
await RoundtripCompressDecompress(useAsync: true, useGzip: true, chunkSize: 1024, totalSize: 8192, level: CompressionLevel.Optimal);
467+
}
468+
469+
[OuterLoop]
470+
[Theory]
471+
[MemberData("RoundtripCompressDecompressOuterData")]
472+
public Task RoundtripCompressDecompressOuter(bool useAsync, bool useGzip, int chunkSize, int totalSize, CompressionLevel level)
473+
{
474+
return RoundtripCompressDecompress(useAsync, useGzip, chunkSize, totalSize, level);
475+
}
476+
477+
public static IEnumerable<object[]> RoundtripCompressDecompressOuterData
478+
{
479+
get
480+
{
481+
foreach (bool useAsync in new[] { true, false }) // whether to use Read/Write or ReadAsync/WriteAsync
482+
{
483+
foreach (bool useGzip in new[] { true, false }) // whether to add on gzip headers/footers
484+
{
485+
foreach (var level in new[] { CompressionLevel.Fastest, CompressionLevel.Optimal, CompressionLevel.NoCompression }) // compression level
486+
{
487+
yield return new object[] { useAsync, useGzip, 1, 5, level }; // smallest possible writes
488+
yield return new object[] { useAsync, useGzip, 1023, 1023*10, level }; // overflowing internal buffer
489+
yield return new object[] { useAsync, useGzip, 1024*1024, 1024*1024, level }; // large single write
490+
}
491+
}
492+
}
493+
}
494+
}
495+
496+
private async Task RoundtripCompressDecompress(bool useAsync, bool useGzip, int chunkSize, int totalSize, CompressionLevel level)
497+
{
498+
byte[] data = new byte[totalSize];
499+
new Random(42).NextBytes(data);
500+
501+
var compressed = new MemoryStream();
502+
using (var compressor = useGzip ? (Stream)new GZipStream(compressed, level, true) : new DeflateStream(compressed, level, true))
503+
{
504+
for (int i = 0; i < data.Length; i += chunkSize) // not using CopyTo{Async} due to optimizations in MemoryStream's implementation that avoid what we're trying to test
505+
{
506+
switch (useAsync)
507+
{
508+
case true: await compressor.WriteAsync(data, i, chunkSize); break;
509+
case false: compressor.Write(data, i, chunkSize); break;
510+
}
511+
}
512+
}
513+
compressed.Position = 0;
514+
515+
var decompressed = new MemoryStream();
516+
using (var decompressor = useGzip ? (Stream)new GZipStream(compressed, CompressionMode.Decompress, true) : new DeflateStream(compressed, CompressionMode.Decompress, true))
517+
{
518+
if (useAsync)
519+
decompressor.CopyTo(decompressed, chunkSize);
520+
else
521+
await decompressor.CopyToAsync(decompressed, chunkSize, CancellationToken.None);
522+
}
523+
524+
Assert.Equal<byte>(data, decompressed.ToArray());
525+
}
526+
527+
[Fact]
528+
public async Task WrapNullReturningTasksStream()
529+
{
530+
using (var ds = new DeflateStream(new BadWrappedStream(BadWrappedStream.Mode.ReturnNullTasks), CompressionMode.Decompress))
531+
await Assert.ThrowsAsync<InvalidOperationException>(() => ds.ReadAsync(new byte[1024], 0, 1024));
532+
}
533+
534+
[Fact]
535+
public async Task WrapStreamReturningBadReadValues()
536+
{
537+
using (var ds = new DeflateStream(new BadWrappedStream(BadWrappedStream.Mode.ReturnTooLargeCounts), CompressionMode.Decompress))
538+
Assert.Throws<InvalidDataException>(() => ds.Read(new byte[1024], 0, 1024));
539+
using (var ds = new DeflateStream(new BadWrappedStream(BadWrappedStream.Mode.ReturnTooLargeCounts), CompressionMode.Decompress))
540+
await Assert.ThrowsAsync<InvalidDataException>(() => ds.ReadAsync(new byte[1024], 0, 1024));
541+
542+
using (var ds = new DeflateStream(new BadWrappedStream(BadWrappedStream.Mode.ReturnTooSmallCounts), CompressionMode.Decompress))
543+
Assert.Equal(0, ds.Read(new byte[1024], 0, 1024));
544+
using (var ds = new DeflateStream(new BadWrappedStream(BadWrappedStream.Mode.ReturnTooSmallCounts), CompressionMode.Decompress))
545+
Assert.Equal(0, await ds.ReadAsync(new byte[1024], 0, 1024));
546+
}
547+
548+
private sealed class BadWrappedStream : Stream
549+
{
550+
public enum Mode
551+
{
552+
Default,
553+
ReturnNullTasks,
554+
ReturnTooSmallCounts,
555+
ReturnTooLargeCounts,
556+
}
557+
558+
private readonly Mode _mode;
559+
560+
public BadWrappedStream(Mode mode) { _mode = mode; }
561+
562+
public override int Read(byte[] buffer, int offset, int count)
563+
{
564+
switch (_mode)
565+
{
566+
case Mode.ReturnTooSmallCounts: return -1;
567+
case Mode.ReturnTooLargeCounts: return buffer.Length + 1;
568+
default: return 0;
569+
}
570+
}
571+
572+
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
573+
{
574+
return _mode == Mode.ReturnNullTasks ?
575+
null :
576+
base.ReadAsync(buffer, offset, count, cancellationToken);
577+
}
578+
579+
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
580+
{
581+
return _mode == Mode.ReturnNullTasks ?
582+
null :
583+
base.WriteAsync(buffer, offset, count, cancellationToken);
584+
}
585+
586+
public override void Write(byte[] buffer, int offset, int count) { }
587+
public override void Flush() { }
588+
public override bool CanRead { get { return true; } }
589+
public override bool CanSeek { get { return false; } }
590+
public override bool CanWrite { get { return true; } }
591+
public override long Length { get { throw new NotSupportedException(); } }
592+
public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } }
593+
public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
594+
public override void SetLength(long value) { throw new NotSupportedException(); }
595+
}
596+
398597
}
399598
}

src/System.IO.Compression/tests/GZipStreamTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,10 @@ public void TestSeekMethodsDecompress()
365365
Assert.Throws<NotSupportedException>(delegate { long value = zip.Position; });
366366
Assert.Throws<NotSupportedException>(delegate { zip.Position = 100L; });
367367
Assert.Throws<NotSupportedException>(delegate { zip.SetLength(100L); });
368-
//Should we try all the enums? doesn't seem necessary
369368
Assert.Throws<NotSupportedException>(delegate { zip.Seek(100L, SeekOrigin.Begin); });
369+
370+
zip.Dispose();
371+
Assert.False(zip.CanSeek);
370372
}
371373

372374
[Fact]
@@ -381,8 +383,10 @@ public void TestSeekMethodsCompress()
381383
Assert.Throws<NotSupportedException>(delegate { long value = zip.Position; });
382384
Assert.Throws<NotSupportedException>(delegate { zip.Position = 100L; });
383385
Assert.Throws<NotSupportedException>(delegate { zip.SetLength(100L); });
384-
//Should we try all the enums? doesn't seem necessary
385386
Assert.Throws<NotSupportedException>(delegate { zip.Seek(100L, SeekOrigin.Begin); });
387+
388+
zip.Dispose();
389+
Assert.False(zip.CanSeek);
386390
}
387391
}
388392
}

0 commit comments

Comments
 (0)