-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathXisoFileTimeTests.cs
More file actions
223 lines (199 loc) · 9.01 KB
/
Copy pathXisoFileTimeTests.cs
File metadata and controls
223 lines (199 loc) · 9.01 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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
using XISOSharp.BlockDevice;
namespace XISOSharp.Tests;
/// <summary>
/// Tests for #37 — filetime generate/parse/display.
/// Covers FileTimeHelper conversions and XisoReader Get/Set round-trip
/// plus rewrite preservation.
/// </summary>
[Collection("Sequential")]
public class XisoFileTimeTests : IDisposable
{
private readonly List<string> _tempDirs = [];
private readonly bool _savedQuiet;
private readonly bool _savedRealQuiet;
public XisoFileTimeTests()
{
_savedQuiet = Logger.Quiet;
_savedRealQuiet = Logger.RealQuiet;
}
public void Dispose()
{
Logger.Quiet = _savedQuiet;
Logger.RealQuiet = _savedRealQuiet;
foreach (string dir in _tempDirs)
{
try
{
if (Directory.Exists(dir)) Directory.Delete(dir, true);
}
catch
{
// ignored
}
}
}
private string CreateTempDir()
{
string dir = Path.Combine(Path.GetTempPath(), $"xiso_ft_{Guid.NewGuid():N}");
Directory.CreateDirectory(dir);
_tempDirs.Add(dir);
return dir;
}
private string CreateSimpleIso(out string outDir)
{
string srcDir = CreateTempDir();
outDir = CreateTempDir();
File.WriteAllText(Path.Combine(srcDir, "hello.txt"), "hello world");
File.WriteAllText(Path.Combine(srcDir, "data.bin"), "12345");
int rc = XisoWriter.CreateXiso(srcDir, outDir, null, null, out string? isoPath, null, null);
Assert.Equal(0, rc);
Assert.NotNull(isoPath);
Assert.True(File.Exists(isoPath));
return isoPath;
}
[Fact]
public void FileTimeHelper_RoundTrip_DtoToRawAndBack()
{
DateTimeOffset dto = new(2020, 6, 15, 12, 34, 56, TimeSpan.Zero);
ulong raw = FileTimeHelper.ToFileTimeRaw(dto);
DateTimeOffset back = FileTimeHelper.FromFileTimeRaw(raw);
// BCL conversion is lossless for UTC times within range; allow 100ns tolerance (1 tick)
Assert.Equal(dto.UtcDateTime, back.UtcDateTime);
// Raw should be non-zero and reasonable (after 1601)
Assert.True(raw > 0);
// Re-encode should give same raw
ulong raw2 = FileTimeHelper.ToFileTimeRaw(back);
Assert.Equal(raw, raw2);
}
[Fact]
public void FileTimeHelper_Zero_MapsTo1601()
{
const ulong rawZero = 0UL;
DateTimeOffset epoch = FileTimeHelper.FromFileTimeRaw(rawZero);
Assert.Equal(new DateTimeOffset(1601, 1, 1, 0, 0, 0, TimeSpan.Zero), epoch);
// Encoding the epoch should give 0
ulong backRaw = FileTimeHelper.ToFileTimeRaw(epoch);
Assert.Equal(0UL, backRaw);
// xdvdfs generates 0 for deterministic images (ProposedEnhancements #37)
Span<byte> buf = stackalloc byte[8];
FileTimeHelper.WriteFileTime(buf, rawZero);
Assert.Equal(0UL, FileTimeHelper.ReadFileTimeRaw(buf));
Assert.Equal("1601-01-01T00:00:00.0000000+00:00 (0)", FileTimeHelper.FormatFileTime(0));
}
[Fact]
public void FileTimeHelper_Max_Handling()
{
// Max valid FILETIME is near DateTime.MaxValue; test that large values don't throw and clamp sanely.
ulong maxRaw = (ulong)DateTime.MaxValue.ToFileTimeUtc();
DateTimeOffset dtoMax = FileTimeHelper.FromFileTimeRaw(maxRaw);
// Should round-trip without exception; dtoMax should be close to MaxValue
Assert.True(dtoMax.Year >= 9990);
// Zero and now parsing
Assert.True(FileTimeHelper.TryParseFileTime("0", out ulong r0, out DateTimeOffset d0));
Assert.Equal(0UL, r0);
Assert.Equal(new DateTimeOffset(1601, 1, 1, 0, 0, 0, TimeSpan.Zero), d0);
Assert.True(FileTimeHelper.TryParseFileTime("now", out ulong rNow, out DateTimeOffset dNow));
Assert.True(rNow > 0);
// BUG-TEST-015: wall-clock assertion must survive debugger pauses and
// loaded CI agents — allow a generous window, not 5 seconds.
Assert.True((DateTimeOffset.UtcNow - dNow).Duration() < TimeSpan.FromMinutes(5),
$"wall-clock drift exceeded 5 minutes: now={DateTimeOffset.UtcNow:O} parsed={dNow:O}");
// Hex parsing and ISO8601
Assert.True(FileTimeHelper.TryParseFileTime("0x0", out ulong rh, out _));
Assert.Equal(0UL, rh);
Assert.True(FileTimeHelper.TryParseFileTime("2023-08-26T15:30:00Z", out ulong rIso, out DateTimeOffset dIso));
Assert.Equal(new DateTimeOffset(2023, 8, 26, 15, 30, 0, TimeSpan.Zero), dIso);
Assert.True(rIso > 0);
// Decimal raw parsing
string dec = maxRaw.ToString();
Assert.True(FileTimeHelper.TryParseFileTime(dec, out ulong rDec, out _));
Assert.Equal(maxRaw, rDec);
}
[Fact]
public void XisoReader_GetSetFileTime_RoundTrip()
{
string isoPath = CreateSimpleIso(out _);
// Initial filetime is non-zero (current time)
ulong initialRaw = XisoReader.GetFileTimeRaw(isoPath);
DateTimeOffset initialDto = XisoReader.GetFileTime(isoPath);
Assert.Equal(initialDto, FileTimeHelper.FromFileTimeRaw(initialRaw));
// Set to zero (xdvdfs deterministic) and verify
XisoReader.SetFileTime(isoPath, 0UL);
ulong zeroRaw = XisoReader.GetFileTimeRaw(isoPath);
Assert.Equal(0UL, zeroRaw);
Assert.Equal(new DateTimeOffset(1601, 1, 1, 0, 0, 0, TimeSpan.Zero), XisoReader.GetFileTime(isoPath));
// Set to specific ISO8601 via helper and verify
DateTimeOffset targetDto = new(2021, 12, 31, 23, 59, 59, TimeSpan.Zero);
XisoReader.SetFileTime(isoPath, targetDto);
ulong afterRaw = XisoReader.GetFileTimeRaw(isoPath);
DateTimeOffset afterDto = XisoReader.GetFileTime(isoPath);
Assert.Equal(targetDto, afterDto);
Assert.Equal(FileTimeHelper.ToFileTimeRaw(targetDto), afterRaw);
// Set via raw ulong max (hex) and verify format
const ulong hexRaw = 0x01D7A3C8F1234567UL; // arbitrary valid
XisoReader.SetFileTime(isoPath, hexRaw);
ulong readBack = XisoReader.GetFileTimeRaw(isoPath);
Assert.Equal(hexRaw, readBack);
// BlockDevice overload parity
using FileStream fs = new(isoPath, FileMode.Open, FileAccess.Read, FileShare.Read, 65536);
FileBlockDevice dev = new(fs, false);
ulong devRaw = XisoReader.GetFileTimeRaw(dev, "test.iso");
Assert.Equal(hexRaw, devRaw);
}
[Fact]
public void XisoReader_FileTime_RewritePreserved()
{
// Create ISO, set known filetime, rewrite via XisoReader.Rewrite (which copies filetime from source stream)
string isoPath = CreateSimpleIso(out string outDir);
DateTimeOffset knownDto = new(2019, 5, 17, 10, 0, 0, TimeSpan.Zero);
XisoReader.SetFileTime(isoPath, knownDto);
ulong beforeRaw = XisoReader.GetFileTimeRaw(isoPath);
// Rewrite: requires .old dance as in Program.cs rewrite path; use XisoReader.Rewrite wrapper
// XisoReader.Rewrite expects .old file handling via DecodeXiso; easier to test via direct CreateXiso rewrite path:
// Use XisoReader.DecodeXiso with Rewrite mode requires renaming to .old.
string oldPath = isoPath + ".old";
File.Move(isoPath, oldPath);
try
{
int rc = XisoReader.Rewrite(oldPath, outDir, out string? rewriteOut, CancellationToken.None, null, null,
null,
null);
Assert.Equal(0, rc);
// Rewrite may create new file in outDir or cwd; find it
// Rewrite creates file named after source without .old suffix, with .iso if needed
// Locate the rewritten iso (newIsoPath)
string rewrittenIso = rewriteOut ?? Directory.GetFiles(outDir, "*.iso").FirstOrDefault() ?? isoPath;
Assert.NotNull(rewrittenIso);
if (!File.Exists(rewrittenIso))
{
// Fallback: check current directory? outDir already has it
rewrittenIso = Directory.GetFiles(outDir, "*")
.FirstOrDefault(f => f.EndsWith(".iso", StringComparison.OrdinalIgnoreCase)) ?? oldPath;
}
Assert.True(File.Exists(rewrittenIso),
$"Rewritten ISO not found; outDir contents: {string.Join(",", Directory.GetFiles(outDir))}");
ulong afterRaw = XisoReader.GetFileTimeRaw(rewrittenIso);
Assert.Equal(beforeRaw, afterRaw);
DateTimeOffset afterDto = XisoReader.GetFileTime(rewrittenIso);
Assert.Equal(knownDto, afterDto);
}
finally
{
try
{
if (File.Exists(oldPath)) File.Delete(oldPath);
}
catch
{
// ignored
}
}
}
[Fact]
public void FileTimeHelper_TryParse_InvalidReturnsFalse()
{
Assert.False(FileTimeHelper.TryParseFileTime("not-a-date", out _, out _));
Assert.False(FileTimeHelper.TryParseFileTime("0xZZZ", out _, out _));
Assert.False(FileTimeHelper.TryParseFileTime("", out _, out _));
}
}