Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formatter v2 part 4: Core algorithm #10673

Merged
merged 19 commits into from
May 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Bicep.Core.PrettyPrint;
using Bicep.Core.PrettyPrintV2;
using Bicep.Core.Samples;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Utils;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bicep.Core.IntegrationTests.PrettyPrint
{
[TestClass]
public class PrettyPrinterV2Tests
{
public TestContext TestContext { get; set; } = null!;

[DataTestMethod]
[DataRow(40)]
[DataRow(80)]
[TestCategory(BaselineHelper.BaselineTestCategory)]
public void Print_DifferentWidth_ShouldOptimizeLayoutAccordingly(int width)
{
var dataSet = DataSets.PrettyPrint_LF;
var program = ParserHelper.Parse(dataSet.Bicep, out var lexingErrorLookup, out var parsingErrorLookup);

var writer = new StringWriter();
var context = PrettyPrinterV2Context.Create(program, new(Width: width), lexingErrorLookup, parsingErrorLookup);

PrettyPrinterV2.PrintTo(writer, context);
var output = writer.ToString();

var outputFileName = $"main.pprint.w{width}.bicep";
var outputFile = FileHelper.SaveResultFile(this.TestContext, Path.Combine(dataSet.Name, outputFileName), output);

var expected = dataSet.ReadDataSetFile(outputFileName);

output.Should().EqualWithLineByLineDiffOutput(
TestContext,
expected,
expectedLocation: DataSet.GetBaselineUpdatePath(dataSet, outputFileName),
actualLocation: outputFile);
}

[DataTestMethod]
[DataRow(40)]
[DataRow(80)]
[TestCategory(BaselineHelper.BaselineTestCategory)]
public void Print_FormattedOutput_ProducesTheSameOutput(int width)
{
var dataSet = DataSets.PrettyPrint_LF;
var options = new PrettyPrinterV2Options(Width: width);

var program = ParserHelper.Parse(dataSet.Bicep, out var lexingErrorLookup, out var parsingErrorLookup);

var writer = new StringWriter();
var context = PrettyPrinterV2Context.Create(program, options, lexingErrorLookup, parsingErrorLookup);

PrettyPrinterV2.PrintTo(writer, context);
var output = writer.ToString();

writer = new StringWriter();
program = ParserHelper.Parse(output, out lexingErrorLookup, out parsingErrorLookup);
context = PrettyPrinterV2Context.Create(program, options, lexingErrorLookup, parsingErrorLookup);

PrettyPrinterV2.PrintTo(writer, context);

var newOutput = writer.ToString();

newOutput.Should().Be(output);
}
}
}
2 changes: 1 addition & 1 deletion src/Bicep.Core.Samples/DataSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ private Lazy<string> CreateRequired(string fileName)

public static string GetDisplayName(MethodInfo info, object[] data) => $"{info.Name}_{((DataSet)data[0]).Name}";

private string ReadDataSetFile(string fileName) => ReadFile(GetStreamName(fileName));
public string ReadDataSetFile(string fileName) => ReadFile(GetStreamName(fileName));

private string GetStreamName(string fileName) => $"{GetStreamPrefix()}/{fileName}";

Expand Down
2 changes: 2 additions & 0 deletions src/Bicep.Core.Samples/DataSets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ public static class DataSets

public static DataSet Lambdas_LF => CreateDataSet();

public static DataSet PrettyPrint_LF => CreateDataSet();

public static IEnumerable<DataSet> AllDataSets =>
typeof(DataSets)
.GetProperties(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Static)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ param storageAccount1 string = 'testStorageAccount'
# disable-next-line no-unused-params
param storageAccount2 string = 'testStorageAccount'

/* comment before */ #disable-next-line no-unused-params
/* comment before */#disable-next-line no-unused-params
param storageAccount3 string = 'testStorageAccount'

#disable-next-line/* comment between */ no-unused-params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,5 +144,4 @@ output keyVaultSecretArrayInterpolatedOutput array = [
@
// #completionTest(5) -> decorators
@sys.

