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

Commit fc2d772

Browse files
committed
Test both managed/zlib System.IO.Compression implementations
System.IO.Compression has two implementations for compression/decompression: one based on zlib, and one implemented in managed code. As we can use the managed implementation as a fallback in case zlib is unavailable, we need to ensure it's functioning properly. This commit adds a debug-only static field to DeflateStream that supports overriding the normal logic for whether zlib or the managed implementation is used. The DeflateStream and GZipStream tests are then augmented to force both implementations to be used.
1 parent 41b90e6 commit fc2d772

File tree

5 files changed

+139
-69
lines changed

5 files changed

+139
-69
lines changed

src/System.IO.Compression/src/System/IO/Compression/DeflateStream.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,13 @@ public partial class DeflateStream : Stream
2525
private bool _wroteHeader;
2626
private bool _wroteBytes;
2727

28-
private enum WorkerType : byte { Managed, ZLib, Unknown };
28+
private enum WorkerType : byte { Unknown = 0, Managed = 1, ZLib = 2 };
2929
private static readonly WorkerType s_deflaterType = GetDeflaterType();
30+
#if DEBUG
31+
// This field is used for testing purposes and is accessed via reflection.
32+
// NOTE: If the name of this field changes, the test must also be updated.
33+
private static WorkerType s_forcedTestingDeflaterType = WorkerType.Unknown;
34+
#endif
3035

