Skip to content

Commit d339358

Browse files
authored
Add a new more complex unit test (#105)
Add a new more complete unit test which emulates how Xamarin.Android uses LibZipSharp. Also made a small change to the way we handle reading from a stream. According to the documentation stream.Read can return a value less than what was asked. So we need to keep reading until we get all the data we expected or an error is thrown.
1 parent 9bccd74 commit d339358

3 files changed

Lines changed: 152 additions & 2 deletions

File tree

‎LibZipSharp.UnitTest/ZipTests.cs‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,85 @@ public void CheckForUnknownCompressionMethods ()
257257
}
258258
}
259259

260+
[Test]
261+
publicvoidSimulateXamarinAndroidUsage([Values(true,false)]boolcopyArchive,[Values(true,false)]booluseFiles)
262+
{
263+
stringfilePath=Path.GetFullPath("packaged_resources");
264+
if(!File.Exists(filePath)){
265+
filePath=Path.GetFullPath(Path.Combine("LibZipSharp.UnitTest","packaged_resources"));
266+
}
267+
268+
stringbaseArchive=$"base_{copyArchive}_{useFiles}.zip";
269+
270+
if(File.Exists(baseArchive))
271+
File.Delete(baseArchive);
272+
273+
varmode=FileMode.Create;
274+
if(copyArchive){
275+
File.Copy(filePath,baseArchive);
276+
mode=FileMode.Open;
277+
}
278+
279+
List<(stringname,CompressionMethodc,ulongsize)>expectedFiles=newList<(stringname,CompressionMethodc,ulongsize)>();
280+
// use a specific seed so we always generate the same files
281+
Randomrnd=newRandom(3456464);
282+
283+
using(varbaseZip=newZipWrapper(baseArchive,mode)){
284+
using(varzip=ZipArchive.Open(filePath,FileMode.Open)){
285+
foreach(varentryinzip){
286+
varentryName=entry.FullName;
287+
if(entryName.Contains("\\")){
288+
entryName=entryName.Replace('\\','/');
289+
}
290+
expectedFiles.Add((entryName,entry.CompressionMethod,entry.Size));
291+
if(copyArchive)
292+
continue;
293+
varms=newMemoryStream();
294+
entry.Extract(ms);
295+
TestContext.Out.WriteLine($"Adding {entryName} to base.zip");
296+
baseZip.Archive.AddStream(ms,entryName,compressionMethod:entry.CompressionMethod);
297+
}
298+
}
299+
300+
baseZip.FixupWindowsPathSeparators((a,b)=>TestContext.Out.WriteLine($"Fixing up malformed entry `{a}` -> `{b}`"));
301+
302+
for(inti=0;i<200;i++){
303+
uintfileSize=(uint)rnd.Next(341,3535592);
304+
byte[]buffer=newbyte[fileSize];
305+
rnd.NextBytes(buffer);
306+
CompressionMethodcompression=rnd.NextDouble()<0.8?CompressionMethod.Deflate:CompressionMethod.Store;
307+
stringentryName=$"temp/file_{i}_size_{fileSize}_{compression}.bin";
308+
stringarchivePath=rnd.NextDouble()<0.3?entryName:Path.GetFileName(entryName);
309+
TestContext.Out.WriteLine($"Adding {entryName} to base.zip");
310+
if(useFiles){
311+
Directory.CreateDirectory("temp");
312+
File.WriteAllBytes(entryName,buffer);
313+
baseZip.Archive.AddFile(entryName,archivePath,compressionMethod:compression);
314+
}else{
315+
varms=newMemoryStream(buffer);
316+
ms.Position=0;
317+
baseZip.Archive.AddStream(ms,archivePath,compressionMethod:compression);
318+
}
319+
expectedFiles.Add((archivePath,compression,fileSize));
320+
321+
if(rnd.NextDouble()<0.2)
322+
baseZip.Flush();
323+
}
324+
325+
}
326+
using(varzip=ZipArchive.Open(baseArchive,FileMode.Open,strictConsistencyChecks:true)){
327+
foreach(varfileinexpectedFiles){
328+
Assert.IsTrue(zip.ContainsEntry(file.name),$"zip should contain {file}.");
329+
vare=zip.ReadEntry(file.name);
330+
Assert.AreEqual(file.size,e.Size,$"{file} should be {file.size} but was {e.Size}.");
331+
Assert.AreEqual(file.c,e.CompressionMethod,$"{file} should be {file.c} but was {e.CompressionMethod}.");
332+
}
333+
}
334+
335+
if(File.Exists(baseArchive))
336+
File.Delete(baseArchive);
337+
}
338+
260339
[Test]
261340
publicvoidInMemoryZipFile()
262341
{

‎LibZipSharp.UnitTest/ZipWrapper.cs‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
usingNUnit.Framework;
2+
usingSystem;
3+
usingSystem.Collections.Generic;
4+
usingSystem.IO;
5+
usingSystem.Text;
6+
usingSystem.Threading;
7+
usingXamarin.Tools.Zip;
8+
usingUnix=Mono.Unix;
9+
10+
namespaceTests{
11+
publicclassZipWrapper:IDisposable{
12+
ZipArchivearchive;
13+
stringfilename;
14+
publicZipArchiveArchive=>archive;
15+
16+
publicZipWrapper(stringfile,FileModemode=FileMode.CreateNew){
17+
filename=file;
18+
archive=ZipArchive.Open(filename,mode);
19+
}
20+
21+
publicvoidFlush(){
22+
if(archive!=null){
23+
archive.Close();
24+
archive.Dispose();
25+
archive=null;
26+
}
27+
archive=ZipArchive.Open(filename,FileMode.Open);
28+
}
29+
30+
/// <summary>
31+
/// HACK: aapt2 is creating zip entries on Windows such as `assets\subfolder/asset2.txt`
32+
/// </summary>
33+
publicvoidFixupWindowsPathSeparators(Action<string,string>onRename)
34+
{
35+
boolmodified=false;
36+
foreach(varentryinarchive){
37+
if(entry.FullName.Contains("\\")){
38+
varname=entry.FullName.Replace('\\','/');
39+
onRename?.Invoke(entry.FullName,name);
40+
entry.Rename(name);
41+
modified=true;
42+
}
43+
}
44+
if(modified){
45+
Flush();
46+
}
47+
}
48+
49+
publicvoidDispose()
50+
{
51+
Dispose(true);
52+
GC.SuppressFinalize(this);
53+
}
54+
55+
protectedvirtualvoidDispose(booldisposing){
56+
if(disposing){
57+
if(archive!=null){
58+
archive.Close();
59+
archive.Dispose();
60+
archive=null;
61+
}
62+
}
63+
}
64+
}
65+
}

‎LibZipSharp/Xamarin.Tools.Zip/ZipArchive.cs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,14 @@ internal static unsafe Int64 stream_callback (IntPtr state, IntPtr data, UInt64
852852
length=(int)Math.Min(stream.Length-stream.Position,length);
853853
buffer=ArrayPool<byte>.Shared.Rent(length);
854854
try{
855-
intbytesRead=stream.Read(buffer,0,length);
856-
Marshal.Copy(buffer,0,data,bytesRead);
855+
intbytesRead=0;
856+
intstartIndex=0;
857+
while(length>0){
858+
bytesRead=stream.Read(buffer,0,length);
859+
Marshal.Copy(buffer,startIndex,data,bytesRead);
860+
startIndex+=bytesRead;
861+
length-=bytesRead;
862+
}
857863
returnbytesRead;
858864
}finally{
859865
ArrayPool<byte>.Shared.Return(buffer);

0 commit comments

Comments
 (0)