// WARNING!!!!! dangling decorators - to make sure the tests work, please do not add contents after this line
88 changes: 88 additions & 0 deletions src/Bicep.Core.Samples/Files/PrettyPrint_LF/main.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Baselines for width 40 ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
var w38 = [true, /* xxxxx */ true, 12] // suffix
var w39 = [true, true
true, true, 123]
var w40 =[
true, true, 1234/* xxxxx */] // suffix
var w41 =[ true, true, true, true, 12345 ]
var w42 =[true, /* xxx */ 12 /* xx */, 1]

var w38_= { foo: true, bar: 1234567
} // suffix
var w39_= { foo: true
bar: 12345678 } // suffix
var w40_= { foo: 1, bar: 1 /* xxxx */ }
var w41_={ foo: true, bar : 1234567890 }
var w42_= { foo: true
bar: 12345678901 } // suffix

var w38__ = concat('xxxxxx', 'xxxxxx')
var w39__ = concat('xxxxxx', 'xxxxxxx'
) // suffix
var w40__ = concat('xxxxxx',
'xxxxxxxx') // suffix

var w41__= concat('xxxxx'/* xxxxxxx */)
var w42__ = concat('xxxxx', 'xxxxxxxxxxx')

////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Baselines for width 80 ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
var w78 = [
true, { foo: 'object width: 37' /* xxx */ }, 'xxxxxxxxxxxxxxxxxxx' ]
var w79 = [true
{ /* xxxx */ foo: 'object width: 38' }
'xxxxxxxxxxxxxxxxxx' ]
var w80 = [true, { foo: 'object width: 39 xxxxxxxxxxx' }
'xxxxxxxxxxxxxxxxxxx']
var w81 = [true, { foo: 'object width: 40 xxxxxxxxxxxx' }, 'xxxxxxxxxxxxxxxxxxx' ]
var w82 = [ true, concat(/* function width: 41 */123, 456) /* xxxxxxxxxxxxxxxx */ ]

var w78_ ={ foo: 123, /* xxxx */ baz: ['xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxx'] }
var w79_ = { foo: 123, bar: true, baz: ['xxxxxxxxxxx', 'xxxxxxxx'] }
var w80_ = { foo: 123, bar: true, baz: [
'xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxx'] } // suffix
var w81_ = { foo: 123, bar: true, baz: ['xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxx'] }
var w82_ = { foo: 123, bar: true, baz: ['array length: 41', 'xxxxxxxxxxxxxxxxx'] }

var w78__ = union({ foo: 'xxxxx' }, { bar: 'xxxxxxxxx' }, { baz: 'xxxxxxxxx'})
var w79__ = union({ foo: 'xxxxx' }, { bar: 'xxxxxxxxx' },
{ baz: 'xxxxxxxxxx'}) // suffix
var w80__ = union(
{ foo: 'xxxxxx' },
{ bar: 'xxxxxx' },
{ baz: 'xxxxxxxxxxxxx'})
var w81__ = union({ foo: 'x' } /* xxx */, any({ baz: 'func call length: 38 ' }))
var w82__ = union({ foo: 'x', bar: 'x' }, any({ baz: 'func call length: 39 ' }))

////////////////////////////////////////////////////////////////////////////////
////////////////////////// Baselines for line breakers /////////////////////////
////////////////////////////////////////////////////////////////////////////////
var forceBreak1 = {
foo: true
}
var forceBreak2 = {
foo: true, bar: false
}
var forceBreak3 = [1, 2, {
foo: true }, 3, 4]
var forceBreak4 = { foo: true, bar: false // force break
}
var forceBreak5 = { foo: true
/* force break */}
var forceBreak6 = { foo: true
bar: false
baz: 123
/* force break */}
var forceBreak7 = [1, 2 // force break
]
var forceBreak8 = [1, 2
/* force break */ ]
var forceBreak9 = [1, 2, {
foo: true
bar: false
}]
var forceBreak10 = [1, 2, intersection({ foo: true, bar: false }, {
foo: true})]
134 changes: 134 additions & 0 deletions src/Bicep.Core.Samples/Files/PrettyPrint_LF/main.diagnostics.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Baselines for width 40 ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
var w38 = [true, /* xxxxx */ true, 12] // suffix
//@[04:07) [no-unused-vars (Warning)] Variable "w38" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w38|
var w39 = [true, true
//@[04:07) [no-unused-vars (Warning)] Variable "w39" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w39|
true, true, 123]
var w40 =[
//@[04:07) [no-unused-vars (Warning)] Variable "w40" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w40|
true, true, 1234/* xxxxx */] // suffix
var w41 =[ true, true, true, true, 12345 ]
//@[04:07) [no-unused-vars (Warning)] Variable "w41" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w41|
var w42 =[true, /* xxx */ 12 /* xx */, 1]
//@[04:07) [no-unused-vars (Warning)] Variable "w42" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w42|

