Skip to content

Commit 53ad133

Browse files
committed
Add more tests
1 parent 9207b98 commit 53ad133

4 files changed

Lines changed: 255 additions & 0 deletions

File tree

ValvePak/ValvePak.Test/MemoryMapTest.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,5 +84,28 @@ public void ReturnsCorrectStreamsWhenUsingMemoryStream()
8484
Assert.That(stream2, Is.InstanceOf<MemoryStream>());
8585
VerifyProto(stream2);
8686
}
87+
88+
[Test]
89+
public void GetMemoryMappedStreamIfPossibleThrowsOnNullEntry()
90+
{
91+
using var package = new Package();
92+
Assert.Throws<ArgumentNullException>(() => package.GetMemoryMappedStreamIfPossible(null!));
93+
}
94+
95+
[Test]
96+
public void GetMemoryMappedStreamIfPossibleWithPreloadedBytesReturnsMemoryStream()
97+
{
98+
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "preload.vpk");
99+
100+
using var package = new Package();
101+
package.Read(path);
102+
103+
var entry = package.FindEntry("lorem.txt");
104+
Assert.That(entry, Is.Not.Null);
105+
Assert.That(entry.SmallData, Has.Length.GreaterThan(0));
106+
107+
using var stream = package.GetMemoryMappedStreamIfPossible(entry);
108+
Assert.That(stream, Is.InstanceOf<MemoryStream>());
109+
}
87110
}
88111
}

ValvePak/ValvePak.Test/PackageTest.cs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,95 @@ public void TestVerifyChunkHashesBlake3()
534534
Assert.DoesNotThrow(() => package.VerifyChunkHashes(null));
535535
}
536536

