Skip to content

Commit c0998f2

Browse files
CopilotViktorHofer
andauthored
Add TarDirectory tests and docs; verified end-to-end
Co-authored-by: ViktorHofer <7412651+ViktorHofer@users.noreply.github.com>
1 parent 695b6fa commit c0998f2

2 files changed

Lines changed: 207 additions & 0 deletions

File tree

documentation/specs/question.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ Error when SkipUnchangedFiles is true.
7878
`ZipDirectory`
7979
Error if the destination zip file doesn't exists.
8080

81+
`TarDirectory`
82+
Error if the destination tar file doesn't exists.
83+
8184
## Common Error
8285

8386
- **Typographical error**. Spelling, casing, or incorrect path. Check if the target inputs and outputs real files.
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
// TarDirectory relies on System.Formats.Tar which is only available on .NET (not .NET Framework).
5+
#if NET
6+
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Formats.Tar;
10+
using System.IO;
11+
using System.IO.Compression;
12+
using Microsoft.Build.UnitTests;
13+
using Microsoft.Build.Utilities;
14+
using Shouldly;
15+
using Xunit;
16+
17+
namespace Microsoft.Build.Tasks.UnitTests
18+
{
19+
public class TarDirectory_Tests
20+
{
21+
private readonly MockEngine _mockEngine = new MockEngine();
22+
23+
[Theory]
24+
[InlineData(null)]
25+
[InlineData("None")]
26+
[InlineData("GZip")]
27+
[InlineData("gz")]
28+
public void CanTarDirectory(string? compression)
29+
{
30+
using (TestEnvironment testEnvironment = TestEnvironment.Create())
31+
{
32+
TransientTestFolder sourceFolder = testEnvironment.CreateFolder(createFolder: true);
33+
34+
testEnvironment.CreateFile(sourceFolder, "6DE6060259C44DB6B145159376751C22.txt", "6DE6060259C44DB6B145159376751C22");
35+
testEnvironment.CreateFile(sourceFolder, "CDA3DD8C25A54A7CAC638A444CB1EAD0.txt", "CDA3DD8C25A54A7CAC638A444CB1EAD0");
36+
37+
string tarFilePath = Path.Combine(testEnvironment.CreateFolder(createFolder: true).Path, "test.tar");
38+
39+
TarDirectory tarDirectory = new TarDirectory
40+
{
41+
BuildEngine = _mockEngine,
42+
Compression = compression,
43+
DestinationFile = new TaskItem(tarFilePath),
44+
SourceDirectory = new TaskItem(sourceFolder.Path),
45+
TaskEnvironment = TaskEnvironmentHelper.CreateForTest(),
46+
};
47+
48+
tarDirectory.Execute().ShouldBeTrue(_mockEngine.Log);
49+
50+
_mockEngine.Log.ShouldContain(sourceFolder.Path, customMessage: _mockEngine.Log);
51+
_mockEngine.Log.ShouldContain(tarFilePath, customMessage: _mockEngine.Log);
52+
53+
// Should not contain any warnings in the TarDirectory bucket (MSB4321 - MSB4330).
54+
_mockEngine.Log.ShouldNotContain("MSB432", customMessage: _mockEngine.Log);
55+
56+
bool isGZip = compression is not null && !StringComparer.OrdinalIgnoreCase.Equals(compression, "None");
57+
58+
GetTarEntryNames(tarFilePath, isGZip)
59+
.ShouldBe(
60+
[
61+
"6DE6060259C44DB6B145159376751C22.txt",
62+
"CDA3DD8C25A54A7CAC638A444CB1EAD0.txt"
63+
],
64+
ignoreOrder: true);
65+
}
66+
}
67+
68+
[Fact]
69+
public void CanOverwriteExistingFile()
70+
{
71+
using (TestEnvironment testEnvironment = TestEnvironment.Create())
72+
{
73+
TransientTestFolder sourceFolder = testEnvironment.CreateFolder(createFolder: true);
74+
75+
testEnvironment.CreateFile(sourceFolder, "F1C22D660B0D4DAAA296C1B980320B03.txt", "F1C22D660B0D4DAAA296C1B980320B03");
76+
testEnvironment.CreateFile(sourceFolder, "AA825D1CB154492BAA58E1002CE1DFEB.txt", "AA825D1CB154492BAA58E1002CE1DFEB");
77+
78+
TransientTestFile file = testEnvironment.CreateFile(testEnvironment.DefaultTestDirectory, "test.tar", contents: "test");
79+
80+
TarDirectory tarDirectory = new TarDirectory
81+
{
82+
BuildEngine = _mockEngine,
83+
DestinationFile = new TaskItem(file.Path),
84+
Overwrite = true,
85+
SourceDirectory = new TaskItem(sourceFolder.Path),
86+
TaskEnvironment = TaskEnvironmentHelper.CreateForTest(),
87+
};
88+
89+
tarDirectory.Execute().ShouldBeTrue(_mockEngine.Log);
90+
91+
_mockEngine.Log.ShouldContain(sourceFolder.Path, customMessage: _mockEngine.Log);
92+
_mockEngine.Log.ShouldContain(file.Path, customMessage: _mockEngine.Log);
93+
94+
GetTarEntryNames(file.Path, isGZip: false)
95+
.ShouldBe(
96+
[
97+
"F1C22D660B0D4DAAA296C1B980320B03.txt",
98+
"AA825D1CB154492BAA58E1002CE1DFEB.txt"
99+
],
100+
ignoreOrder: true);
101+
}
102+
}
103+
104+
[Fact]
105+
public void LogsErrorIfDestinationExists()
106+
{
107+
using (TestEnvironment testEnvironment = TestEnvironment.Create())
108+
{
109+
TransientTestFolder folder = testEnvironment.CreateFolder(createFolder: true);
110+
111+
TransientTestFile file = testEnvironment.CreateFile("foo.tar", "foo");
112+
113+
TarDirectory tarDirectory = new TarDirectory
114+
{
115+
BuildEngine = _mockEngine,
116+
DestinationFile = new TaskItem(file.Path),
117+
SourceDirectory = new TaskItem(folder.Path),
118+
TaskEnvironment = TaskEnvironmentHelper.CreateForTest(),
119+
};
120+
121+
tarDirectory.Execute().ShouldBeFalse(_mockEngine.Log);
122+
123+
_mockEngine.Log.ShouldContain("MSB4322", customMessage: _mockEngine.Log);
124+
}
125+
}
126+
127+
[Fact]
128+
public void LogsErrorIfDirectoryDoesNotExist()
129+
{
130+
TarDirectory tarDirectory = new TarDirectory
131+
{
132+
BuildEngine = _mockEngine,
133+
DestinationFile = new TaskItem(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"), "test.tar")),
134+
SourceDirectory = new TaskItem(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"))),
135+
TaskEnvironment = TaskEnvironmentHelper.CreateForTest(),
136+
};
137+
138+
tarDirectory.Execute().ShouldBeFalse(_mockEngine.Log);
139+
140+
_mockEngine.Log.ShouldContain("MSB4321", customMessage: _mockEngine.Log);
141+
}
142+
143+
[Fact]
144+
public void LogsWarningForInvalidCompression()
145+
{
146+
using (TestEnvironment testEnvironment = TestEnvironment.Create())
147+
{
148+
TransientTestFolder sourceFolder = testEnvironment.CreateFolder(createFolder: true);
149+
150+
testEnvironment.CreateFile(sourceFolder, "9E0A4E0F5C8D4F0FA0B33F79C2F0B0C1.txt", "content");
151+
152+
string tarFilePath = Path.Combine(testEnvironment.CreateFolder(createFolder: true).Path, "test.tar");
153+
154+
TarDirectory tarDirectory = new TarDirectory
155+
{
156+
BuildEngine = _mockEngine,
157+
Compression = "RandomUnsupportedValue",
158+
DestinationFile = new TaskItem(tarFilePath),
159+
SourceDirectory = new TaskItem(sourceFolder.Path),
160+
TaskEnvironment = TaskEnvironmentHelper.CreateForTest(),
161+
};
162+
163+
// Invalid compression is a warning, not an error; an uncompressed tar is created instead.
164+
tarDirectory.Execute().ShouldBeTrue(_mockEngine.Log);
165+
166+
_mockEngine.Log.ShouldContain("MSB4324", customMessage: _mockEngine.Log);
167+
168+
GetTarEntryNames(tarFilePath, isGZip: false)
169+
.ShouldBe(["9E0A4E0F5C8D4F0FA0B33F79C2F0B0C1.txt"]);
170+
}
171+
}
172+
173+
private static List<string> GetTarEntryNames(string tarFilePath, bool isGZip)
174+
{
175+
List<string> names = new List<string>();
176+
177+
using FileStream stream = new FileStream(tarFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
178+
Stream tarStream = isGZip ? new GZipStream(stream, CompressionMode.Decompress) : stream;
179+
180+
try
181+
{
182+
using TarReader reader = new TarReader(tarStream);
183+
for (TarEntry? entry = reader.GetNextEntry(); entry is not null; entry = reader.GetNextEntry())
184+
{
185+
if (entry.EntryType is TarEntryType.RegularFile or TarEntryType.V7RegularFile)
186+
{
187+
names.Add(entry.Name);
188+
}
189+
}
190+
}
191+
finally
192+
{
193+
if (isGZip)
194+
{
195+
tarStream.Dispose();
196+
}
197+
}
198+
199+
return names;
200+
}
201+
}
202+
}
203+
204+
#endif

0 commit comments

Comments
 (0)