Skip to content

Commit

Permalink
Update HereDoc to consider end tag in unindent calculation (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
zentron authored Jan 27, 2023
1 parent 9afc81c commit 2abf077
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 32 deletions.
8 changes: 7 additions & 1 deletion source/Ocl/OclSerializerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ namespace Octopus.Ocl
/// </summary>
public class OclSerializerOptions
{
public char IndentChar { get; set; } = ' ';
/// <summary>
/// What character is used when indenting the OCL text.
/// This is not settable as it is
/// currently not used in some places in the static Parser
/// </summary>
public char IndentChar { get; internal set; } = ' ';

public int IndentDepth { get; set; } = 4;
public string DefaultHeredocTag { get; set; } = "EOT";
public List<IOclConverter> Converters { get; set; } = new List<IOclConverter>();
Expand Down
10 changes: 6 additions & 4 deletions source/Ocl/OclWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ void WriteValue(OclStringLiteral literal)
}

var isIndented = literal.Format == OclStringLiteralFormat.IndentedHeredoc;

var indentSize = 2;

writer.Write("<<");
if (isIndented)
writer.Write("-");
Expand All @@ -245,14 +246,15 @@ void WriteValue(OclStringLiteral literal)
writer.Write('\n');

if (isIndented)
WriteIndent(2);
WriteIndent(indentSize);
writer.Write(lines[x]);
}

writer.WriteLine();

// Ident the ending tag by the same amount as the text value above.
// This ensures that when being read back out the parsed text line indentation can be made relative to this ending tag.
if (isIndented)
WriteIndent(1);
WriteIndent(indentSize);
writer.Write(literal.HeredocTag);
}

Expand Down
16 changes: 8 additions & 8 deletions source/Ocl/Parsing/HeredocParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ from start in Start
from lines in Line.Except(endParser).Many()
from end in endParser
let trimmed = TrimCarriageReturn(lines)
let unindented = Unindent(trimmed.lines, start.format)
let unindented = Unindent(trimmed.lines, end, start.format)
let joined = string.Join(trimmed.lineSeparator, unindented)
select new OclStringLiteral(joined, start.format)
{
Expand All @@ -63,11 +63,11 @@ from end in endParser

internal static Parser<string> End(string tag)
{
var endLine = from leadingWhitespace in ParserCommon.WhitespaceExceptNewline.Many()
var endLine = from leadingWhitespace in ParserCommon.WhitespaceExceptNewline.Many().Text()
from endtag in Parse.String(tag).Text()
from trailingWhitespace in ParserCommon.WhitespaceExceptNewline.Many()
select endtag;

from trailingWhitespace in ParserCommon.WhitespaceExceptNewline.Many().Optional()
select leadingWhitespace + endtag;
var terminateWithNewline = from endtag in endLine
from newline in ParserCommon.NewLine
select endtag;
Expand All @@ -86,7 +86,7 @@ from newline in ParserCommon.NewLine
return (lineSeparator, trimmed);
}

public static IEnumerable<string> Unindent(IReadOnlyList<string> lines, OclStringLiteralFormat format)
public static IEnumerable<string> Unindent(IReadOnlyList<string> lines, string endLine, OclStringLiteralFormat format)
{
if (format != OclStringLiteralFormat.IndentedHeredoc)
return lines;
Expand All @@ -102,8 +102,8 @@ int CountLeadingWhitespace(string input)
return int.MaxValue;
}

var unindentBy = lines
.Min(CountLeadingWhitespace);
var endTagLeadingWhitespace = CountLeadingWhitespace(endLine);
var unindentBy = Math.Min(endTagLeadingWhitespace, lines.Min(CountLeadingWhitespace));

return lines.Select(l => l.Length <= unindentBy ? "" : l.Substring(unindentBy));
}
Expand Down
28 changes: 14 additions & 14 deletions source/Tests/Parsing/HeredocParsingFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ public void StartInvalid(string input)
.Should()
.BeFalse();

[TestCase("ZZZ\n")]
[TestCase("ZZZ")]
[TestCase("\t\tZZZ\t\t\n")]
[TestCase("ZZZ\nFoo\n")]
public void End(string input)
[TestCase("ZZZ", "ZZZ", Reason = "Exact Match")]
[TestCase("ZZZ\n", "ZZZ", Reason = "Trailing line breaks removed")]
[TestCase("\t\tZZZ\t\t\n", "\t\tZZZ", Reason = "Leading whitespace returned for indent count")]
[TestCase("ZZZ\nFoo\n", "ZZZ", Reason = "Proceeding nodes ignored")]
public void End(string input, string expected)
=> HeredocParser.End("ZZZ")
.Parse(input)
.Should()
.Be("ZZZ");
.Be(expected);

[TestCase("ZZZ A\n")]
[TestCase("A ZZZ\n")]
Expand All @@ -71,12 +71,12 @@ public void Heredoc(string input, string expected)
)
);

