Skip to content
Open
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
127 changes: 123 additions & 4 deletions StatePrinter.Tests/IntegrationTests/ObjectGraphsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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));
Expand All @@ -45,7 +51,7 @@ public void Setup()
}

[Test]
public void ThreeLinkedGraph()
public void ThreeLinkedGraph_curly()
{
var expected =
@"new Car()
Expand All @@ -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()
{
Expand All @@ -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);
Expand All @@ -101,6 +186,22 @@ public void ThreeLinkedGraph_xmlstyle()
<Weight>525</Weight>
</steeringWheel>
<Brand>Toyota</Brand>
<Wheels type='Wheel[]'>
<Element type='Wheel'>
<Diameter>0</Diameter>
</Element>
<Element type='Wheel'>
<Diameter>0</Diameter>
</Element>
<Element type='Wheel'>
<Diameter>0</Diameter>
</Element>
<Element type='Wheel'>
<Diameter>0</Diameter>
</Element>
</Wheels>
<Passengers type='Passenger[]'>
</Passengers>
</Root>";

printer.Assert.PrintEquals(expected, car);
Expand Down Expand Up @@ -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<NotSupportedException>(() => printer.PrintObject(course));
}

[Test]
public void CyclicGraph_Json()
{
Expand Down Expand Up @@ -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;
Expand Down
135 changes: 135 additions & 0 deletions StatePrinter/OutputFormatters/StrictCSharpStyle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// 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
{
/// <summary>
/// Formatting the tokens to a compilable C# representation.
///
/// Circular refereces are not supported, as this would lead to infinte loops.
/// </summary>
public class StrictCSharpStyle : IOutputFormatter
{
Configuration configuration;

public StrictCSharpStyle(Configuration configuration)
{
this.configuration = configuration;
}

public string Print(List<Token> tokens)
{
var filter = new UnusedReferencesTokenFilter();
var processed = filter.FilterUnusedReferences(tokens);

return MakeString(processed);
}

string MakeString(IList<Token> 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.");
}
}
}
1 change: 1 addition & 0 deletions StatePrinter/StatePrinter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Compile Include="Introspection\TokenType.cs" />
<Compile Include="OutputFormatters\IndentingStringBuilder.cs" />
<Compile Include="OutputFormatters\JsonStyle.cs" />
<Compile Include="OutputFormatters\StrictCSharpStyle.cs" />
<Compile Include="OutputFormatters\StringBuilderTrimmer.cs" />
<Compile Include="OutputFormatters\UnusedReferencesTokenFilter.cs" />
<Compile Include="OutputFormatters\XmlStyle.cs" />
Expand Down