From 972139bec9a53e94d9a4e3fd4b9afa7c05efbe03 Mon Sep 17 00:00:00 2001 From: Mike Chamberlain Date: Sun, 24 Jun 2018 22:59:08 +0700 Subject: [PATCH 1/4] Trying to implement strict C# style - not quite working yet --- .../IntegrationTests/ObjectGraphsTest.cs | 127 +++++++++++++++- .../OutputFormatters/StrictCSharpStyle.cs | 136 ++++++++++++++++++ StatePrinter/StatePrinter.csproj | 1 + 3 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 StatePrinter/OutputFormatters/StrictCSharpStyle.cs diff --git a/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs b/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs index 5917ce6..2b66a54 100644 --- a/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs +++ b/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs @@ -17,6 +17,7 @@ // specific language governing permissions and limitations // under the License. +using System; using System.Collections.Generic; using NUnit.Framework; using StatePrinting.OutputFormatters; @@ -36,7 +37,12 @@ public void Setup() { printer = TestHelper.CreateTestPrinter(); - car = new Car(new SteeringWheel(new FoamGrip("Plastic"))) { Brand = "Toyota" }; + car = new Car(new SteeringWheel(new FoamGrip("Plastic"))) + { + Brand = "Toyota", + Wheels = new [] { new Wheel(), new Wheel(), new Wheel(), new Wheel() }, // testing populated collection + Passengers = new Passenger[0] // testing empty collection + }; course = new Course(); course.Members.Add(new Student("Stan", course)); @@ -45,7 +51,7 @@ public void Setup() } [Test] - public void ThreeLinkedGraph() + public void ThreeLinkedGraph_curly() { var expected = @"new Car() @@ -61,11 +67,75 @@ public void ThreeLinkedGraph() Weight = 525 } Brand = ""Toyota"" + Wheels = new Wheel[]() + { + [0] = new Wheel() + { + Diameter = 0 + } + [1] = new Wheel() + { + Diameter = 0 + } + [2] = new Wheel() + { + Diameter = 0 + } + [3] = new Wheel() + { + Diameter = 0 + } + } + Passengers = new Passenger[]() + { + } }"; printer.Assert.PrintEquals(expected, car); } + [Test] + public void ThreeLinkedGraph_strictCSharp() + { + printer.Configuration.OutputFormatter = new StrictCSharpStyle(printer.Configuration); + + var expected = + @"new Car() +{ + StereoAmplifiers = null, + steeringWheel = new SteeringWheel() + { + Size = 3, + Grip = new FoamGrip() + { + Material = ""Plastic"", + } + Weight = 525, + } + Brand = ""Toyota"", + Wheels = new Wheel[] + { + new Wheel() + { + Diameter = 0, + }, + new Wheel() + { + Diameter = 0, + }, + new Wheel() + { + Diameter = 0, + }, + new Wheel() + { + Diameter = 0, + } + } +}"; + printer.Assert.PrintEquals(expected, car); + } + [Test] public void ThreeLinkedGraph_json() { @@ -80,7 +150,22 @@ public void ThreeLinkedGraph_json() }, ""Weight"": 525 }, - ""Brand"": ""Toyota"" + ""Brand"": ""Toyota"", + ""Wheels"": [ + { + ""Diameter"": 0 + }, + { + ""Diameter"": 0 + }, + { + ""Diameter"": 0 + }, + { + ""Diameter"": 0 + } + ], + ""Passengers"": [] }"; printer.Assert.PrintEquals(expected, car); @@ -101,6 +186,22 @@ public void ThreeLinkedGraph_xmlstyle() 525 Toyota + + + 0 + + + 0 + + + 0 + + + 0 + + + + "; printer.Assert.PrintEquals(expected, car); @@ -129,7 +230,13 @@ public void CyclicGraph_curly() printer.Assert.PrintEquals(expected, course); } - + [Test] + public void CyclicGraph_strictCSharp() + { + printer.Configuration.OutputFormatter = new StrictCSharpStyle(printer.Configuration); + Assert.Throws(() => printer.PrintObject(course)); + } + [Test] public void CyclicGraph_Json() { @@ -307,18 +414,30 @@ public void CyclicGraph_xmlstyle() } } + internal class Passenger + { + } + #region car class Car { protected int? StereoAmplifiers = null; private SteeringWheel steeringWheel; public string Brand { get; set; } + public Wheel[] Wheels { get; set; } + public Passenger[] Passengers { get; set; } + public Car(SteeringWheel steeringWheel) { this.steeringWheel = steeringWheel; } } + internal class Wheel + { + public decimal Diameter { get; set; } + } + internal class SteeringWheel { internal int Size = 3; diff --git a/StatePrinter/OutputFormatters/StrictCSharpStyle.cs b/StatePrinter/OutputFormatters/StrictCSharpStyle.cs new file mode 100644 index 0000000..1da5dcc --- /dev/null +++ b/StatePrinter/OutputFormatters/StrictCSharpStyle.cs @@ -0,0 +1,136 @@ +// Copyright 2014 Kasper B. Graversen +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using StatePrinting.Configurations; +using StatePrinting.Introspection; + +namespace StatePrinting.OutputFormatters +{ + /// + /// Formatting the tokens to a curly-brace style representation. + /// + /// In order to reduce clutter in the output, only reference that are referred to by later + /// outputted objects will have a referencenumber attached to them. + /// + public class StrictCSharpStyle : IOutputFormatter + { + Configuration configuration; + + public StrictCSharpStyle(Configuration configuration) + { + this.configuration = configuration; + } + + public string Print(List tokens) + { + var filter = new UnusedReferencesTokenFilter(); + var processed = filter.FilterUnusedReferences(tokens); + + return MakeString(processed); + } + + string MakeString(IList tokens) + { + var sb = new IndentingStringBuilder(configuration); + + for (var i = 0; i < tokens.Count; i++) + { + var token = tokens[i]; + MakeTokenString(token, sb); + } + + sb.TrimLast(); + var result = sb.ToString(); + + // remove final superfluous trailing comma - very hacky, could probably be done better + return result.Remove(result.Length - 1); + } + + void MakeTokenString(Token token, IndentingStringBuilder sb) + { + switch (token.Tokenkind) + { + case TokenType.StartScope: + case TokenType.StartList: + case TokenType.StartDict: + sb.AppendFormatLine("{{"); + sb.Indent(); + break; + + case TokenType.EndScope: + case TokenType.EndList: + case TokenType.EndDict: + sb.DeIndent(); + sb.AppendFormatLine("}},"); + break; + + case TokenType.SimpleFieldValue: + sb.AppendFormatLine("{0}", MakeFieldValue(token, token.Value)); + break; + + case TokenType.SeenBeforeWithReference: + throw CreateCyclicalObjectGraphException(); + + case TokenType.FieldnameWithTypeAndReference: + if (token.ReferenceNo != null) + { + throw CreateCyclicalObjectGraphException(); + } + + var fieldType = OutputFormatterHelpers.MakeReadable(token.FieldType); + + string value = string.Format("new {0}{1}", fieldType, token.FieldType.IsArray ? "" : "()"); + sb.AppendFormatLine("{0}", MakeFieldValue(token, value)); + break; + + default: + throw new ArgumentOutOfRangeException(); + } + } + + string MakeFieldValue(Token token, string value, Token nextToken = null) + { + if (token.Field == null) + return string.Format("{0}", value); + + if (token.Field.Index.HasValue) + return string.Format("{0}", value); + + if (token.Field.Key != null) + return string.Format("[{0}] = {1}", token.Field.Key, value); + + if (!string.IsNullOrEmpty(token.Field.Name)) + { + var isEnumerable = token.FieldType != null && token.FieldType.IsAssignableFrom(typeof(IEnumerable)); + return string.Format("{0} = {1}{2}", token.Field.Name, value, isEnumerable ? "" : ","); + } + + return string.Format("{0}", value); + } + + NotSupportedException CreateCyclicalObjectGraphException() + { + return new NotSupportedException("Cyclical object graphs are not supported in StrictCSharp style."); + } + } +} diff --git a/StatePrinter/StatePrinter.csproj b/StatePrinter/StatePrinter.csproj index 4004082..3c6a831 100644 --- a/StatePrinter/StatePrinter.csproj +++ b/StatePrinter/StatePrinter.csproj @@ -80,6 +80,7 @@ + From bec9e0790c6217b74f13be24dfd5818072d7535d Mon Sep 17 00:00:00 2001 From: Mike Chamberlain Date: Sun, 24 Jun 2018 23:54:25 +0700 Subject: [PATCH 2/4] Making test valid C# --- StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs b/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs index 2b66a54..5baa7c2 100644 --- a/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs +++ b/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs @@ -110,7 +110,7 @@ public void ThreeLinkedGraph_strictCSharp() Material = ""Plastic"", } Weight = 525, - } + }, Brand = ""Toyota"", Wheels = new Wheel[] { From 5287b0b51756c197af55e6cb3ef68e06d78a4bb4 Mon Sep 17 00:00:00 2001 From: Mike Chamberlain Date: Mon, 25 Jun 2018 00:23:58 +0700 Subject: [PATCH 3/4] Better comments --- StatePrinter/OutputFormatters/StrictCSharpStyle.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/StatePrinter/OutputFormatters/StrictCSharpStyle.cs b/StatePrinter/OutputFormatters/StrictCSharpStyle.cs index 1da5dcc..e72b93f 100644 --- a/StatePrinter/OutputFormatters/StrictCSharpStyle.cs +++ b/StatePrinter/OutputFormatters/StrictCSharpStyle.cs @@ -27,10 +27,9 @@ namespace StatePrinting.OutputFormatters { /// - /// Formatting the tokens to a curly-brace style representation. + /// Formatting the tokens to a compilable C# representation. /// - /// In order to reduce clutter in the output, only reference that are referred to by later - /// outputted objects will have a referencenumber attached to them. + /// Circular refereces are not supported, as this would lead to infinte loops. /// public class StrictCSharpStyle : IOutputFormatter { From 86ebc30d8e2371a55e31b74becfd448db12e05dc Mon Sep 17 00:00:00 2001 From: Mike Chamberlain Date: Mon, 25 Jun 2018 00:26:49 +0700 Subject: [PATCH 4/4] Proper C# --- StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs b/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs index 5baa7c2..c9aff46 100644 --- a/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs +++ b/StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs @@ -108,7 +108,7 @@ public void ThreeLinkedGraph_strictCSharp() Grip = new FoamGrip() { Material = ""Plastic"", - } + }, Weight = 525, }, Brand = ""Toyota"", @@ -129,8 +129,8 @@ public void ThreeLinkedGraph_strictCSharp() new Wheel() { Diameter = 0, - } - } + }, + }, }"; printer.Assert.PrintEquals(expected, car); }