diff --git a/CodeBlocker.Test/CodeBlockerExtensionsTests.cs b/CodeBlocker.Test/CodeBlockerExtensionsTests.cs index b6bfae1..25ffe88 100644 --- a/CodeBlocker.Test/CodeBlockerExtensionsTests.cs +++ b/CodeBlocker.Test/CodeBlockerExtensionsTests.cs @@ -162,6 +162,30 @@ public void NoUsingsWritesNothingIncludingTheBlankLine() Assert.AreEqual(string.Empty, emptySequence.ToString()); } + [TestMethod] + public void BlankUsingEntriesAreSkipped() + { + // A generator that builds optional usings as `condition ? "Ns" : ""` must not get `using ;`. + using CodeBlocker codeBlocker = Create(); + + codeBlocker.WriteUsings("System", "", " ", null!, "System.Linq"); + + Assert.AreEqual("using System;\nusing System.Linq;\n\n", codeBlocker.ToString()); + } + + [TestMethod] + public void OnlyBlankUsingEntriesWriteNothingIncludingTheBlankLine() + { + using CodeBlocker arrayOverload = Create(); + using CodeBlocker sequenceOverload = Create(); + + arrayOverload.WriteUsings("", " ", "\t"); + sequenceOverload.WriteUsings(new List { "", " " }); + + Assert.AreEqual(string.Empty, arrayOverload.ToString()); + Assert.AreEqual(string.Empty, sequenceOverload.ToString()); + } + [TestMethod] public void APreambleComposesWithConsistentSpacing() { diff --git a/CodeBlocker.Test/TemplateTests.cs b/CodeBlocker.Test/TemplateTests.cs index 3fd8237..72d4d8b 100644 --- a/CodeBlocker.Test/TemplateTests.cs +++ b/CodeBlocker.Test/TemplateTests.cs @@ -1536,6 +1536,20 @@ private class Inner public void AnEmptySourceFileWritesNothing() => Assert.AreEqual(string.Empty, Render(codeBlocker => codeBlocker.AddSourceFile(new SourceFileTemplate()))); + [TestMethod] + public void ASourceFileSkipsBlankUsings() + { + SourceFileTemplate file = new() + { + Namespace = "Contoso", + Usings = { "System", "", "System.Linq" }, + }; + + Assert.AreEqual( + "namespace Contoso;\n\nusing System;\nusing System.Linq;\n\n", + Render(codeBlocker => codeBlocker.AddSourceFile(file))); + } + [TestMethod] public void ASourceFileWithAnInvalidClassWritesNothing() { diff --git a/CodeBlocker/CodeBlockerExtensions.cs b/CodeBlocker/CodeBlockerExtensions.cs index 00365ef..b1fae56 100644 --- a/CodeBlocker/CodeBlockerExtensions.cs +++ b/CodeBlocker/CodeBlockerExtensions.cs @@ -95,13 +95,15 @@ public static CodeBlocker WriteFileScopedNamespace(this CodeBlocker codeBlocker, /// /// Writes one using directive per entry followed by a blank line, or nothing at all when - /// the sequence is empty. + /// the sequence has no namespaces in it. /// /// The to write to. /// /// The namespaces to import, without the using keyword or the trailing semicolon. An /// entry may carry a modifier or alias — static System.Math, Alias = System.Text — - /// because it is written verbatim after the keyword. + /// because it is written verbatim after the keyword. Entries that are , + /// empty or whitespace are skipped, so a generator can pass condition ? "Some.Namespace" : "" + /// without producing using ;. /// /// The same , for chaining. /// @@ -115,6 +117,11 @@ public static CodeBlocker WriteUsings(this CodeBlocker codeBlocker, IEnumerable< bool wroteAny = false; foreach (string usingDirective in usings) { + if (string.IsNullOrWhiteSpace(usingDirective)) + { + continue; + } + codeBlocker.WriteLine($"using {usingDirective};"); wroteAny = true; }