Skip to content

Commit 1aba44b

Browse files
authored
update XmlPeek and XmlPoke tasks (#9194)
Add `[Required]` to parameters. - `XmlPeek` Task - Change `Query` parameter. - Remove redundant `Dispose` that was flagged by the analyzer. - Change XmlPeek.XmlInput class from `Internal` to `private sealed` and change access of some members - Minor cleanup changes - `XmlPoke` Task - Change `Query` parameter. - Change `XmlInputPath` parameter. - Minor cleanup changes - XmlPeek_Tests class - Add new `PeekWithNoParameters` test - XmlPoke_Tests class - Remove `PokeMissingParams` test - The test was defined as a `[Fact]` and used a for loop to test 4 distinct cases - The test expected `ArgumentNullException` to be thrown - Add 4 new tests, one for each of the four cases: - `PokeWithNoParameters` - `PokeWithMissingRequiredQuery` - `PokeWithMissingRequiredXmlInputPath` - `PokeWithRequiredParameters` (completes the replacement of `PokeMissingParams` but might be a redundant test) Fixes #9140.
1 parent df858b4 commit 1aba44b

File tree

4 files changed

+90
-99
lines changed

4 files changed

+90
-99
lines changed

src/Tasks.UnitTests/XmlPeek_Tests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@
33

44
using System;
55
using System.IO;
6+
7+
using Microsoft.Build.Evaluation;
68
using Microsoft.Build.Tasks;
79
using Microsoft.Build.Utilities;
10+
11+
using Shouldly;
12+
813
using Xunit;
914

1015
#nullable disable
@@ -316,6 +321,17 @@ public void PeekWithoutUsingTask()
316321
logger.AssertLogDoesntContain("MSB4036");
317322
}
318323

324+
[Fact]
325+
public void PeekWithNoParameters()
326+
{
327+
MockLogger log = new();
328+
Project project = ObjectModelHelpers.CreateInMemoryProject(@"<Project><Target Name=""Test""><XmlPeek /></Target></Project>", log);
329+
330+
project.Build().ShouldBeFalse();
331+
log.AssertLogContains("MSB4044");
332+
log.AssertLogContains("\"Query\"");
333+
}
334+
319335
private void Prepare(string xmlFile, out string xmlInputPath)
320336
{
321337
string dir = Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString());

src/Tasks.UnitTests/XmlPoke_Tests.cs

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@
66
using System.IO;
77
using System.Linq;
88
using System.Xml;
9+
10+
using Microsoft.Build.Evaluation;
911
using Microsoft.Build.Tasks;
1012
using Microsoft.Build.Utilities;
13+
1114
using Shouldly;
15+
1216
using Xunit;
1317

1418
#nullable disable
@@ -135,37 +139,55 @@ public void PokeAttributeWithCondition()
135139
}
136140

137141
[Fact]
138-
public void PokeMissingParams()
142+
public void PokeWithNoParameters()
139143
{
140-
MockEngine engine = new MockEngine(true);
141-
string xmlInputPath;
142-
Prepare(_xmlFileNoNs, out xmlInputPath);
144+
MockLogger log = new();
145+
Project project = ObjectModelHelpers.CreateInMemoryProject(@"<Project><Target Name=""Test""><XmlPoke /></Target></Project>", log);
143146

144-
for (int i = 0; i < 4; i++)
145-
{
146-
XmlPoke p = new XmlPoke();
147-
p.BuildEngine = engine;
147+
project.Build().ShouldBeFalse();
148+
log.AssertLogContains("MSB4044");
149+
}
148150

149-
if ((i & 1) == 1)
150-
{
151-
p.XmlInputPath = new TaskItem(xmlInputPath);
152-
}
151+
[Fact]
152+
public void PokeWithMissingRequiredQuery()
153+
{
154+
const string projectContent = @"<Project><Target Name=""Test""><XmlPoke XmlInputPath=""nonesuch"" /></Target></Project>";
153155

154-
if ((i & 2) == 2)
155-
{
156-
p.Query = "//variable/@Name";
157-
}
156+
MockLogger log = new();
157+
Project project = ObjectModelHelpers.CreateInMemoryProject(projectContent, log);
158158

159-
// "Expecting argumentnullexception for the first 3 tests"
160-
if (i < 3)
161-
{
162-
Should.Throw<ArgumentNullException>(() => p.Execute());
163-
}
164-
else
165-
{
166-
Should.NotThrow(() => p.Execute());
167-
}
168-
}
159+
project.Build().ShouldBeFalse();
160+
log.AssertLogContains("MSB4044");
161+
log.AssertLogContains("\"Query\"");
162+
}
163+
164+
[Fact]
165+
public void PokeWithMissingRequiredXmlInputPath()
166+
{
167+
const string projectContent = @"<Project><Target Name=""Test""><XmlPoke Query=""nonesuch"" /></Target></Project>";
168+
169+
MockLogger log = new();
170+
Project project = ObjectModelHelpers.CreateInMemoryProject(projectContent, log);
171+
172+
project.Build().ShouldBeFalse();
173+
log.AssertLogContains("MSB4044");
174+
log.AssertLogContains("\"XmlInputPath\"");
175+
}
176+
177+
[Fact]
178+
public void PokeWithRequiredParameters()
179+
{
180+
MockEngine engine = new(true);
181+
Prepare(_xmlFileNoNs, out string xmlInputPath);
182+
183+
XmlPoke task = new()
184+
{
185+
BuildEngine = engine,
186+
XmlInputPath = new TaskItem(xmlInputPath),
187+
Query = "//variable/@Name",
188+
};
189+
190+
task.Execute().ShouldBeTrue();
169191
}
170192