3136
public DeflateStream(Stream stream, CompressionMode mode)
3237
: this(stream, mode, false)
@@ -105,7 +110,17 @@ public DeflateStream(Stream stream, CompressionLevel compressionLevel, bool leav
105110

106111
private static IDeflater CreateDeflater(CompressionLevel? compressionLevel)
107112
{
108-
switch (s_deflaterType)
113+
// The deflator type (zlib or managed) is normally determined by s_deflatorType,
114+
// which is initialized by the provider based on what's available on the system.
115+
// But for testing purposes, we sometimes want to override this, forcing
116+
// compression/decompression to use a particular type.
117+
WorkerType deflatorType = s_deflaterType;
118+
#if DEBUG
119+
if (s_forcedTestingDeflaterType != WorkerType.Unknown)
120+
deflatorType = s_forcedTestingDeflaterType;
121+
#endif
122+
123+
switch (deflatorType)
109124
{
110125
case WorkerType.Managed:
111126
return new DeflaterManaged();

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

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
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;
5-
using System.Collections.Generic;
4+
using System.Reflection;
65
using System.Text;
76
using System.Threading.Tasks;
8-
using System.IO;
9-
using System.Reflection;
10-
using System.IO.Compression;
117
using Xunit;
128

139
namespace System.IO.Compression.Tests
1410
{
15-
public partial class DeflateStreamTests
11+
public class ZLibDeflateStreamTests : DeflateStreamTests, IDisposable
12+
{
13+
public ZLibDeflateStreamTests() { SetWorkerMode("zlib"); }
14+
public void Dispose() { SetWorkerMode("unknown"); }
15+
}
16+
17+
public class ManagedDeflateStreamTests : DeflateStreamTests, IDisposable
18+
{
19+
public ManagedDeflateStreamTests() { SetWorkerMode("managed"); }
20+
public void Dispose() { SetWorkerMode("unknown"); }
21+
}
22+
23+
public abstract class DeflateStreamTests
1624
{
1725
static string gzTestFile(String fileName) { return Path.Combine("GZTestData", fileName); }
1826

27+
internal static void SetWorkerMode(string mode)
28+
{
29+
FieldInfo forceType = typeof(DeflateStream).GetTypeInfo().GetDeclaredField("s_forcedTestingDeflaterType");
30+
if (forceType != null)
31+
{
32+
forceType.SetValue(null, mode == "zlib" ? (byte)2 : mode == "managed" ? (byte)1 : (byte)0);
33+
}
34+
}
35+
1936
[Fact]
20-
public static void BaseStream1()
37+
public void BaseStream1()
2138
{
2239
var writeStream = new MemoryStream();
2340
var zip = new DeflateStream(writeStream, CompressionMode.Compress);
@@ -27,7 +44,7 @@ public static void BaseStream1()
2744
}
2845

2946
[Fact]
30-
public static void BaseStream2()
47+
public void BaseStream2()
3148
{
3249
var ms = new MemoryStream();
3350
var zip = new DeflateStream(ms, CompressionMode.Decompress);
@@ -37,7 +54,7 @@ public static void BaseStream2()
3754
}
3855

3956
[Fact]
40-
public static async Task ModifyBaseStream()
57+
public async Task ModifyBaseStream()
4158
{
4259
var ms = await LocalMemoryStream.readAppFileAsync(gzTestFile("GZTestDocument.txt.gz"));
4360
var newMs = StripHeaderAndFooter.Strip(ms);
@@ -52,7 +69,7 @@ public static async Task ModifyBaseStream()
5269
}
5370

5471
[Fact]
55-
public static void DecompressCanRead()
72+
public void DecompressCanRead()
5673
{
5774
var ms = new MemoryStream();
5875
var zip = new DeflateStream(ms, CompressionMode.Decompress);
@@ -64,7 +81,7 @@ public static void DecompressCanRead()
6481
}
6582

6683
[Fact]
67-
public static void CompressCanWrite()
84+
public void CompressCanWrite()
6885
{
6986
var ms = new MemoryStream();
7087
var zip = new DeflateStream(ms, CompressionMode.Compress);
@@ -75,15 +92,15 @@ public static void CompressCanWrite()
7592
}
7693

7794
[Fact]
78-
public static void CanDisposeBaseStream()
95+
public void CanDisposeBaseStream()
7996
{
8097
var ms = new MemoryStream();
8198
var zip = new DeflateStream(ms, CompressionMode.Compress);
8299
ms.Dispose(); // This would throw if this was invalid
83100
}
84101

85102
[Fact]
86-
public static void CanDisposeDeflateStream()
103+
public void CanDisposeDeflateStream()
87104
{
88105
var ms = new MemoryStream();
89106
var zip = new DeflateStream(ms, CompressionMode.Compress);
@@ -96,7 +113,7 @@ public static void CanDisposeDeflateStream()
96113
}
97114

98115
[Fact]
99-
public static async Task CanReadBaseStreamAfterDispose()
116+
public async Task CanReadBaseStreamAfterDispose()
100117
{
101118
var ms = await LocalMemoryStream.readAppFileAsync(gzTestFile("GZTestDocument.txt.gz"));
102119
var newMs = StripHeaderAndFooter.Strip(ms);
@@ -114,7 +131,7 @@ public static async Task CanReadBaseStreamAfterDispose()
114131
}
115132

116133
[Fact]
117-
public static async Task DecompressWorks()
134+
public async Task DecompressWorks()
118135
{
119136
var compareStream = await LocalMemoryStream.readAppFileAsync(gzTestFile("GZTestDocument.txt"));
120137
var gzStream = await LocalMemoryStream.readAppFileAsync(gzTestFile("GZTestDocument.txt.gz"));
@@ -123,7 +140,7 @@ public static async Task DecompressWorks()
123140
}
124141

125142
[Fact]
126-
public static async Task DecompressWorksWithBinaryFile()
143+
public async Task DecompressWorksWithBinaryFile()
127144
{
128145
var compareStream = await LocalMemoryStream.readAppFileAsync(gzTestFile("GZTestDocument.doc"));
129146
var gzStream = await LocalMemoryStream.readAppFileAsync(gzTestFile("GZTestDocument.doc.gz"));
@@ -132,7 +149,7 @@ public static async Task DecompressWorksWithBinaryFile()
132149
}
133150

134151
// Making this async since regular read/write are tested below
135-
private static async Task DecompressAsync(MemoryStream compareStream, MemoryStream gzStream)
152+
private async Task DecompressAsync(MemoryStream compareStream, MemoryStream gzStream)
136153
{
137154
var strippedMs = StripHeaderAndFooter.Strip(gzStream);
138155

@@ -167,8 +184,9 @@ private static async Task DecompressAsync(MemoryStream compareStream, MemoryStre
167184
Assert.Equal(compareArray[i], writtenArray[i]);
168185
}
169186
}
187+
170188
[Fact]
171-
public static async Task DecompressFailsWithRealGzStream()
189+
public async Task DecompressFailsWithRealGzStream()
172190
{
173191
String[] files = { gzTestFile("GZTestDocument.doc.gz"), gzTestFile("GZTestDocument.txt.gz") };
174192
foreach (String fileName in files)
@@ -181,8 +199,9 @@ public static async Task DecompressFailsWithRealGzStream()
181199
zip.Dispose();
182200
}
183201
}
202+
184203
[Fact]
185-
public static void NullBaseStreamThrows()
204+
public void NullBaseStreamThrows()
186205
{
187206
Assert.Throws<ArgumentNullException>(() =>
188207
{
@@ -194,8 +213,9 @@ public static void NullBaseStreamThrows()
194213
var deflate = new DeflateStream(null, CompressionMode.Compress);
195214
});
196215
}
216+
197217
[Fact]
198-
public static void DisposedBaseStreamThrows()
218+
public void DisposedBaseStreamThrows()
199219
{
200220
var ms = new MemoryStream();
201221
ms.Dispose();
@@ -209,8 +229,9 @@ public static void DisposedBaseStreamThrows()
209229
var deflate = new DeflateStream(ms, CompressionMode.Compress);
210230
});
211231
}
232+
212233
[Fact]
213-
public static void ReadOnlyStreamThrowsOnCompress()
234+
public void ReadOnlyStreamThrowsOnCompress()
214235
{
215236
var ms = new LocalMemoryStream();
216237
ms.SetCanWrite(false);
@@ -220,8 +241,9 @@ public static void ReadOnlyStreamThrowsOnCompress()
220241
var gzip = new DeflateStream(ms, CompressionMode.Compress);
221242
});
222243
}
244+
223245
[Fact]
224-
public static void WriteOnlyStreamThrowsOnDecompress()
246+
public void WriteOnlyStreamThrowsOnDecompress()
225247
{
226248
var ms = new LocalMemoryStream();
227249
ms.SetCanRead(false);
@@ -231,8 +253,9 @@ public static void WriteOnlyStreamThrowsOnDecompress()
231253
var gzip = new DeflateStream(ms, CompressionMode.Decompress);
232254
});
233255
}
256+
234257
[Fact]
235-
public static void TestCtors()
258+
public void TestCtors()
236259
{
237260
CompressionLevel[] legalValues = new CompressionLevel[] { CompressionLevel.Optimal, CompressionLevel.Fastest, CompressionLevel.NoCompression };
238261

@@ -246,23 +269,26 @@ public static void TestCtors()
246269
}
247270
}
248271
}
272+
249273
[Fact]
250-
public static void TestLevelOptimial()
274+
public void TestLevelOptimial()
251275
{
252276
TestCtor(CompressionLevel.Optimal);
253277
}
278+
254279
[Fact]
255-
public static void TestLevelNoCompression()
280+
public void TestLevelNoCompression()
256281
{
257282
TestCtor(CompressionLevel.NoCompression);
258283
}
284+
259285
[Fact]
260-
public static void TestLevelFastest()
286+
public void TestLevelFastest()
261287
{
262288
TestCtor(CompressionLevel.Fastest);
263289
}
264290

