diff --git a/src/Sdk/DTObjectTemplating/ObjectTemplating/TemplateContext.cs b/src/Sdk/DTObjectTemplating/ObjectTemplating/TemplateContext.cs index af8cf76ec..87c4762ec 100644 --- a/src/Sdk/DTObjectTemplating/ObjectTemplating/TemplateContext.cs +++ b/src/Sdk/DTObjectTemplating/ObjectTemplating/TemplateContext.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -120,15 +120,9 @@ namespace GitHub.DistributedTask.ObjectTemplating } } - internal void Error(TemplateValidationError error) - { - Errors.Add(error); - TraceWriter.Error(error.Message); - } - internal void Error( - TemplateToken value, - Exception ex) + TemplateToken value, + Exception ex) { Error(value?.FileId, value?.Line, value?.Column, ex); } diff --git a/src/Test/L0/Sdk/DTObjectTemplating/TemplateContextL0.cs b/src/Test/L0/Sdk/DTObjectTemplating/TemplateContextL0.cs index 2a4815305..6a7798011 100644 --- a/src/Test/L0/Sdk/DTObjectTemplating/TemplateContextL0.cs +++ b/src/Test/L0/Sdk/DTObjectTemplating/TemplateContextL0.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using GitHub.DistributedTask.ObjectTemplating.Tokens; using Xunit; @@ -10,22 +11,198 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tests [Fact] [Trait("Level", "L0")] [Trait("Category", "Common")] - public void VerifyError() + public void VerifyErrorWithTokenAndException() { TemplateContext context = buildContext(); - TemplateToken value = new StringToken(1, 1, 1, "some-token"); - System.Exception ex = new System.Exception(); - List expectedErrors = new(); - expectedErrors.Add(new TemplateValidationError("(Line: 1, Col: 1): Exception of type 'System.Exception' was thrown.")); + List expectedErrors = new List { new TemplateValidationError("(Line: 1, Col: 1): Exception of type 'System.Exception' was thrown.") }; - context.Error(value, ex); + context.Error(new StringToken(1, 1, 1, "some-token"), new System.Exception()); - - Assert.True(expectedErrors.SequenceEqual(toList(context.Errors.GetEnumerator()))); + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + } - Assert.True(true); + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithNullTokenAndException() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("System.Exception: Exception of type 'System.Exception' was thrown.") }; + + context.Error(null, new System.Exception()); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithTokenAndMessage() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("(Line: 1, Col: 1): message") }; + + context.Error(new StringToken(1, 1, 1, "some-token"), "message"); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithNullTokenAndMessage() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("message") }; + + context.Error(null, "message"); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithException() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("(Line: 2, Col: 3): Fatal template exception") }; + List expectedTracewriterErrors = new List { "(Line: 2, Col: 3):" }; + + context.Error(1, 2, 3, new Exception("Fatal template exception")); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + ListTraceWriter listTraceWriter = (ListTraceWriter)context.TraceWriter; + List tracewriterErrors = listTraceWriter.GetErrors(); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + Assert.True(expectedTracewriterErrors.SequenceEqual(tracewriterErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithExceptionAndInnerException() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("(Line: 2, Col: 3): Fatal template exception"), + new TemplateValidationError("(Line: 2, Col: 3): Inner Exception") }; + List expectedTracewriterErrors = new List { "(Line: 2, Col: 3):" }; + + Exception e = new Exception("Fatal template exception", new Exception("Inner Exception")); + + context.Error(1, 2, 3, e); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + ListTraceWriter listTraceWriter = (ListTraceWriter)context.TraceWriter; + List tracewriterErrors = listTraceWriter.GetErrors(); + + Assert.Equal(2, templateValidationErrors.Count); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + Assert.True(expectedTracewriterErrors.SequenceEqual(tracewriterErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithLineNumbersAndMessage() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("(Line: 2, Col: 3): Fatal template exception") }; + List expectedTracewriterErrors = new List { "(Line: 2, Col: 3): Fatal template exception" }; + + context.Error(1, 2, 3, "Fatal template exception"); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + ListTraceWriter listTraceWriter = (ListTraceWriter)context.TraceWriter; + List tracewriterErrors = listTraceWriter.GetErrors(); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + Assert.True(expectedTracewriterErrors.SequenceEqual(tracewriterErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithNullLineNumbersAndMessage() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("Fatal template exception") }; + List expectedTracewriterErrors = new List { "Fatal template exception" }; + + context.Error(null, null, null, "Fatal template exception"); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + ListTraceWriter listTraceWriter = (ListTraceWriter)context.TraceWriter; + List tracewriterErrors = listTraceWriter.GetErrors(); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + Assert.True(expectedTracewriterErrors.SequenceEqual(tracewriterErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithLineNumbersAndException() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("(Line: 2, Col: 3): Fatal template exception") }; + List expectedTracewriterErrors = new List { "(Line: 2, Col: 3):" }; + + context.Error(1, 2, 3, new Exception("Fatal template exception")); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + ListTraceWriter listTraceWriter = (ListTraceWriter)context.TraceWriter; + List tracewriterErrors = listTraceWriter.GetErrors(); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + Assert.True(expectedTracewriterErrors.SequenceEqual(tracewriterErrors)); + } + + [Fact] + [Trait("Level", "L0")] + [Trait("Category", "Common")] + public void VerifyErrorWithNullLineNumbersAndException() + { + TemplateContext context = buildContext(); + + List expectedErrors = new List { new TemplateValidationError("System.Exception: Fatal template exception") }; + List expectedTracewriterErrors = new List { "" }; + + context.Error(null, null, null, new Exception("Fatal template exception")); + + List templateValidationErrors = toList(context.Errors.GetEnumerator()); + ListTraceWriter listTraceWriter = (ListTraceWriter)context.TraceWriter; + List tracewriterErrors = listTraceWriter.GetErrors(); + + Assert.Single(templateValidationErrors); + Assert.True(areEqual(expectedErrors, templateValidationErrors)); + Assert.True(expectedTracewriterErrors.SequenceEqual(tracewriterErrors)); } private TemplateContext buildContext() @@ -39,7 +216,7 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tests maxEvents: 1000000, maxBytes: 10 * 1024 * 1024), Schema = null, - TraceWriter = new EmptyTraceWriter(), + TraceWriter = new ListTraceWriter(), }; } @@ -53,5 +230,46 @@ namespace GitHub.DistributedTask.ObjectTemplating.Tests } return result; } + + private bool areEqual(List l1, List l2) + { + if (l1.Count != l2.Count) return false; + + var twoLists = l1.Zip(l2, (l1Error, l2Error) => new { Elem1 = l1Error, Elem2 = l2Error }); + + foreach (var elem in twoLists) + { + if (elem.Elem1.Message != elem.Elem2.Message) return false; + if (elem.Elem1.Code != elem.Elem2.Code) return false; + } + return true; + } + + internal sealed class ListTraceWriter : ITraceWriter + { + + private List errors = new(); + private List infoMessages = new(); + private List verboseMessages = new(); + public void Error(string format, params object[] args) + { + errors.Add(string.Format(System.Globalization.CultureInfo.CurrentCulture, $"{format}", args)); + } + + public void Info(string format, params object[] args) + { + throw new NotImplementedException(); + } + + public void Verbose(string format, params object[] args) + { + throw new NotImplementedException(); + } + + public List GetErrors() + { + return errors; + } + } } }