var w38_= { foo: true, bar: 1234567
//@[04:08) [no-unused-vars (Warning)] Variable "w38_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w38_|
} // suffix
var w39_= { foo: true
//@[11:15) [no-unused-vars (Warning)] Variable "w39_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w39_|
bar: 12345678 } // suffix
var w40_= { foo: 1, bar: 1 /* xxxx */ }
//@[08:12) [no-unused-vars (Warning)] Variable "w40_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w40_|
var w41_={ foo: true, bar : 1234567890 }
//@[04:08) [no-unused-vars (Warning)] Variable "w41_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w41_|
var w42_= { foo: true
//@[04:08) [no-unused-vars (Warning)] Variable "w42_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w42_|
bar: 12345678901 } // suffix

var w38__ = concat('xxxxxx', 'xxxxxx')
//@[07:12) [no-unused-vars (Warning)] Variable "w38__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w38__|
//@[18:44) [prefer-interpolation (Warning)] Use string interpolation instead of the concat function. (CodeDescription: bicep core(https://aka.ms/bicep/linter/prefer-interpolation)) |concat('xxxxxx', 'xxxxxx')|
var w39__ = concat('xxxxxx', 'xxxxxxx'
//@[04:09) [no-unused-vars (Warning)] Variable "w39__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w39__|
//@[12:40) [prefer-interpolation (Warning)] Use string interpolation instead of the concat function. (CodeDescription: bicep core(https://aka.ms/bicep/linter/prefer-interpolation)) |concat('xxxxxx', 'xxxxxxx'\n)|
) // suffix
var w40__ = concat('xxxxxx',
//@[04:09) [no-unused-vars (Warning)] Variable "w40__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w40__|
//@[12:40) [prefer-interpolation (Warning)] Use string interpolation instead of the concat function. (CodeDescription: bicep core(https://aka.ms/bicep/linter/prefer-interpolation)) |concat('xxxxxx',\n'xxxxxxxx')|
'xxxxxxxx') // suffix

var w41__= concat('xxxxx'/* xxxxxxx */)
//@[11:16) [no-unused-vars (Warning)] Variable "w41__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w41__|
var w42__ = concat('xxxxx', 'xxxxxxxxxxx')
//@[04:09) [no-unused-vars (Warning)] Variable "w42__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w42__|
//@[12:42) [prefer-interpolation (Warning)] Use string interpolation instead of the concat function. (CodeDescription: bicep core(https://aka.ms/bicep/linter/prefer-interpolation)) |concat('xxxxx', 'xxxxxxxxxxx')|

////////////////////////////////////////////////////////////////////////////////
//////////////////////////// Baselines for width 80 ////////////////////////////
////////////////////////////////////////////////////////////////////////////////
var w78 = [
//@[04:07) [no-unused-vars (Warning)] Variable "w78" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w78|
true, { foo: 'object width: 37' /* xxx */ }, 'xxxxxxxxxxxxxxxxxxx' ]
var w79 = [true
//@[04:07) [no-unused-vars (Warning)] Variable "w79" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w79|
{ /* xxxx */ foo: 'object width: 38' }
'xxxxxxxxxxxxxxxxxx' ]
var w80 = [true, { foo: 'object width: 39 xxxxxxxxxxx' }
//@[04:07) [no-unused-vars (Warning)] Variable "w80" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w80|
'xxxxxxxxxxxxxxxxxxx']
var w81 = [true, { foo: 'object width: 40 xxxxxxxxxxxx' }, 'xxxxxxxxxxxxxxxxxxx' ]
//@[04:07) [no-unused-vars (Warning)] Variable "w81" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w81|
var w82 = [ true, concat(/* function width: 41 */123, 456) /* xxxxxxxxxxxxxxxx */ ]
//@[04:07) [no-unused-vars (Warning)] Variable "w82" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w82|
//@[19:59) [prefer-interpolation (Warning)] Use string interpolation instead of the concat function. (CodeDescription: bicep core(https://aka.ms/bicep/linter/prefer-interpolation)) |concat(/* function width: 41 */123, 456)|