265-
public static void TestCtor(CompressionLevel level, bool? leaveOpen = null)
291+
private static void TestCtor(CompressionLevel level, bool? leaveOpen = null)
266292
{
267293
//Create the DeflateStream
268294
int _bufferSize = 1024;
@@ -314,7 +340,7 @@ public static void TestCtor(CompressionLevel level, bool? leaveOpen = null)
314340
}
315341

316342
[Fact]
317-
public static async Task Flush()
343+
public async Task Flush()
318344
{
319345
var ms = new MemoryStream();
320346
var ds = new DeflateStream(ms, CompressionMode.Compress);
@@ -323,16 +349,18 @@ public static async Task Flush()
323349

324350
// Just ensuring Flush doesn't throw
325351
}
352+
326353
[Fact]
327-
public static void FlushFailsAfterDispose()
354+
public void FlushFailsAfterDispose()
328355
{
329356
var ms = new MemoryStream();
330357
var ds = new DeflateStream(ms, CompressionMode.Compress);
331358
ds.Dispose();
332359
Assert.Throws<ObjectDisposedException>(() => { ds.Flush(); });
333360
}
361+
334362
[Fact]
335-
public static async Task FlushAsyncFailsAfterDispose()
363+
public async Task FlushAsyncFailsAfterDispose()
336364
{
337365

338366
var ms = new MemoryStream();
@@ -346,7 +374,7 @@ await Assert.ThrowsAsync<ObjectDisposedException>(async () =>
346374
}
347375

348376
[Fact]
349-
public static void TestSeekMethodsDecompress()
377+
public void TestSeekMethodsDecompress()
350378
{
351379
var ms = new MemoryStream();
352380
var zip = new DeflateStream(ms, CompressionMode.Decompress);
@@ -360,8 +388,9 @@ public static void TestSeekMethodsDecompress()
360388
//Should we try all the enums? doesn't seem necessary
361389
Assert.Throws<NotSupportedException>(delegate { zip.Seek(100L, SeekOrigin.Begin); });
362390
}
391+
363392
[Fact]
364-
public static void TestSeekMethodsCompress()
393+
public void TestSeekMethodsCompress()
365394
{
366395
var ms = new MemoryStream();
367396
var zip = new DeflateStream(ms, CompressionMode.Compress);

0 commit comments

Comments
 (0)