-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathXisoOpenReadStreamCsoTests.cs
More file actions
157 lines (134 loc) · 5.23 KB
/
Copy pathXisoOpenReadStreamCsoTests.cs
File metadata and controls
157 lines (134 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
namespace XISOSharp.Tests;
/// <summary>
/// <see cref="XisoExplorer.OpenReadStream(string)"/> over CISO containers —
/// single <c>.cso</c> and split <c>.1.cso</c> part sets must expose the same
/// bounded file streams as the source ISO (bytes, lengths, EOF clamp), proving
/// the random-access path routes through the decompressed block device.
/// </summary>
[Collection("Sequential")]
public sealed class XisoOpenReadStreamCsoTests : IDisposable
{
private readonly List<string> _tempDirs = [];
public void Dispose()
{
foreach (string dir in _tempDirs)
{
try
{
if (Directory.Exists(dir)) Directory.Delete(dir, true);
}
catch
{
// ignored
}
}
}
private string CreateTempDir(string prefix)
{
string dir = Path.Combine(Path.GetTempPath(), $"{prefix}_{Guid.NewGuid():N}");
Directory.CreateDirectory(dir);
_tempDirs.Add(dir);
return dir;
}
private string CreateIso(out byte[] fileA, out byte[] fileB)
{
fileA = new byte[Constants.SectorSize];
for (int i = 0; i < fileA.Length; i++) fileA[i] = (byte)(i & 0xFF);
fileB = new byte[(3 * Constants.SectorSize) + 11];
for (int i = 0; i < fileB.Length; i++) fileB[i] = (byte)(0x5A ^ (i & 0xFF));
string src = CreateTempDir("xiso_orsc_src");
File.WriteAllBytes(Path.Combine(src, "a.bin"), fileA);
File.WriteAllBytes(Path.Combine(src, "b.bin"), fileB);
File.WriteAllText(Path.Combine(src, "readme.txt"), "cso read stream");
Directory.CreateDirectory(Path.Combine(src, "sub"));
File.WriteAllText(Path.Combine(src, "sub", "c.txt"), "nested");
string outDir = CreateTempDir("xiso_orsc_iso");
int result = XisoWriter.CreateXiso(src, outDir, null, null, out string? isoPath, null, null);
Assert.Equal(0, result);
Assert.NotNull(isoPath);
return isoPath;
}
private static string Compress(string iso, string csoName, long? splitBytes = null)
{
string cso = Path.Combine(Path.GetDirectoryName(iso)!, csoName);
int rc = CisoWriter.CompressToCso(iso, cso, level: 0, splitBytes: splitBytes);
Assert.Equal(0, rc);
return cso;
}
private static byte[] ReadAll(Stream stream)
{
using MemoryStream copy = new();
stream.CopyTo(copy);
return copy.ToArray();
}
[Fact]
public void SingleCso_FullReads_MatchSourceBytes()
{
string iso = CreateIso(out byte[] fileA, out byte[] fileB);
string cso = Compress(iso, "game.cso");
XisoExplorer explorer = new(cso);
using (Stream a = explorer.OpenReadStream("/a.bin"))
{
Assert.Equal(fileA.Length, a.Length);
Assert.Equal(fileA, ReadAll(a));
}
using (Stream b = explorer.OpenReadStream("/b.bin"))
{
Assert.Equal(fileB.Length, b.Length);
Assert.Equal(fileB, ReadAll(b));
}
using Stream fromNode = explorer.OpenReadStream(explorer.GetNode("/readme.txt")!);
Assert.Equal("cso read stream", System.Text.Encoding.ASCII.GetString(ReadAll(fromNode)));
}
[Fact]
public void SingleCso_RandomSeeks_ClampToFileSize()
{
string iso = CreateIso(out byte[] fileA, out byte[] fileB);
_ = fileA;
string cso = Compress(iso, "game.cso");
XisoExplorer explorer = new(cso);
using Stream b = explorer.OpenReadStream("/b.bin");
b.Seek(fileB.Length - 5, SeekOrigin.Begin);
byte[] tail = new byte[64];
int n = b.Read(tail);
Assert.Equal(5, n);
Assert.Equal(fileB.AsSpan(fileB.Length - 5, 5).ToArray(), tail.AsSpan(0, n).ToArray());
b.Seek(b.Length, SeekOrigin.Begin);
Assert.Equal(0, b.Read(new byte[32]));
}
[Fact]
public void SplitCso_FirstPart_FullReadsMatchSourceBytes()
{
string iso = CreateIso(out byte[] fileA, out byte[] fileB);
string csoBase = Compress(iso, "game.cso", splitBytes: 300L * 1024);
string first = Path.ChangeExtension(csoBase, ".1.cso");
Assert.True(File.Exists(first));
XisoExplorer explorer = new(first);
using (Stream a = explorer.OpenReadStream("/a.bin"))
{
Assert.Equal(fileA, ReadAll(a));
}
using (Stream b = explorer.OpenReadStream("/b.bin"))
{
Assert.Equal(fileB, ReadAll(b));
}
}
[Fact]
public void SingleCso_MissingAndDirectory_ThrowInvalidData()
{
string iso = CreateIso(out _, out _);
string cso = Compress(iso, "game.cso");
XisoExplorer explorer = new(cso);
Assert.Throws<InvalidDataException>(() => explorer.OpenReadStream("/nope.bin"));
Assert.Throws<InvalidDataException>(() => explorer.OpenReadStream("/sub"));
}
[Fact]
public void SingleCso_KeepOpen_ReadStreamMatchesStateless()
{
string iso = CreateIso(out byte[] fileA, out _);
string cso = Compress(iso, "game.cso");
using XisoExplorer explorer = new(cso, new XisoExplorerOptions { KeepOpen = true });
using Stream a = explorer.OpenReadStream("/a.bin");
Assert.Equal(fileA, ReadAll(a));
}
}