var w78_ ={ foo: 123, /* xxxx */ baz: ['xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxx'] }
//@[04:08) [no-unused-vars (Warning)] Variable "w78_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w78_|
var w79_ = { foo: 123, bar: true, baz: ['xxxxxxxxxxx', 'xxxxxxxx'] }
//@[04:08) [no-unused-vars (Warning)] Variable "w79_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w79_|
var w80_ = { foo: 123, bar: true, baz: [
//@[04:08) [no-unused-vars (Warning)] Variable "w80_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w80_|
'xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxx'] } // suffix
var w81_ = { foo: 123, bar: true, baz: ['xxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxx'] }
//@[04:08) [no-unused-vars (Warning)] Variable "w81_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w81_|
var w82_ = { foo: 123, bar: true, baz: ['array length: 41', 'xxxxxxxxxxxxxxxxx'] }
//@[04:08) [no-unused-vars (Warning)] Variable "w82_" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w82_|

var w78__ = union({ foo: 'xxxxx' }, { bar: 'xxxxxxxxx' }, { baz: 'xxxxxxxxx'})
//@[04:09) [no-unused-vars (Warning)] Variable "w78__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w78__|
var w79__ = union({ foo: 'xxxxx' }, { bar: 'xxxxxxxxx' },
//@[04:09) [no-unused-vars (Warning)] Variable "w79__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w79__|
{ baz: 'xxxxxxxxxx'}) // suffix
var w80__ = union(
//@[04:09) [no-unused-vars (Warning)] Variable "w80__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w80__|
{ foo: 'xxxxxx' },
{ bar: 'xxxxxx' },
{ baz: 'xxxxxxxxxxxxx'})
var w81__ = union({ foo: 'x' } /* xxx */, any({ baz: 'func call length: 38 ' }))
//@[04:09) [no-unused-vars (Warning)] Variable "w81__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w81__|
var w82__ = union({ foo: 'x', bar: 'x' }, any({ baz: 'func call length: 39 ' }))
//@[04:09) [no-unused-vars (Warning)] Variable "w82__" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |w82__|

////////////////////////////////////////////////////////////////////////////////
////////////////////////// Baselines for line breakers /////////////////////////
////////////////////////////////////////////////////////////////////////////////
var forceBreak1 = {
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak1" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak1|
foo: true
}
var forceBreak2 = {
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak2" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak2|
foo: true, bar: false
}
var forceBreak3 = [1, 2, {
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak3" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak3|
foo: true }, 3, 4]
var forceBreak4 = { foo: true, bar: false // force break
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak4" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak4|
}
var forceBreak5 = { foo: true
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak5" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak5|
/* force break */}
var forceBreak6 = { foo: true
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak6" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak6|
bar: false
baz: 123
/* force break */}
var forceBreak7 = [1, 2 // force break
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak7" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak7|
]
var forceBreak8 = [1, 2
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak8" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak8|
/* force break */ ]
var forceBreak9 = [1, 2, {
//@[04:15) [no-unused-vars (Warning)] Variable "forceBreak9" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak9|
foo: true
bar: false
}]
var forceBreak10 = [1, 2, intersection({ foo: true, bar: false }, {
//@[04:16) [no-unused-vars (Warning)] Variable "forceBreak10" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-vars)) |forceBreak10|
foo: true})]

Loading