[TestCase("<<-ZZZ\nZZZ", "", Description = "IndentedHeredoc - Empty")]
[TestCase("<<-ZZZ\n \n \nZZZ", "\n", Description = "IndentedHeredoc - Whitespace")]
[TestCase("<<-ZZZ\n A\n B\nZZZ", "A\nB", Description = "IndentedHeredoc - NoExtraIndent")]
[TestCase("<<-ZZZ\n A\n B\n ZZZ", "A\n B", Description = "IndentedHeredoc - ExtraIndent")]
[TestCase("<<-ZZZ\n A ZZZ\n ZZZ B\nZZZ", "A ZZZ\n ZZZ B", Description = "IndentedHeredoc - End Marker In Text")]
[TestCase("<<-ZZZ\n A\n B\nZZZ", "A\n B", Description = "IndentedHeredoc - End marker does not affect indent")]
[TestCase("<<-ZZZ\nZZZ", "", Reason = "IndentedHeredoc - Empty")]
[TestCase("<<-ZZZ\n \n \nZZZ", " \n ", Reason = "IndentedHeredoc - Whitespace Preserved")]
[TestCase("<<-ZZZ\n \n \n ZZZ", "\n", Reason = "IndentedHeredoc - Whitespace Removed")]
[TestCase("<<-ZZZ\n A\n B\n ZZZ", "A\n B", Reason = "IndentedHeredoc - Offset By End Indent")]
[TestCase("<<-ZZZ\n A ZZZ\nZZZ B\nZZZ", " A ZZZ\nZZZ B", Reason = "IndentedHeredoc - End Marker In Text")]
[TestCase("<<-ZZZ\n A\nB\n ZZZ", " A\nB", Reason = "IndentedHeredoc - Min Across All Lines")]
public void IndentedHeredoc(string input, string expected)
=> OclParser.Execute("Foo = " + input.ToUnixLineEndings())
.Should()
Expand Down Expand Up @@ -124,7 +124,7 @@ public void LineEndingsArePreserved(string lineEnding)
[TestCase(" A", "B")]
public void UnindentNoChange(params string[] input)
{
var result = HeredocParser.Unindent(input, OclStringLiteralFormat.IndentedHeredoc);
var result = HeredocParser.Unindent(input, "", OclStringLiteralFormat.IndentedHeredoc);
result.Should().BeEquivalentTo(input);
}

Expand All @@ -141,7 +141,7 @@ public void UnindentNoChange(params string[] input)
public void UnindentBy4Chars(params string[] input)
{
var expected = input.Select(i => i.Length < 4 ? "" : i.Substring(4));
var result = HeredocParser.Unindent(input, OclStringLiteralFormat.IndentedHeredoc);
var result = HeredocParser.Unindent(input, "", OclStringLiteralFormat.IndentedHeredoc);
result.Should().BeEquivalentTo(expected);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description = <<-EOT
This is a
multiline a description with trailing newline

EOT
EOT
environment_scope = "Specified"
environments = ["Production", "Development"]
multi_tenancy_mode = "TenantedOrUntenanted"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ steps "Backup the Database" {

write-output $entryResult | ft

EOT
EOT
Octopus.Action.Script.ScriptSource = "Inline"
Octopus.Action.Script.Syntax = "PowerShell"
}
Expand Down
39 changes: 36 additions & 3 deletions source/Tests/ToString/OclWriterFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ public void Heredoc()
.Be(expected.ToUnixLineEndings());
}


[Test]
public void HeredocIndented()
{
Expand All @@ -126,9 +127,9 @@ public void HeredocIndented()
MyAttr = <<-EOT
a
b
EOT
EOT
}";

Execute(w => w.Write(block))
.Should()
.Be(expected.ToUnixLineEndings());
Expand All @@ -145,12 +146,44 @@ public void MultilineStringsUseHeredocAndTheHeredocIdentifierFromOptions()
var expected = @"MyAttr = <<-YYY
a
b
YYY";
YYY";

Execute(w => w.Write(new OclAttribute("MyAttr", "a\nb")), options)
.Should()
.Be(expected.ToUnixLineEndings());
}

[Test]
[TestCase(@"Hello
World", @"blah = <<-EOT
Hello
World
EOT", Description = "No Indentation")]
[TestCase(@" Hello
World", @"blah = <<-EOT
Hello
World
EOT", Description = "Double Indent Preserved")]
[TestCase(@"Hello
World", @"blah = <<-EOT
Hello
World
EOT", Description = "Single Property Indented")]
public void MultilineStringsSupportHeredocLineFormat(string propertyText, string expectedOcl)
{
var serializer = new OclSerializer(new OclSerializerOptions());

var serializedOcl = serializer.Serialize(new Foo() { Blah = propertyText });
serializedOcl.Should().Be(expectedOcl);

var deserializedFoo = serializer.Deserialize<Foo>(expectedOcl);
deserializedFoo.Blah.Should().Be(propertyText);
}

class Foo
{
public string? Blah { get; set; }
}

[Test]
public void WriteBlockEmpty()
Expand Down

0 comments on commit 2abf077

Please sign in to comment.