diff --git a/CodeBlocker.Test/TemplateTests.cs b/CodeBlocker.Test/TemplateTests.cs index f3a63bb..e9dfce8 100644 --- a/CodeBlocker.Test/TemplateTests.cs +++ b/CodeBlocker.Test/TemplateTests.cs @@ -74,6 +74,35 @@ public void ParameterEscapesALoneSurrogateInAQuotedDefaultValue() } } + [TestMethod] + public void ParameterWritesAQuotedEmptyDefaultValue() => + Assert.AreEqual( + "string separator = \"\"", + Render(new ParameterTemplate { Type = "string", Name = "separator", DefaultValue = "", DefaultValueIsQuoted = true })); + + [TestMethod] + public void ParameterWithAnEmptyUnquotedDefaultValueHasNone() => + Assert.AreEqual("string separator", Render(new ParameterTemplate { Type = "string", Name = "separator", DefaultValue = "" })); + + [TestMethod] + public void AQuotedEmptyDefaultKeepsAParameterOptional() + { + MethodTemplate method = new() + { + Type = "void", + Name = "M", + Keywords = { "public" }, + BodyFactory = _ => { }, + Parameters = + { + new ParameterTemplate { Type = "int", Name = "count", DefaultValue = "0" }, + new ParameterTemplate { Type = "string", Name = "separator", DefaultValue = "", DefaultValueIsQuoted = true }, + }, + }; + + Assert.AreEqual("public void M(int count = 0, string separator = \"\") { }\n", Render(method)); + } + [TestMethod] public void ParameterKeepsItsAttributesOnTheDeclarationLine() { @@ -102,6 +131,12 @@ public void FieldEscapesAQuotedInitialiser() => "private string p = \"C:\\\\temp\\\\\\\"x\\\"\";\n", Render(new FieldTemplate { Type = "string", Name = "p", Keywords = { "private" }, DefaultValue = "C:\\temp\\\"x\"", DefaultValueIsQuoted = true })); + [TestMethod] + public void FieldWritesAQuotedEmptyInitialiser() => + Assert.AreEqual( + "public const string Empty = \"\";\n", + Render(new FieldTemplate { Type = "string", Name = "Empty", Keywords = { "public", "const" }, DefaultValue = "", DefaultValueIsQuoted = true })); + [TestMethod] public void FieldCommentsAndAttributesGoOnTheirOwnLines() { @@ -190,6 +225,49 @@ public void AShorthandPropertyKeepsItsInitialiser() Assert.AreEqual("public int Count { get; set; } = 7;\n", Render(property)); } + [TestMethod] + public void AShorthandPropertyKeepsAQuotedEmptyInitialiser() + { + PropertyTemplate property = new() + { + Type = "string", + Name = "Prefix", + Keywords = { "public" }, + Getter = AccessorTemplate.Auto(), + Setter = AccessorTemplate.Auto(), + DefaultValue = "", + DefaultValueIsQuoted = true, + }; + + Assert.AreEqual("public string Prefix { get; set; } = \"\";\n", Render(property)); + } + + [TestMethod] + public void ABracedPropertyKeepsAQuotedEmptyInitialiser() + { + PropertyTemplate property = new() + { + Type = "string", + Name = "Prefix", + Keywords = { "public" }, + Getter = AccessorTemplate.Auto(), + Setter = new AccessorTemplate { Modifier = "private" }, + DefaultValue = "", + DefaultValueIsQuoted = true, + }; + + Assert.AreEqual( + """ + public string Prefix + { + get; + private set; + } = ""; + + """.ReplaceLineEndings("\n"), + Render(property)); + } + [TestMethod] public void AnAccessorModifierForcesTheBracedForm() { diff --git a/CodeBlocker/Templates/PropertyTemplate.cs b/CodeBlocker/Templates/PropertyTemplate.cs index dfe82a7..c817d28 100644 --- a/CodeBlocker/Templates/PropertyTemplate.cs +++ b/CodeBlocker/Templates/PropertyTemplate.cs @@ -125,11 +125,9 @@ private void WriteShorthand(CodeBlocker codeBlocker) codeBlocker.Write(" }"); WriteDefaultValueTo(codeBlocker); - codeBlocker.WriteLine(DefaultValueIsSet ? ";" : string.Empty); + codeBlocker.WriteLine(HasDefaultValue ? ";" : string.Empty); } - private bool DefaultValueIsSet => !string.IsNullOrEmpty(DefaultValue); - private void WriteAccessorList(CodeBlocker codeBlocker) { codeBlocker.WriteLine(); @@ -145,6 +143,6 @@ private void WriteAccessorList(CodeBlocker codeBlocker) // Scope would not allow. codeBlocker.Write("}"); WriteDefaultValueTo(codeBlocker); - codeBlocker.WriteLine(DefaultValueIsSet ? ";" : string.Empty); + codeBlocker.WriteLine(HasDefaultValue ? ";" : string.Empty); } } diff --git a/CodeBlocker/Templates/TemplateBase.cs b/CodeBlocker/Templates/TemplateBase.cs index d8a224a..1abb91b 100644 --- a/CodeBlocker/Templates/TemplateBase.cs +++ b/CodeBlocker/Templates/TemplateBase.cs @@ -22,7 +22,8 @@ public abstract class TemplateBase public string Type { get; set; } = string.Empty; /// - /// Gets or sets the initialiser or default value. Empty means no initialiser is written. + /// Gets or sets the initialiser or default value. Empty means no initialiser is written, unless + /// is set, in which case it is the empty string "". /// public string DefaultValue { get; set; } = string.Empty; @@ -33,6 +34,12 @@ public abstract class TemplateBase /// public bool DefaultValueIsQuoted { get; set; } + /// + /// Gets a value indicating whether an initialiser is written: is not + /// empty, or it is quoted, where empty raw text is the empty string literal. + /// + private protected bool HasDefaultValue => DefaultValueIsQuoted || !string.IsNullOrEmpty(DefaultValue); + /// /// Gets the attributes to write before the declaration, each without its square brackets. /// @@ -90,7 +97,7 @@ internal virtual void Validate() } /// - /// Writes = value when is set, as an escaped string literal + /// Writes = value when is set, as an escaped string literal /// when is set. /// /// The to write to. @@ -98,7 +105,7 @@ protected void WriteDefaultValueTo(CodeBlocker codeBlocker) { Ensure.NotNull(codeBlocker); - if (string.IsNullOrEmpty(DefaultValue)) + if (!HasDefaultValue) { return; }