537+
[Test]
538+
public void SetFileNameStripsVpkExtensionAndDirSuffix()
539+
{
540+
using var package1 = new Package();
541+
package1.SetFileName("foo_dir.vpk");
542+
543+
using (Assert.EnterMultipleScope())
544+
{
545+
Assert.That(package1.FileName, Is.EqualTo("foo"));
546+
Assert.That(package1.IsDirVPK, Is.True);
547+
}
548+
549+
using var package2 = new Package();
550+
package2.SetFileName("bar.vpk");
551+
552+
using (Assert.EnterMultipleScope())
553+
{
554+
Assert.That(package2.FileName, Is.EqualTo("bar"));
555+
Assert.That(package2.IsDirVPK, Is.False);
556+
}
557+
}
558+
559+
[Test]
560+
public void VerifyHashesThrowsOnVersion1()
561+
{
562+
using var package = new Package();
563+
package.SetFileName("a.vpk");
564+
565+
// VPK v1 header: correct magic, version 1, tree size 1
566+
using var ms = new MemoryStream([0x34, 0x12, 0xAA, 0x55, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00]);
567+
package.Read(ms);
568+
569+
var ex = Assert.Throws<InvalidDataException>(() => package.VerifyHashes());
570+
Assert.That(ex.Message, Is.EqualTo("Only version 2 is supported."));
571+
}
572+
573+
[Test]
574+
public void VerifyFileChecksumsDoesNothingOnNullEntries()
575+
{
576+
using var package = new Package();
577+
Assert.DoesNotThrow(() => package.VerifyFileChecksums());
578+
}
579+
580+
[Test]
581+
public void VerifyFileChecksumsWithProgressReporter()
582+
{
583+
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "broken_dir.vpk");
584+
585+
using var package = new Package();
586+
package.Read(path);
587+
588+
var reports = new List<string>();
589+
var progress = new Progress<string>(report => reports.Add(report));
590+
package.VerifyFileChecksums(progress);
591+
592+
Assert.That(reports, Is.Not.Empty);
593+
}
594+
595+
[Test]
596+
public void DisposeCanBeCalledMultipleTimes()
597+
{
598+
var package = new Package();
599+
package.Dispose();
600+
Assert.DoesNotThrow(() => package.Dispose());
601+
}
602+
603+
[Test]
604+
public void IsSignatureValidReturnsTrueWhenNoSignature()
605+
{
606+
using var package = new Package();
607+
Assert.That(package.IsSignatureValid(), Is.True);
608+
}
609+
610+
[Test]
611+
public void IsSignatureValidReturnsFalseAfterDispose()
612+
{
613+
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "platform_misc_dir.vpk");
614+
615+
var package = new Package();
616+
package.Read(path);
617+
618+
Assert.That(package.Signature, Is.Not.Null);
619+
Assert.That(package.PublicKey, Is.Not.Null);
620+
621+
package.Dispose();
622+
623+
Assert.That(package.IsSignatureValid(), Is.False);
624+
}
625+
537626
private static void TestVPKExtraction(string path)
538627
{
539628
using var package = new Package();

ValvePak/ValvePak.Test/WriteTest.cs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.IO;
23
using System.Text;
34
using NUnit.Framework;
@@ -164,5 +165,145 @@ public void NormalizesSlashes()
164165
Assert.That(file.FileName, Is.EqualTo("d"));
165166
}
166167
}
168+
169+
[Test]
170+
public void WriteThrowsWhenIsDirVPK()
171+
{
172+
var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "Files", "steamdb_test_dir.vpk");
173+
174+
using var package = new Package();
175+
package.Read(path);
176+
177+
using var output = new MemoryStream();
178+
var ex = Assert.Throws<InvalidOperationException>(() => package.Write(output));
179+
Assert.That(ex.Message, Is.EqualTo("This package was opened from a _dir.vpk, writing back is currently unsupported."));
180+
}
181+
182+
[Test]
183+
public void WriteThrowsOnNonSeekableStream()
184+
{
185+
using var package = new Package();
186+
package.AddFile("test.txt", Encoding.UTF8.GetBytes("hello"));
187+
188+
using var nonSeekable = new NonSeekableStream();
189+
var ex = Assert.Throws<InvalidOperationException>(() => package.Write(nonSeekable));
190+
Assert.That(ex.Message, Is.EqualTo("Stream must be seekable and readable."));
191+
}
192+
193+
[Test]
194+
public void AddFileThrowsOnNullFilePath()
195+
{
196+
using var package = new Package();
197+
Assert.Throws<ArgumentNullException>(() => package.AddFile(null!, []));
198+
}
199+
200+
[Test]
201+
public void RemoveFileThrowsOnNullEntry()
202+
{
203+
using var package = new Package();
204+
Assert.Throws<ArgumentNullException>(() => package.RemoveFile(null!));
205+
}
206+
207+
[Test]
208+
public void RemoveFileReturnsFalseOnEmptyPackage()
209+
{
210+
using var package = new Package();
211+
var result = package.RemoveFile(new PackageEntry
212+
{
213+
FileName = "test",
214+
TypeName = "txt",
215+
DirectoryName = " ",
216+
});
217+
Assert.That(result, Is.False);
218+
}
219+
220+
[Test]
221+
public void WriteAndVerifyRoundTrip()
222+
{
223+
using var output = new MemoryStream();
224+
225+
using (var package = new Package())
226+
{
227+
package.AddFile("hello.txt", Encoding.UTF8.GetBytes("world"));
228+
package.AddFile("folder/image.jpg", Encoding.UTF8.GetBytes("not really a jpg"));
229+
package.Write(output);
230+
}
231+
232+
output.Position = 0;
233+
234+
using var readBack = new Package();
235+
readBack.SetFileName("test.vpk");
236+
readBack.Read(output);
237+
238+
using (Assert.EnterMultipleScope())
239+
{
240+
Assert.That(readBack.Version, Is.EqualTo(2));
241+
Assert.That(readBack.HeaderSize, Is.GreaterThan(0u));
242+
Assert.That(readBack.TreeSize, Is.GreaterThan(0u));
243+
Assert.That(readBack.FileDataSectionSize, Is.GreaterThan(0u));
244+
Assert.That(readBack.OtherMD5SectionSize, Is.EqualTo(48u));
245+
}
246+
247+
Assert.DoesNotThrow(() => readBack.VerifyHashes());
248+
}
249+
250+
[Test]
251+
public void WriteToFile()
252+
{
253+
var tempFile = Path.GetTempFileName();
254+
255+
try
256+
{
257+
using (var package = new Package())
258+
{
259+
package.AddFile("test.txt", Encoding.UTF8.GetBytes("hello from file"));
260+
package.Write(tempFile);
261+
}
262+
263+
using var readBack = new Package();
264+
readBack.Read(tempFile);
265+
readBack.VerifyHashes();
266+
267+
var entry = readBack.FindEntry("test.txt");
268+
Assert.That(entry, Is.Not.Null);
269+
270+
readBack.ReadEntry(entry, out var data);
271+
Assert.That(Encoding.UTF8.GetString(data), Is.EqualTo("hello from file"));
272+
}
273+
finally
274+
{
275+
File.Delete(tempFile);
276+
}
277+
}
278+
279+
[Test]
280+
public void RemoveFileReturnsFalseForWrongType()
281+
{
282+
using var package = new Package();
283+
package.AddFile("test.txt", []);
284+
285+
var result = package.RemoveFile(new PackageEntry
286+
{
287+
FileName = "test",
288+
TypeName = "jpg",
289+
DirectoryName = " ",
290+
});
291+
292+
Assert.That(result, Is.False);
293+
}
294+
295+
private sealed class NonSeekableStream : Stream
296+
{
297+
public override bool CanRead => true;
298+
public override bool CanSeek => false;
299+
public override bool CanWrite => true;
300+
public override long Length => 0;
301+
public override long Position { get => 0; set { } }
302+
public override void Flush() { }
303+
public override int Read(byte[] buffer, int offset, int count) => 0;
304+
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
305+
public override void SetLength(long value) { }
306+
public override void Write(byte[] buffer, int offset, int count) { }
307+
}
167308
}
168309
}

ValvePak/ValvePak/Package.Verify.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Diagnostics;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.IO;
45
using System.Linq;
56
using System.Security.Cryptography;
@@ -11,6 +12,7 @@ namespace SteamDatabase.ValvePak
1112
/// </summary>
1213
public partial class Package : IDisposable
1314
{
15+
[ExcludeFromCodeCoverage]
1416
sealed class SubStream : Stream, IDisposable
1517
{
1618
#pragma warning disable CA2213 // Disposable fields should be disposed

0 commit comments

Comments
 (0)