diff --git a/src/JsonPoke/JsonPoke.cs b/src/JsonPoke/JsonPoke.cs
index cd40d87..e2279b2 100644
--- a/src/JsonPoke/JsonPoke.cs
+++ b/src/JsonPoke/JsonPoke.cs
@@ -1,283 +1,291 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-///
-/// Sets values as specified by a JSONPath query into a JSON file.
-///
-public class JsonPoke : Task
-{
- static readonly Regex JPathExpr = new(@"(?\['(?[^\]]+)'\])|(?\.(?[^\.\[]+))|(?\[(?\^)?(?\d+)\])", RegexOptions.Compiled);
-
- ///
- /// Specifies the JSON input as a string.
- ///
- [Output]
- public string? Content { get; set; }
-
- ///
- /// Specifies the JSON input as a file path.
- ///
- public ITaskItem? ContentPath { get; set; }
-
- ///
- /// Specifies the JSONPath expression.
- ///
- [Required]
- public string Query { get; set; } = "$";
-
- ///
- /// Specifies the value to be inserted into the specified path.
- ///
- public ITaskItem[] Value { get; set; } = Array.Empty();
-
- ///
- /// Specifies the raw (JSON) value to be inserted into the specified path.
- ///
- public string? RawValue { get; set; }
-
- ///
- /// Property names to set for a JSON object value from matching
- /// item metadata values from item(s).
- ///
- public ITaskItem[] Properties { get; set; } = Array.Empty();
-
- ///
- /// Contains the updated JSON nodes.
- ///
- [Output]
- public ITaskItem[] Result { get; private set; } = new ITaskItem[0];
-
- ///
- /// Locates nodes matching the and replaces their contents
- /// with the provided .
- ///
- public override bool Execute()
- {
- if (Content == null && ContentPath == null)
- return Log.Error("JPO01", $"Either {nameof(Content)} or {nameof(ContentPath)} must be provided.");
-
- if (ContentPath != null && !File.Exists(ContentPath.GetMetadata("FullPath")))
- return Log.Error("JPO02", $"Specified {nameof(ContentPath)} not found at {ContentPath.GetMetadata("FullPath")}.");
-
- if (Content != null && ContentPath != null)
- return Log.Error("JPO03", $"Cannot specify both {nameof(Content)} and {nameof(ContentPath)}.");
-
- var content = ContentPath != null ?
- File.ReadAllText(ContentPath.GetMetadata("FullPath")) : Content;
-
- if (string.IsNullOrEmpty(content))
- return Log.Error("JPO04", $"Empty JSON content.");
-
- if (Value.Length == 0 && RawValue == null)
- return Log.Warn("JPO05", $"No value(s) specified.", true);
-
- if (Value.Length > 0 && RawValue != null)
- return Log.Error("JPO06", $"Cannot specify both {nameof(Value)} and {nameof(RawValue)}.");
-
- var jvalue = new Lazy(GetValue);
-
- var json = JObject.Parse(content!);
- var matches = JPathExpr.Matches(Query).Cast().ToList();
- // If we have any part of teh expression using our own "from end" syntax for array indexing,
- // we know we'll be inserting a *new*
- var nodes = matches.Any(m => m.Groups["end"].Success) ? new() : json.SelectTokens(Query).ToList();
- var result = new List();
- var owned = new HashSet();
-
- // We couldn't match anything to Query, so attempt to
- // create an object at the specified path.
- if (nodes.Count == 0)
- {
- // If we can't match anything, we can't create any objects.
- if (matches.Count == 0)
- return true;
-
- // Split paths, try to match sequentially, can't do wildcards as final segment
- for (var midx = 0; midx < matches.Count; midx++)
- {
- var match = matches[midx];
- var parent = json.SelectToken(Query[..match.Index]);
- var token = match.Groups["end"].Success ? null : json.SelectToken(Query[..(match.Index + match.Length)]);
- if (token != null)
- continue;
-
- if (parent == null)
- return Log.Error("JPO07", $"Could not find parent node for {Query[..match.Index]}.");
-
- // For arrays, if we don't find the element, create/add it if we can
- if (match.Groups["array"].Success)
- {
- if (parent is not JArray array)
- {
- // We own the node (meaning we created it previously), so we can replace it with an array instead.
- if (owned.Contains(Query[..match.Index]))
- {
- array = new JArray();
- parent.Replace(array);
- }
- else
- {
- return Log.Warn("JPO08", $"JSONPath segment '{Query[..match.Index]}' didn't match a JSON array.");
- }
- }
-
- if (match.Groups["index"].Success)
- {
- var index = int.Parse(match.Groups["index"].Value, CultureInfo.InvariantCulture);
- if (match.Groups["end"].Success)
- {
- index = array.Count + 1 - index;
- // In this case, we'll be changing the index value, so we'll need
- // to replace the query and matches for subsequent segments.
- Query = Query[..match.Index] + "[" + index + "]" + Query[(match.Index + match.Length)..];
- matches = JPathExpr.Matches(Query).Cast().ToList();
- match = matches[midx];
- }
-
- if (index >= 0 && index <= array.Count)
- {
- // We can simply add the new object at the given index.
- token = new JObject();
- array.Insert(index, token);
- owned.Add(Query[..(match.Index + match.Length)]);
- }
- else
- {
- return Log.Warn("JPO09", $"JSONPath index {index} out of range.");
- }
- }
- else
- {
- return Log.Warn("JPO10", $"JSONPath array index not specified.");
- }
- }
- else
- {
- // If parent is not an object, we can't set a property on it.
- if (parent is not JObject obj)
- return Log.Warn("JPO11", $"JSONPath segment '{Query[..match.Index]}' didn't match a JSON object.");
-
- token = new JProperty(match.Groups["name"].Value, new JObject());
- owned.Add(Query[..(match.Index + match.Length)]);
- obj.Add(token);
- }
-
- if (token == null)
- return false;
- }
- }
-
- nodes = json.SelectTokens(Query).ToList();
-
- void AddResult(JToken node, int index)
- {
- if (nodes.Count == 1)
- {
- result.Add(new TaskItem(Query, new Dictionary
- {
- { "Value", node.AsString() }
- }));
- }
- else
- {
- result.Add(new TaskItem(Query + "[" + index + "]", new Dictionary
- {
- { "Value", node.AsString() }
- }));
- }
- }
-
- for (var i = 0; i < nodes.Count; i++)
- {
- var node = nodes[i];
-
- if (Value.Length > 1 || Properties.Length != 0 || RawValue != null)
- {
- // We'll be doing complex object replacement,
- // so just replace the whole thing in one shot,
- // no smarts for target-type selection.
- node.Replace(jvalue.Value);
- AddResult(jvalue.Value, i);
- continue;
- }
-
- // If the Value.Length == 1 OR Properties.Length == 0 (meaning
- // we're not entering above condition for either arrays or complex
- // objects), it's a single value, which we can target-type to the
- // native node type being replaced. This allows us to preserve the
- // native JSON type whenever possible.
-
- var value = node.Type switch
- {
- JTokenType.String => new JValue(Value[0].ItemSpec),
- JTokenType.Array => new JArray(jvalue.Value),
- JTokenType.Integer when long.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
- JTokenType.Float when decimal.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
- JTokenType.Boolean when bool.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
- JTokenType.Date when DateTime.TryParseExact(Value[0].ItemSpec, "O", CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out var typed) => new JValue(typed),
- JTokenType.Date when DateTime.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
- JTokenType.Guid when Guid.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
- JTokenType.Uri when Uri.TryCreate(Value[0].ItemSpec, UriKind.RelativeOrAbsolute, out var typed) => new JValue(typed),
- JTokenType.TimeSpan when TimeSpan.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
- _ => jvalue.Value,
- };
-
- node.Replace(value);
- AddResult(value, i);
- }
-
- Content = json.ToString(Formatting.Indented);
- if (ContentPath != null)
- File.WriteAllText(ContentPath.GetMetadata("FullPath"), Content);
-
- Result = result.ToArray();
-
- return true;
- }
-
- JToken GetValue()
- {
- if (Value.Length == 1)
- return GetValue(Value[0]);
- else if (RawValue != null)
- return JToken.Parse(RawValue);
-
- return new JArray(Value.Select(GetValue).ToArray());
- }
-
- JToken GetValue(ITaskItem item)
- {
- if (Properties.Length == 0)
- return GetTypedValue(item.ItemSpec);
-
- var value = new JObject();
- foreach (var prop in Properties)
- value[prop.ItemSpec] = GetTypedValue(item.GetMetadata(prop.ItemSpec));
-
- return value;
- }
-
- JToken GetTypedValue(string itemSpec)
- {
- if ((itemSpec.StartsWith("\"") && itemSpec.EndsWith("\"")) ||
- (itemSpec.StartsWith("'") && itemSpec.EndsWith("'")))
- return new JValue(itemSpec.Trim('\'', '"'));
-
- try
- {
- return JToken.Parse(itemSpec);
- }
- catch
- {
- return new JValue(itemSpec);
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+///
+/// Sets values as specified by a JSONPath query into a JSON file.
+///
+public class JsonPoke : Task
+{
+ static readonly Regex JPathExpr = new(@"(?\['(?[^\]]+)'\])|(?\.(?[^\.\[]+))|(?\[(?\^)?(?\d+)\])", RegexOptions.Compiled);
+
+ ///
+ /// Specifies the JSON input as a string.
+ ///
+ [Output]
+ public string? Content { get; set; }
+
+ ///
+ /// Specifies the JSON input as a file path.
+ ///
+ public ITaskItem? ContentPath { get; set; }
+
+ ///
+ /// Specifies the JSONPath expression.
+ ///
+ [Required]
+ public string Query { get; set; } = "$";
+
+ ///
+ /// Specifies the value to be inserted into the specified path.
+ ///
+ public ITaskItem[] Value { get; set; } = Array.Empty();
+
+ ///
+ /// Specifies the raw (JSON) value to be inserted into the specified path.
+ ///
+ public string? RawValue { get; set; }
+
+ ///
+ /// Property names to set for a JSON object value from matching
+ /// item metadata values from item(s).
+ ///
+ public ITaskItem[] Properties { get; set; } = Array.Empty();
+
+ ///
+ /// Contains the updated JSON nodes.
+ ///
+ [Output]
+ public ITaskItem[] Result { get; private set; } = new ITaskItem[0];
+
+ ///
+ /// Locates nodes matching the and replaces their contents
+ /// with the provided .
+ ///
+ public override bool Execute()
+ {
+ if (Content == null && ContentPath == null)
+ return Log.Error("JPO01", $"Either {nameof(Content)} or {nameof(ContentPath)} must be provided.");
+
+ if (ContentPath != null && !File.Exists(ContentPath.GetMetadata("FullPath")))
+ return Log.Error("JPO02", $"Specified {nameof(ContentPath)} not found at {ContentPath.GetMetadata("FullPath")}.");
+
+ if (Content != null && ContentPath != null)
+ return Log.Error("JPO03", $"Cannot specify both {nameof(Content)} and {nameof(ContentPath)}.");
+
+ var content = ContentPath != null ?
+ File.ReadAllText(ContentPath.GetMetadata("FullPath")) : Content;
+
+ if (string.IsNullOrEmpty(content))
+ return Log.Error("JPO04", $"Empty JSON content.");
+
+ if (Value.Length == 0 && RawValue == null)
+ return Log.Warn("JPO05", $"No value(s) specified.", true);
+
+ if (Value.Length > 0 && RawValue != null)
+ return Log.Error("JPO06", $"Cannot specify both {nameof(Value)} and {nameof(RawValue)}.");
+
+ var jvalue = new Lazy(GetValue);
+
+ var json = JToken.Parse(content!);
+ var matches = JPathExpr.Matches(Query).Cast().ToList();
+
+ void SetToken(JToken node, JToken value)
+ {
+ if (node.Parent == null)
+ json = value;
+ else
+ node.Replace(value);
+ }
+ // If we have any part of teh expression using our own "from end" syntax for array indexing,
+ // we know we'll be inserting a *new*
+ var nodes = matches.Any(m => m.Groups["end"].Success) ? new() : json.SelectTokens(Query).ToList();
+ var result = new List();
+ var owned = new HashSet();
+
+ // We couldn't match anything to Query, so attempt to
+ // create an object at the specified path.
+ if (nodes.Count == 0)
+ {
+ // If we can't match anything, we can't create any objects.
+ if (matches.Count == 0)
+ return true;
+
+ // Split paths, try to match sequentially, can't do wildcards as final segment
+ for (var midx = 0; midx < matches.Count; midx++)
+ {
+ var match = matches[midx];
+ var parent = json.SelectToken(Query[..match.Index]);
+ var token = match.Groups["end"].Success ? null : json.SelectToken(Query[..(match.Index + match.Length)]);
+ if (token != null)
+ continue;
+
+ if (parent == null)
+ return Log.Error("JPO07", $"Could not find parent node for {Query[..match.Index]}.");
+
+ // For arrays, if we don't find the element, create/add it if we can
+ if (match.Groups["array"].Success)
+ {
+ if (parent is not JArray array)
+ {
+ // We own the node (meaning we created it previously), so we can replace it with an array instead.
+ if (owned.Contains(Query[..match.Index]))
+ {
+ array = new JArray();
+ parent.Replace(array);
+ }
+ else
+ {
+ return Log.Warn("JPO08", $"JSONPath segment '{Query[..match.Index]}' didn't match a JSON array.");
+ }
+ }
+
+ if (match.Groups["index"].Success)
+ {
+ var index = int.Parse(match.Groups["index"].Value, CultureInfo.InvariantCulture);
+ if (match.Groups["end"].Success)
+ {
+ index = array.Count + 1 - index;
+ // In this case, we'll be changing the index value, so we'll need
+ // to replace the query and matches for subsequent segments.
+ Query = Query[..match.Index] + "[" + index + "]" + Query[(match.Index + match.Length)..];
+ matches = JPathExpr.Matches(Query).Cast().ToList();
+ match = matches[midx];
+ }
+
+ if (index >= 0 && index <= array.Count)
+ {
+ // We can simply add the new object at the given index.
+ token = new JObject();
+ array.Insert(index, token);
+ owned.Add(Query[..(match.Index + match.Length)]);
+ }
+ else
+ {
+ return Log.Warn("JPO09", $"JSONPath index {index} out of range.");
+ }
+ }
+ else
+ {
+ return Log.Warn("JPO10", $"JSONPath array index not specified.");
+ }
+ }
+ else
+ {
+ // If parent is not an object, we can't set a property on it.
+ if (parent is not JObject obj)
+ return Log.Warn("JPO11", $"JSONPath segment '{Query[..match.Index]}' didn't match a JSON object.");
+
+ token = new JProperty(match.Groups["name"].Value, new JObject());
+ owned.Add(Query[..(match.Index + match.Length)]);
+ obj.Add(token);
+ }
+
+ if (token == null)
+ return false;
+ }
+ }
+
+ nodes = json.SelectTokens(Query).ToList();
+
+ void AddResult(JToken node, int index)
+ {
+ if (nodes.Count == 1)
+ {
+ result.Add(new TaskItem(Query, new Dictionary
+ {
+ { "Value", node.AsString() }
+ }));
+ }
+ else
+ {
+ result.Add(new TaskItem(Query + "[" + index + "]", new Dictionary
+ {
+ { "Value", node.AsString() }
+ }));
+ }
+ }
+
+ for (var i = 0; i < nodes.Count; i++)
+ {
+ var node = nodes[i];
+
+ if (Value.Length > 1 || Properties.Length != 0 || RawValue != null)
+ {
+ // We'll be doing complex object replacement,
+ // so just replace the whole thing in one shot,
+ // no smarts for target-type selection.
+ SetToken(node, jvalue.Value);
+ AddResult(jvalue.Value, i);
+ continue;
+ }
+
+ // If the Value.Length == 1 OR Properties.Length == 0 (meaning
+ // we're not entering above condition for either arrays or complex
+ // objects), it's a single value, which we can target-type to the
+ // native node type being replaced. This allows us to preserve the
+ // native JSON type whenever possible.
+
+ var value = node.Type switch
+ {
+ JTokenType.String => new JValue(Value[0].ItemSpec),
+ JTokenType.Array => new JArray(jvalue.Value),
+ JTokenType.Integer when long.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
+ JTokenType.Float when decimal.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
+ JTokenType.Boolean when bool.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
+ JTokenType.Date when DateTime.TryParseExact(Value[0].ItemSpec, "O", CultureInfo.CurrentCulture, DateTimeStyles.RoundtripKind, out var typed) => new JValue(typed),
+ JTokenType.Date when DateTime.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
+ JTokenType.Guid when Guid.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
+ JTokenType.Uri when Uri.TryCreate(Value[0].ItemSpec, UriKind.RelativeOrAbsolute, out var typed) => new JValue(typed),
+ JTokenType.TimeSpan when TimeSpan.TryParse(Value[0].ItemSpec, out var typed) => new JValue(typed),
+ _ => jvalue.Value,
+ };
+
+ SetToken(node, value);
+ AddResult(value, i);
+ }
+
+ Content = json.ToString(Formatting.Indented);
+ if (ContentPath != null)
+ File.WriteAllText(ContentPath.GetMetadata("FullPath"), Content);
+
+ Result = result.ToArray();
+
+ return true;
+ }
+
+ JToken GetValue()
+ {
+ if (Value.Length == 1)
+ return GetValue(Value[0]);
+ else if (RawValue != null)
+ return JToken.Parse(RawValue);
+
+ return new JArray(Value.Select(GetValue).ToArray());
+ }
+
+ JToken GetValue(ITaskItem item)
+ {
+ if (Properties.Length == 0)
+ return GetTypedValue(item.ItemSpec);
+
+ var value = new JObject();
+ foreach (var prop in Properties)
+ value[prop.ItemSpec] = GetTypedValue(item.GetMetadata(prop.ItemSpec));
+
+ return value;
+ }
+
+ JToken GetTypedValue(string itemSpec)
+ {
+ if ((itemSpec.StartsWith("\"") && itemSpec.EndsWith("\"")) ||
+ (itemSpec.StartsWith("'") && itemSpec.EndsWith("'")))
+ return new JValue(itemSpec.Trim('\'', '"'));
+
+ try
+ {
+ return JToken.Parse(itemSpec);
+ }
+ catch
+ {
+ return new JValue(itemSpec);
+ }
+ }
+}
diff --git a/src/Tests/Poke.targets b/src/Tests/Poke.targets
index c61c7db..d38cd86 100644
--- a/src/Tests/Poke.targets
+++ b/src/Tests/Poke.targets
@@ -284,6 +284,30 @@
+
+
+ $.a
+ Value of a
+
+
+
+
+ Value of a
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Tests/Tests.cs b/src/Tests/Tests.cs
index 2a6d992..a96b8fc 100644
--- a/src/Tests/Tests.cs
+++ b/src/Tests/Tests.cs
@@ -1,239 +1,275 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Xml.Linq;
-using Microsoft.Build.Execution;
-using Microsoft.Build.Framework;
-using Microsoft.Build.Utilities;
-using Newtonsoft.Json.Linq;
-using Xunit;
-using Xunit.Abstractions;
-
-public record Tests(ITestOutputHelper Output)
-{
- [Fact]
- public void AddObjectPath()
- {
- var poke = new JsonPoke
- {
- Content = @"{ ""profiles"": { } }",
- Query = "$.profiles['Foo.cs'].commandName",
- RawValue = "'Project'",
- };
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
- string? value = obj?.profiles?["Foo.cs"]?.commandName;
-
- Assert.Equal("Project", value);
- }
-
- [Fact]
- public void AddArrayElement()
- {
- var poke = new JsonPoke
- {
- Content = @"{ ""values"": [] }",
- Query = "$.values[0].commandName",
- RawValue = "'Project'",
- };
-
- Assert.True(poke.Execute());
-
- poke.Query = "$.values[1].commandName";
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
-
- Assert.Equal("Project", (string?)obj?.values?[0]?.commandName);
- Assert.Equal("Project", (string?)obj?.values?[1]?.commandName);
- }
-
- [Fact]
- public void AddLastArrayElement()
- {
- var poke = new JsonPoke
- {
- Content = @"{ ""values"": [ ""foo"", ""bar"" ] }",
- Query = "$.values[^1]",
- RawValue = "'baz'",
- };
-
- Assert.True(poke.Execute());
-
- poke.Query = "$.values[^1]";
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
-
- Assert.Equal("baz", (string?)obj?.values?[2]);
- Assert.Equal("baz", (string?)obj?.values?[3]);
- }
-
- [Fact]
- public void AddMiddleArrayElement()
- {
- var poke = new JsonPoke
- {
- Content = @"{ ""values"": [ ""foo"", ""bar"" ] }",
- Query = "$.values[1]",
- RawValue = "'baz'",
- };
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
-
- Assert.Equal("baz", (string?)obj?.values?[1]);
- }
-
- [Fact]
- public void AddMiddleArrayElementFromEnd()
- {
- var poke = new JsonPoke
- {
- Content = @"{ ""values"": [ { }, { } ] }",
- Query = "$.values[^2].data",
- RawValue = "'baz'",
- };
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
-
- Assert.Equal("baz", (string?)obj?.values?[1]?.data);
- }
-
- [Fact]
- public void AddLastArrayElementWithEmptyArray()
- {
- var poke = new JsonPoke
- {
- Content = @"{ ""values"": [ ] }",
- Query = "$.values[^1]",
- RawValue = "'baz'",
- };
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
-
- Assert.Equal("baz", (string?)obj?.values?[0]);
- }
-
- [Fact]
- public void AddLastArrayElementWithNoArray()
- {
- var poke = new JsonPoke
- {
- Content = @"{ }",
- Query = "$.values[^1]",
- RawValue = "'baz'",
- };
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
-
- Assert.Equal("baz", (string?)obj?.values?[0]);
- }
-
- [Fact]
- public void AddObjectArray()
- {
- var poke = new JsonPoke
- {
- Content = @"{ }",
- Query = "$.foo[0].bar[0].baz",
- RawValue = "'yay'",
- };
-
- Assert.True(poke.Execute());
-
- dynamic obj = JObject.Parse(poke.Content);
- string? value = obj?.foo?[0]?.bar?[0]?.baz;
-
- Assert.Equal("yay", value);
- }
-
- [Theory]
- [MemberData(nameof(GetTargets))]
- public void Run(string file, string name, bool failure = false, string? code = null)
- {
- var logger = new TestLogger();
- var result = BuildManager.DefaultBuildManager.Build(
- new BuildParameters
- {
- ResetCaches = true,
- Loggers = new ILogger[] { logger }
- },
- new BuildRequestData(
- Path.Combine(Directory.GetCurrentDirectory(), file),
- new Dictionary(), null, new[] { name }, null));
-
- if (failure)
- {
- if (result.OverallResult != BuildResultCode.Failure)
- Output.WriteLine(string.Join(Environment.NewLine, logger.Events
- .Select(e => e.Message)));
-
- Assert.Equal(BuildResultCode.Failure, result.OverallResult);
- Assert.Contains(code, logger.Errors);
- }
- else
- {
- if (result.OverallResult != BuildResultCode.Success)
- Output.WriteLine(string.Join(Environment.NewLine, logger.Events
- .Select(e => e.Message)));
-
- Assert.Equal(BuildResultCode.Success, result.OverallResult);
- if (code != null)
- Assert.Contains(code, logger.Warnings);
- }
-
- Output.WriteLine(string.Join(Environment.NewLine, logger.Events.OfType()
- .Where(e => e.Importance == MessageImportance.High)
- .Select(e => e.Message)));
- }
-
- public static IEnumerable