171193
[Fact]

src/Tasks/XmlPeek.cs

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,11 @@ namespace Microsoft.Build.Tasks
2121
/// </summary>
2222
public class XmlPeek : TaskExtension
2323
{
24-
#region Members
24+
#region Properties
2525

2626
/// <summary>
2727
/// The XPath Query.
2828
/// </summary>
29-
private string _query;
30-
31-
#endregion
32-
33-
#region Properties
34-
/// <summary>
35-
/// The XML input as a file path.
36-
/// </summary>
3729
public ITaskItem XmlInputPath { get; set; }
3830

3931
/// <summary>
@@ -44,16 +36,8 @@ public class XmlPeek : TaskExtension
4436
/// <summary>
4537
/// The XPath Query.
4638
/// </summary>
47-
public string Query
48-
{
49-
get
50-
{
51-
ErrorUtilities.VerifyThrowArgumentNull(_query, "Query");
52-
return _query;
53-
}
54-
55-
set => _query = value;
56-
}
39+
[Required]
40+
public string Query { get; set; }
5741

5842
/// <summary>
5943
/// The results returned by this task.
@@ -71,6 +55,7 @@ public string Query
7155
/// if DTD is present. This was a pre-v15 behavior. By default, a DTD clause if any is ignored.
7256
/// </summary>
7357
public bool ProhibitDtd { get; set; }
58+
7459
#endregion
7560

7661
/// <summary>
@@ -80,8 +65,6 @@ public string Query
8065
public override bool Execute()
8166
{
8267
XmlInput xmlinput;
83-
ErrorUtilities.VerifyThrowArgumentNull(_query, nameof(Query));
84-
8568
try
8669
{
8770
xmlinput = new XmlInput(XmlInputPath, XmlContent);
@@ -99,7 +82,6 @@ public override bool Execute()
9982
using (XmlReader xr = xmlinput.CreateReader(ProhibitDtd))
10083
{
10184
xpathdoc = new XPathDocument(xr);
102-
xr.Dispose();
10385
}
10486
}
10587
catch (Exception e) when (!ExceptionHandling.IsCriticalException(e))
@@ -117,11 +99,11 @@ public override bool Execute()
11799
try
118100
{
119101
// Create the expression from query
120-
expr = nav.Compile(_query);
102+
expr = nav.Compile(Query);
121103
}
122104
catch (Exception e) when (!ExceptionHandling.IsCriticalException(e))
123105
{
124-
Log.LogErrorWithCodeFromResources("XmlPeekPoke.XPathError", _query, e.Message);
106+
Log.LogErrorWithCodeFromResources("XmlPeekPoke.XPathError", Query, e.Message);
125107
return false;
126108
}
127109

@@ -230,15 +212,15 @@ private static void LoadNamespaces(ref XmlNamespaceManager namespaceManager, str
230212
/// <summary>
231213
/// This class prepares XML input from XMLInputPath and XMLContent parameters
232214
/// </summary>
233-
internal class XmlInput
215+
private sealed class XmlInput
234216
{
235217
/// <summary>
236218
/// This either contains the raw Xml or the path to Xml file.
237219
/// </summary>
238220
private readonly string _data;
239221

240222
/// <summary>
241-
/// Filestream used to read XML.
223+
/// FileStream used to read XML.
242224
/// </summary>
243225
private FileStream _fs;
244226

@@ -254,7 +236,8 @@ public XmlInput(ITaskItem xmlInputPath, string xmlContent)
254236
{
255237
throw new ArgumentException(ResourceUtilities.GetResourceString("XmlPeek.XmlInput.TooMany"));
256238
}
257-
else if (xmlInputPath == null && xmlContent == null)
239+
240+
if (xmlInputPath == null && xmlContent == null)
258241
{
259242
throw new ArgumentException(ResourceUtilities.GetResourceString("XmlPeek.XmlInput.TooFew"));
260243
}
@@ -274,7 +257,7 @@ public XmlInput(ITaskItem xmlInputPath, string xmlContent)
274257
/// <summary>
275258
/// Possible accepted types of XML input.
276259
/// </summary>
277-
public enum XmlModes
260+
private enum XmlModes
278261
{
279262
/// <summary>
280263
/// If the mode is a XML file.
@@ -290,7 +273,7 @@ public enum XmlModes
290273
/// <summary>
291274
/// Returns the current mode of the XmlInput
292275
/// </summary>
293-
public XmlModes XmlMode { get; }
276+
private XmlModes XmlMode { get; }
294277

295278
/// <summary>
296279
/// Creates correct reader based on the input type.

src/Tasks/XmlPoke.cs

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,23 @@ namespace Microsoft.Build.Tasks
2020
/// </summary>
2121
public class XmlPoke : TaskExtension
2222
{
23-
#region Members
24-
/// <summary>
25-
/// The XML input as file paths.
26-
/// </summary>
27-
private ITaskItem _xmlInputPath;
28-
29-
/// <summary>
30-
/// The XPath Query.
31-
/// </summary>
32-
private string _query;
33-
34-
#endregion
35-
3623
#region Properties
24+
3725
/// <summary>
3826
/// The XML input as file path.
3927
/// </summary>
40-
public ITaskItem XmlInputPath
41-
{
42-
get
43-
{
44-
ErrorUtilities.VerifyThrowArgumentNull(_xmlInputPath, nameof(XmlInputPath));
45-
return _xmlInputPath;
46-
}
47-
48-
set => _xmlInputPath = value;
49-
}
28+
[Required]
29+
public ITaskItem XmlInputPath { get; set; }
5030

5131
/// <summary>
5232
/// The XPath Query.
5333
/// </summary>
54-
public string Query
55-
{
56-
get
57-
{
58-
ErrorUtilities.VerifyThrowArgumentNull(_query, nameof(Query));
59-
return _query;
60-
}
61-
62-
set => _query = value;
63-
}
34+
[Required]
35+
public string Query { get; set; }
6436

6537
/// <summary>
6638
/// The value to be inserted into the specified location.
67-
/// </summary>
39+
/// </summary>
6840
public ITaskItem Value { get; set; }
6941

7042
/// <summary>
@@ -77,23 +49,21 @@ public string Query
7749
/// <summary>
7850
/// Executes the XMLPoke task.
7951
/// </summary>
80-
/// <returns>true if transformation succeeds.</returns>
52+
/// <returns>true if task execution succeeds.</returns>
8153
public override bool Execute()
8254
{
83-
ErrorUtilities.VerifyThrowArgumentNull(_query, "Query");
84-
ErrorUtilities.VerifyThrowArgumentNull(_xmlInputPath, "XmlInputPath");
8555
if (Value == null)
8656
{
8757
// When Value is null, it means Value is not set or empty. Here we treat them all as empty.
88-
Value = new TaskItem(String.Empty);
58+
Value = new TaskItem(string.Empty);
8959
}
9060

9161
// Load the XPath Document
9262
XmlDocument xmlDoc = new XmlDocument();
9363

9464
try
9565
{
96-
using (FileStream fs = new FileStream(_xmlInputPath.ItemSpec, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
66+
using (FileStream fs = new FileStream(XmlInputPath.ItemSpec, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
9767
{
9868
XmlReaderSettings xrs = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore };
9969
using (XmlReader sr = XmlReader.Create(fs, xrs))
@@ -104,7 +74,7 @@ public override bool Execute()
10474
}
10575
catch (Exception e) when (!ExceptionHandling.IsCriticalException(e))
10676
{
107-
Log.LogErrorWithCodeFromResources("XmlPeekPoke.InputFileError", _xmlInputPath.ItemSpec, e.Message);
77+
Log.LogErrorWithCodeFromResources("XmlPeekPoke.InputFileError", XmlInputPath.ItemSpec, e.Message);
10878
return false;
10979
}
11080

@@ -114,11 +84,11 @@ public override bool Execute()
11484
try
11585
{
11686
// Create the expression from query
117-
expr = nav.Compile(_query);
87+
expr = nav.Compile(Query);
11888
}
11989
catch (Exception e) when (!ExceptionHandling.IsCriticalException(e))
12090
{
121-
Log.LogErrorWithCodeFromResources("XmlPeekPoke.XPathError", _query, e.Message);
91+
Log.LogErrorWithCodeFromResources("XmlPeekPoke.XPathError", Query, e.Message);
12292
return false;
12393
}
12494

@@ -169,12 +139,12 @@ public override bool Execute()
169139
if (count > 0)
170140
{
171141
#if RUNTIME_TYPE_NETCORE
172-
using (Stream stream = File.Create(_xmlInputPath.ItemSpec))
142+
using (Stream stream = File.Create(XmlInputPath.ItemSpec))
173143
{
174144
xmlDoc.Save(stream);
175145
}
176146
#else
177-
xmlDoc.Save(_xmlInputPath.ItemSpec);
147+
xmlDoc.Save(XmlInputPath.ItemSpec);
178148
#endif
179149
}
180150

0 commit comments

Comments
 (0)