From 77b47f3a6dc0b02ba3b0669b57c16ed22eb62b84 Mon Sep 17 00:00:00 2001 From: Valentin Date: Fri, 27 Jan 2023 22:29:23 +0100 Subject: [PATCH 01/15] Clean --- LICENSE.txt | 2 +- README.md | 6 +- Sources/DotNetGraph.Tests/BasicGraphTests.cs | 84 ---- .../DotCompilerWorkerTests.cs | 64 ---- .../DotNetGraph.Tests.csproj | 3 +- .../DotNetGraph.Tests/Edge/BasicEdgeTests.cs | 308 --------------- .../Extensions/DotGraphExtensionsTests.cs | 80 ---- .../Extensions/EnumExtensionsTests.cs | 42 -- .../Indentation/IndentedGraphTests.cs | 179 --------- .../DotNetGraph.Tests/Node/BasicNodeTests.cs | 362 ------------------ .../SubGraph/BasicSubGraphTests.cs | 248 ------------ .../Attributes/DotColorAttribute.cs | 20 - .../Attributes/DotEdgeArrowHeadAttribute.cs | 20 - .../Attributes/DotEdgeArrowTailAttribute.cs | 20 - .../Attributes/DotEdgeStyleAttribute.cs | 19 - .../Attributes/DotFillColorAttribute.cs | 16 - .../Attributes/DotFontColorAttribute.cs | 16 - .../Attributes/DotLabelAttribute.cs | 19 - .../Attributes/DotNodeHeightAttribute.cs | 24 -- .../Attributes/DotNodeShapeAttribute.cs | 20 - .../Attributes/DotNodeStyleAttribute.cs | 20 - .../Attributes/DotNodeWidthAttribute.cs | 24 -- .../Attributes/DotPenWidthAttribute.cs | 24 -- .../Attributes/DotPositionAttribute.cs | 19 - .../Attributes/DotSubGraphStyleAttribute.cs | 20 - Sources/DotNetGraph/Compiler/DotCompiler.cs | 50 --- .../DotNetGraph/Compiler/DotCompilerWorker.cs | 331 ---------------- .../DotNetGraph/Core/DotCustomAttribute.cs | 26 -- .../Core/DotElementWithAttributes.cs | 45 --- Sources/DotNetGraph/Core/DotException.cs | 11 - Sources/DotNetGraph/Core/DotPosition.cs | 19 - Sources/DotNetGraph/Core/IDotAttribute.cs | 7 - Sources/DotNetGraph/Core/IDotElement.cs | 6 - Sources/DotNetGraph/DotGraph.cs | 27 -- Sources/DotNetGraph/DotNetGraph.nuspec | 10 +- Sources/DotNetGraph/DotString.cs | 14 - Sources/DotNetGraph/Edge/DotEdge.cs | 104 ----- Sources/DotNetGraph/Edge/DotEdgeArrowType.cs | 25 -- Sources/DotNetGraph/Edge/DotEdgeStyle.cs | 13 - .../Extensions/DotColorExtensions.cs | 12 - .../Extensions/DotGraphExtensions.cs | 106 ----- .../DotNetGraph/Extensions/EnumExtensions.cs | 23 -- .../Extensions/TextWriterExtensions.cs | 41 -- Sources/DotNetGraph/IDotGraph.cs | 11 - Sources/DotNetGraph/Node/DotNode.cs | 105 ----- Sources/DotNetGraph/Node/DotNodeShape.cs | 65 ---- Sources/DotNetGraph/Node/DotNodeStyle.cs | 18 - Sources/DotNetGraph/SubGraph/DotSubGraph.cs | 44 --- .../DotNetGraph/SubGraph/DotSubGraphStyle.cs | 16 - 49 files changed, 11 insertions(+), 2777 deletions(-) delete mode 100644 Sources/DotNetGraph.Tests/BasicGraphTests.cs delete mode 100644 Sources/DotNetGraph.Tests/DotCompilerWorkerTests.cs delete mode 100644 Sources/DotNetGraph.Tests/Edge/BasicEdgeTests.cs delete mode 100644 Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs delete mode 100644 Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs delete mode 100644 Sources/DotNetGraph.Tests/Indentation/IndentedGraphTests.cs delete mode 100644 Sources/DotNetGraph.Tests/Node/BasicNodeTests.cs delete mode 100644 Sources/DotNetGraph.Tests/SubGraph/BasicSubGraphTests.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotColorAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotEdgeArrowHeadAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotEdgeArrowTailAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotFillColorAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotFontColorAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotLabelAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotNodeHeightAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotNodeWidthAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotPenWidthAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotPositionAttribute.cs delete mode 100644 Sources/DotNetGraph/Attributes/DotSubGraphStyleAttribute.cs delete mode 100644 Sources/DotNetGraph/Compiler/DotCompiler.cs delete mode 100644 Sources/DotNetGraph/Compiler/DotCompilerWorker.cs delete mode 100644 Sources/DotNetGraph/Core/DotCustomAttribute.cs delete mode 100644 Sources/DotNetGraph/Core/DotElementWithAttributes.cs delete mode 100644 Sources/DotNetGraph/Core/DotException.cs delete mode 100644 Sources/DotNetGraph/Core/DotPosition.cs delete mode 100644 Sources/DotNetGraph/Core/IDotAttribute.cs delete mode 100644 Sources/DotNetGraph/Core/IDotElement.cs delete mode 100644 Sources/DotNetGraph/DotGraph.cs delete mode 100644 Sources/DotNetGraph/DotString.cs delete mode 100644 Sources/DotNetGraph/Edge/DotEdge.cs delete mode 100644 Sources/DotNetGraph/Edge/DotEdgeArrowType.cs delete mode 100644 Sources/DotNetGraph/Edge/DotEdgeStyle.cs delete mode 100644 Sources/DotNetGraph/Extensions/DotColorExtensions.cs delete mode 100644 Sources/DotNetGraph/Extensions/DotGraphExtensions.cs delete mode 100644 Sources/DotNetGraph/Extensions/EnumExtensions.cs delete mode 100644 Sources/DotNetGraph/Extensions/TextWriterExtensions.cs delete mode 100644 Sources/DotNetGraph/IDotGraph.cs delete mode 100644 Sources/DotNetGraph/Node/DotNode.cs delete mode 100644 Sources/DotNetGraph/Node/DotNodeShape.cs delete mode 100644 Sources/DotNetGraph/Node/DotNodeStyle.cs delete mode 100644 Sources/DotNetGraph/SubGraph/DotSubGraph.cs delete mode 100644 Sources/DotNetGraph/SubGraph/DotSubGraphStyle.cs diff --git a/LICENSE.txt b/LICENSE.txt index 97a5e15..6b5e4ea 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019-2020 Valentin Fritz (aka. VFRZ) +Copyright (c) 2019-2023 Valentin Fritz (aka. VFRZ) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c2a0a56..007e4e2 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # DotNetGraph -Create **GraphViz DOT graph** with **.NET** +Create **GraphViz DOT graph** with **dotnet**. Available on NuGet: [![#](https://img.shields.io/nuget/v/DotNetGraph.svg)](https://www.nuget.org/packages/DotNetGraph/) -Compatible with **.NET Standard 2.0** and higher +Compatible with **.NET Standard 2.0** and higher. -# Documentation +# Usage ## Create a graph (*DotGraph*) diff --git a/Sources/DotNetGraph.Tests/BasicGraphTests.cs b/Sources/DotNetGraph.Tests/BasicGraphTests.cs deleted file mode 100644 index 84ceac7..0000000 --- a/Sources/DotNetGraph.Tests/BasicGraphTests.cs +++ /dev/null @@ -1,84 +0,0 @@ -using DotNetGraph.Extensions; -using DotNetGraph.Node; -using NFluent; -using Xunit; - -namespace DotNetGraph.Tests -{ - public class BasicGraphTests - { - [Fact] - public void GraphWithSpaceInIdentifier() - { - var graph = new DotGraph("My test graph"); - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph \"My test graph\" { }"); - } - - [Fact] - public void EmptyDirectedGraph() - { - var graph = new DotGraph("TestGraph", true); - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("digraph TestGraph { }"); - } - - [Fact] - public void EmptyGraph() - { - var graph = new DotGraph("TestGraph"); - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { }"); - } - - [Fact] - public void EmptyStrictGraph() - { - var graph = new DotGraph("TestGraph") - { - Strict = true - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("strict graph TestGraph { }"); - } - - [Fact] - public void GraphWithoutStringsFormat() - { - var graph = new DotGraph("TestGraph", true); - - graph.Elements.Add(new DotNode("TestNode") - { - Label = "\\lTesting" - }); - - var compiled = graph.Compile(false, false); - - Check.That(compiled).HasSameValueAs("digraph TestGraph { TestNode[label=\"\\lTesting\"]; }"); - } - - [Fact] - public void DotGraph_WhenRawLineAdded_ThenItsCompiled() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotString("rankdir = TB;") - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { rankdir = TB; }"); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/DotCompilerWorkerTests.cs b/Sources/DotNetGraph.Tests/DotCompilerWorkerTests.cs deleted file mode 100644 index 34b9127..0000000 --- a/Sources/DotNetGraph.Tests/DotCompilerWorkerTests.cs +++ /dev/null @@ -1,64 +0,0 @@ -using DotNetGraph.Compiler; -using NFluent; -using Xunit; - -namespace DotNetGraph.Tests -{ - public class DotCompilerWorkerTests - { - [Fact] - public void Format() - { - const string text = "Je m'appelle \"Jack\",\r\n je suis un test\\essai\nCela marche!"; - - var formatted = DotCompilerWorker.FormatString(text, true); - - Check.That(formatted).HasSameValueAs("Je m'appelle \\\"Jack\\\",\\n je suis un test\\\\essai\\nCela marche!"); - } - - [Fact] - public void Format_Disabled() - { - const string text = "Je m'appelle \"Jack\",\r\n je suis un test\\essai\nCela marche!"; - - var formatted = DotCompilerWorker.FormatString(text, false); - - Check.That(formatted).HasSameValueAs(text); - } - - [Theory] - [InlineData("node")] - [InlineData("node123")] - [InlineData("underscores_are_allowed")] - [InlineData("-123")] - [InlineData("123")] - [InlineData("1.23")] - [InlineData("-1.23")] - public void SurroundWithDoubleQuotes_Without(string text) - { - var formatted = DotCompilerWorker.SurroundStringWithQuotes(text, false); - - Check.That(formatted).HasSameValueAs(text); - } - - [Theory] - [InlineData("no[]de")] - [InlineData("no\"de")] - [InlineData("no\nde")] - [InlineData("123start_with_number")] - [InlineData("identifier with space")] - [InlineData("\"node\"")] - [InlineData("節点")] - [InlineData("узел")] - [InlineData("1a")] - [InlineData("-1a")] - [InlineData("1.1a")] - [InlineData("-1.1a")] - public void SurroundWithDoubleQuotes_With(string text) - { - var formatted = DotCompilerWorker.SurroundStringWithQuotes(text, false); - - Check.That(formatted).HasSameValueAs("\"" + text + "\""); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj b/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj index db9c998..c1ce48b 100644 --- a/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj +++ b/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj @@ -17,7 +17,8 @@ - + + diff --git a/Sources/DotNetGraph.Tests/Edge/BasicEdgeTests.cs b/Sources/DotNetGraph.Tests/Edge/BasicEdgeTests.cs deleted file mode 100644 index 7e9d6fb..0000000 --- a/Sources/DotNetGraph.Tests/Edge/BasicEdgeTests.cs +++ /dev/null @@ -1,308 +0,0 @@ -using System; -using System.Drawing; -using DotNetGraph.Core; -using DotNetGraph.Edge; -using DotNetGraph.Extensions; -using DotNetGraph.Node; -using NFluent; -using Xunit; - -namespace DotNetGraph.Tests.Edge -{ - public class BasicEdgeTests - { - [Fact] - public void EdgeWithIdentifierToIdentifier() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world; }"); - } - - [Fact] - public void EdgeWithIdentifierToIdentifierDirectedGraph() - { - var graph = new DotGraph("TestGraph") - { - Directed = true, - Elements = - { - new DotEdge("hello", "world") - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("digraph TestGraph { hello -> world; }"); - } - - [Fact] - public void EdgeWithNodeToNode() - { - var helloNode = new DotNode("hello"); - - var worldNode = new DotNode("world"); - - var graph = new DotGraph("TestGraph") - { - Elements = - { - helloNode, - worldNode, - new DotEdge(helloNode, worldNode) - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello; world; hello -- world; }"); - } - - [Fact] - public void EdgeWithMultipleAttributes() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - Color = Color.Red, - ArrowHead = DotEdgeArrowType.Box, - ArrowTail = DotEdgeArrowType.Diamond - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[color=\"#FF0000\",arrowhead=box,arrowtail=diamond]; }"); - } - - [Fact] - public void EdgeWithColor() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - Color = Color.Red - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[color=\"#FF0000\"]; }"); - } - - [Fact] - public void EdgeWithFontColor() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - FontColor = Color.Blue - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[fontcolor=\"#0000FF\"]; }"); - } - - [Fact] - public void EdgeWithPosition() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - Position = new DotPosition(4, 2) - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[pos=\"4,2!\"]; }"); - } - - [Fact] - public void EdgeWithPenWidth() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - PenWidth = 0.46f - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[penwidth=0.46]; }"); - } - - [Fact] - public void EdgeWithLabel() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - Label = "Hello, \"world\"!" - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[label=\"Hello, \\\"world\\\"!\"]; }"); - } - - [Fact] - public void EdgeWithStyle() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - Style = DotEdgeStyle.Dashed - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[style=dashed]; }"); - } - - [Fact] - public void EdgeWithMultipleStyles() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - Style = DotEdgeStyle.Dashed | DotEdgeStyle.Dotted - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[style=\"dashed,dotted\"]; }"); - } - - [Fact] - public void EdgeWithArrowHead() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - ArrowHead = DotEdgeArrowType.Box - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[arrowhead=box]; }"); - } - - [Fact] - public void EdgeWithArrowTail() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotEdge("hello", "world") - { - ArrowTail = DotEdgeArrowType.Diamond - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[arrowtail=diamond]; }"); - } - - [Fact] - public void EdgeWithNullNodesThrowsException() - { - var node = new DotNode("example"); - - Check.ThatCode(() => new DotEdge(null, node)).Throws(); - Check.ThatCode(() => new DotEdge(node, null)).Throws(); - - Check.ThatCode(() => new DotEdge(null, "test")).Throws(); - Check.ThatCode(() => new DotEdge("test", null)).Throws(); - } - - [Fact] - public void EdgeWithEmptyNodeIdentifierThrowsException() - { - Check.ThatCode(() => new DotEdge(string.Empty, "test")).Throws(); - Check.ThatCode(() => new DotEdge(" ", "test")).Throws(); - Check.ThatCode(() => new DotEdge("test", string.Empty)).Throws(); - Check.ThatCode(() => new DotEdge("test", " ")).Throws(); - } - - [Fact] - public void ModifyEdgeWithNullNodesThrowsException() - { - var edge = new DotEdge(new DotNode("left"), new DotNode("right")); - - Check.ThatCode(() => edge.Left = null).Throws(); - Check.ThatCode(() => edge.Right = null).Throws(); - } - - [Theory] - [InlineData("style")] - [InlineData("Style")] - [InlineData("STYLE")] - public void DotEdge_WhenCustomAttributeSet_ThenItsCompiled(string styleName) - { - var graph = new DotGraph("TestGraph") - .AddEdge("hello", "world", e => - { - e.SetCustomAttribute(styleName, "dashed"); - }); - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { hello -- world[style=dashed]; }"); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs deleted file mode 100644 index 5388e03..0000000 --- a/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -using DotNetGraph.SubGraph; -using DotNetGraph.Extensions; -using System.Collections.Generic; -using Xunit; -using NFluent; -using DotNetGraph.Core; -using DotNetGraph.Node; -using DotNetGraph.Edge; - -namespace DotNetGraph.Tests.Extensions -{ - public class DotGraphExtensionsTests - { - public static IEnumerable GetGraphs() - { - yield return new[] { new DotGraph("G") }; - yield return new[] { new DotSubGraph("cluster_0") }; - } - - private void AssertSingleElement(IDotGraph sut) - where T : IDotElement - { - Check.That(sut.Elements).CountIs(1); - Check.That(sut.Elements[0]).IsInstanceOfType(typeof(T)); - } - - [Theory] - [MemberData(nameof(GetGraphs))] - public void AddNode_WhenCalled_ThenNewNodeIsAdded(IDotGraph sut) - { - var id = "A"; - sut.AddNode(id); - - AssertSingleElement(sut); - } - - [Theory] - [MemberData(nameof(GetGraphs))] - public void AddEdge_WhenCalledWithStrings_ThenNewEdgeIsAdded(IDotGraph sut) - { - var left = "A"; - var right = "B"; - sut.AddEdge(left, right); - - AssertSingleElement(sut); - } - - [Theory] - [MemberData(nameof(GetGraphs))] - public void AddEdge_WhenCalledWithElements_ThenNewEdgeIsAdded(IDotGraph sut) - { - var left = new DotNode("A"); - var right = new DotNode("B"); - sut.AddEdge(left, right); - - AssertSingleElement(sut); - } - - [Theory] - [MemberData(nameof(GetGraphs))] - public void AddSubGraph_WhenCalled_ThenSubGraphIsAdded(IDotGraph sut) - { - var id = "A"; - sut.AddSubGraph(id); - - AssertSingleElement(sut); - } - - [Theory] - [MemberData(nameof(GetGraphs))] - public void AddLine_WhenCalled_ThenLineIsAdded(IDotGraph sut) - { - var line = "raw line"; - sut.AddLine(line); - - Check.That(sut.Elements).CountIs(1); - Check.That(((DotString)sut.Elements[0]).Value).HasSameValueAs(line); - } - } -} diff --git a/Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs deleted file mode 100644 index af981a3..0000000 --- a/Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs +++ /dev/null @@ -1,42 +0,0 @@ -using DotNetGraph.Extensions; -using NFluent; -using System; -using Xunit; - -namespace DotNetGraph.Tests.Extensions -{ - public class EnumExtensionsTests - { - public enum EnumWithoutFlags - { - One, Two, Three - } - - [Flags] - public enum EnumWithFlags - { - One = 1, - Two = 2, - Three = 4 - } - - [Fact] - public void FlagsToString_WhenEnumWithoutFlagsProvided_ThenThereIsAnException() - { - var e = EnumWithoutFlags.One | EnumWithoutFlags.Three; - - Check.ThatCode(() => e.FlagsToString()) - .Throws(); - } - - [Theory] - [InlineData(EnumWithFlags.One, "one")] - [InlineData(default(EnumWithFlags), "")] - [InlineData(EnumWithFlags.One | EnumWithFlags.Three, "one,three")] - public void FlagsToString_WhenEnumWithFlagsProvided_ThenCorrectStringIsReturned(EnumWithFlags e, string expected) - { - var result = e.FlagsToString(); - Check.That(result).HasSameValueAs(expected); - } - } -} diff --git a/Sources/DotNetGraph.Tests/Indentation/IndentedGraphTests.cs b/Sources/DotNetGraph.Tests/Indentation/IndentedGraphTests.cs deleted file mode 100644 index d98b5d6..0000000 --- a/Sources/DotNetGraph.Tests/Indentation/IndentedGraphTests.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System.Drawing; -using DotNetGraph.Edge; -using DotNetGraph.Extensions; -using DotNetGraph.Node; -using DotNetGraph.SubGraph; -using NFluent; -using Xunit; -using Xunit.Abstractions; - -namespace DotNetGraph.Tests.Indentation -{ - public class IndentedGraphTests - { - private readonly ITestOutputHelper _output; - - public IndentedGraphTests(ITestOutputHelper output) - { - _output = output; - } - - [Fact] - public void BasicIndentedGraph() - { - var graph = new DotGraph("TestGraph"); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n}"); - } - - [Fact] - public void BasicIndentedDirectedGraph() - { - var graph = new DotGraph("TestGraph", true); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("digraph TestGraph { \n}"); - } - - [Fact] - public void BasicIndentedEdge() - { - var graph = new DotGraph("TestGraph"); - - graph.Elements.Add(new DotEdge("A", "B")); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n\tA -- B; \n}"); - } - - [Fact] - public void IndentedEdgeWithAttributes() - { - var graph = new DotGraph("TestGraph"); - - var edge = new DotEdge("A", "B") - { - Style = DotEdgeStyle.Dashed, - Color = Color.Red - }; - - graph.Elements.Add(edge); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n\tA -- B[style=dashed,color=\"#FF0000\"]; \n}"); - } - - [Fact] - public void BasicIndentedSubGraph() - { - var graph = new DotGraph("TestGraph"); - - graph.Elements.Add(new DotSubGraph("TestSubGraph")); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n\tsubgraph TestSubGraph { \n\t} \n}"); - } - - [Fact] - public void IndentedSubGraphWithEdge() - { - var graph = new DotGraph("TestGraph"); - - var subGraph = new DotSubGraph("TestSubGraph"); - - subGraph.Elements.Add(new DotEdge("A", "B")); - - graph.Elements.Add(subGraph); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n\tsubgraph TestSubGraph { \n\t\tA -- B; \n\t} \n}"); - } - - [Fact] - public void BasicIndentedNode() - { - var graph = new DotGraph("TestGraph"); - - graph.Elements.Add(new DotNode("TestNode")); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n\tTestNode; \n}"); - } - - [Fact] - public void IndentedNodeWithAttributes() - { - var graph = new DotGraph("TestGraph"); - - var edge = new DotNode("TestNode") - { - Color = Color.Red, - Style = DotNodeStyle.Bold - }; - - graph.Elements.Add(edge); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - Check.That(compiled).HasSameValueAs("graph TestGraph { \n\tTestNode[color=\"#FF0000\",style=bold]; \n}"); - } - - [Fact] - public void DotGraph_WhenNodesSubGraphsEdgesAndCustomLinesProvided_ThenCompilationIsFormattedCorrectly() - { - var graph = new DotGraph("TestGraph", true) - .AddLine("rankdir = TB;") - .AddSubGraph("cluster_0", s => - { - s.Label = "Test Sub Graph"; - s.AddNode("A") - .AddNode("B") - .AddLine("{rank = same; A; X;}"); - }) - .AddEdge("A", "B"); - - var compiled = graph.Compile(true); - - _output.WriteLine(compiled); - - // digraph TestGraph { - // rankdir = TB; - // subgraph cluster_0 { - // label="Test Sub Graph"; - // A; - // B; - // {rank = same; A; X;} - // } - // A -> B; - // } - - var expected = "digraph TestGraph { \n\trankdir = TB; \n\tsubgraph cluster_0 { \n\t\tlabel=\"Test Sub Graph\"; \n\t\tA; \n\t\tB; \n\t\t{rank = same; A; X;} \n\t} \n\tA -> B; \n}"; - - Check.That(compiled).HasSameValueAs(expected); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Node/BasicNodeTests.cs b/Sources/DotNetGraph.Tests/Node/BasicNodeTests.cs deleted file mode 100644 index bb99ad1..0000000 --- a/Sources/DotNetGraph.Tests/Node/BasicNodeTests.cs +++ /dev/null @@ -1,362 +0,0 @@ -using System; -using System.Drawing; -using System.Globalization; -using System.Threading; -using DotNetGraph.Core; -using DotNetGraph.Extensions; -using DotNetGraph.Node; -using NFluent; -using Xunit; - -namespace DotNetGraph.Tests.Node -{ - public class BasicNodeTests - { - [Fact] - public void EmptyNode() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode; }"); - } - - [Fact] - public void NodeWithMultipleAttributes() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Color = Color.Blue, - Label = "Test", - Shape = DotNodeShape.Box - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[color=\"#0000FF\",label=Test,shape=box]; }"); - } - - [Fact] - public void NodeWithColor() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode", Color.Red) - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[color=\"#FF0000\"]; }"); - } - - [Fact] - public void NodeWithPosition() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Position = new DotPosition(4, 2) - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[pos=\"4,2!\"]; }"); - } - - [Fact] - public void NodeWithShape() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Shape = DotNodeShape.Square - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[shape=square]; }"); - } - - [Fact] - public void NodeWithStyle() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Style = DotNodeStyle.Dashed - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[style=dashed]; }"); - } - - [Fact] - public void NodeWithMultipleStyles() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Style = DotNodeStyle.Rounded | DotNodeStyle.Filled - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[style=\"rounded,filled\"]; }"); - } - - [Fact] - public void NodeWithFontColor() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - FontColor = Color.Red - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[fontcolor=\"#FF0000\"]; }"); - } - - [Fact] - public void NodeWithFillColor() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - FillColor = Color.Red - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[fillcolor=\"#FF0000\"]; }"); - } - - [Fact] - public void NodeWithLabel() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Label = "Hello, \"world\"!" - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[label=\"Hello, \\\"world\\\"!\"]; }"); - } - - [Fact] - public void NodeWithPenWidth() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - PenWidth = 0.64f - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[penwidth=0.64]; }"); - } - - [Fact] - public void NodeWithWidth() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Width = 0.64f - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[width=0.64]; }"); - } - - [Fact] - public void NodeWithHeight() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Height = 0.64f - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[height=0.64]; }"); - } - - [Fact] - public void NodeWithWidthAndHeightUsesCorrectCulture() - { - var currentCulture = Thread.CurrentThread.CurrentCulture; - var currentUiCulture = Thread.CurrentThread.CurrentUICulture; - - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Width = 0.46f, - Height = 0.64f - } - } - }; - - var cultureInfo = new CultureInfo("de-DE"); - Thread.CurrentThread.CurrentCulture = cultureInfo; - Thread.CurrentThread.CurrentUICulture = cultureInfo; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[width=0.46,height=0.64]; }"); - - Thread.CurrentThread.CurrentCulture = currentCulture; - Thread.CurrentThread.CurrentUICulture = currentUiCulture; - } - - [Fact] - public void NodeWithLargeHeightUsesCorrectCulture() - { - var currentCulture = Thread.CurrentThread.CurrentCulture; - var currentUiCulture = Thread.CurrentThread.CurrentUICulture; - - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotNode("TestNode") - { - Height = 12345.67f - } - } - }; - - var cultureInfo = new CultureInfo("fr-FR"); - Thread.CurrentThread.CurrentCulture = cultureInfo; - Thread.CurrentThread.CurrentUICulture = cultureInfo; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[height=12345.67]; }"); - - Thread.CurrentThread.CurrentCulture = currentCulture; - Thread.CurrentThread.CurrentUICulture = currentUiCulture; - } - - [Fact] - public void NodeWithNullIdentifierThrowsException() - { - Check.ThatCode(() => new DotNode(null)).Throws(); - } - - [Fact] - public void NodeWithEmptyIdentifierThrowsException() - { - Check.ThatCode(() => new DotNode(string.Empty)).Throws(); - Check.ThatCode(() => new DotNode(" ")).Throws(); - } - - [Fact] - public void ModifyNodeIdentifierWithNullIdentifierThrowsException() - { - var node = new DotNode("test"); - Check.ThatCode(() => node.Identifier = null).Throws(); - } - - [Fact] - public void ModifyNodeIdentifierWithEmptyIdentifierThrowsException() - { - var node = new DotNode("test"); - Check.ThatCode(() => node.Identifier = string.Empty).Throws(); - Check.ThatCode(() => node.Identifier = " ").Throws(); - } - - [Theory] - [InlineData("shape")] - [InlineData("Shape")] - [InlineData("SHAPE")] - public void DotNode_WhenCustomAttributeSet_ThenItsCompiled(string shapeName) - { - var graph = new DotGraph("TestGraph") - .AddNode("TestNode", n => - { - n.SetCustomAttribute(shapeName, "square"); - }); - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { TestNode[shape=square]; }"); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/SubGraph/BasicSubGraphTests.cs b/Sources/DotNetGraph.Tests/SubGraph/BasicSubGraphTests.cs deleted file mode 100644 index 4f088c7..0000000 --- a/Sources/DotNetGraph.Tests/SubGraph/BasicSubGraphTests.cs +++ /dev/null @@ -1,248 +0,0 @@ -using System.Drawing; -using DotNetGraph.Edge; -using DotNetGraph.Extensions; -using DotNetGraph.Node; -using DotNetGraph.SubGraph; -using NFluent; -using Xunit; - -namespace DotNetGraph.Tests.SubGraph -{ - public class BasicSubGraphTests - { - [Fact] - public void EmptySubGraph() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { } }"); - } - - [Fact] - public void SubGraphWithSpaceInIdentifier() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("My test subgraph") - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph \"My test subgraph\" { } }"); - } - - [Fact] - public void SubGraphWithMultipleAttributes() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Style = DotSubGraphStyle.Dashed, - Color = Color.Red, - Label = "Hello, world!" - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { style=dashed; color=\"#FF0000\"; label=\"Hello, world!\"; } }"); - } - - [Fact] - public void SubGraphWithStyle() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Style = DotSubGraphStyle.Dashed - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { style=dashed; } }"); - } - - [Fact] - public void SubGraphWithMultipleStyles() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Style = DotSubGraphStyle.Rounded | DotSubGraphStyle.Filled - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { style=\"rounded,filled\"; } }"); - } - - [Fact] - public void SubGraphWithLabel() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Label = "Hello, \"world\"!" - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { label=\"Hello, \\\"world\\\"!\"; } }"); - } - - [Fact] - public void SubGraphWithColor() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Color = Color.Red - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { color=\"#FF0000\"; } }"); - } - - [Fact] - public void SubGraphWithEdge() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Elements = - { - new DotEdge("hello", "world") - } - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { hello -- world; } }"); - } - - [Fact] - public void SubGraphWithEdgeDirected() - { - var graph = new DotGraph("TestGraph") - { - Directed = true, - Elements = - { - new DotSubGraph("TestSubGraph") - { - Elements = - { - new DotEdge("hello", "world") - } - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("digraph TestGraph { subgraph TestSubGraph { hello -> world; } }"); - } - - [Fact] - public void SubGraphWithNode() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Elements = - { - new DotNode("TestNode") - } - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { TestNode; } }"); - } - - [Fact] - public void DotSubGraph_WhenRawLineAdded_ThenItsCompiled() - { - var graph = new DotGraph("TestGraph") - { - Elements = - { - new DotSubGraph("TestSubGraph") - { - Elements = - { - new DotString("{rank = same; A; X;}") - } - } - } - }; - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { {rank = same; A; X;} } }"); - } - - [Theory] - [InlineData("rank")] - [InlineData("Rank")] - [InlineData("RANK")] - public void DotSubGraph_WhenCustomAttributeSet_ThenItsCompiled(string rankName) - { - var graph = new DotGraph("TestGraph") - .AddSubGraph("TestSubGraph", s => - { - s.SetCustomAttribute(rankName, "same; A; X;"); - }); - - var compiled = graph.Compile(); - - Check.That(compiled).HasSameValueAs("graph TestGraph { subgraph TestSubGraph { rank=same; A; X; } }"); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotColorAttribute.cs b/Sources/DotNetGraph/Attributes/DotColorAttribute.cs deleted file mode 100644 index 870b714..0000000 --- a/Sources/DotNetGraph/Attributes/DotColorAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Drawing; -using DotNetGraph.Core; - -namespace DotNetGraph.Attributes -{ - public class DotColorAttribute : IDotAttribute - { - public Color Color { get; set; } - - public DotColorAttribute(Color color = default) - { - Color = color; - } - - public static implicit operator DotColorAttribute(Color? color) - { - return color.HasValue ? new DotColorAttribute(color.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeArrowHeadAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeArrowHeadAttribute.cs deleted file mode 100644 index 43411a1..0000000 --- a/Sources/DotNetGraph/Attributes/DotEdgeArrowHeadAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetGraph.Core; -using DotNetGraph.Edge; - -namespace DotNetGraph.Attributes -{ - public class DotEdgeArrowHeadAttribute : IDotAttribute - { - public DotEdgeArrowType ArrowType { get; set; } - - public DotEdgeArrowHeadAttribute(DotEdgeArrowType arrowType = default) - { - ArrowType = arrowType; - } - - public static implicit operator DotEdgeArrowHeadAttribute(DotEdgeArrowType? arrowType) - { - return arrowType.HasValue ? new DotEdgeArrowHeadAttribute(arrowType.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeArrowTailAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeArrowTailAttribute.cs deleted file mode 100644 index b1a06c0..0000000 --- a/Sources/DotNetGraph/Attributes/DotEdgeArrowTailAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetGraph.Core; -using DotNetGraph.Edge; - -namespace DotNetGraph.Attributes -{ - public class DotEdgeArrowTailAttribute : IDotAttribute - { - public DotEdgeArrowType ArrowType { get; set; } - - public DotEdgeArrowTailAttribute(DotEdgeArrowType arrowType = default) - { - ArrowType = arrowType; - } - - public static implicit operator DotEdgeArrowTailAttribute(DotEdgeArrowType? arrowType) - { - return arrowType.HasValue ? new DotEdgeArrowTailAttribute(arrowType.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs deleted file mode 100644 index 7f8c078..0000000 --- a/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using DotNetGraph.Edge; - -namespace DotNetGraph.Attributes -{ - public class DotEdgeStyleAttribute : DotColorAttribute - { - public DotEdgeStyle Style { get; set; } - - public DotEdgeStyleAttribute(DotEdgeStyle style = default) - { - Style = style; - } - - public static implicit operator DotEdgeStyleAttribute(DotEdgeStyle? style) - { - return style.HasValue ? new DotEdgeStyleAttribute(style.Value) : null; - } - } -} diff --git a/Sources/DotNetGraph/Attributes/DotFillColorAttribute.cs b/Sources/DotNetGraph/Attributes/DotFillColorAttribute.cs deleted file mode 100644 index b2bc948..0000000 --- a/Sources/DotNetGraph/Attributes/DotFillColorAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Drawing; - -namespace DotNetGraph.Attributes -{ - public class DotFillColorAttribute : DotColorAttribute - { - public DotFillColorAttribute(Color color = default) : base(color) - { - } - - public static implicit operator DotFillColorAttribute(Color? color) - { - return color.HasValue ? new DotFillColorAttribute(color.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotFontColorAttribute.cs b/Sources/DotNetGraph/Attributes/DotFontColorAttribute.cs deleted file mode 100644 index daf93a1..0000000 --- a/Sources/DotNetGraph/Attributes/DotFontColorAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Drawing; - -namespace DotNetGraph.Attributes -{ - public class DotFontColorAttribute : DotColorAttribute - { - public DotFontColorAttribute(Color color = default) : base(color) - { - } - - public static implicit operator DotFontColorAttribute(Color? color) - { - return color.HasValue ? new DotFontColorAttribute(color.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs deleted file mode 100644 index 5c6aff7..0000000 --- a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using DotNetGraph.Core; - -namespace DotNetGraph.Attributes -{ - public class DotLabelAttribute : IDotAttribute - { - public string Text { get; set; } - - public DotLabelAttribute(string text = default) - { - Text = text; - } - - public static implicit operator DotLabelAttribute(string text) - { - return text is null ? null : new DotLabelAttribute(text); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeHeightAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeHeightAttribute.cs deleted file mode 100644 index 6d1aa2a..0000000 --- a/Sources/DotNetGraph/Attributes/DotNodeHeightAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using DotNetGraph.Core; - -namespace DotNetGraph.Attributes -{ - public class DotNodeHeightAttribute : IDotAttribute - { - public float Value { get; set; } - - public DotNodeHeightAttribute(float value = default) - { - Value = value; - } - - public static implicit operator DotNodeHeightAttribute(float? value) - { - return value.HasValue ? new DotNodeHeightAttribute(value.Value) : null; - } - - public static implicit operator DotNodeHeightAttribute(int? value) - { - return value.HasValue ? new DotNodeHeightAttribute(value.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs deleted file mode 100644 index e32be94..0000000 --- a/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetGraph.Core; -using DotNetGraph.Node; - -namespace DotNetGraph.Attributes -{ - public class DotNodeShapeAttribute : IDotAttribute - { - public DotNodeShape Shape { get; set; } - - public DotNodeShapeAttribute(DotNodeShape shape = default) - { - Shape = shape; - } - - public static implicit operator DotNodeShapeAttribute(DotNodeShape? shape) - { - return shape.HasValue ? new DotNodeShapeAttribute(shape.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs deleted file mode 100644 index 02e208b..0000000 --- a/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetGraph.Core; -using DotNetGraph.Node; - -namespace DotNetGraph.Attributes -{ - public class DotNodeStyleAttribute : DotColorAttribute - { - public DotNodeStyle Style { get; set; } - - public DotNodeStyleAttribute(DotNodeStyle style = default) - { - Style = style; - } - - public static implicit operator DotNodeStyleAttribute(DotNodeStyle? style) - { - return style.HasValue ? new DotNodeStyleAttribute(style.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeWidthAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeWidthAttribute.cs deleted file mode 100644 index 27927c7..0000000 --- a/Sources/DotNetGraph/Attributes/DotNodeWidthAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using DotNetGraph.Core; - -namespace DotNetGraph.Attributes -{ - public class DotNodeWidthAttribute : IDotAttribute - { - public float Value { get; set; } - - public DotNodeWidthAttribute(float value = default) - { - Value = value; - } - - public static implicit operator DotNodeWidthAttribute(float? value) - { - return value.HasValue ? new DotNodeWidthAttribute(value.Value) : null; - } - - public static implicit operator DotNodeWidthAttribute(int? value) - { - return value.HasValue ? new DotNodeWidthAttribute(value.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotPenWidthAttribute.cs b/Sources/DotNetGraph/Attributes/DotPenWidthAttribute.cs deleted file mode 100644 index 9133b8b..0000000 --- a/Sources/DotNetGraph/Attributes/DotPenWidthAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using DotNetGraph.Core; - -namespace DotNetGraph.Attributes -{ - public class DotPenWidthAttribute : IDotAttribute - { - public float Value { get; set; } - - public DotPenWidthAttribute(float value = default) - { - Value = value; - } - - public static implicit operator DotPenWidthAttribute(float? value) - { - return value.HasValue ? new DotPenWidthAttribute(value.Value) : null; - } - - public static implicit operator DotPenWidthAttribute(int? value) - { - return value.HasValue ? new DotPenWidthAttribute(value.Value) : null; - } - } -} diff --git a/Sources/DotNetGraph/Attributes/DotPositionAttribute.cs b/Sources/DotNetGraph/Attributes/DotPositionAttribute.cs deleted file mode 100644 index d9aefcd..0000000 --- a/Sources/DotNetGraph/Attributes/DotPositionAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using DotNetGraph.Core; - -namespace DotNetGraph.Attributes -{ - public class DotPositionAttribute : IDotAttribute - { - public DotPosition Position { get; set; } - - public DotPositionAttribute(DotPosition position = default) - { - Position = position; - } - - public static implicit operator DotPositionAttribute(DotPosition position) - { - return new DotPositionAttribute(position); - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotSubGraphStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotSubGraphStyleAttribute.cs deleted file mode 100644 index fe13031..0000000 --- a/Sources/DotNetGraph/Attributes/DotSubGraphStyleAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using DotNetGraph.Core; -using DotNetGraph.SubGraph; - -namespace DotNetGraph.Attributes -{ - public class DotSubGraphStyleAttribute : IDotAttribute - { - public DotSubGraphStyle Style { get; set; } - - public DotSubGraphStyleAttribute(DotSubGraphStyle style = default) - { - Style = style; - } - - public static implicit operator DotSubGraphStyleAttribute(DotSubGraphStyle? style) - { - return style.HasValue ? new DotSubGraphStyleAttribute(style.Value) : null; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Compiler/DotCompiler.cs b/Sources/DotNetGraph/Compiler/DotCompiler.cs deleted file mode 100644 index 57d8b20..0000000 --- a/Sources/DotNetGraph/Compiler/DotCompiler.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace DotNetGraph.Compiler -{ - public class DotCompiler - { - private readonly DotGraph _graph; - - public DotCompiler(DotGraph graph) - { - _graph = graph ?? throw new ArgumentNullException(nameof(graph)); - } - - public string Compile(bool indented = false, bool formatStrings = true) - { - var builder = new StringBuilder(); - using (var writer = new StringWriter(builder)) - { - Compile(writer, indented, formatStrings); - return builder.ToString(); - } - } - - public void Compile(Stream stream, bool indented = false, bool formatStrings = true) - { - if (stream == null) - { - throw new ArgumentNullException(nameof(stream)); - } - - var writer = new StreamWriter(stream); - Compile(writer, indented, formatStrings); - } - - public void Compile(TextWriter writer, bool indented = false, bool formatStrings = true) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - using (var worker = new DotCompilerWorker(_graph, writer, indented, formatStrings)) - { - worker.Compile(); - } - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Compiler/DotCompilerWorker.cs b/Sources/DotNetGraph/Compiler/DotCompilerWorker.cs deleted file mode 100644 index dfcd968..0000000 --- a/Sources/DotNetGraph/Compiler/DotCompilerWorker.cs +++ /dev/null @@ -1,331 +0,0 @@ -using DotNetGraph.Attributes; -using DotNetGraph.Core; -using DotNetGraph.Edge; -using DotNetGraph.Extensions; -using DotNetGraph.Node; -using DotNetGraph.SubGraph; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text.RegularExpressions; - -namespace DotNetGraph.Compiler -{ - internal sealed class DotCompilerWorker : IDisposable - { - private static readonly Regex ValidIdentifierPattern = new Regex("^([a-zA-Z\\200-\\377_][a-zA-Z\\200-\\3770-9_]*|[-]?(.[0-9]+|[0-9]+(.[0-9]+)?))$"); - - private readonly DotGraph _graph; - private readonly TextWriter _writer; - private readonly bool _disposeWriter; - - public bool Indented { get; } - public bool FormatStrings { get; } - - public DotCompilerWorker(DotGraph graph, - TextWriter writer, - bool indented, - bool formatStrings, - bool disposeWriter = false) - { - _graph = graph ?? throw new ArgumentNullException(nameof(graph)); - _writer = writer ?? throw new ArgumentNullException(nameof(writer)); - Indented = indented; - FormatStrings = formatStrings; - _disposeWriter = disposeWriter; - } - - public void Dispose() - { - if (_disposeWriter) - { - _writer?.Dispose(); - } - } - - public void Compile() - { - CompileGraph(); - _writer.Flush(); - } - - private void CompileGraph() - { - var indentationLevel = 0; - - if (_graph.Strict) - { - _writer.Write("strict "); - } - - _writer.Write(_graph.Directed ? "digraph " : "graph "); - - _writer.Write($"{SurroundStringWithQuotes(_graph.Identifier, FormatStrings)} {{ "); - - _writer.AddIndentationNewLine(Indented); - - indentationLevel++; - - foreach (var element in _graph.Elements) - { - if (element is DotEdge edge) - { - CompileEdge(edge, indentationLevel); - } - else if (element is DotNode node) - { - CompileNode(node, indentationLevel); - } - else if (element is DotSubGraph subGraph) - { - CompileSubGraph(subGraph, indentationLevel); - } - else if (element is DotString stringElement) - { - CompileStringElement(stringElement, indentationLevel); - } - else - { - throw new DotException($"Graph body can't contain element of type: {element.GetType()}"); - } - } - - indentationLevel--; - - _writer.Write("}"); - } - - private void CompileSubGraph(DotSubGraph subGraph, int indentationLevel) - { - _writer.AddIndentation(Indented, indentationLevel); - - _writer.Write($"subgraph {SurroundStringWithQuotes(subGraph.Identifier, FormatStrings)} {{ "); - - _writer.AddIndentationNewLine(Indented); - - indentationLevel++; - - CompileSubGraphAttributes(subGraph.Attributes, indentationLevel); - - foreach (var element in subGraph.Elements) - { - if (element is DotEdge edge) - { - CompileEdge(edge, indentationLevel); - } - else if (element is DotNode node) - { - CompileNode(node, indentationLevel); - } - else if (element is DotSubGraph subSubGraph) - { - CompileSubGraph(subSubGraph, indentationLevel); - } - else if (element is DotString stringElement) - { - CompileStringElement(stringElement, indentationLevel); - } - else - { - throw new DotException($"Subgraph body can't contain element of type: {element.GetType()}"); - } - } - - indentationLevel--; - - _writer.AddIndentation(Indented, indentationLevel); - - _writer.Write("} "); - - _writer.AddIndentationNewLine(Indented); - } - - private void CompileSubGraphAttributes(IReadOnlyList attributes, int indentationLevel) - { - if (attributes.Count == 0) - return; - - foreach (var attribute in attributes) - { - string line; - if (attribute is DotSubGraphStyleAttribute subGraphStyleAttribute) - { - line = $"style={SurroundStringWithQuotes(subGraphStyleAttribute.Style.FlagsToString(), FormatStrings)};"; - } - else if (attribute is DotColorAttribute colorAttribute) - { - line = $"color=\"{colorAttribute.ToHex()}\";"; - } - else if (attribute is DotLabelAttribute labelAttribute) - { - line = $"label={SurroundStringWithQuotes(labelAttribute.Text, FormatStrings)};"; - } - else if (attribute is DotCustomAttribute customAttribute) - { - line = customAttribute.ToString(); - } - else - { - throw new DotException($"Attribute type not supported: {attribute.GetType()}"); - } - - CompileLine(line, indentationLevel); - } - } - - private void CompileEdge(DotEdge edge, int indentationLevel) - { - _writer.AddIndentation(Indented, indentationLevel); - - CompileEdgeEndPoint(edge.Left); - - _writer.Write(_graph.Directed ? " -> " : " -- "); - - CompileEdgeEndPoint(edge.Right); - - CompileAttributes(edge.Attributes); - - _writer.Write("; "); - - _writer.AddIndentationNewLine(Indented); - } - - private void CompileEdgeEndPoint(IDotElement endPoint) - { - if (endPoint is DotString leftEdgeString) - { - _writer.Write(SurroundStringWithQuotes(leftEdgeString.Value, FormatStrings)); - } - else if (endPoint is DotNode leftEdgeNode) - { - _writer.Write(SurroundStringWithQuotes(leftEdgeNode.Identifier, FormatStrings)); - } - else - { - throw new DotException($"Endpoint of an edge can't be of type: {endPoint.GetType()}"); - } - } - - private void CompileNode(DotNode node, int indentationLevel) - { - _writer.AddIndentation(Indented, indentationLevel); - - _writer.Write(SurroundStringWithQuotes(node.Identifier, FormatStrings)); - - CompileAttributes(node.Attributes); - - _writer.Write("; "); - - _writer.AddIndentationNewLine(Indented); - } - - private void CompileAttributes(IReadOnlyList attributes) - { - if (attributes.Count == 0) - return; - - _writer.Write("["); - - var attributeValues = new List(); - - foreach (var attribute in attributes) - { - if (attribute is DotNodeShapeAttribute nodeShapeAttribute) - { - attributeValues.Add($"shape={nodeShapeAttribute.Shape.ToString().ToLowerInvariant()}"); - } - else if (attribute is DotNodeStyleAttribute nodeStyleAttribute) - { - attributeValues.Add($"style={SurroundStringWithQuotes(nodeStyleAttribute.Style.FlagsToString(), FormatStrings)}"); - } - else if (attribute is DotEdgeStyleAttribute edgeStyleAttribute) - { - attributeValues.Add($"style={SurroundStringWithQuotes(edgeStyleAttribute.Style.FlagsToString(), FormatStrings)}"); - } - else if (attribute is DotFontColorAttribute fontColorAttribute) - { - attributeValues.Add($"fontcolor=\"{fontColorAttribute.ToHex()}\""); - } - else if (attribute is DotFillColorAttribute fillColorAttribute) - { - attributeValues.Add($"fillcolor=\"{fillColorAttribute.ToHex()}\""); - } - else if (attribute is DotColorAttribute colorAttribute) - { - attributeValues.Add($"color=\"{colorAttribute.ToHex()}\""); - } - else if (attribute is DotLabelAttribute labelAttribute) - { - attributeValues.Add($"label={SurroundStringWithQuotes(labelAttribute.Text, FormatStrings)}"); - } - else if (attribute is DotNodeWidthAttribute nodeWidthAttribute) - { - attributeValues.Add(string.Format(CultureInfo.InvariantCulture, "width={0:F2}", nodeWidthAttribute.Value)); - } - else if (attribute is DotNodeHeightAttribute nodeHeightAttribute) - { - attributeValues.Add(string.Format(CultureInfo.InvariantCulture, "height={0:F2}", nodeHeightAttribute.Value)); - } - else if (attribute is DotPenWidthAttribute dotPenwidthAttribute) - { - attributeValues.Add(string.Format(CultureInfo.InvariantCulture, "penwidth={0:F2}", dotPenwidthAttribute.Value)); - } - else if (attribute is DotEdgeArrowTailAttribute edgeArrowTailAttribute) - { - attributeValues.Add($"arrowtail={edgeArrowTailAttribute.ArrowType.ToString().ToLowerInvariant()}"); - } - else if (attribute is DotEdgeArrowHeadAttribute edgeArrowHeadAttribute) - { - attributeValues.Add($"arrowhead={edgeArrowHeadAttribute.ArrowType.ToString().ToLowerInvariant()}"); - } - else if (attribute is DotPositionAttribute positionAttribute && positionAttribute.Position != null) - { - attributeValues.Add($"pos=\"{positionAttribute.Position.X},{positionAttribute.Position.Y}!\""); - } - else if (attribute is DotCustomAttribute customAttribute) - { - attributeValues.Add(customAttribute.ToString()); - } - else - { - throw new DotException($"Attribute type not supported: {attribute.GetType()}"); - } - } - - _writer.Write(string.Join(",", attributeValues)); - - _writer.Write("]"); - } - - private void CompileStringElement(DotString stringElement, int indentationLevel) - { - CompileLine(stringElement.Value, indentationLevel); - } - - private void CompileLine(string value, int indentationLevel) - { - _writer.AddIndentation(Indented, indentationLevel); - _writer.Write(value + " "); - _writer.AddIndentationNewLine(Indented); - } - - internal static string SurroundStringWithQuotes(string value, bool format) - { - var formatted = FormatString(value, format); - return ValidIdentifierPattern.IsMatch(value) ? formatted : "\"" + formatted + "\""; - } - - internal static string FormatString(string value, bool format) - { - if (!format) - return value; - - return value - .Replace("\\", "\\\\") - .Replace("\"", "\\\"") - .Replace("\r\n", "\\n") - .Replace("\n", "\\n"); - } - } -} diff --git a/Sources/DotNetGraph/Core/DotCustomAttribute.cs b/Sources/DotNetGraph/Core/DotCustomAttribute.cs deleted file mode 100644 index b84b333..0000000 --- a/Sources/DotNetGraph/Core/DotCustomAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace DotNetGraph.Core -{ - public class DotCustomAttribute : IDotAttribute - { - public DotCustomAttribute(string name, string value) - { - if (string.IsNullOrWhiteSpace(name)) - { - throw new ArgumentException("Argument name cannot be empty", nameof(name)); - } - - Name = name; - Value = value; - } - - public string Name { get; } - public string Value { get; } - - public override string ToString() - { - return $"{Name.ToLowerInvariant()}={Value}"; - } - } -} diff --git a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs b/Sources/DotNetGraph/Core/DotElementWithAttributes.cs deleted file mode 100644 index 1fdbdcc..0000000 --- a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using DotNetGraph.Attributes; - -namespace DotNetGraph.Core -{ - public class DotElementWithAttributes : IDotElement - { - public ReadOnlyCollection Attributes => _attributes.Values - .Concat(_customAttributes.Values) - .ToList() - .AsReadOnly(); - - private readonly Dictionary _attributes; - private readonly Dictionary _customAttributes = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public DotElementWithAttributes(string identifier = null, DotColorAttribute color = null) - { - _attributes = new Dictionary(); - } - - protected T GetAttribute() where T : IDotAttribute - { - if (_attributes.TryGetValue(typeof(T).Name, out var colorAttribute)) - return (T)colorAttribute; - return default; - } - - protected void SetAttribute(T value) where T : IDotAttribute - { - if (value != null) - _attributes[typeof(T).Name] = value; - else if (_attributes.ContainsKey(typeof(T).Name)) - _attributes.Remove(typeof(T).Name); - } - - protected void SetCustomAttributeInternal(string name, string value) - { - var attr = new DotCustomAttribute(name, value); - _customAttributes[name] = attr; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotException.cs b/Sources/DotNetGraph/Core/DotException.cs deleted file mode 100644 index 1a504bb..0000000 --- a/Sources/DotNetGraph/Core/DotException.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; - -namespace DotNetGraph.Core -{ - public class DotException : Exception - { - public DotException(string message) : base(message) - { - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotPosition.cs b/Sources/DotNetGraph/Core/DotPosition.cs deleted file mode 100644 index 69f6ec1..0000000 --- a/Sources/DotNetGraph/Core/DotPosition.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace DotNetGraph.Core -{ - public class DotPosition - { - public int X { get; set; } - - public int Y { get; set; } - - public DotPosition() - { - } - - public DotPosition(int x, int y) - { - X = x; - Y = y; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/IDotAttribute.cs b/Sources/DotNetGraph/Core/IDotAttribute.cs deleted file mode 100644 index b000d85..0000000 --- a/Sources/DotNetGraph/Core/IDotAttribute.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DotNetGraph.Core -{ - public interface IDotAttribute - { - - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/IDotElement.cs b/Sources/DotNetGraph/Core/IDotElement.cs deleted file mode 100644 index 997ba3b..0000000 --- a/Sources/DotNetGraph/Core/IDotElement.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace DotNetGraph.Core -{ - public interface IDotElement - { - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/DotGraph.cs b/Sources/DotNetGraph/DotGraph.cs deleted file mode 100644 index fe0e309..0000000 --- a/Sources/DotNetGraph/DotGraph.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using DotNetGraph.Core; - -namespace DotNetGraph -{ - public class DotGraph : IDotElement, IDotGraph - { - public bool Directed { get; set; } - - public string Identifier { get; set; } - - public bool Strict { get; set; } - - public List Elements { get; } - - public DotGraph() - { - Elements = new List(); - } - - public DotGraph(string identifier, bool directed = false) : this() - { - Identifier = identifier; - Directed = directed; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/DotNetGraph.nuspec b/Sources/DotNetGraph/DotNetGraph.nuspec index 64daadb..40b354b 100644 --- a/Sources/DotNetGraph/DotNetGraph.nuspec +++ b/Sources/DotNetGraph/DotNetGraph.nuspec @@ -3,16 +3,16 @@ xmlns="https://raw.githubusercontent.com/NuGet/NuGet.Client/dev/src/NuGet.Core/NuGet.Packaging/compiler/resources/nuspec.xsd"> DotNetGraph - 2.7.0 + 3.0.0 DotNetGraph VFRZ VFRZ https://github.com/vfrz/DotNetGraph - Create GraphViz DOT diagram / graph using C#/.Net - Custom attributes, extension methods and more. - Copyright 2022 - DOT Graphviz + Create Graphviz DOT graph with dotnet + Initial 3.0 release + Copyright 2023 + DOT Graphviz Graph Visualization Graphs true LICENSE.txt netstandard2.0 diff --git a/Sources/DotNetGraph/DotString.cs b/Sources/DotNetGraph/DotString.cs deleted file mode 100644 index c999820..0000000 --- a/Sources/DotNetGraph/DotString.cs +++ /dev/null @@ -1,14 +0,0 @@ -using DotNetGraph.Core; - -namespace DotNetGraph -{ - public class DotString : IDotElement - { - public string Value { get; set; } - - public DotString(string value = null) - { - Value = value; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Edge/DotEdge.cs b/Sources/DotNetGraph/Edge/DotEdge.cs deleted file mode 100644 index 0c6d182..0000000 --- a/Sources/DotNetGraph/Edge/DotEdge.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System; -using System.Drawing; -using DotNetGraph.Attributes; -using DotNetGraph.Core; - -namespace DotNetGraph.Edge -{ - public class DotEdge : DotElementWithAttributes - { - private IDotElement _left; - private IDotElement _right; - - public IDotElement Left - { - get => _left; - set => _left = value ?? throw new ArgumentNullException(nameof(value)); - } - - public IDotElement Right - { - get => _right; - set => _right = value ?? throw new ArgumentNullException(nameof(value)); - } - - public DotColorAttribute Color - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotFontColorAttribute FontColor - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotEdgeStyleAttribute Style - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotLabelAttribute Label - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotPenWidthAttribute PenWidth - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotEdgeArrowHeadAttribute ArrowHead - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotEdgeArrowTailAttribute ArrowTail - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotPositionAttribute Position - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotEdge(IDotElement left, IDotElement right) - { - Left = left ?? throw new ArgumentNullException(nameof(left)); - Right = right ?? throw new ArgumentNullException(nameof(right)); - } - - public DotEdge(string left, string right) - { - if (left == null) - throw new ArgumentNullException(nameof(left)); - - if (right == null) - throw new ArgumentNullException(nameof(right)); - - if (string.IsNullOrWhiteSpace(left)) - throw new ArgumentException("Node cannot be empty", nameof(left)); - - if (string.IsNullOrWhiteSpace(right)) - throw new ArgumentException("Node cannot be empty", nameof(right)); - - Left = new DotString(left); - Right = new DotString(right); - } - - public DotEdge SetCustomAttribute(string name, string value) - { - SetCustomAttributeInternal(name, value); - - return this; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Edge/DotEdgeArrowType.cs b/Sources/DotNetGraph/Edge/DotEdgeArrowType.cs deleted file mode 100644 index 6818dbd..0000000 --- a/Sources/DotNetGraph/Edge/DotEdgeArrowType.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace DotNetGraph.Edge -{ - public enum DotEdgeArrowType - { - Normal, - Inv, - Dot, - InvDot, - ODot, - InvODot, - None, - Tee, - Empty, - InvEmpty, - Diamond, - ODiamond, - EDiamond, - Crow, - Box, - OBox, - Open, - HalfOpen, - Vee - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Edge/DotEdgeStyle.cs b/Sources/DotNetGraph/Edge/DotEdgeStyle.cs deleted file mode 100644 index cddeb27..0000000 --- a/Sources/DotNetGraph/Edge/DotEdgeStyle.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace DotNetGraph.Edge -{ - [Flags] - public enum DotEdgeStyle - { - Solid = 1, - Dashed = 2, - Dotted = 4, - Bold = 8 - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotColorExtensions.cs b/Sources/DotNetGraph/Extensions/DotColorExtensions.cs deleted file mode 100644 index 8a12f34..0000000 --- a/Sources/DotNetGraph/Extensions/DotColorExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using DotNetGraph.Attributes; - -namespace DotNetGraph.Extensions -{ - public static class DotColorExtensions - { - public static string ToHex(this DotColorAttribute colorAttribute) - { - return $"#{colorAttribute.Color.R:X2}{colorAttribute.Color.G:X2}{colorAttribute.Color.B:X2}"; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotGraphExtensions.cs b/Sources/DotNetGraph/Extensions/DotGraphExtensions.cs deleted file mode 100644 index 6aa7316..0000000 --- a/Sources/DotNetGraph/Extensions/DotGraphExtensions.cs +++ /dev/null @@ -1,106 +0,0 @@ -using DotNetGraph.Compiler; -using DotNetGraph.Core; -using DotNetGraph.Edge; -using DotNetGraph.Node; -using DotNetGraph.SubGraph; -using System; -using System.IO; - -namespace DotNetGraph.Extensions -{ - public static class DotGraphExtensions - { - public static string Compile(this DotGraph graph, bool indented = false, bool formatStrings = true) - { - return new DotCompiler(graph).Compile(indented, formatStrings); - } - - public static void Compile(this DotGraph graph, Stream stream, bool indented = false, bool formatStrings = true) - { - new DotCompiler(graph).Compile(stream, indented, formatStrings); - } - - public static void Compile(this DotGraph graph, TextWriter writer, bool indented = false, bool formatStrings = true) - { - new DotCompiler(graph).Compile(writer, indented, formatStrings); - } - - public static T AddNode(this T graph, string identifier, Action nodeSetup = null) - where T : IDotGraph - { - if (graph == null) - { - throw new ArgumentNullException(nameof(graph)); - } - - var node = new DotNode(identifier); - graph.Elements.Add(node); - - nodeSetup?.Invoke(node); - return graph; - } - - public static T AddEdge(this T graph, IDotElement left, IDotElement right, Action edgeSetup = null) - where T : IDotGraph - { - if (graph == null) - { - throw new ArgumentNullException(nameof(graph)); - } - - var edge = new DotEdge(left, right); - graph.Elements.Add(edge); - - edgeSetup?.Invoke(edge); - return graph; - } - - public static T AddEdge(this T graph, string left, string right, Action edgeSetup = null) - where T : IDotGraph - { - if (graph == null) - { - throw new ArgumentNullException(nameof(graph)); - } - - var edge = new DotEdge(left, right); - graph.Elements.Add(edge); - - edgeSetup?.Invoke(edge); - return graph; - } - - public static T AddSubGraph(this T graph, string identifier, Action subGraphSetup = null) - where T : IDotGraph - { - if (graph == null) - { - throw new ArgumentNullException(nameof(graph)); - } - - var subGraph = new DotSubGraph(identifier); - graph.Elements.Add(subGraph); - - subGraphSetup?.Invoke(subGraph); - return graph; - } - - public static T AddLine(this T graph, string rawLine) - where T : IDotGraph - { - if (graph == null) - { - throw new ArgumentNullException(nameof(graph)); - } - if (string.IsNullOrWhiteSpace(rawLine)) - { - throw new ArgumentException("Line cannot be empty", nameof(rawLine)); - } - - var stringElement = new DotString(rawLine); - graph.Elements.Add(stringElement); - - return graph; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/EnumExtensions.cs b/Sources/DotNetGraph/Extensions/EnumExtensions.cs deleted file mode 100644 index 211e716..0000000 --- a/Sources/DotNetGraph/Extensions/EnumExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Linq; -using System.Reflection; - -namespace DotNetGraph.Extensions -{ - internal static class EnumExtensions - { - public static string FlagsToString(this T @enum) where T : Enum - { - var type = typeof(T); - if (type.GetCustomAttribute() == null) - { - throw new InvalidOperationException($"The type '{type}' doesn't have the [Flags] attribute specified."); - } - - return string.Join(",", Enum.GetValues(type) - .Cast() - .Where(a => @enum.HasFlag(a)) - .Select(a => a.ToString().ToLowerInvariant())); - } - } -} diff --git a/Sources/DotNetGraph/Extensions/TextWriterExtensions.cs b/Sources/DotNetGraph/Extensions/TextWriterExtensions.cs deleted file mode 100644 index 02b8119..0000000 --- a/Sources/DotNetGraph/Extensions/TextWriterExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.IO; - -namespace DotNetGraph.Extensions -{ - internal static class TextWriterExtensions - { - public static TextWriter AddIndentation(this TextWriter writer, bool indented, int indentationLevel) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (!indented) - return writer; - - for (var i = 0; i < indentationLevel; i++) - { - writer.Write("\t"); - } - - return writer; - } - - public static TextWriter AddIndentationNewLine(this TextWriter writer, bool indented) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (indented) - { - writer.Write("\n"); - } - - return writer; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/IDotGraph.cs b/Sources/DotNetGraph/IDotGraph.cs deleted file mode 100644 index a88f922..0000000 --- a/Sources/DotNetGraph/IDotGraph.cs +++ /dev/null @@ -1,11 +0,0 @@ -using DotNetGraph.Core; -using System.Collections.Generic; - -namespace DotNetGraph -{ - public interface IDotGraph - { - List Elements { get; } - string Identifier { get; set; } - } -} diff --git a/Sources/DotNetGraph/Node/DotNode.cs b/Sources/DotNetGraph/Node/DotNode.cs deleted file mode 100644 index 8adb998..0000000 --- a/Sources/DotNetGraph/Node/DotNode.cs +++ /dev/null @@ -1,105 +0,0 @@ -using DotNetGraph.Attributes; -using DotNetGraph.Core; -using System; - -namespace DotNetGraph.Node -{ - public class DotNode : DotElementWithAttributes - { - private string _identifier; - - public string Identifier - { - get => _identifier; - set - { - if (value == null) - throw new ArgumentNullException(nameof(value)); - - if (string.IsNullOrWhiteSpace(value)) - throw new ArgumentException("Identifier cannot be empty", nameof(value)); - - _identifier = value; - } - } - - public DotColorAttribute Color - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotFontColorAttribute FontColor - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotFillColorAttribute FillColor - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotNodeShapeAttribute Shape - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotNodeStyleAttribute Style - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotLabelAttribute Label - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotNodeWidthAttribute Width - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotPenWidthAttribute PenWidth - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotNodeHeightAttribute Height - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotPositionAttribute Position - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotNode(string identifier, DotColorAttribute color = null) - { - if (identifier == null) - throw new ArgumentNullException(nameof(identifier)); - - if (string.IsNullOrWhiteSpace(identifier)) - throw new ArgumentException("Identifier cannot be empty", nameof(identifier)); - - Identifier = identifier; - Color = color; - } - - public DotNode SetCustomAttribute(string name, string value) - { - SetCustomAttributeInternal(name, value); - - return this; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Node/DotNodeShape.cs b/Sources/DotNetGraph/Node/DotNodeShape.cs deleted file mode 100644 index 1fefece..0000000 --- a/Sources/DotNetGraph/Node/DotNodeShape.cs +++ /dev/null @@ -1,65 +0,0 @@ -namespace DotNetGraph.Node -{ - public enum DotNodeShape - { - Box, - Polygon, - Ellipse, - Oval, - Circle, - Point, - Egg, - Triangle, - PlainText, - Plain, - Diamond, - Trapezium, - Parallelogram, - House, - Pentagon, - Hexagon, - Septagon, - Octagon, - DoubleCircle, - DoubleOctagon, - TripleOctagon, - InvTriangle, - InvTrapezium, - InvHouse, - MDiamond, - MSquare, - MCircle, - Rect, - Rectangle, - Square, - Star, - None, - Underline, - Cylinder, - Note, - Tab, - Folder, - Box3D, - Component, - Promoter, - CDS, - Terminator, - UTR, - PrimerSite, - RestrictionSite, - FivePOverHang, - ThreePOveHang, - NOverHang, - Assembly, - Signature, - Insulator, - Ribosite, - RNasTab, - ProteaseSite, - ProteinsTab, - RPromoter, - RArrow, - LArrow, - LPromoter - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/Node/DotNodeStyle.cs b/Sources/DotNetGraph/Node/DotNodeStyle.cs deleted file mode 100644 index 1867f6a..0000000 --- a/Sources/DotNetGraph/Node/DotNodeStyle.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace DotNetGraph.Node -{ - [Flags] - public enum DotNodeStyle - { - Solid = 1, - Dashed = 2, - Dotted = 4, - Bold = 8, - Rounded = 16, - Diagonals = 32, - Filled = 64, - Striped = 128, - Wedged = 256 - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/SubGraph/DotSubGraph.cs b/Sources/DotNetGraph/SubGraph/DotSubGraph.cs deleted file mode 100644 index 5fc95f4..0000000 --- a/Sources/DotNetGraph/SubGraph/DotSubGraph.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using DotNetGraph.Attributes; -using DotNetGraph.Core; - -namespace DotNetGraph.SubGraph -{ - public class DotSubGraph : DotElementWithAttributes, IDotGraph - { - public string Identifier { get; set; } - - public DotColorAttribute Color - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotSubGraphStyleAttribute Style - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public DotLabelAttribute Label - { - get => GetAttribute(); - set => SetAttribute(value); - } - - public List Elements { get; } - - public DotSubGraph(string identifier = null) - { - Elements = new List(); - Identifier = identifier; - } - - public DotSubGraph SetCustomAttribute(string name, string value) - { - SetCustomAttributeInternal(name, value); - - return this; - } - } -} \ No newline at end of file diff --git a/Sources/DotNetGraph/SubGraph/DotSubGraphStyle.cs b/Sources/DotNetGraph/SubGraph/DotSubGraphStyle.cs deleted file mode 100644 index e311931..0000000 --- a/Sources/DotNetGraph/SubGraph/DotSubGraphStyle.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace DotNetGraph.SubGraph -{ - [Flags] - public enum DotSubGraphStyle - { - Solid = 1, - Dashed = 2, - Dotted = 4, - Bold = 8, - Rounded = 16, - Filled = 32, - Striped = 64 - } -} \ No newline at end of file From 4151e9b19c929a755814a98eae974d0f7dd3a998 Mon Sep 17 00:00:00 2001 From: Valentin Fritz Date: Fri, 27 Jan 2023 22:30:40 +0100 Subject: [PATCH 02/15] Update CI --- .github/workflows/dotnet-test.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/dotnet-test.yml diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml new file mode 100644 index 0000000..290aa04 --- /dev/null +++ b/.github/workflows/dotnet-test.yml @@ -0,0 +1,15 @@ +name: dotnet test + +on: [ push ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup dotnet + uses: actions/setup-dotnet@v3 + with: + dotnet-version: 7.X + - name: Test + run: dotnet test ./Sources -v n -c Release From 985756ac92ea88a37e01ef89daf60b0d445c6781 Mon Sep 17 00:00:00 2001 From: Valentin Date: Fri, 27 Jan 2023 23:36:24 +0100 Subject: [PATCH 03/15] WIP --- .../Attributes/DotLabelAttribute.cs | 27 +++++++ .../DotNetGraph/Attributes/IDotAttribute.cs | 8 ++ .../Compilation/CompilationOptions.cs | 7 ++ Sources/DotNetGraph/Core/DotBaseGraph.cs | 14 ++++ Sources/DotNetGraph/Core/DotEdge.cs | 7 ++ .../Core/DotElementWithAttributes.cs | 73 +++++++++++++++++++ Sources/DotNetGraph/Core/DotGraph.cs | 16 ++++ Sources/DotNetGraph/Core/DotNode.cs | 12 +++ Sources/DotNetGraph/Core/DotSubgraph.cs | 12 +++ Sources/DotNetGraph/Core/IDotElement.cs | 9 +++ .../Extensions/DotBaseGraphExtensions.cs | 19 +++++ .../Extensions/StringExtensions.cs | 14 ++++ 12 files changed, 218 insertions(+) create mode 100644 Sources/DotNetGraph/Attributes/DotLabelAttribute.cs create mode 100644 Sources/DotNetGraph/Attributes/IDotAttribute.cs create mode 100644 Sources/DotNetGraph/Compilation/CompilationOptions.cs create mode 100644 Sources/DotNetGraph/Core/DotBaseGraph.cs create mode 100644 Sources/DotNetGraph/Core/DotEdge.cs create mode 100644 Sources/DotNetGraph/Core/DotElementWithAttributes.cs create mode 100644 Sources/DotNetGraph/Core/DotGraph.cs create mode 100644 Sources/DotNetGraph/Core/DotNode.cs create mode 100644 Sources/DotNetGraph/Core/DotSubgraph.cs create mode 100644 Sources/DotNetGraph/Core/IDotElement.cs create mode 100644 Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs create mode 100644 Sources/DotNetGraph/Extensions/StringExtensions.cs diff --git a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs new file mode 100644 index 0000000..fb48782 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs @@ -0,0 +1,27 @@ +using DotNetGraph.Compilation; +using DotNetGraph.Extensions; + +namespace DotNetGraph.Attributes +{ + public class DotLabelAttribute : IDotAttribute + { + public string Value { get; set; } + + public bool IsHtml { get; set; } = false; + + public DotLabelAttribute(string value, bool isHtml = false) + { + Value = value; + IsHtml = isHtml; + } + + public string Compile(CompilationOptions options) + { + if (IsHtml) + return $"<{Value}>"; + + var value = options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; + return $"\"{value}\""; + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/IDotAttribute.cs b/Sources/DotNetGraph/Attributes/IDotAttribute.cs new file mode 100644 index 0000000..832a699 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/IDotAttribute.cs @@ -0,0 +1,8 @@ +using DotNetGraph.Core; + +namespace DotNetGraph.Attributes +{ + public interface IDotAttribute : IDotElement + { + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Compilation/CompilationOptions.cs b/Sources/DotNetGraph/Compilation/CompilationOptions.cs new file mode 100644 index 0000000..4f0dd3a --- /dev/null +++ b/Sources/DotNetGraph/Compilation/CompilationOptions.cs @@ -0,0 +1,7 @@ +namespace DotNetGraph.Compilation +{ + public class CompilationOptions + { + public bool AutomaticEscapedCharactersFormat { get; set; } = true; + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotBaseGraph.cs b/Sources/DotNetGraph/Core/DotBaseGraph.cs new file mode 100644 index 0000000..23994d0 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotBaseGraph.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using DotNetGraph.Compilation; + +namespace DotNetGraph.Core +{ + public abstract class DotBaseGraph : DotElementWithAttributes + { + public string Identifier { get; set; } + + public List Elements { get; } = new List(); + + public abstract override string Compile(CompilationOptions options); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotEdge.cs b/Sources/DotNetGraph/Core/DotEdge.cs new file mode 100644 index 0000000..6112e11 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotEdge.cs @@ -0,0 +1,7 @@ +namespace DotNetGraph.Core +{ + public class DotEdge + { + + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs b/Sources/DotNetGraph/Core/DotElementWithAttributes.cs new file mode 100644 index 0000000..057782d --- /dev/null +++ b/Sources/DotNetGraph/Core/DotElementWithAttributes.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; + +namespace DotNetGraph.Core +{ + public abstract class DotElementWithAttributes : IDotElement + { + private readonly Dictionary _attributes = new Dictionary(); + + public IDotAttribute GetAttribute(string name) + { + if (_attributes.TryGetValue(name, out var attribute)) + return attribute; + throw new Exception($"There is no attribute named '{name}'"); + } + + public T GetAttribute(string name) where T : IDotAttribute + { + var attribute = GetAttribute(name); + if (attribute is T result) + return result; + throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {attribute.GetType()})"); + } + + public bool TryGetAttribute(string name, out IDotAttribute attribute) + { + var result = _attributes.TryGetValue(name, out var outAttribute); + if (result) + { + attribute = outAttribute; + return true; + } + + attribute = default; + return false; + } + + public bool TryGetAttribute(string name, out T attribute) where T : IDotAttribute + { + var result = TryGetAttribute(name, out var untypedAttribute); + if (result is false) + { + attribute = default; + return false; + } + + if (untypedAttribute is T typedAttribute) + { + attribute = typedAttribute; + return true; + } + + throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {untypedAttribute.GetType()})"); + } + + public void SetAttribute(string name, IDotAttribute value) + { + if (value is null) + RemoveAttribute(name); + else + _attributes[name] = value; + } + + public bool RemoveAttribute(string name) + { + return _attributes.Remove(name); + } + + public abstract string Compile(CompilationOptions options); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotGraph.cs b/Sources/DotNetGraph/Core/DotGraph.cs new file mode 100644 index 0000000..de67e2f --- /dev/null +++ b/Sources/DotNetGraph/Core/DotGraph.cs @@ -0,0 +1,16 @@ +using DotNetGraph.Compilation; + +namespace DotNetGraph.Core +{ + public class DotGraph : DotBaseGraph + { + public bool Strict { get; set; } = false; + + public bool Directed { get; set; } = false; + + public override string Compile(CompilationOptions options) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotNode.cs b/Sources/DotNetGraph/Core/DotNode.cs new file mode 100644 index 0000000..1f862a5 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotNode.cs @@ -0,0 +1,12 @@ +using DotNetGraph.Compilation; + +namespace DotNetGraph.Core +{ + public class DotNode : IDotElement + { + public string Compile(CompilationOptions options) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotSubgraph.cs b/Sources/DotNetGraph/Core/DotSubgraph.cs new file mode 100644 index 0000000..1ce327b --- /dev/null +++ b/Sources/DotNetGraph/Core/DotSubgraph.cs @@ -0,0 +1,12 @@ +using DotNetGraph.Compilation; + +namespace DotNetGraph.Core +{ + public class DotSubgraph : DotBaseGraph + { + public override string Compile(CompilationOptions options) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/IDotElement.cs b/Sources/DotNetGraph/Core/IDotElement.cs new file mode 100644 index 0000000..07c7f7d --- /dev/null +++ b/Sources/DotNetGraph/Core/IDotElement.cs @@ -0,0 +1,9 @@ +using DotNetGraph.Compilation; + +namespace DotNetGraph.Core +{ + public interface IDotElement + { + string Compile(CompilationOptions options); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs b/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs new file mode 100644 index 0000000..1c37cf5 --- /dev/null +++ b/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs @@ -0,0 +1,19 @@ +using DotNetGraph.Core; + +namespace DotNetGraph.Extensions +{ + public static class DotBaseGraphExtensions + { + public static T WithIdentifier(this T graph, string identifier) where T : DotBaseGraph + { + graph.Identifier = identifier; + return graph; + } + + public static T Add(this T graph, IDotElement element) where T : DotBaseGraph + { + graph.Elements.Add(element); + return graph; + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/StringExtensions.cs b/Sources/DotNetGraph/Extensions/StringExtensions.cs new file mode 100644 index 0000000..27d8bb1 --- /dev/null +++ b/Sources/DotNetGraph/Extensions/StringExtensions.cs @@ -0,0 +1,14 @@ +namespace DotNetGraph.Extensions +{ + public static class StringExtensions + { + internal static string FormatGraphvizEscapedCharacters(this string value) + { + return value + .Replace("\\", "\\\\") + .Replace("\"", "\\\"") + .Replace("\r\n", "\\n") + .Replace("\n", "\\n"); + } + } +} \ No newline at end of file From e6371142de3e5f7137dc9a01072d51b3b3a35a87 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 28 Jan 2023 15:17:08 +0100 Subject: [PATCH 04/15] WIP --- Sources/DotNetGraph.Tests/DotGraphTests.cs | 27 ++++++++++++ .../Attributes/DotLabelAttribute.cs | 9 ++-- .../Compilation/CompilationContext.cs | 41 +++++++++++++++++++ .../Compilation/CompilationOptions.cs | 2 + Sources/DotNetGraph/Core/DotBaseGraph.cs | 5 ++- .../Core/DotElementWithAttributes.cs | 40 +++++++++++++++++- Sources/DotNetGraph/Core/DotGraph.cs | 15 ++++++- Sources/DotNetGraph/Core/DotIdentifier.cs | 28 +++++++++++++ Sources/DotNetGraph/Core/DotNode.cs | 3 +- Sources/DotNetGraph/Core/DotSubgraph.cs | 3 +- Sources/DotNetGraph/Core/IDotElement.cs | 3 +- .../Extensions/DotBaseGraphExtensions.cs | 4 +- .../Extensions/DotGraphExtensions.cs | 19 +++++++++ 13 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 Sources/DotNetGraph.Tests/DotGraphTests.cs create mode 100644 Sources/DotNetGraph/Compilation/CompilationContext.cs create mode 100644 Sources/DotNetGraph/Core/DotIdentifier.cs create mode 100644 Sources/DotNetGraph/Extensions/DotGraphExtensions.cs diff --git a/Sources/DotNetGraph.Tests/DotGraphTests.cs b/Sources/DotNetGraph.Tests/DotGraphTests.cs new file mode 100644 index 0000000..760cda6 --- /dev/null +++ b/Sources/DotNetGraph.Tests/DotGraphTests.cs @@ -0,0 +1,27 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests; + +[TestClass] +public class DotGraphTests +{ + [TestMethod] + public async Task CompileEmptyGraph() + { + var graph = new DotGraph() + .WithIdentifier("Test"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await graph.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("graph \"Test\" {\n}\n"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs index fb48782..9f8207f 100644 --- a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using DotNetGraph.Compilation; using DotNetGraph.Extensions; @@ -15,13 +16,13 @@ public DotLabelAttribute(string value, bool isHtml = false) IsHtml = isHtml; } - public string Compile(CompilationOptions options) + public async Task CompileAsync(CompilationContext context) { if (IsHtml) - return $"<{Value}>"; + await context.TextWriter.WriteAsync($"<{Value}>"); - var value = options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; - return $"\"{value}\""; + var value = context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; + await context.TextWriter.WriteAsync($"\"{value}\""); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Compilation/CompilationContext.cs b/Sources/DotNetGraph/Compilation/CompilationContext.cs new file mode 100644 index 0000000..91555f3 --- /dev/null +++ b/Sources/DotNetGraph/Compilation/CompilationContext.cs @@ -0,0 +1,41 @@ +using System.IO; +using System.Threading.Tasks; + +namespace DotNetGraph.Compilation +{ + public class CompilationContext + { + public TextWriter TextWriter { get; } + + public CompilationOptions Options { get; } + + public int IndentationLevel { get; set; } + + public CompilationContext(TextWriter textWriter, CompilationOptions options) + { + TextWriter = textWriter; + Options = options; + IndentationLevel = 0; + } + + public async Task WriteIndentationAsync() + { + if (!Options.Indented) + return; + + for (var i = 0; i < IndentationLevel; i++) + await TextWriter.WriteAsync("\t"); + } + + public async Task WriteAsync(string value) + { + await TextWriter.WriteAsync(value); + } + + public async Task WriteLineAsync(string value = null) + { + await TextWriter.WriteAsync(value); + await TextWriter.WriteAsync(Options.Indented ? '\n' : ' '); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Compilation/CompilationOptions.cs b/Sources/DotNetGraph/Compilation/CompilationOptions.cs index 4f0dd3a..070d8af 100644 --- a/Sources/DotNetGraph/Compilation/CompilationOptions.cs +++ b/Sources/DotNetGraph/Compilation/CompilationOptions.cs @@ -3,5 +3,7 @@ namespace DotNetGraph.Compilation public class CompilationOptions { public bool AutomaticEscapedCharactersFormat { get; set; } = true; + + public bool Indented { get; set; } = true; } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotBaseGraph.cs b/Sources/DotNetGraph/Core/DotBaseGraph.cs index 23994d0..a3d509a 100644 --- a/Sources/DotNetGraph/Core/DotBaseGraph.cs +++ b/Sources/DotNetGraph/Core/DotBaseGraph.cs @@ -1,14 +1,15 @@ using System.Collections.Generic; +using System.Threading.Tasks; using DotNetGraph.Compilation; namespace DotNetGraph.Core { public abstract class DotBaseGraph : DotElementWithAttributes { - public string Identifier { get; set; } + public DotIdentifier Identifier { get; set; } public List Elements { get; } = new List(); - public abstract override string Compile(CompilationOptions options); + public abstract override Task CompileAsync(CompilationContext context); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs b/Sources/DotNetGraph/Core/DotElementWithAttributes.cs index 057782d..2f4fb8a 100644 --- a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs +++ b/Sources/DotNetGraph/Core/DotElementWithAttributes.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using DotNetGraph.Attributes; using DotNetGraph.Compilation; +using DotNetGraph.Extensions; namespace DotNetGraph.Core { @@ -9,6 +11,14 @@ public abstract class DotElementWithAttributes : IDotElement { private readonly Dictionary _attributes = new Dictionary(); + // Common attributes + public DotLabelAttribute Label + { + get => GetAttributeOrDefault("label"); + set => SetAttribute("label", value); + } + + // Attribute methods public IDotAttribute GetAttribute(string name) { if (_attributes.TryGetValue(name, out var attribute)) @@ -16,6 +26,11 @@ public IDotAttribute GetAttribute(string name) throw new Exception($"There is no attribute named '{name}'"); } + public IDotAttribute GetAttributeOrDefault(string name, IDotAttribute defaultValue = default) + { + return defaultValue; + } + public T GetAttribute(string name) where T : IDotAttribute { var attribute = GetAttribute(name); @@ -24,6 +39,18 @@ public T GetAttribute(string name) where T : IDotAttribute throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {attribute.GetType()})"); } + public T GetAttributeOrDefault(string name, T defaultValue = default) where T : IDotAttribute + { + if (_attributes.TryGetValue(name, out var attribute)) + { + if (attribute is T result) + return result; + throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {attribute.GetType()})"); + } + + return defaultValue; + } + public bool TryGetAttribute(string name, out IDotAttribute attribute) { var result = _attributes.TryGetValue(name, out var outAttribute); @@ -68,6 +95,17 @@ public bool RemoveAttribute(string name) return _attributes.Remove(name); } - public abstract string Compile(CompilationOptions options); + protected async Task CompileAttributesAsync(CompilationContext context) + { + foreach (var attributePair in _attributes) + { + await context.WriteIndentationAsync(); + await context.WriteAsync($"\"{attributePair.Key}\"="); + await attributePair.Value.CompileAsync(context); + await context.WriteLineAsync(); + } + } + + public abstract Task CompileAsync(CompilationContext context); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotGraph.cs b/Sources/DotNetGraph/Core/DotGraph.cs index de67e2f..f848a2c 100644 --- a/Sources/DotNetGraph/Core/DotGraph.cs +++ b/Sources/DotNetGraph/Core/DotGraph.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using DotNetGraph.Compilation; namespace DotNetGraph.Core @@ -8,9 +9,19 @@ public class DotGraph : DotBaseGraph public bool Directed { get; set; } = false; - public override string Compile(CompilationOptions options) + public override async Task CompileAsync(CompilationContext context) { - throw new System.NotImplementedException(); + await context.WriteIndentationAsync(); + if (Strict) + await context.WriteAsync("strict "); + await context.WriteAsync(Directed ? "digraph " : "graph "); + await Identifier.CompileAsync(context); + await context.WriteLineAsync(" {"); + context.IndentationLevel++; + await CompileAttributesAsync(context); + context.IndentationLevel--; + await context.WriteIndentationAsync(); + await context.WriteLineAsync("}"); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotIdentifier.cs b/Sources/DotNetGraph/Core/DotIdentifier.cs new file mode 100644 index 0000000..2e26830 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotIdentifier.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Extensions; + +namespace DotNetGraph.Core +{ + public class DotIdentifier : IDotElement + { + public string Value { get; set; } + + public bool IsHtml { get; set; } = false; + + public DotIdentifier(string value, bool isHtml = false) + { + Value = value; + IsHtml = isHtml; + } + + public async Task CompileAsync(CompilationContext context) + { + if (IsHtml) + await context.TextWriter.WriteAsync($"<{Value}>"); + + var value = context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; + await context.TextWriter.WriteAsync($"\"{value}\""); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotNode.cs b/Sources/DotNetGraph/Core/DotNode.cs index 1f862a5..a7aacf6 100644 --- a/Sources/DotNetGraph/Core/DotNode.cs +++ b/Sources/DotNetGraph/Core/DotNode.cs @@ -1,10 +1,11 @@ +using System.Threading.Tasks; using DotNetGraph.Compilation; namespace DotNetGraph.Core { public class DotNode : IDotElement { - public string Compile(CompilationOptions options) + public Task CompileAsync(CompilationContext context) { throw new System.NotImplementedException(); } diff --git a/Sources/DotNetGraph/Core/DotSubgraph.cs b/Sources/DotNetGraph/Core/DotSubgraph.cs index 1ce327b..4fc9988 100644 --- a/Sources/DotNetGraph/Core/DotSubgraph.cs +++ b/Sources/DotNetGraph/Core/DotSubgraph.cs @@ -1,10 +1,11 @@ +using System.Threading.Tasks; using DotNetGraph.Compilation; namespace DotNetGraph.Core { public class DotSubgraph : DotBaseGraph { - public override string Compile(CompilationOptions options) + public override Task CompileAsync(CompilationContext context) { throw new System.NotImplementedException(); } diff --git a/Sources/DotNetGraph/Core/IDotElement.cs b/Sources/DotNetGraph/Core/IDotElement.cs index 07c7f7d..d42eb0c 100644 --- a/Sources/DotNetGraph/Core/IDotElement.cs +++ b/Sources/DotNetGraph/Core/IDotElement.cs @@ -1,9 +1,10 @@ +using System.Threading.Tasks; using DotNetGraph.Compilation; namespace DotNetGraph.Core { public interface IDotElement { - string Compile(CompilationOptions options); + Task CompileAsync(CompilationContext context); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs b/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs index 1c37cf5..d5bd74f 100644 --- a/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs +++ b/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs @@ -4,9 +4,9 @@ namespace DotNetGraph.Extensions { public static class DotBaseGraphExtensions { - public static T WithIdentifier(this T graph, string identifier) where T : DotBaseGraph + public static T WithIdentifier(this T graph, string identifier, bool isHtml = false) where T : DotBaseGraph { - graph.Identifier = identifier; + graph.Identifier = new DotIdentifier(identifier, isHtml); return graph; } diff --git a/Sources/DotNetGraph/Extensions/DotGraphExtensions.cs b/Sources/DotNetGraph/Extensions/DotGraphExtensions.cs new file mode 100644 index 0000000..c3a300c --- /dev/null +++ b/Sources/DotNetGraph/Extensions/DotGraphExtensions.cs @@ -0,0 +1,19 @@ +using DotNetGraph.Core; + +namespace DotNetGraph.Extensions +{ + public static class DotGraphExtensions + { + public static DotGraph Directed(this DotGraph graph, bool directed = true) + { + graph.Directed = directed; + return graph; + } + + public static DotGraph Strict(this DotGraph graph, bool strict = true) + { + graph.Strict = strict; + return graph; + } + } +} \ No newline at end of file From df3e18056039c801f25c738e650d57d24cee157f Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 28 Jan 2023 16:01:42 +0100 Subject: [PATCH 05/15] WIP --- Sources/DotNetGraph.Tests/DotGraphTests.cs | 30 +++++++++ .../DotNetGraph/Attributes/DotAttribute.cs | 20 ++++++ .../Attributes/DotColorAttribute.cs | 27 ++++++++ .../Attributes/DotNodeShapeAttribute.cs | 26 ++++++++ Sources/DotNetGraph/Core/DotBaseGraph.cs | 2 +- ...ElementWithAttributes.cs => DotElement.cs} | 9 ++- Sources/DotNetGraph/Core/DotNode.cs | 34 +++++++++- Sources/DotNetGraph/Core/DotNodeShape.cs | 65 +++++++++++++++++++ .../DotNetGraph/Extensions/ColorExtensions.cs | 14 ++++ .../Extensions/DotElementExtensions.cs | 39 +++++++++++ .../Extensions/DotNodeExtensions.cs | 51 +++++++++++++++ 11 files changed, 311 insertions(+), 6 deletions(-) create mode 100644 Sources/DotNetGraph/Attributes/DotAttribute.cs create mode 100644 Sources/DotNetGraph/Attributes/DotColorAttribute.cs create mode 100644 Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs rename Sources/DotNetGraph/Core/{DotElementWithAttributes.cs => DotElement.cs} (93%) create mode 100644 Sources/DotNetGraph/Core/DotNodeShape.cs create mode 100644 Sources/DotNetGraph/Extensions/ColorExtensions.cs create mode 100644 Sources/DotNetGraph/Extensions/DotElementExtensions.cs create mode 100644 Sources/DotNetGraph/Extensions/DotNodeExtensions.cs diff --git a/Sources/DotNetGraph.Tests/DotGraphTests.cs b/Sources/DotNetGraph.Tests/DotGraphTests.cs index 760cda6..0cdf6ab 100644 --- a/Sources/DotNetGraph.Tests/DotGraphTests.cs +++ b/Sources/DotNetGraph.Tests/DotGraphTests.cs @@ -24,4 +24,34 @@ public async Task CompileEmptyGraph() var result = writer.GetStringBuilder().ToString(); result.Should().Be("graph \"Test\" {\n}\n"); } + + [TestMethod] + public async Task CompileEmptyStrictGraph() + { + var graph = new DotGraph() + .WithIdentifier("Test") + .Strict(); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await graph.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("strict graph \"Test\" {\n}\n"); + } + + [TestMethod] + public async Task CompileEmptyDirectedGraph() + { + var graph = new DotGraph() + .WithIdentifier("Test") + .Directed(); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await graph.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("digraph \"Test\" {\n}\n"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotAttribute.cs b/Sources/DotNetGraph/Attributes/DotAttribute.cs new file mode 100644 index 0000000..9c18c90 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotAttribute.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; + +namespace DotNetGraph.Attributes +{ + public class DotAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotAttribute(string value) + { + Value = value; + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync(Value); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotColorAttribute.cs b/Sources/DotNetGraph/Attributes/DotColorAttribute.cs new file mode 100644 index 0000000..f019622 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotColorAttribute.cs @@ -0,0 +1,27 @@ +using System.Drawing; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Extensions; + +namespace DotNetGraph.Attributes +{ + public class DotColorAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotColorAttribute(Color color) + { + Value = color.ToHexString(); + } + + public DotColorAttribute(string value) + { + Value = value; + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync($"\"{Value}\""); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs new file mode 100644 index 0000000..385a557 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; + +namespace DotNetGraph.Attributes +{ + public class DotNodeShapeAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotNodeShapeAttribute(string value) + { + Value = value; + } + + public DotNodeShapeAttribute(DotNodeShape shape) + { + Value = shape.ToString().ToLowerInvariant(); + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync($"\"{Value}\""); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotBaseGraph.cs b/Sources/DotNetGraph/Core/DotBaseGraph.cs index a3d509a..73f0070 100644 --- a/Sources/DotNetGraph/Core/DotBaseGraph.cs +++ b/Sources/DotNetGraph/Core/DotBaseGraph.cs @@ -4,7 +4,7 @@ namespace DotNetGraph.Core { - public abstract class DotBaseGraph : DotElementWithAttributes + public abstract class DotBaseGraph : DotElement { public DotIdentifier Identifier { get; set; } diff --git a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs b/Sources/DotNetGraph/Core/DotElement.cs similarity index 93% rename from Sources/DotNetGraph/Core/DotElementWithAttributes.cs rename to Sources/DotNetGraph/Core/DotElement.cs index 2f4fb8a..dc5cf2b 100644 --- a/Sources/DotNetGraph/Core/DotElementWithAttributes.cs +++ b/Sources/DotNetGraph/Core/DotElement.cs @@ -3,11 +3,10 @@ using System.Threading.Tasks; using DotNetGraph.Attributes; using DotNetGraph.Compilation; -using DotNetGraph.Extensions; namespace DotNetGraph.Core { - public abstract class DotElementWithAttributes : IDotElement + public abstract class DotElement : IDotElement { private readonly Dictionary _attributes = new Dictionary(); @@ -18,6 +17,12 @@ public DotLabelAttribute Label set => SetAttribute("label", value); } + public DotColorAttribute FontColor + { + get => GetAttributeOrDefault("fontcolor"); + set => SetAttribute("fontcolor", value); + } + // Attribute methods public IDotAttribute GetAttribute(string name) { diff --git a/Sources/DotNetGraph/Core/DotNode.cs b/Sources/DotNetGraph/Core/DotNode.cs index a7aacf6..8018121 100644 --- a/Sources/DotNetGraph/Core/DotNode.cs +++ b/Sources/DotNetGraph/Core/DotNode.cs @@ -1,13 +1,41 @@ using System.Threading.Tasks; +using DotNetGraph.Attributes; using DotNetGraph.Compilation; namespace DotNetGraph.Core { - public class DotNode : IDotElement + public class DotNode : DotElement { - public Task CompileAsync(CompilationContext context) + public DotIdentifier Identifier { get; set; } + + public DotColorAttribute Color + { + get => GetAttributeOrDefault("color"); + set => SetAttribute("color", value); + } + + public DotColorAttribute FillColor + { + get => GetAttributeOrDefault("fillcolor"); + set => SetAttribute("fillcolor", value); + } + + public DotNodeShapeAttribute Shape + { + get => GetAttributeOrDefault("shape"); + set => SetAttribute("shape", value); + } + + public override async Task CompileAsync(CompilationContext context) { - throw new System.NotImplementedException(); + await context.WriteIndentationAsync(); + await Identifier.CompileAsync(context); + await context.WriteLineAsync(" {"); + context.IndentationLevel++; + await CompileAttributesAsync(context); + context.IndentationLevel--; + await context.WriteIndentationAsync(); + await context.WriteLineAsync("}"); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotNodeShape.cs b/Sources/DotNetGraph/Core/DotNodeShape.cs new file mode 100644 index 0000000..2087692 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotNodeShape.cs @@ -0,0 +1,65 @@ +namespace DotNetGraph.Core +{ + public enum DotNodeShape + { + Box, + Polygon, + Ellipse, + Oval, + Circle, + Point, + Egg, + Triangle, + PlainText, + Plain, + Diamond, + Trapezium, + Parallelogram, + House, + Pentagon, + Hexagon, + Septagon, + Octagon, + DoubleCircle, + DoubleOctagon, + TripleOctagon, + InvTriangle, + InvTrapezium, + InvHouse, + MDiamond, + MSquare, + MCircle, + Rect, + Rectangle, + Square, + Star, + None, + Underline, + Cylinder, + Note, + Tab, + Folder, + Box3D, + Component, + Promoter, + CDS, + Terminator, + UTR, + PrimerSite, + RestrictionSite, + FivePOverHang, + ThreePOveHang, + NOverHang, + Assembly, + Signature, + Insulator, + Ribosite, + RNasTab, + ProteaseSite, + ProteinsTab, + RPromoter, + RArrow, + LArrow, + LPromoter + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/ColorExtensions.cs b/Sources/DotNetGraph/Extensions/ColorExtensions.cs new file mode 100644 index 0000000..e404c90 --- /dev/null +++ b/Sources/DotNetGraph/Extensions/ColorExtensions.cs @@ -0,0 +1,14 @@ +using System.Drawing; + +namespace DotNetGraph.Extensions +{ + public static class ColorExtensions + { + public static string ToHexString(this Color color) + { + if (color.A == 255) + return $"#{color.R:X2}{color.G:X2}{color.B:X2}"; + return $"#{color.R:X2}{color.G:X2}{color.B:X2}{color.A:X2}"; + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotElementExtensions.cs b/Sources/DotNetGraph/Extensions/DotElementExtensions.cs new file mode 100644 index 0000000..48fcde7 --- /dev/null +++ b/Sources/DotNetGraph/Extensions/DotElementExtensions.cs @@ -0,0 +1,39 @@ +using System.Drawing; +using DotNetGraph.Attributes; +using DotNetGraph.Core; + +namespace DotNetGraph.Extensions +{ + public static class DotElementExtensions + { + public static T WithAttribute(this T element, string name, IDotAttribute attribute) where T : DotElement + { + element.SetAttribute(name, attribute); + return element; + } + + public static T WithAttribute(this T element, string name, string value) where T : DotElement + { + element.SetAttribute(name, new DotAttribute(value)); + return element; + } + + public static T WithLabel(this T element, string label, bool isHtml = false) where T : DotElement + { + element.Label = new DotLabelAttribute(label, isHtml); + return element; + } + + public static T WithFontColor(this T element, string color) where T : DotElement + { + element.FontColor = new DotColorAttribute(color); + return element; + } + + public static T WithFontColor(this T element, Color color) where T : DotElement + { + element.FontColor = new DotColorAttribute(color); + return element; + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs b/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs new file mode 100644 index 0000000..bbb2b1d --- /dev/null +++ b/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs @@ -0,0 +1,51 @@ +using System.Drawing; +using DotNetGraph.Attributes; +using DotNetGraph.Core; + +namespace DotNetGraph.Extensions +{ + public static class DotNodeExtensions + { + public static DotNode WithIdentifier(this DotNode node, string identifier, bool isHtml = false) + { + node.Identifier = new DotIdentifier(identifier, isHtml); + return node; + } + + public static DotNode WithColor(this DotNode node, string color) + { + node.Color = new DotColorAttribute(color); + return node; + } + + public static DotNode WithColor(this DotNode node, Color color) + { + node.Color = new DotColorAttribute(color); + return node; + } + + public static DotNode WithFillColor(this DotNode node, string color) + { + node.FillColor = new DotColorAttribute(color); + return node; + } + + public static DotNode WithFillColor(this DotNode node, Color color) + { + node.FillColor = new DotColorAttribute(color); + return node; + } + + public static DotNode WithShape(this DotNode node, string shape) + { + node.Shape = new DotNodeShapeAttribute(shape); + return node; + } + + public static DotNode WithShape(this DotNode node, DotNodeShape shape) + { + node.Shape = new DotNodeShapeAttribute(shape); + return node; + } + } +} \ No newline at end of file From f809ea48edf901c3369629155a1436d0741a6b2f Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 29 Jan 2023 14:04:07 +0100 Subject: [PATCH 06/15] WIP --- Sources/DotNetGraph.Tests/DotNodeTests.cs | 43 ++++++++++++++ .../Attributes/DotDoubleAttribute.cs | 23 ++++++++ .../Attributes/DotNodeStyleAttribute.cs | 27 +++++++++ .../Attributes/DotPointAttribute.cs | 26 +++++++++ Sources/DotNetGraph/Core/DotElement.cs | 19 +++--- Sources/DotNetGraph/Core/DotNode.cs | 50 ++++++++++++++-- Sources/DotNetGraph/Core/DotNodeStyle.cs | 18 ++++++ Sources/DotNetGraph/Core/DotPoint.cs | 39 +++++++++++++ .../Extensions/DotNodeExtensions.cs | 58 +++++++++++++++++-- .../DotNetGraph/Extensions/EnumExtensions.cs | 20 +++++++ .../Extensions/StringExtensions.cs | 3 +- 11 files changed, 306 insertions(+), 20 deletions(-) create mode 100644 Sources/DotNetGraph.Tests/DotNodeTests.cs create mode 100644 Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs create mode 100644 Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs create mode 100644 Sources/DotNetGraph/Attributes/DotPointAttribute.cs create mode 100644 Sources/DotNetGraph/Core/DotNodeStyle.cs create mode 100644 Sources/DotNetGraph/Core/DotPoint.cs create mode 100644 Sources/DotNetGraph/Extensions/EnumExtensions.cs diff --git a/Sources/DotNetGraph.Tests/DotNodeTests.cs b/Sources/DotNetGraph.Tests/DotNodeTests.cs new file mode 100644 index 0000000..e05c65c --- /dev/null +++ b/Sources/DotNetGraph.Tests/DotNodeTests.cs @@ -0,0 +1,43 @@ +using System.Drawing; +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests; + +[TestClass] +public class DotNodeTests +{ + [TestMethod] + public async Task CompileEmptyNode() + { + var node = new DotNode() + .WithIdentifier("Test"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await node.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"Test\"\n"); + } + + [TestMethod] + public async Task CompileNodeWithColor() + { + var node = new DotNode() + .WithIdentifier("Test") + .WithColor(Color.Red); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await node.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"Test\" [\n\t\"color\"=\"#FF0000\"\n]\n"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs b/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs new file mode 100644 index 0000000..aaccdc2 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; + +namespace DotNetGraph.Attributes +{ + public class DotDoubleAttribute : IDotAttribute + { + public double Value { get; set; } + + public string Format { get; set; } + + public DotDoubleAttribute(double value, string format = "F2") + { + Value = value; + Format = format; + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync(Value.ToString(Format)); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs new file mode 100644 index 0000000..61e7313 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; + +namespace DotNetGraph.Attributes +{ + public class DotNodeStyleAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotNodeStyleAttribute(string value) + { + Value = value; + } + + public DotNodeStyleAttribute(DotNodeStyle style) + { + Value = style.FlagsToString(); + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync($"\"{Value}\""); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotPointAttribute.cs b/Sources/DotNetGraph/Attributes/DotPointAttribute.cs new file mode 100644 index 0000000..a397b56 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotPointAttribute.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; + +namespace DotNetGraph.Attributes +{ + public class DotPointAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotPointAttribute(string value) + { + Value = value; + } + + public DotPointAttribute(DotPoint point) + { + Value = point.ToString(); + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync(Value); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotElement.cs b/Sources/DotNetGraph/Core/DotElement.cs index dc5cf2b..201f3cf 100644 --- a/Sources/DotNetGraph/Core/DotElement.cs +++ b/Sources/DotNetGraph/Core/DotElement.cs @@ -8,7 +8,7 @@ namespace DotNetGraph.Core { public abstract class DotElement : IDotElement { - private readonly Dictionary _attributes = new Dictionary(); + protected readonly Dictionary Attributes = new Dictionary(); // Common attributes public DotLabelAttribute Label @@ -24,9 +24,14 @@ public DotColorAttribute FontColor } // Attribute methods + public bool HasAttribute(string name) + { + return Attributes.ContainsKey(name); + } + public IDotAttribute GetAttribute(string name) { - if (_attributes.TryGetValue(name, out var attribute)) + if (Attributes.TryGetValue(name, out var attribute)) return attribute; throw new Exception($"There is no attribute named '{name}'"); } @@ -46,7 +51,7 @@ public T GetAttribute(string name) where T : IDotAttribute public T GetAttributeOrDefault(string name, T defaultValue = default) where T : IDotAttribute { - if (_attributes.TryGetValue(name, out var attribute)) + if (Attributes.TryGetValue(name, out var attribute)) { if (attribute is T result) return result; @@ -58,7 +63,7 @@ public T GetAttributeOrDefault(string name, T defaultValue = default) where T public bool TryGetAttribute(string name, out IDotAttribute attribute) { - var result = _attributes.TryGetValue(name, out var outAttribute); + var result = Attributes.TryGetValue(name, out var outAttribute); if (result) { attribute = outAttribute; @@ -92,17 +97,17 @@ public void SetAttribute(string name, IDotAttribute value) if (value is null) RemoveAttribute(name); else - _attributes[name] = value; + Attributes[name] = value; } public bool RemoveAttribute(string name) { - return _attributes.Remove(name); + return Attributes.Remove(name); } protected async Task CompileAttributesAsync(CompilationContext context) { - foreach (var attributePair in _attributes) + foreach (var attributePair in Attributes) { await context.WriteIndentationAsync(); await context.WriteAsync($"\"{attributePair.Key}\"="); diff --git a/Sources/DotNetGraph/Core/DotNode.cs b/Sources/DotNetGraph/Core/DotNode.cs index 8018121..f9fcde0 100644 --- a/Sources/DotNetGraph/Core/DotNode.cs +++ b/Sources/DotNetGraph/Core/DotNode.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Threading.Tasks; using DotNetGraph.Attributes; using DotNetGraph.Compilation; @@ -26,16 +27,53 @@ public DotNodeShapeAttribute Shape set => SetAttribute("shape", value); } + public DotNodeStyleAttribute Style + { + get => GetAttributeOrDefault("style"); + set => SetAttribute("style", value); + } + + public DotDoubleAttribute Width + { + get => GetAttribute("width"); + set => SetAttribute("width", value); + } + + public DotDoubleAttribute Height + { + get => GetAttribute("height"); + set => SetAttribute("height", value); + } + + public DotDoubleAttribute PenWidth + { + get => GetAttribute("penwidth"); + set => SetAttribute("penwidth", value); + } + + public DotPointAttribute Pos + { + get => GetAttribute("pos"); + set => SetAttribute("pos", value); + } + public override async Task CompileAsync(CompilationContext context) { await context.WriteIndentationAsync(); await Identifier.CompileAsync(context); - await context.WriteLineAsync(" {"); - context.IndentationLevel++; - await CompileAttributesAsync(context); - context.IndentationLevel--; - await context.WriteIndentationAsync(); - await context.WriteLineAsync("}"); + if (Attributes.Any()) + { + await context.WriteLineAsync(" ["); + context.IndentationLevel++; + await CompileAttributesAsync(context); + context.IndentationLevel--; + await context.WriteIndentationAsync(); + await context.WriteLineAsync("]"); + } + else + { + await context.WriteLineAsync(); + } } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotNodeStyle.cs b/Sources/DotNetGraph/Core/DotNodeStyle.cs new file mode 100644 index 0000000..ba29764 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotNodeStyle.cs @@ -0,0 +1,18 @@ +using System; + +namespace DotNetGraph.Core +{ + [Flags] + public enum DotNodeStyle + { + Solid = 1, + Dashed = 2, + Dotted = 4, + Bold = 8, + Rounded = 16, + Diagonals = 32, + Filled = 64, + Striped = 128, + Wedged = 256 + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotPoint.cs b/Sources/DotNetGraph/Core/DotPoint.cs new file mode 100644 index 0000000..40b5a09 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotPoint.cs @@ -0,0 +1,39 @@ +namespace DotNetGraph.Core +{ + public struct DotPoint + { + public int X; + + public int Y; + + public int? Z; + + public bool Fixed; + + public DotPoint(int x, int y, bool @fixed = false) + { + X = x; + Y = y; + Z = null; + Fixed = @fixed; + } + + public DotPoint(int x, int y, int z, bool @fixed = false) + { + X = x; + Y = y; + Z = z; + Fixed = @fixed; + } + + public override string ToString() + { + var value = $"{X},{Y}"; + if (Z != null) + value += $",{Z}"; + if (Fixed) + value += "!"; + return value; + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs b/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs index bbb2b1d..759a7b1 100644 --- a/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs +++ b/Sources/DotNetGraph/Extensions/DotNodeExtensions.cs @@ -17,35 +17,83 @@ public static DotNode WithColor(this DotNode node, string color) node.Color = new DotColorAttribute(color); return node; } - + public static DotNode WithColor(this DotNode node, Color color) { node.Color = new DotColorAttribute(color); return node; } - + public static DotNode WithFillColor(this DotNode node, string color) { node.FillColor = new DotColorAttribute(color); return node; } - + public static DotNode WithFillColor(this DotNode node, Color color) { node.FillColor = new DotColorAttribute(color); return node; } - + public static DotNode WithShape(this DotNode node, string shape) { node.Shape = new DotNodeShapeAttribute(shape); return node; } - + public static DotNode WithShape(this DotNode node, DotNodeShape shape) { node.Shape = new DotNodeShapeAttribute(shape); return node; } + + public static DotNode WithStyle(this DotNode node, string style) + { + node.Style = new DotNodeStyleAttribute(style); + return node; + } + + public static DotNode WithStyle(this DotNode node, DotNodeStyle style) + { + node.Style = new DotNodeStyleAttribute(style); + return node; + } + + public static DotNode WithWidth(this DotNode node, double width) + { + node.Width = new DotDoubleAttribute(width); + return node; + } + + public static DotNode WithHeight(this DotNode node, double height) + { + node.Height = new DotDoubleAttribute(height); + return node; + } + + public static DotNode WithPenWidth(this DotNode node, double width) + { + node.PenWidth = new DotDoubleAttribute(width); + return node; + } + + public static DotNode WithPos(this DotNode node, string value) + { + node.Pos = new DotPointAttribute(value); + return node; + } + + public static DotNode WithPos(this DotNode node, int x, int y, bool @fixed = false) + { + node.Pos = new DotPointAttribute(new DotPoint(x, y, @fixed)); + return node; + } + + public static DotNode WithPos(this DotNode node, int x, int y, int z, bool @fixed = false) + { + node.Pos = new DotPointAttribute(new DotPoint(x, y, z, @fixed)); + return node; + } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/EnumExtensions.cs b/Sources/DotNetGraph/Extensions/EnumExtensions.cs new file mode 100644 index 0000000..0c3ac6f --- /dev/null +++ b/Sources/DotNetGraph/Extensions/EnumExtensions.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace DotNetGraph.Extensions +{ + public static class EnumExtensions + { + public static string FlagsToString(this T enumValue) where T : Enum + { + if (typeof(T).GetCustomAttribute() is null) + throw new InvalidOperationException($"The type '{typeof(T)}' doesn't have the [Flags] attribute specified."); + + return string.Join(",", Enum.GetValues(typeof(T)) + .Cast() + .Where(a => enumValue.HasFlag(a)) + .Select(a => a.ToString().ToLowerInvariant())); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/StringExtensions.cs b/Sources/DotNetGraph/Extensions/StringExtensions.cs index 27d8bb1..c3f2322 100644 --- a/Sources/DotNetGraph/Extensions/StringExtensions.cs +++ b/Sources/DotNetGraph/Extensions/StringExtensions.cs @@ -4,8 +4,7 @@ public static class StringExtensions { internal static string FormatGraphvizEscapedCharacters(this string value) { - return value - .Replace("\\", "\\\\") + return value?.Replace("\\", "\\\\") .Replace("\"", "\\\"") .Replace("\r\n", "\\n") .Replace("\n", "\\n"); From 8ca84d8b138e7d395c3fc069e29112ac9d2dce37 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 29 Jan 2023 14:53:30 +0100 Subject: [PATCH 07/15] WIP --- README.md | 87 +++++++-------- Sources/DotNetGraph.Tests/DotEdgeTests.cs | 46 ++++++++ Sources/DotNetGraph.Tests/DotSubgraphTests.cs | 27 +++++ .../Attributes/DotEdgeArrowTypeAttribute.cs | 26 +++++ .../Attributes/DotEdgeStyleAttribute.cs | 27 +++++ .../Compilation/CompilationContext.cs | 3 + Sources/DotNetGraph/Core/DotEdge.cs | 70 +++++++++++- Sources/DotNetGraph/Core/DotEdgeArrowType.cs | 25 +++++ Sources/DotNetGraph/Core/DotEdgeStyle.cs | 15 +++ Sources/DotNetGraph/Core/DotElement.cs | 2 +- Sources/DotNetGraph/Core/DotGraph.cs | 1 + Sources/DotNetGraph/Core/DotNodeStyle.cs | 3 +- Sources/DotNetGraph/Core/DotSubgraph.cs | 12 +- .../Extensions/DotEdgeExtensions.cs | 105 ++++++++++++++++++ 14 files changed, 400 insertions(+), 49 deletions(-) create mode 100644 Sources/DotNetGraph.Tests/DotEdgeTests.cs create mode 100644 Sources/DotNetGraph.Tests/DotSubgraphTests.cs create mode 100644 Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs create mode 100644 Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs create mode 100644 Sources/DotNetGraph/Core/DotEdgeArrowType.cs create mode 100644 Sources/DotNetGraph/Core/DotEdgeStyle.cs create mode 100644 Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs diff --git a/README.md b/README.md index 007e4e2..a480818 100644 --- a/README.md +++ b/README.md @@ -11,83 +11,82 @@ Compatible with **.NET Standard 2.0** and higher. ## Create a graph (*DotGraph*) ```csharp -var graph = new DotGraph("MyGraph"); +var graph = new DotGraph().WithIdentifier("MyGraph"); -var directedGraph = new DotGraph("MyDirectedGraph", true); +var directedGraph = new DotGraph().WithIdentifier("MyDirectedGraph").Directed(); ``` ## Create and add a node (*DotNode*) ```csharp -var myNode = new DotNode("MyNode") -{ - Shape = DotNodeShape.Ellipse, - Label = "My node!", - FillColor = Color.Coral, - FontColor = Color.Black, - Style = DotNodeStyle.Dotted, - Width = 0.5f, - Height = 0.5f, - PenWidth = 1.5f -}; +var myNode = new DotNode() + .WithIdentifier("MyNode") + .WithShape(DotNodeShape.Ellipse) + .WithLabel("My node!") + .WithFillColor(Color.Coral) + .WithFontColor(Color.Black) + .WithStyle(DotNodeStyle.Dotted) + .WithWidth(0.5) + .WithHeight(0.5) + .WithPenWidth(1.5); // Add the node to the graph -graph.Elements.Add(myNode); +graph.Add(myNode); ``` ## Create and add an edge (*DotEdge*) ```csharp // Create an edge with identifiers -var myEdge = new DotEdge("myNode1", "myNode2"); - -// Create an edge with nodes and attributes -var myEdge = new DotEdge(myNode1, myNode2) -{ - ArrowHead = DotEdgeArrowType.Box, - ArrowTail = DotEdgeArrowType.Diamond, - Color = Color.Red, - FontColor = Color.Black, - Label = "My edge!", - Style = DotEdgeStyle.Dashed, - PenWidth = 1.5f -}; +var myEdge = new DotEdge().From("Node1").To("Node2"); + +// Or with nodes and attributes +var myEdge = new DotEdge() + .From(node1) + .To(node2) + .WithArrowHead(DotEdgeArrowType.Box) + .WithArrowTail(DotEdgeArrowType.Diamond) + .WithColor(Color.Red) + .WithFontColor(Color.Black) + .WithLabel("My edge!") + .WithStyle(DotEdgeStyle.Dashed) + .WithPenWidth(1.5); // Add the edge to the graph -graph.Elements.Add(myEdge); +graph.Add(myEdge); ``` ## Create a subgraph / cluster ```csharp // Subgraph identifier need to start with "cluster" to be identified as a cluster -var mySubGraph = new DotSubGraph("cluster_0"); +var mySubGraph = new DotSubGraph().WithIdentifier("cluster_0"); // Create a subgraph with attributes (only used for cluster) -var mySubGraph = new DotSubGraph("cluster_0") -{ - Color = Color.Red, - Style = DotSubGraphStyle.Dashed, - Label = "My subgraph!" -}; +var mySubGraph = new DotSubGraph() + .WithIdentifier("cluster_0") + .WithColor(Color.Red) + .WithStyle(DotSubGraphStyle.Dashed) + .WithLabel("My subgraph!"); // Add node, edge, subgraph -subGraph.Elements.Add(myNode); -subGraph.Elements.Add(myEdge); -subGraph.Elements.Add(mySubGraph2); +subGraph.Add(myNode); +subGraph.Add(myEdge); +subGraph.Add(mySubGraph2); // Add subgraph to main graph -graph.Elements.Add(mySubGraph); +graph.Add(mySubGraph); ``` ## Compile to DOT format ```csharp -// Non indented version -var dot = graph.Compile(); -// Indented version -var dot = graph.Compile(true); +await using var writer = new StringWriter(); +var context = new CompilationContext(writer, new CompilationOptions()); +await graph.CompileAsync(context); + +var result = writer.GetStringBuilder().ToString(); // Save it to a file -File.WriteAllText("myFile.dot", dot); +File.WriteAllText("graph.dot", result); ``` \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/DotEdgeTests.cs b/Sources/DotNetGraph.Tests/DotEdgeTests.cs new file mode 100644 index 0000000..c02da0c --- /dev/null +++ b/Sources/DotNetGraph.Tests/DotEdgeTests.cs @@ -0,0 +1,46 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests; + +[TestClass] +public class DotEdgeTests +{ + [TestMethod] + public async Task CompileEmptyEdge() + { + var edge = new DotEdge() + .From("A") + .To("B"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await edge.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"A\" -- \"B\"\n"); + } + + [TestMethod] + public async Task CompileEmptyDirectedEdge() + { + var edge = new DotEdge() + .From("A") + .To("B"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()) + { + DirectedGraph = true + }; + await edge.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"A\" -> \"B\"\n"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/DotSubgraphTests.cs b/Sources/DotNetGraph.Tests/DotSubgraphTests.cs new file mode 100644 index 0000000..f14d8ee --- /dev/null +++ b/Sources/DotNetGraph.Tests/DotSubgraphTests.cs @@ -0,0 +1,27 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests; + +[TestClass] +public class DotSubgraphTests +{ + [TestMethod] + public async Task CompileEmptySubgraph() + { + var subgraph = new DotSubgraph() + .WithIdentifier("Test"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await subgraph.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("subgraph \"Test\" {\n}\n"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs new file mode 100644 index 0000000..afd71e0 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; + +namespace DotNetGraph.Attributes +{ + public class DotEdgeArrowTypeAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotEdgeArrowTypeAttribute(string value) + { + Value = value; + } + + public DotEdgeArrowTypeAttribute(DotEdgeArrowType type) + { + Value = type.ToString().ToLowerInvariant(); + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync(Value); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs new file mode 100644 index 0000000..fc3d355 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; + +namespace DotNetGraph.Attributes +{ + public class DotEdgeStyleAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotEdgeStyleAttribute(string value) + { + Value = value; + } + + public DotEdgeStyleAttribute(DotEdgeStyle style) + { + Value = style.FlagsToString(); + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync($"\"{Value}\""); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Compilation/CompilationContext.cs b/Sources/DotNetGraph/Compilation/CompilationContext.cs index 91555f3..88783a1 100644 --- a/Sources/DotNetGraph/Compilation/CompilationContext.cs +++ b/Sources/DotNetGraph/Compilation/CompilationContext.cs @@ -10,12 +10,15 @@ public class CompilationContext public CompilationOptions Options { get; } public int IndentationLevel { get; set; } + + public bool DirectedGraph { get; set; } public CompilationContext(TextWriter textWriter, CompilationOptions options) { TextWriter = textWriter; Options = options; IndentationLevel = 0; + DirectedGraph = false; } public async Task WriteIndentationAsync() diff --git a/Sources/DotNetGraph/Core/DotEdge.cs b/Sources/DotNetGraph/Core/DotEdge.cs index 6112e11..7f13640 100644 --- a/Sources/DotNetGraph/Core/DotEdge.cs +++ b/Sources/DotNetGraph/Core/DotEdge.cs @@ -1,7 +1,75 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; + namespace DotNetGraph.Core { - public class DotEdge + public class DotEdge : DotElement { + public DotIdentifier From { get; set; } + + public DotIdentifier To { get; set; } + + public DotColorAttribute Color + { + get => GetAttributeOrDefault("color"); + set => SetAttribute("color", value); + } + + public DotEdgeStyleAttribute Style + { + get => GetAttributeOrDefault("style"); + set => SetAttribute("style", value); + } + + public DotDoubleAttribute PenWidth + { + get => GetAttribute("penwidth"); + set => SetAttribute("penwidth", value); + } + + public DotEdgeArrowTypeAttribute ArrowHead + { + get => GetAttribute("arrowhead"); + set => SetAttribute("arrowhead", value); + } + + public DotEdgeArrowTypeAttribute ArrowTail + { + get => GetAttribute("arrowtail"); + set => SetAttribute("arrowtail", value); + } + public DotPointAttribute Pos + { + get => GetAttribute("pos"); + set => SetAttribute("pos", value); + } + + public override async Task CompileAsync(CompilationContext context) + { + if (From is null || To is null) + throw new Exception("Can't compile edge with null From and/or To"); + + await context.WriteIndentationAsync(); + await From.CompileAsync(context); + await context.WriteAsync($" {(context.DirectedGraph ? "->" : "--")} "); + await To.CompileAsync(context); + if (Attributes.Any()) + { + await context.WriteLineAsync(" ["); + context.IndentationLevel++; + await CompileAttributesAsync(context); + context.IndentationLevel--; + await context.WriteIndentationAsync(); + await context.WriteLineAsync("]"); + } + else + { + await context.WriteLineAsync(); + } + } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotEdgeArrowType.cs b/Sources/DotNetGraph/Core/DotEdgeArrowType.cs new file mode 100644 index 0000000..a72635c --- /dev/null +++ b/Sources/DotNetGraph/Core/DotEdgeArrowType.cs @@ -0,0 +1,25 @@ +namespace DotNetGraph.Core +{ + public enum DotEdgeArrowType + { + Normal, + Inv, + Dot, + InvDot, + ODot, + InvODot, + None, + Tee, + Empty, + InvEmpty, + Diamond, + ODiamond, + EDiamond, + Crow, + Box, + OBox, + Open, + HalfOpen, + Vee + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotEdgeStyle.cs b/Sources/DotNetGraph/Core/DotEdgeStyle.cs new file mode 100644 index 0000000..f1795cc --- /dev/null +++ b/Sources/DotNetGraph/Core/DotEdgeStyle.cs @@ -0,0 +1,15 @@ +using System; + +namespace DotNetGraph.Core +{ + [Flags] + public enum DotEdgeStyle + { + Solid = 1, + Dashed = 2, + Dotted = 4, + Bold = 8, + Tapered = 16, + Invis = 32 + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotElement.cs b/Sources/DotNetGraph/Core/DotElement.cs index 201f3cf..5694604 100644 --- a/Sources/DotNetGraph/Core/DotElement.cs +++ b/Sources/DotNetGraph/Core/DotElement.cs @@ -105,7 +105,7 @@ public bool RemoveAttribute(string name) return Attributes.Remove(name); } - protected async Task CompileAttributesAsync(CompilationContext context) + public async Task CompileAttributesAsync(CompilationContext context) { foreach (var attributePair in Attributes) { diff --git a/Sources/DotNetGraph/Core/DotGraph.cs b/Sources/DotNetGraph/Core/DotGraph.cs index f848a2c..a6d0fd7 100644 --- a/Sources/DotNetGraph/Core/DotGraph.cs +++ b/Sources/DotNetGraph/Core/DotGraph.cs @@ -11,6 +11,7 @@ public class DotGraph : DotBaseGraph public override async Task CompileAsync(CompilationContext context) { + context.DirectedGraph = Directed; await context.WriteIndentationAsync(); if (Strict) await context.WriteAsync("strict "); diff --git a/Sources/DotNetGraph/Core/DotNodeStyle.cs b/Sources/DotNetGraph/Core/DotNodeStyle.cs index ba29764..e45e4be 100644 --- a/Sources/DotNetGraph/Core/DotNodeStyle.cs +++ b/Sources/DotNetGraph/Core/DotNodeStyle.cs @@ -13,6 +13,7 @@ public enum DotNodeStyle Diagonals = 32, Filled = 64, Striped = 128, - Wedged = 256 + Wedged = 256, + Invis = 512 } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotSubgraph.cs b/Sources/DotNetGraph/Core/DotSubgraph.cs index 4fc9988..aecc384 100644 --- a/Sources/DotNetGraph/Core/DotSubgraph.cs +++ b/Sources/DotNetGraph/Core/DotSubgraph.cs @@ -5,9 +5,17 @@ namespace DotNetGraph.Core { public class DotSubgraph : DotBaseGraph { - public override Task CompileAsync(CompilationContext context) + public override async Task CompileAsync(CompilationContext context) { - throw new System.NotImplementedException(); + await context.WriteIndentationAsync(); + await context.WriteAsync("subgraph "); + await Identifier.CompileAsync(context); + await context.WriteLineAsync(" {"); + context.IndentationLevel++; + await CompileAttributesAsync(context); + context.IndentationLevel--; + await context.WriteIndentationAsync(); + await context.WriteLineAsync("}"); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs b/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs new file mode 100644 index 0000000..1125d38 --- /dev/null +++ b/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs @@ -0,0 +1,105 @@ +using System.Drawing; +using DotNetGraph.Attributes; +using DotNetGraph.Core; + +namespace DotNetGraph.Extensions +{ + public static class DotEdgeExtensions + { + public static DotEdge From(this DotEdge edge, string from, bool isHtml = false) + { + edge.From = new DotIdentifier(from, isHtml); + return edge; + } + + public static DotEdge From(this DotEdge edge, DotNode from) + { + edge.From = from.Identifier; + return edge; + } + + public static DotEdge To(this DotEdge edge, string to, bool isHtml = false) + { + edge.To = new DotIdentifier(to, isHtml); + return edge; + } + + public static DotEdge To(this DotEdge edge, DotNode to) + { + edge.To = to.Identifier; + return edge; + } + + public static DotEdge WithColor(this DotEdge edge, string color) + { + edge.Color = new DotColorAttribute(color); + return edge; + } + + public static DotEdge WithColor(this DotEdge edge, Color color) + { + edge.Color = new DotColorAttribute(color); + return edge; + } + + public static DotEdge WithStyle(this DotEdge edge, string style) + { + edge.Style = new DotEdgeStyleAttribute(style); + return edge; + } + + public static DotEdge WithStyle(this DotEdge edge, DotEdgeStyle style) + { + edge.Style = new DotEdgeStyleAttribute(style); + return edge; + } + + public static DotNode WithPenWidth(this DotNode node, double width) + { + node.PenWidth = new DotDoubleAttribute(width); + return node; + } + + public static DotEdge WithArrowHead(this DotEdge edge, string arrowType) + { + edge.ArrowHead = new DotEdgeArrowTypeAttribute(arrowType); + return edge; + } + + public static DotEdge WithArrowHead(this DotEdge edge, DotEdgeArrowType arrowType) + { + edge.ArrowHead = new DotEdgeArrowTypeAttribute(arrowType); + return edge; + } + + public static DotEdge WithArrowTail(this DotEdge edge, string arrowType) + { + edge.ArrowTail = new DotEdgeArrowTypeAttribute(arrowType); + return edge; + } + + public static DotEdge WithArrowTail(this DotEdge edge, DotEdgeArrowType arrowType) + { + edge.ArrowTail = new DotEdgeArrowTypeAttribute(arrowType); + return edge; + } + + public static DotEdge WithPos(this DotEdge edge, string value) + { + edge.Pos = new DotPointAttribute(value); + return edge; + } + + public static DotEdge WithPos(this DotEdge edge, int x, int y, bool @fixed = false) + { + edge.Pos = new DotPointAttribute(new DotPoint(x, y, @fixed)); + return edge; + } + + public static DotEdge WithPos(this DotEdge edge, int x, int y, int z, bool @fixed = false) + { + edge.Pos = new DotPointAttribute(new DotPoint(x, y, z, @fixed)); + return edge; + } + } +} \ No newline at end of file From 79e4e8ff8c655cae71435eac087b5c0e5df25d3a Mon Sep 17 00:00:00 2001 From: Valentin Date: Sun, 29 Jan 2023 15:02:00 +0100 Subject: [PATCH 08/15] WIP --- .../Attributes/DotSubgraphStyleAttribute.cs | 27 +++++++++++++++ Sources/DotNetGraph/Core/DotSubgraph.cs | 13 ++++++++ Sources/DotNetGraph/Core/DotSubgraphStyle.cs | 17 ++++++++++ .../Extensions/DotSubgraphExtensions.cs | 33 +++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs create mode 100644 Sources/DotNetGraph/Core/DotSubgraphStyle.cs create mode 100644 Sources/DotNetGraph/Extensions/DotSubgraphExtensions.cs diff --git a/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs new file mode 100644 index 0000000..f435a24 --- /dev/null +++ b/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using DotNetGraph.Extensions; + +namespace DotNetGraph.Attributes +{ + public class DotSubgraphStyleAttribute : IDotAttribute + { + public string Value { get; set; } + + public DotSubgraphStyleAttribute(string value) + { + Value = value; + } + + public DotSubgraphStyleAttribute(DotSubgraphStyle style) + { + Value = style.FlagsToString(); + } + + public async Task CompileAsync(CompilationContext context) + { + await context.WriteAsync($"\"{Value}\""); + } + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotSubgraph.cs b/Sources/DotNetGraph/Core/DotSubgraph.cs index aecc384..81add85 100644 --- a/Sources/DotNetGraph/Core/DotSubgraph.cs +++ b/Sources/DotNetGraph/Core/DotSubgraph.cs @@ -1,10 +1,23 @@ using System.Threading.Tasks; +using DotNetGraph.Attributes; using DotNetGraph.Compilation; namespace DotNetGraph.Core { public class DotSubgraph : DotBaseGraph { + public DotColorAttribute Color + { + get => GetAttributeOrDefault("color"); + set => SetAttribute("color", value); + } + + public DotSubgraphStyleAttribute Style + { + get => GetAttributeOrDefault("style"); + set => SetAttribute("style", value); + } + public override async Task CompileAsync(CompilationContext context) { await context.WriteIndentationAsync(); diff --git a/Sources/DotNetGraph/Core/DotSubgraphStyle.cs b/Sources/DotNetGraph/Core/DotSubgraphStyle.cs new file mode 100644 index 0000000..03bd885 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotSubgraphStyle.cs @@ -0,0 +1,17 @@ +using System; + +namespace DotNetGraph.Core +{ + [Flags] + public enum DotSubgraphStyle + { + Solid = 1, + Dashed = 2, + Dotted = 4, + Bold = 8, + Rounded = 16, + Filled = 32, + Striped = 64, + Invis = 128 + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Extensions/DotSubgraphExtensions.cs b/Sources/DotNetGraph/Extensions/DotSubgraphExtensions.cs new file mode 100644 index 0000000..e0f33e0 --- /dev/null +++ b/Sources/DotNetGraph/Extensions/DotSubgraphExtensions.cs @@ -0,0 +1,33 @@ +using System.Drawing; +using DotNetGraph.Attributes; +using DotNetGraph.Core; + +namespace DotNetGraph.Extensions +{ + public static class DotSubgraphExtensions + { + public static DotSubgraph WithColor(this DotSubgraph subgraph, string color) + { + subgraph.Color = new DotColorAttribute(color); + return subgraph; + } + + public static DotSubgraph WithColor(this DotSubgraph subgraph, Color color) + { + subgraph.Color = new DotColorAttribute(color); + return subgraph; + } + + public static DotSubgraph WithStyle(this DotSubgraph subgraph, string style) + { + subgraph.Style = new DotSubgraphStyleAttribute(style); + return subgraph; + } + + public static DotSubgraph WithStyle(this DotSubgraph subgraph, DotSubgraphStyle style) + { + subgraph.Style = new DotSubgraphStyleAttribute(style); + return subgraph; + } + } +} \ No newline at end of file From 1349bb787b3fc5d7efee7da2b86566538e01bbc4 Mon Sep 17 00:00:00 2001 From: Valentin Date: Mon, 30 Jan 2023 22:15:06 +0100 Subject: [PATCH 09/15] WIP --- .../Attributes/DotColorAttributeTests.cs | 39 ++++ .../Attributes/DotDoubleAttributeTests.cs | 38 ++++ .../DotEdgeArrowTypeAttributeTests.cs | 39 ++++ .../Attributes/DotEdgeStyleAttributeTests.cs | 39 ++++ .../Attributes/DotLabelAttributeTests.cs | 54 +++++ .../Attributes/DotNodeShapeAttributeTests.cs | 39 ++++ .../Attributes/DotNodeStyleAttributeTests.cs | 39 ++++ .../Attributes/DotPointAttributeTests.cs | 40 ++++ .../DotSubgraphStyleAttributeTests.cs | 39 ++++ .../{ => Core}/DotEdgeTests.cs | 2 +- .../{ => Core}/DotGraphTests.cs | 2 +- .../{ => Core}/DotNodeTests.cs | 2 +- .../{ => Core}/DotSubgraphTests.cs | 2 +- .../Extensions/ColorExtensionsTests.cs | 30 +++ .../Extensions/DotBaseGraphExtensionsTests.cs | 41 ++++ .../Extensions/DotEdgeExtensionsTests.cs | 211 ++++++++++++++++++ .../Extensions/DotElementExtensionsTests.cs | 60 +++++ .../Attributes/DotDoubleAttribute.cs | 3 +- .../Attributes/DotEdgeArrowTypeAttribute.cs | 2 +- .../Attributes/DotLabelAttribute.cs | 5 +- .../Extensions/DotEdgeExtensions.cs | 6 +- 21 files changed, 722 insertions(+), 10 deletions(-) create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs rename Sources/DotNetGraph.Tests/{ => Core}/DotEdgeTests.cs (97%) rename Sources/DotNetGraph.Tests/{ => Core}/DotGraphTests.cs (97%) rename Sources/DotNetGraph.Tests/{ => Core}/DotNodeTests.cs (97%) rename Sources/DotNetGraph.Tests/{ => Core}/DotSubgraphTests.cs (95%) create mode 100644 Sources/DotNetGraph.Tests/Extensions/ColorExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/DotEdgeExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/DotElementExtensionsTests.cs diff --git a/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs new file mode 100644 index 0000000..c307f1e --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs @@ -0,0 +1,39 @@ +using System.Drawing; +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotColorAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotColorAttribute("red"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"red\""); + } + + [TestMethod] + public async Task RenderFromColor() + { + var attribute = new DotColorAttribute(Color.Red); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"#FF0000\""); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs new file mode 100644 index 0000000..98e074d --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs @@ -0,0 +1,38 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotDoubleAttributeTests +{ + [TestMethod] + public async Task RenderWithDefaultFormat() + { + var attribute = new DotDoubleAttribute(123.456); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("123.46"); + } + + [TestMethod] + public async Task RenderWithSpecifiedFormat() + { + var attribute = new DotDoubleAttribute(123.456, "F3"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("123.456"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs new file mode 100644 index 0000000..0e1c1f6 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotEdgeArrowTypeAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotEdgeArrowTypeAttribute("custom"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"custom\""); + } + + [TestMethod] + public async Task RenderFromEnum() + { + var attribute = new DotEdgeArrowTypeAttribute(DotEdgeArrowType.Box); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"box\""); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs new file mode 100644 index 0000000..008e7b0 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotEdgeStyleAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotEdgeStyleAttribute("custom"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"custom\""); + } + + [TestMethod] + public async Task RenderFromEnum() + { + var attribute = new DotEdgeStyleAttribute(DotEdgeStyle.Solid); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"solid\""); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs new file mode 100644 index 0000000..d01d5e8 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs @@ -0,0 +1,54 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotLabelAttributeTests +{ + [TestMethod] + public async Task RenderDefault() + { + var attribute = new DotLabelAttribute("Hello,\r\n \"world\"!"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"Hello,\\n \\\"world\\\"!\""); + } + + [TestMethod] + public async Task RenderWithoutAutomaticEscapedCharactersFormat() + { + var attribute = new DotLabelAttribute("Hello,\r\n \"world\"!"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions + { + AutomaticEscapedCharactersFormat = false + }); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"Hello,\r\n \"world\"!\""); + } + + [TestMethod] + public async Task RenderHtml() + { + var attribute = new DotLabelAttribute("Hello, world!", true); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("<Hello, world!>"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs new file mode 100644 index 0000000..f31f710 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotNodeShapeAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotNodeShapeAttribute("custom"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"custom\""); + } + + [TestMethod] + public async Task RenderFromEnum() + { + var attribute = new DotNodeShapeAttribute(DotNodeShape.Terminator); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"terminator\""); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs new file mode 100644 index 0000000..5ba96be --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotNodeStyleAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotNodeStyleAttribute("custom"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"custom\""); + } + + [TestMethod] + public async Task RenderFromEnum() + { + var attribute = new DotNodeStyleAttribute(DotNodeStyle.Bold); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"bold\""); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs new file mode 100644 index 0000000..277c90e --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs @@ -0,0 +1,40 @@ +using System.Drawing; +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotPointAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotPointAttribute("66,99"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("66,99"); + } + + [TestMethod] + public async Task RenderFromDotPoint() + { + var attribute = new DotPointAttribute(new DotPoint(42, 69, 75, true)); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("42,69,75!"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs new file mode 100644 index 0000000..bba49aa --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs @@ -0,0 +1,39 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotSubgraphStyleAttributeTests +{ + [TestMethod] + public async Task RenderFromString() + { + var attribute = new DotSubgraphStyleAttribute("custom"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"custom\""); + } + + [TestMethod] + public async Task RenderFromEnum() + { + var attribute = new DotSubgraphStyleAttribute(DotSubgraphStyle.Rounded); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"rounded\""); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/DotEdgeTests.cs b/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs similarity index 97% rename from Sources/DotNetGraph.Tests/DotEdgeTests.cs rename to Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs index c02da0c..856aeb8 100644 --- a/Sources/DotNetGraph.Tests/DotEdgeTests.cs +++ b/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs @@ -6,7 +6,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace DotNetGraph.Tests; +namespace DotNetGraph.Tests.Core; [TestClass] public class DotEdgeTests diff --git a/Sources/DotNetGraph.Tests/DotGraphTests.cs b/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs similarity index 97% rename from Sources/DotNetGraph.Tests/DotGraphTests.cs rename to Sources/DotNetGraph.Tests/Core/DotGraphTests.cs index 0cdf6ab..6a535cd 100644 --- a/Sources/DotNetGraph.Tests/DotGraphTests.cs +++ b/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs @@ -6,7 +6,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace DotNetGraph.Tests; +namespace DotNetGraph.Tests.Core; [TestClass] public class DotGraphTests diff --git a/Sources/DotNetGraph.Tests/DotNodeTests.cs b/Sources/DotNetGraph.Tests/Core/DotNodeTests.cs similarity index 97% rename from Sources/DotNetGraph.Tests/DotNodeTests.cs rename to Sources/DotNetGraph.Tests/Core/DotNodeTests.cs index e05c65c..6a4bfec 100644 --- a/Sources/DotNetGraph.Tests/DotNodeTests.cs +++ b/Sources/DotNetGraph.Tests/Core/DotNodeTests.cs @@ -7,7 +7,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace DotNetGraph.Tests; +namespace DotNetGraph.Tests.Core; [TestClass] public class DotNodeTests diff --git a/Sources/DotNetGraph.Tests/DotSubgraphTests.cs b/Sources/DotNetGraph.Tests/Core/DotSubgraphTests.cs similarity index 95% rename from Sources/DotNetGraph.Tests/DotSubgraphTests.cs rename to Sources/DotNetGraph.Tests/Core/DotSubgraphTests.cs index f14d8ee..707e68b 100644 --- a/Sources/DotNetGraph.Tests/DotSubgraphTests.cs +++ b/Sources/DotNetGraph.Tests/Core/DotSubgraphTests.cs @@ -6,7 +6,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace DotNetGraph.Tests; +namespace DotNetGraph.Tests.Core; [TestClass] public class DotSubgraphTests diff --git a/Sources/DotNetGraph.Tests/Extensions/ColorExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/ColorExtensionsTests.cs new file mode 100644 index 0000000..45b9a1b --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/ColorExtensionsTests.cs @@ -0,0 +1,30 @@ +using System.Drawing; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class ColorExtensionsTests +{ + [TestMethod] + public void ToHexStringRgb() + { + var color = Color.FromArgb(123, 123, 255); + + var hex = color.ToHexString(); + + hex.Should().Be("#7B7BFF"); + } + + [TestMethod] + public void ToHexStringRgba() + { + var color = Color.FromArgb(123, 123, 123, 255); + + var hex = color.ToHexString(); + + hex.Should().Be("#7B7BFF7B"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs new file mode 100644 index 0000000..e02e43f --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs @@ -0,0 +1,41 @@ +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class DotBaseGraphExtensionsTests +{ + [TestMethod] + public void WithIdentifier() + { + var graph = new DotGraph() + .WithIdentifier("Test"); + + graph.Identifier.Value.Should().Be("Test"); + graph.Identifier.IsHtml.Should().Be(false); + } + + [TestMethod] + public void WithIdentifierHtml() + { + var graph = new DotGraph() + .WithIdentifier("Test", true); + + graph.Identifier.Value.Should().Be("Test"); + graph.Identifier.IsHtml.Should().Be(true); + } + + [TestMethod] + public void Add() + { + var node = new DotNode(); + + var graph = new DotGraph() + .Add(node); + + graph.Elements.Should().Contain(node); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotEdgeExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotEdgeExtensionsTests.cs new file mode 100644 index 0000000..b787a06 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/DotEdgeExtensionsTests.cs @@ -0,0 +1,211 @@ +using System.Drawing; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class DotEdgeExtensionsTests +{ + [TestMethod] + public void FromStringDefault() + { + var edge = new DotEdge() + .From("a"); + + edge.From.Value.Should().Be("a"); + edge.From.IsHtml.Should().Be(false); + } + + [TestMethod] + public void FromStringHtml() + { + var edge = new DotEdge() + .From("a", true); + + edge.From.Value.Should().Be("a"); + edge.From.IsHtml.Should().Be(true); + } + + [TestMethod] + public void FromNode() + { + var node = new DotNode() + .WithIdentifier("a"); + + var edge = new DotEdge() + .From(node); + + edge.From.Value.Should().Be("a"); + edge.From.IsHtml.Should().Be(false); + } + + [TestMethod] + public void FromNodeHtml() + { + var node = new DotNode() + .WithIdentifier("a", true); + + var edge = new DotEdge() + .From(node); + + edge.From.Value.Should().Be("a"); + edge.From.IsHtml.Should().Be(true); + } + + [TestMethod] + public void ToStringDefault() + { + var edge = new DotEdge() + .To("a"); + + edge.To.Value.Should().Be("a"); + edge.To.IsHtml.Should().Be(false); + } + + [TestMethod] + public void ToStringHtml() + { + var edge = new DotEdge() + .To("a", true); + + edge.To.Value.Should().Be("a"); + edge.To.IsHtml.Should().Be(true); + } + + [TestMethod] + public void ToNode() + { + var node = new DotNode() + .WithIdentifier("a"); + + var edge = new DotEdge() + .To(node); + + edge.To.Value.Should().Be("a"); + edge.To.IsHtml.Should().Be(false); + } + + [TestMethod] + public void ToNodeHtml() + { + var node = new DotNode() + .WithIdentifier("a", true); + + var edge = new DotEdge() + .To(node); + + edge.To.Value.Should().Be("a"); + edge.To.IsHtml.Should().Be(true); + } + + [TestMethod] + public void WithColorString() + { + var edge = new DotEdge() + .WithColor("red"); + + edge.Color.Value.Should().Be("red"); + } + + [TestMethod] + public void WithColor() + { + var edge = new DotEdge() + .WithColor(Color.Red); + + edge.Color.Value.Should().Be("#FF0000"); + } + + [TestMethod] + public void WithStyleString() + { + var edge = new DotEdge() + .WithStyle("custom"); + + edge.Style.Value.Should().Be("custom"); + } + + [TestMethod] + public void WithStyle() + { + var edge = new DotEdge() + .WithStyle(DotEdgeStyle.Dashed); + + edge.Style.Value.Should().Be("dashed"); + } + + [TestMethod] + public void WithPenWidth() + { + var edge = new DotEdge() + .WithPenWidth(123.456); + + edge.PenWidth.Value.Should().Be(123.456); + } + + [TestMethod] + public void WithArrowHeadString() + { + var edge = new DotEdge() + .WithArrowHead("custom"); + + edge.ArrowHead.Value.Should().Be("custom"); + } + + [TestMethod] + public void WithArrowHead() + { + var edge = new DotEdge() + .WithArrowHead(DotEdgeArrowType.Diamond); + + edge.ArrowHead.Value.Should().Be("diamond"); + } + + [TestMethod] + public void WithArrowTailString() + { + var edge = new DotEdge() + .WithArrowTail("custom"); + + edge.ArrowTail.Value.Should().Be("custom"); + } + + [TestMethod] + public void WithArrowTail() + { + var edge = new DotEdge() + .WithArrowTail(DotEdgeArrowType.Diamond); + + edge.ArrowTail.Value.Should().Be("diamond"); + } + + [TestMethod] + public void WithPosString() + { + var edge = new DotEdge() + .WithPos("42,69"); + + edge.Pos.Value.Should().Be("42,69"); + } + + [TestMethod] + public void WithPos2D() + { + var edge = new DotEdge() + .WithPos(42, 69); + + edge.Pos.Value.Should().Be("42,69"); + } + + [TestMethod] + public void WithPos3D() + { + var edge = new DotEdge() + .WithPos(42, 69, 75); + + edge.Pos.Value.Should().Be("42,69,75"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotElementExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotElementExtensionsTests.cs new file mode 100644 index 0000000..da4e3cf --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/DotElementExtensionsTests.cs @@ -0,0 +1,60 @@ +using System.Drawing; +using DotNetGraph.Attributes; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class DotElementExtensionsTests +{ + [TestMethod] + public void WithLabel() + { + var node = new DotNode() + .WithLabel("Test"); + + node.Label.Value.Should().Be("Test"); + node.Label.IsHtml.Should().Be(false); + } + + [TestMethod] + public void WithAttributeString() + { + var node = new DotNode() + .WithAttribute("hello", "world"); + + var attribute = node.GetAttribute("hello") as DotAttribute; + attribute?.Value.Should().Be("world"); + } + + [TestMethod] + public void WithAttribute() + { + var node = new DotNode() + .WithAttribute("hello", new DotAttribute("world")); + + var attribute = node.GetAttribute("hello") as DotAttribute; + attribute?.Value.Should().Be("world"); + } + + [TestMethod] + public void WithFontColorString() + { + var node = new DotNode() + .WithFontColor("red"); + + node.FontColor.Value.Should().Be("red"); + } + + [TestMethod] + public void WithFontColor() + { + var node = new DotNode() + .WithFontColor(Color.Red); + + node.FontColor.Value.Should().Be("#FF0000"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs b/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs index aaccdc2..c64f7b8 100644 --- a/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Threading.Tasks; using DotNetGraph.Compilation; @@ -17,7 +18,7 @@ public DotDoubleAttribute(double value, string format = "F2") public async Task CompileAsync(CompilationContext context) { - await context.WriteAsync(Value.ToString(Format)); + await context.WriteAsync(Value.ToString(Format, NumberFormatInfo.InvariantInfo)); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs index afd71e0..514dc97 100644 --- a/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs @@ -20,7 +20,7 @@ public DotEdgeArrowTypeAttribute(DotEdgeArrowType type) public async Task CompileAsync(CompilationContext context) { - await context.WriteAsync(Value); + await context.WriteAsync($"\"{Value}\""); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs index 9f8207f..3747853 100644 --- a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs @@ -19,8 +19,11 @@ public DotLabelAttribute(string value, bool isHtml = false) public async Task CompileAsync(CompilationContext context) { if (IsHtml) + { await context.TextWriter.WriteAsync($"<{Value}>"); - + return; + } + var value = context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; await context.TextWriter.WriteAsync($"\"{value}\""); } diff --git a/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs b/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs index 1125d38..3a0a999 100644 --- a/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs +++ b/Sources/DotNetGraph/Extensions/DotEdgeExtensions.cs @@ -54,10 +54,10 @@ public static DotEdge WithStyle(this DotEdge edge, DotEdgeStyle style) return edge; } - public static DotNode WithPenWidth(this DotNode node, double width) + public static DotEdge WithPenWidth(this DotEdge edge, double width) { - node.PenWidth = new DotDoubleAttribute(width); - return node; + edge.PenWidth = new DotDoubleAttribute(width); + return edge; } public static DotEdge WithArrowHead(this DotEdge edge, string arrowType) From d8c7a00b58434a9cc51b752a7846b01c7266aa5d Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 31 Jan 2023 18:49:36 +0100 Subject: [PATCH 10/15] Add tests --- .../Attributes/DotAttributeTests.cs | 25 +++ .../Attributes/DotColorAttributeTests.cs | 4 +- .../Attributes/DotDoubleAttributeTests.cs | 4 +- .../DotEdgeArrowTypeAttributeTests.cs | 4 +- .../Attributes/DotEdgeStyleAttributeTests.cs | 4 +- .../Attributes/DotLabelAttributeTests.cs | 6 +- .../Attributes/DotNodeShapeAttributeTests.cs | 4 +- .../Attributes/DotNodeStyleAttributeTests.cs | 4 +- .../Attributes/DotPointAttributeTests.cs | 4 +- .../DotSubgraphStyleAttributeTests.cs | 4 +- .../Compilation/CompilationContextTests.cs | 87 ++++++++++ .../Core/DotIdentifierTests.cs | 38 +++++ .../Extensions/DotGraphExtensionsTests.cs | 28 ++++ .../Extensions/DotNodeExtensionsTests.cs | 157 ++++++++++++++++++ .../Extensions/DotSubgraphExtensionsTests.cs | 48 ++++++ .../Extensions/EnumExtensionsTests.cs | 65 ++++++++ .../Extensions/StringExtensionsTests.cs | 22 +++ Sources/DotNetGraph/Core/DotIdentifier.cs | 3 + 18 files changed, 492 insertions(+), 19 deletions(-) create mode 100644 Sources/DotNetGraph.Tests/Attributes/DotAttributeTests.cs create mode 100644 Sources/DotNetGraph.Tests/Compilation/CompilationContextTests.cs create mode 100644 Sources/DotNetGraph.Tests/Core/DotIdentifierTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/DotNodeExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/DotSubgraphExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs create mode 100644 Sources/DotNetGraph.Tests/Extensions/StringExtensionsTests.cs diff --git a/Sources/DotNetGraph.Tests/Attributes/DotAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotAttributeTests.cs new file mode 100644 index 0000000..0719c0d --- /dev/null +++ b/Sources/DotNetGraph.Tests/Attributes/DotAttributeTests.cs @@ -0,0 +1,25 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Attributes; +using DotNetGraph.Compilation; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Attributes; + +[TestClass] +public class DotAttributeTests +{ + [TestMethod] + public async Task Compile() + { + var attribute = new DotAttribute("testing"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await attribute.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("testing"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs index c307f1e..6642539 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs @@ -12,7 +12,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotColorAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotColorAttribute("red"); @@ -25,7 +25,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromColor() + public async Task CompileFromColor() { var attribute = new DotColorAttribute(Color.Red); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs index 98e074d..3064007 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs @@ -11,7 +11,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotDoubleAttributeTests { [TestMethod] - public async Task RenderWithDefaultFormat() + public async Task CompileWithDefaultFormat() { var attribute = new DotDoubleAttribute(123.456); @@ -24,7 +24,7 @@ public async Task RenderWithDefaultFormat() } [TestMethod] - public async Task RenderWithSpecifiedFormat() + public async Task CompileWithSpecifiedFormat() { var attribute = new DotDoubleAttribute(123.456, "F3"); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs index 0e1c1f6..29ef120 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs @@ -12,7 +12,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotEdgeArrowTypeAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotEdgeArrowTypeAttribute("custom"); @@ -25,7 +25,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromEnum() + public async Task CompileFromEnum() { var attribute = new DotEdgeArrowTypeAttribute(DotEdgeArrowType.Box); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs index 008e7b0..c6fb332 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs @@ -12,7 +12,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotEdgeStyleAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotEdgeStyleAttribute("custom"); @@ -25,7 +25,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromEnum() + public async Task CompileFromEnum() { var attribute = new DotEdgeStyleAttribute(DotEdgeStyle.Solid); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs index d01d5e8..4251288 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs @@ -11,7 +11,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotLabelAttributeTests { [TestMethod] - public async Task RenderDefault() + public async Task CompileDefault() { var attribute = new DotLabelAttribute("Hello,\r\n \"world\"!"); @@ -24,7 +24,7 @@ public async Task RenderDefault() } [TestMethod] - public async Task RenderWithoutAutomaticEscapedCharactersFormat() + public async Task CompileWithoutAutomaticEscapedCharactersFormat() { var attribute = new DotLabelAttribute("Hello,\r\n \"world\"!"); @@ -40,7 +40,7 @@ public async Task RenderWithoutAutomaticEscapedCharactersFormat() } [TestMethod] - public async Task RenderHtml() + public async Task CompileHtml() { var attribute = new DotLabelAttribute("Hello, world!", true); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs index f31f710..4630146 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs @@ -12,7 +12,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotNodeShapeAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotNodeShapeAttribute("custom"); @@ -25,7 +25,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromEnum() + public async Task CompileFromEnum() { var attribute = new DotNodeShapeAttribute(DotNodeShape.Terminator); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs index 5ba96be..6645903 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs @@ -12,7 +12,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotNodeStyleAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotNodeStyleAttribute("custom"); @@ -25,7 +25,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromEnum() + public async Task CompileFromEnum() { var attribute = new DotNodeStyleAttribute(DotNodeStyle.Bold); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs index 277c90e..78ca2d9 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs @@ -13,7 +13,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotPointAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotPointAttribute("66,99"); @@ -26,7 +26,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromDotPoint() + public async Task CompileFromDotPoint() { var attribute = new DotPointAttribute(new DotPoint(42, 69, 75, true)); diff --git a/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs index bba49aa..81c2558 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs @@ -12,7 +12,7 @@ namespace DotNetGraph.Tests.Attributes; public class DotSubgraphStyleAttributeTests { [TestMethod] - public async Task RenderFromString() + public async Task CompileFromString() { var attribute = new DotSubgraphStyleAttribute("custom"); @@ -25,7 +25,7 @@ public async Task RenderFromString() } [TestMethod] - public async Task RenderFromEnum() + public async Task CompileFromEnum() { var attribute = new DotSubgraphStyleAttribute(DotSubgraphStyle.Rounded); diff --git a/Sources/DotNetGraph.Tests/Compilation/CompilationContextTests.cs b/Sources/DotNetGraph.Tests/Compilation/CompilationContextTests.cs new file mode 100644 index 0000000..5159974 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Compilation/CompilationContextTests.cs @@ -0,0 +1,87 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Compilation; + +[TestClass] +public class CompilationContextTests +{ + [TestMethod] + public async Task WriteIndentationAsyncIndentedLevel3() + { + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions + { + Indented = true + }) + { + IndentationLevel = 3 + }; + await context.WriteIndentationAsync(); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\t\t\t"); + } + + [TestMethod] + public async Task WriteIndentationAsyncNonIndentedLevel3() + { + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions + { + Indented = false + }) + { + IndentationLevel = 3 + }; + await context.WriteIndentationAsync(); + + var result = writer.GetStringBuilder().ToString(); + result.Should().BeEmpty(); + } + + [TestMethod] + public async Task WriteAsync() + { + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + + await context.WriteAsync("Hello, world!"); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("Hello, world!"); + } + + [TestMethod] + public async Task WriteLineAsyncIndented() + { + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions + { + Indented = true + }); + + await context.WriteLineAsync("Hello, world!"); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("Hello, world!\n"); + } + + [TestMethod] + public async Task WriteLineAsyncNonIndented() + { + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions + { + Indented = false + }); + + await context.WriteLineAsync("Hello, world!"); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("Hello, world! "); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Core/DotIdentifierTests.cs b/Sources/DotNetGraph.Tests/Core/DotIdentifierTests.cs new file mode 100644 index 0000000..8c756ef --- /dev/null +++ b/Sources/DotNetGraph.Tests/Core/DotIdentifierTests.cs @@ -0,0 +1,38 @@ +using System.IO; +using System.Threading.Tasks; +using DotNetGraph.Compilation; +using DotNetGraph.Core; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Core; + +[TestClass] +public class DotIdentifierTests +{ + [TestMethod] + public async Task Compile() + { + var identifier = new DotIdentifier("Test"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await identifier.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"Test\""); + } + + [TestMethod] + public async Task CompileHtml() + { + var identifier = new DotIdentifier("Test", true); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await identifier.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("<Test>"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs new file mode 100644 index 0000000..f54570c --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs @@ -0,0 +1,28 @@ +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class DotGraphExtensionsTests +{ + [TestMethod] + public void Directed() + { + var graph = new DotGraph() + .Directed(); + + graph.Directed.Should().Be(true); + } + + [TestMethod] + public void Strict() + { + var graph = new DotGraph() + .Strict(); + + graph.Strict.Should().Be(true); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotNodeExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotNodeExtensionsTests.cs new file mode 100644 index 0000000..bdb5b1c --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/DotNodeExtensionsTests.cs @@ -0,0 +1,157 @@ +using System.Drawing; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class DotNodeExtensionsTests +{ + [TestMethod] + public void WithIdentifier() + { + var node = new DotNode() + .WithIdentifier("Test"); + + node.Identifier.Value.Should().Be("Test"); + node.Identifier.IsHtml.Should().Be(false); + } + + [TestMethod] + public void WithIdentifierHtml() + { + var node = new DotNode() + .WithIdentifier("Test", true); + + node.Identifier.Value.Should().Be("Test"); + node.Identifier.IsHtml.Should().Be(true); + } + + [TestMethod] + public void WithColorString() + { + var node = new DotNode() + .WithColor("red"); + + node.Color.Value.Should().Be("red"); + } + + [TestMethod] + public void WithColor() + { + var node = new DotNode() + .WithColor(Color.Red); + + node.Color.Value.Should().Be("#FF0000"); + } + + [TestMethod] + public void WithFillColorString() + { + var node = new DotNode() + .WithFillColor("red"); + + node.FillColor.Value.Should().Be("red"); + } + + [TestMethod] + public void WithFillColor() + { + var node = new DotNode() + .WithFillColor(Color.Red); + + node.FillColor.Value.Should().Be("#FF0000"); + } + + [TestMethod] + public void WithShapeString() + { + var node = new DotNode() + .WithShape("custom"); + + node.Shape.Value.Should().Be("custom"); + } + + [TestMethod] + public void WithShape() + { + var node = new DotNode() + .WithShape(DotNodeShape.Diamond); + + node.Shape.Value.Should().Be("diamond"); + } + + [TestMethod] + public void WithStyleString() + { + var node = new DotNode() + .WithStyle("custom"); + + node.Style.Value.Should().Be("custom"); + } + + [TestMethod] + public void WithStyle() + { + var node = new DotNode() + .WithStyle(DotNodeStyle.Diagonals); + + node.Style.Value.Should().Be("diagonals"); + } + + [TestMethod] + public void WithWidth() + { + var node = new DotNode() + .WithWidth(123.456); + + node.Width.Value.Should().Be(123.456); + } + + [TestMethod] + public void WithHeight() + { + var node = new DotNode() + .WithHeight(123.456); + + node.Height.Value.Should().Be(123.456); + } + + [TestMethod] + public void WithPenWidth() + { + var node = new DotNode() + .WithPenWidth(123.456); + + node.PenWidth.Value.Should().Be(123.456); + } + + [TestMethod] + public void WithPosString() + { + var node = new DotNode() + .WithPos("42,69"); + + node.Pos.Value.Should().Be("42,69"); + } + + [TestMethod] + public void WithPos2D() + { + var node = new DotNode() + .WithPos(42, 69); + + node.Pos.Value.Should().Be("42,69"); + } + + [TestMethod] + public void WithPos3D() + { + var node = new DotNode() + .WithPos(42, 69, 75); + + node.Pos.Value.Should().Be("42,69,75"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotSubgraphExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotSubgraphExtensionsTests.cs new file mode 100644 index 0000000..eed343e --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/DotSubgraphExtensionsTests.cs @@ -0,0 +1,48 @@ +using System.Drawing; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class DotSubgraphExtensionsTests +{ + [TestMethod] + public void WithColorString() + { + var subgraph = new DotSubgraph() + .WithColor("red"); + + subgraph.Color.Value.Should().Be("red"); + } + + [TestMethod] + public void WithColor() + { + var subgraph = new DotSubgraph() + .WithColor(Color.Red); + + subgraph.Color.Value.Should().Be("#FF0000"); + } + + + [TestMethod] + public void WithStyleString() + { + var subgraph = new DotSubgraph() + .WithStyle("custom"); + + subgraph.Style.Value.Should().Be("custom"); + } + + [TestMethod] + public void WithStyle() + { + var subgraph = new DotSubgraph() + .WithStyle(DotSubgraphStyle.Striped); + + subgraph.Style.Value.Should().Be("striped"); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs new file mode 100644 index 0000000..fb12cdf --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/EnumExtensionsTests.cs @@ -0,0 +1,65 @@ +using System; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class EnumExtensionsTests +{ + [Flags] + private enum TestFlaggedEnum + { + Hello = 1, + World = 2, + Lorem = 4, + Ipsum = 8 + } + + private enum TestNonFlaggedEnum + { + Hello, + World + } + + [TestMethod] + public void FlagsToStringNoFlag() + { + var value = (TestFlaggedEnum) 0; + + var result = value.FlagsToString(); + + result.Should().BeEmpty(); + } + + [TestMethod] + public void FlagsToStringOneFlag() + { + var value = TestFlaggedEnum.Lorem; + + var result = value.FlagsToString(); + + result.Should().Be("lorem"); + } + + [TestMethod] + public void FlagsToStringMultipleFlags() + { + var value = TestFlaggedEnum.Hello | TestFlaggedEnum.World | TestFlaggedEnum.Ipsum; + + var result = value.FlagsToString(); + + result.Should().Be("hello,world,ipsum"); + } + + [TestMethod] + public void FlagsToStringNonFlaggedEnum() + { + var value = TestNonFlaggedEnum.Hello; + + value.Invoking(v => v.FlagsToString()) + .Should() + .Throw(); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/StringExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/StringExtensionsTests.cs new file mode 100644 index 0000000..5a7f0a6 --- /dev/null +++ b/Sources/DotNetGraph.Tests/Extensions/StringExtensionsTests.cs @@ -0,0 +1,22 @@ +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Extensions; + +[TestClass] +public class StringExtensionsTests +{ + [DataTestMethod] + [DataRow("", "")] + [DataRow("Hello,\r\n world!", "Hello,\\n world!")] + [DataRow("Hello,\n world!", "Hello,\\n world!")] + [DataRow("Hello, \"world\"!", "Hello, \\\"world\\\"!")] + [DataRow("C:\\", "C:\\\\")] + public void FormatGraphvizEscapedCharacters(string input, string expectedOutput) + { + var result = input.FormatGraphvizEscapedCharacters(); + + result.Should().Be(expectedOutput); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotIdentifier.cs b/Sources/DotNetGraph/Core/DotIdentifier.cs index 2e26830..816b932 100644 --- a/Sources/DotNetGraph/Core/DotIdentifier.cs +++ b/Sources/DotNetGraph/Core/DotIdentifier.cs @@ -19,7 +19,10 @@ public DotIdentifier(string value, bool isHtml = false) public async Task CompileAsync(CompilationContext context) { if (IsHtml) + { await context.TextWriter.WriteAsync($"<{Value}>"); + return; + } var value = context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; await context.TextWriter.WriteAsync($"\"{value}\""); From abae8f1472aaececc5af7dc8d009b0168ac2d544 Mon Sep 17 00:00:00 2001 From: Valentin Date: Sat, 4 Feb 2023 18:10:12 +0100 Subject: [PATCH 11/15] Add tests --- .../DotNetGraph.Tests/Core/DotEdgeTests.cs | 55 +++++++ .../DotNetGraph.Tests/Core/DotElementTests.cs | 152 ++++++++++++++++++ Sources/DotNetGraph/Core/DotElement.cs | 2 + 3 files changed, 209 insertions(+) create mode 100644 Sources/DotNetGraph.Tests/Core/DotElementTests.cs diff --git a/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs b/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs index 856aeb8..4896c5e 100644 --- a/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs +++ b/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Threading.Tasks; using DotNetGraph.Compilation; @@ -43,4 +44,58 @@ public async Task CompileEmptyDirectedEdge() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"A\" -> \"B\"\n"); } + + [TestMethod] + public async Task CompileWithMissingFrom() + { + var edge = new DotEdge() + .To("B"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()) + { + DirectedGraph = true + }; + + await edge.Invoking(e => e.CompileAsync(context)) + .Should() + .ThrowAsync(); + } + + [TestMethod] + public async Task CompileWithMissingTo() + { + var edge = new DotEdge() + .From("A"); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()) + { + DirectedGraph = true + }; + + await edge.Invoking(e => e.CompileAsync(context)) + .Should() + .ThrowAsync(); + } + + [TestMethod] + public async Task CompileWithAttributes() + { + var edge = new DotEdge() + .From("A") + .To("B") + .WithLabel("Test") + .WithStyle(DotEdgeStyle.Bold); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()) + { + DirectedGraph = true + }; + await edge.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("\"A\" -> \"B\" [\n\t\"label\"=\"Test\"\n\t\"style\"=\"bold\"\n]\n"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Core/DotElementTests.cs b/Sources/DotNetGraph.Tests/Core/DotElementTests.cs new file mode 100644 index 0000000..ba110cd --- /dev/null +++ b/Sources/DotNetGraph.Tests/Core/DotElementTests.cs @@ -0,0 +1,152 @@ +using System; +using DotNetGraph.Attributes; +using DotNetGraph.Core; +using DotNetGraph.Extensions; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DotNetGraph.Tests.Core; + +[TestClass] +public class DotElementTests +{ + [TestMethod] + public void HasAttributeTrue() + { + var node = new DotNode() + .WithLabel("Test"); + + var hasAttribute = node.HasAttribute("label"); + + hasAttribute.Should().BeTrue(); + } + + [TestMethod] + public void HasAttributeFalse() + { + var node = new DotNode(); + + var hasAttribute = node.HasAttribute("label"); + + hasAttribute.Should().BeFalse(); + } + + [TestMethod] + public void GetAttributeMissing() + { + var node = new DotNode(); + + node.Invoking(n => n.GetAttribute("label")) + .Should() + .Throw(); + } + + [TestMethod] + public void GetAttributeOrDefault() + { + var node = new DotNode() + .WithLabel("Test"); + + var attribute = node.GetAttributeOrDefault("label"); + + attribute.Should().NotBeNull(); + } + + [TestMethod] + public void GetAttributeOrDefaultMissing() + { + var node = new DotNode(); + + var attribute = node.GetAttributeOrDefault("label"); + + attribute.Should().BeNull(); + } + + [TestMethod] + public void GetAttributeGenericWrongType() + { + var node = new DotNode() + .WithLabel("Test"); + + node.Invoking(n => n.GetAttribute("label")) + .Should() + .Throw(); + } + + [TestMethod] + public void GetAttributeOrDefaultGenericWrongType() + { + var node = new DotNode() + .WithLabel("Test"); + + node.Invoking(n => n.GetAttributeOrDefault("label")) + .Should() + .Throw(); + } + + [TestMethod] + public void GetAttributeOrDefaultGeneric() + { + var node = new DotNode(); + + var attribute = node.GetAttributeOrDefault("label"); + + attribute.Should().BeNull(); + } + + [TestMethod] + public void SetAttributeToNull() + { + var node = new DotNode() + .WithLabel("Test"); + + node.SetAttribute("label", null); + + node.Label.Should().BeNull(); + } + + [TestMethod] + public void TryGetAttributeMissing() + { + var node = new DotNode(); + + var success = node.TryGetAttribute("label", out var attribute); + + success.Should().BeFalse(); + attribute.Should().BeNull(); + } + + [TestMethod] + public void TryGetAttributeGeneric() + { + var node = new DotNode() + .WithLabel("Test"); + + var success = node.TryGetAttribute("label", out var attribute); + + success.Should().BeTrue(); + attribute.Should().NotBeNull(); + } + + [TestMethod] + public void TryGetAttributeGenericMissing() + { + var node = new DotNode(); + + var success = node.TryGetAttribute("label", out var attribute); + + success.Should().BeFalse(); + attribute.Should().BeNull(); + } + + [TestMethod] + public void TryGetAttributeGenericWrongType() + { + var node = new DotNode() + .WithLabel("Test"); + + node.Invoking(n => node.TryGetAttribute("label", out _)) + .Should() + .Throw(); + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotElement.cs b/Sources/DotNetGraph/Core/DotElement.cs index 5694604..632ccd3 100644 --- a/Sources/DotNetGraph/Core/DotElement.cs +++ b/Sources/DotNetGraph/Core/DotElement.cs @@ -38,6 +38,8 @@ public IDotAttribute GetAttribute(string name) public IDotAttribute GetAttributeOrDefault(string name, IDotAttribute defaultValue = default) { + if (Attributes.TryGetValue(name, out var attribute)) + return attribute; return defaultValue; } From 29b989c512ea1fd0cc74751ad02d8a93925009b7 Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 8 Aug 2023 01:35:50 +0200 Subject: [PATCH 12/15] Some update --- .github/workflows/dotnet-test.yml | 15 --------------- .../DotNetGraph.Tests/DotNetGraph.Tests.csproj | 14 ++++---------- Sources/DotNetGraph/Core/DotGraph.cs | 4 ++-- Sources/DotNetGraph/DotNetGraph.csproj | 17 +++++++++-------- 4 files changed, 15 insertions(+), 35 deletions(-) delete mode 100644 .github/workflows/dotnet-test.yml diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml deleted file mode 100644 index 290aa04..0000000 --- a/.github/workflows/dotnet-test.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: dotnet test - -on: [ push ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Setup dotnet - uses: actions/setup-dotnet@v3 - with: - dotnet-version: 7.X - - name: Test - run: dotnet test ./Sources -v n -c Release diff --git a/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj b/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj index c1ce48b..e7a061c 100644 --- a/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj +++ b/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj @@ -2,23 +2,17 @@ net6.0 - false + enable - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + - - + diff --git a/Sources/DotNetGraph/Core/DotGraph.cs b/Sources/DotNetGraph/Core/DotGraph.cs index a6d0fd7..80fc3b5 100644 --- a/Sources/DotNetGraph/Core/DotGraph.cs +++ b/Sources/DotNetGraph/Core/DotGraph.cs @@ -5,9 +5,9 @@ namespace DotNetGraph.Core { public class DotGraph : DotBaseGraph { - public bool Strict { get; set; } = false; + public bool Strict { get; set; } - public bool Directed { get; set; } = false; + public bool Directed { get; set; } public override async Task CompileAsync(CompilationContext context) { diff --git a/Sources/DotNetGraph/DotNetGraph.csproj b/Sources/DotNetGraph/DotNetGraph.csproj index 04cfe75..849297f 100644 --- a/Sources/DotNetGraph/DotNetGraph.csproj +++ b/Sources/DotNetGraph/DotNetGraph.csproj @@ -1,13 +1,14 @@ - - netstandard2.0 - + + netstandard2.0 + enable + - - - <_Parameter1>DotNetGraph.Tests - - + + + <_Parameter1>DotNetGraph.Tests + + From d8fbe9cf1f15f2e1d3aaae383a74234b34a4efa6 Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 8 Aug 2023 01:51:52 +0200 Subject: [PATCH 13/15] Fix nullable setting and add RankDir for graph --- .../DotNetGraph.Tests/Core/DotGraphTests.cs | 16 ++++++++++++++++ .../Extensions/DotBaseGraphExtensionsTests.cs | 9 +++++++++ Sources/DotNetGraph/Core/DotBaseGraph.cs | 18 ++++++++++++++++++ Sources/DotNetGraph/Core/DotGraph.cs | 10 ++-------- Sources/DotNetGraph/Core/DotRankDir.cs | 11 +++++++++++ Sources/DotNetGraph/Core/DotSubgraph.cs | 8 +------- Sources/DotNetGraph/DotNetGraph.csproj | 1 - .../Extensions/DotBaseGraphExtensions.cs | 6 ++++++ 8 files changed, 63 insertions(+), 16 deletions(-) create mode 100644 Sources/DotNetGraph/Core/DotRankDir.cs diff --git a/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs b/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs index 6a535cd..9cbd341 100644 --- a/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs +++ b/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs @@ -54,4 +54,20 @@ public async Task CompileEmptyDirectedGraph() var result = writer.GetStringBuilder().ToString(); result.Should().Be("digraph \"Test\" {\n}\n"); } + + [TestMethod] + public async Task CompileEmptyDirectedGraphWithRankDir() + { + var graph = new DotGraph() + .WithIdentifier("Test") + .WithRankDir(DotRankDir.RL) + .Directed(); + + await using var writer = new StringWriter(); + var context = new CompilationContext(writer, new CompilationOptions()); + await graph.CompileAsync(context); + + var result = writer.GetStringBuilder().ToString(); + result.Should().Be("digraph \"Test\" {\n\trankdir=\"RL\"\n}\n"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs index e02e43f..3422c6b 100644 --- a/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs +++ b/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs @@ -28,6 +28,15 @@ public void WithIdentifierHtml() graph.Identifier.IsHtml.Should().Be(true); } + [TestMethod] + public void WithRankDir() + { + var graph = new DotGraph() + .WithRankDir(DotRankDir.TB); + + graph.RankDir.Should().Be(DotRankDir.TB); + } + [TestMethod] public void Add() { diff --git a/Sources/DotNetGraph/Core/DotBaseGraph.cs b/Sources/DotNetGraph/Core/DotBaseGraph.cs index 73f0070..623e578 100644 --- a/Sources/DotNetGraph/Core/DotBaseGraph.cs +++ b/Sources/DotNetGraph/Core/DotBaseGraph.cs @@ -7,9 +7,27 @@ namespace DotNetGraph.Core public abstract class DotBaseGraph : DotElement { public DotIdentifier Identifier { get; set; } + + public DotRankDir? RankDir { get; set; } public List Elements { get; } = new List(); public abstract override Task CompileAsync(CompilationContext context); + + protected async Task CompileBodyAsync(CompilationContext context) + { + await Identifier.CompileAsync(context); + await context.WriteLineAsync(" {"); + context.IndentationLevel++; + if (RankDir != null) + { + await context.WriteIndentationAsync(); + await context.WriteLineAsync($"rankdir=\"{RankDir.ToString()}\""); + } + await CompileAttributesAsync(context); + context.IndentationLevel--; + await context.WriteIndentationAsync(); + await context.WriteLineAsync("}"); + } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotGraph.cs b/Sources/DotNetGraph/Core/DotGraph.cs index 80fc3b5..f83306e 100644 --- a/Sources/DotNetGraph/Core/DotGraph.cs +++ b/Sources/DotNetGraph/Core/DotGraph.cs @@ -8,7 +8,7 @@ public class DotGraph : DotBaseGraph public bool Strict { get; set; } public bool Directed { get; set; } - + public override async Task CompileAsync(CompilationContext context) { context.DirectedGraph = Directed; @@ -16,13 +16,7 @@ public override async Task CompileAsync(CompilationContext context) if (Strict) await context.WriteAsync("strict "); await context.WriteAsync(Directed ? "digraph " : "graph "); - await Identifier.CompileAsync(context); - await context.WriteLineAsync(" {"); - context.IndentationLevel++; - await CompileAttributesAsync(context); - context.IndentationLevel--; - await context.WriteIndentationAsync(); - await context.WriteLineAsync("}"); + await CompileBodyAsync(context); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotRankDir.cs b/Sources/DotNetGraph/Core/DotRankDir.cs new file mode 100644 index 0000000..249c041 --- /dev/null +++ b/Sources/DotNetGraph/Core/DotRankDir.cs @@ -0,0 +1,11 @@ +// ReSharper disable InconsistentNaming +namespace DotNetGraph.Core +{ + public enum DotRankDir + { + TB = 0, + BT = 1, + LR = 2, + RL = 3 + } +} \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotSubgraph.cs b/Sources/DotNetGraph/Core/DotSubgraph.cs index 81add85..fefb6ee 100644 --- a/Sources/DotNetGraph/Core/DotSubgraph.cs +++ b/Sources/DotNetGraph/Core/DotSubgraph.cs @@ -22,13 +22,7 @@ public override async Task CompileAsync(CompilationContext context) { await context.WriteIndentationAsync(); await context.WriteAsync("subgraph "); - await Identifier.CompileAsync(context); - await context.WriteLineAsync(" {"); - context.IndentationLevel++; - await CompileAttributesAsync(context); - context.IndentationLevel--; - await context.WriteIndentationAsync(); - await context.WriteLineAsync("}"); + await CompileBodyAsync(context); } } } \ No newline at end of file diff --git a/Sources/DotNetGraph/DotNetGraph.csproj b/Sources/DotNetGraph/DotNetGraph.csproj index 849297f..cbcf340 100644 --- a/Sources/DotNetGraph/DotNetGraph.csproj +++ b/Sources/DotNetGraph/DotNetGraph.csproj @@ -2,7 +2,6 @@ netstandard2.0 - enable diff --git a/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs b/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs index d5bd74f..c4eac4c 100644 --- a/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs +++ b/Sources/DotNetGraph/Extensions/DotBaseGraphExtensions.cs @@ -10,6 +10,12 @@ public static T WithIdentifier(this T graph, string identifier, bool isHtml = return graph; } + public static T WithRankDir(this T graph, DotRankDir? rankDir) where T : DotBaseGraph + { + graph.RankDir = rankDir; + return graph; + } + public static T Add(this T graph, IDotElement element) where T : DotBaseGraph { graph.Elements.Add(element); From cc20113eb8b4a267623e96ec452c44c52056846d Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 8 Aug 2023 02:14:45 +0200 Subject: [PATCH 14/15] Added implicit conversion for attributes --- .../Attributes/DotColorAttributeTests.cs | 14 ++++++++++++++ .../Attributes/DotDoubleAttributeTests.cs | 7 +++++++ .../Attributes/DotEdgeArrowTypeAttributeTests.cs | 14 ++++++++++++++ .../Attributes/DotEdgeStyleAttributeTests.cs | 16 +++++++++++++++- .../Attributes/DotLabelAttributeTests.cs | 9 +++++++++ .../Attributes/DotNodeShapeAttributeTests.cs | 14 ++++++++++++++ .../Attributes/DotNodeStyleAttributeTests.cs | 14 ++++++++++++++ .../Attributes/DotPointAttributeTests.cs | 14 ++++++++++++++ .../Attributes/DotSubgraphStyleAttributeTests.cs | 14 ++++++++++++++ .../DotNetGraph/Attributes/DotColorAttribute.cs | 3 +++ .../DotNetGraph/Attributes/DotDoubleAttribute.cs | 2 ++ .../Attributes/DotEdgeArrowTypeAttribute.cs | 3 +++ .../Attributes/DotEdgeStyleAttribute.cs | 3 +++ .../DotNetGraph/Attributes/DotLabelAttribute.cs | 4 +++- .../Attributes/DotNodeShapeAttribute.cs | 3 +++ .../Attributes/DotNodeStyleAttribute.cs | 3 +++ .../DotNetGraph/Attributes/DotPointAttribute.cs | 3 +++ .../Attributes/DotSubgraphStyleAttribute.cs | 3 +++ Sources/DotNetGraph/Core/DotElement.cs | 2 +- 19 files changed, 142 insertions(+), 3 deletions(-) diff --git a/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs index 6642539..2f9403c 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs @@ -36,4 +36,18 @@ public async Task CompileFromColor() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"#FF0000\""); } + + [TestMethod] + public void ImplicitConversionFromColor() + { + DotColorAttribute attribute = Color.Red; + attribute.Value.Should().Be("#FF0000"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotColorAttribute attribute = "#FF0000"; + attribute.Value.Should().Be("#FF0000"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs index 3064007..9cb1d54 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs @@ -35,4 +35,11 @@ public async Task CompileWithSpecifiedFormat() var result = writer.GetStringBuilder().ToString(); result.Should().Be("123.456"); } + + [TestMethod] + public void ImplicitConversionFromDouble() + { + DotDoubleAttribute attribute = 123.456d; + attribute.Value.Should().Be(123.456d); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs index 29ef120..d8e6ddd 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs @@ -36,4 +36,18 @@ public async Task CompileFromEnum() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"box\""); } + + [TestMethod] + public void ImplicitConversionFromDotEdgeArrowType() + { + DotEdgeArrowTypeAttribute attribute = DotEdgeArrowType.Box; + attribute.Value.Should().Be("box"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotEdgeArrowTypeAttribute attribute = "box"; + attribute.Value.Should().Be("box"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs index c6fb332..f6d88b7 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs @@ -23,7 +23,7 @@ public async Task CompileFromString() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"custom\""); } - + [TestMethod] public async Task CompileFromEnum() { @@ -36,4 +36,18 @@ public async Task CompileFromEnum() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"solid\""); } + + [TestMethod] + public void ImplicitConversionFromDotEdgeStyle() + { + DotEdgeStyleAttribute attribute = DotEdgeStyle.Solid; + attribute.Value.Should().Be("solid"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotEdgeStyleAttribute attribute = "solid"; + attribute.Value.Should().Be("solid"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs index 4251288..35b3fea 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs @@ -51,4 +51,13 @@ public async Task CompileHtml() var result = writer.GetStringBuilder().ToString(); result.Should().Be("<Hello, world!>"); } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotLabelAttribute attribute = "Hello, world!"; + + attribute.Value.Should().Be("Hello, world!"); + attribute.IsHtml.Should().Be(false); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs index 4630146..2195e68 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs @@ -36,4 +36,18 @@ public async Task CompileFromEnum() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"terminator\""); } + + [TestMethod] + public void ImplicitConversionFromDotNodeShape() + { + DotNodeShapeAttribute attribute = DotNodeShape.Terminator; + attribute.Value.Should().Be("terminator"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotNodeShapeAttribute attribute = "terminator"; + attribute.Value.Should().Be("terminator"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs index 6645903..faad002 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs @@ -36,4 +36,18 @@ public async Task CompileFromEnum() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"bold\""); } + + [TestMethod] + public void ImplicitConversionFromDotNodeStyle() + { + DotNodeStyleAttribute attribute = DotNodeStyle.Bold; + attribute.Value.Should().Be("bold"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotNodeStyleAttribute attribute = "bold"; + attribute.Value.Should().Be("bold"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs index 78ca2d9..deaa6ce 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs @@ -37,4 +37,18 @@ public async Task CompileFromDotPoint() var result = writer.GetStringBuilder().ToString(); result.Should().Be("42,69,75!"); } + + [TestMethod] + public void ImplicitConversionFromDotPoint() + { + DotPointAttribute attribute = new DotPoint(42, 69, 75, true); + attribute.Value.Should().Be("42,69,75!"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotPointAttribute attribute = "42,69,75!"; + attribute.Value.Should().Be("42,69,75!"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs index 81c2558..9dde479 100644 --- a/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs +++ b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs @@ -36,4 +36,18 @@ public async Task CompileFromEnum() var result = writer.GetStringBuilder().ToString(); result.Should().Be("\"rounded\""); } + + [TestMethod] + public void ImplicitConversionFromDotSubgraphStyle() + { + DotSubgraphStyleAttribute attribute = DotSubgraphStyle.Rounded; + attribute.Value.Should().Be("rounded"); + } + + [TestMethod] + public void ImplicitConversionFromString() + { + DotSubgraphStyleAttribute attribute = "rounded"; + attribute.Value.Should().Be("rounded"); + } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotColorAttribute.cs b/Sources/DotNetGraph/Attributes/DotColorAttribute.cs index f019622..3ca1550 100644 --- a/Sources/DotNetGraph/Attributes/DotColorAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotColorAttribute.cs @@ -23,5 +23,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync($"\"{Value}\""); } + + public static implicit operator DotColorAttribute(Color value) => new DotColorAttribute(value); + public static implicit operator DotColorAttribute(string value) => new DotColorAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs b/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs index c64f7b8..f052fd5 100644 --- a/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotDoubleAttribute.cs @@ -20,5 +20,7 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync(Value.ToString(Format, NumberFormatInfo.InvariantInfo)); } + + public static implicit operator DotDoubleAttribute(double value) => new DotDoubleAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs index 514dc97..03d5000 100644 --- a/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotEdgeArrowTypeAttribute.cs @@ -22,5 +22,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync($"\"{Value}\""); } + + public static implicit operator DotEdgeArrowTypeAttribute(DotEdgeArrowType value) => new DotEdgeArrowTypeAttribute(value); + public static implicit operator DotEdgeArrowTypeAttribute(string value) => new DotEdgeArrowTypeAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs index fc3d355..59e0f79 100644 --- a/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotEdgeStyleAttribute.cs @@ -23,5 +23,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync($"\"{Value}\""); } + + public static implicit operator DotEdgeStyleAttribute(DotEdgeStyle value) => new DotEdgeStyleAttribute(value); + public static implicit operator DotEdgeStyleAttribute(string value) => new DotEdgeStyleAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs index 3747853..bf0b50b 100644 --- a/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotLabelAttribute.cs @@ -8,7 +8,7 @@ public class DotLabelAttribute : IDotAttribute { public string Value { get; set; } - public bool IsHtml { get; set; } = false; + public bool IsHtml { get; set; } public DotLabelAttribute(string value, bool isHtml = false) { @@ -27,5 +27,7 @@ public async Task CompileAsync(CompilationContext context) var value = context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value; await context.TextWriter.WriteAsync($"\"{value}\""); } + + public static implicit operator DotLabelAttribute(string value) => new DotLabelAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs index 385a557..b8c81d7 100644 --- a/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotNodeShapeAttribute.cs @@ -22,5 +22,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync($"\"{Value}\""); } + + public static implicit operator DotNodeShapeAttribute(DotNodeShape value) => new DotNodeShapeAttribute(value); + public static implicit operator DotNodeShapeAttribute(string value) => new DotNodeShapeAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs index 61e7313..be0f557 100644 --- a/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotNodeStyleAttribute.cs @@ -23,5 +23,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync($"\"{Value}\""); } + + public static implicit operator DotNodeStyleAttribute(DotNodeStyle value) => new DotNodeStyleAttribute(value); + public static implicit operator DotNodeStyleAttribute(string value) => new DotNodeStyleAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotPointAttribute.cs b/Sources/DotNetGraph/Attributes/DotPointAttribute.cs index a397b56..5505a01 100644 --- a/Sources/DotNetGraph/Attributes/DotPointAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotPointAttribute.cs @@ -22,5 +22,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync(Value); } + + public static implicit operator DotPointAttribute(DotPoint value) => new DotPointAttribute(value); + public static implicit operator DotPointAttribute(string value) => new DotPointAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs b/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs index f435a24..acb22b4 100644 --- a/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs +++ b/Sources/DotNetGraph/Attributes/DotSubgraphStyleAttribute.cs @@ -23,5 +23,8 @@ public async Task CompileAsync(CompilationContext context) { await context.WriteAsync($"\"{Value}\""); } + + public static implicit operator DotSubgraphStyleAttribute(DotSubgraphStyle value) => new DotSubgraphStyleAttribute(value); + public static implicit operator DotSubgraphStyleAttribute(string value) => new DotSubgraphStyleAttribute(value); } } \ No newline at end of file diff --git a/Sources/DotNetGraph/Core/DotElement.cs b/Sources/DotNetGraph/Core/DotElement.cs index 632ccd3..1bd2cde 100644 --- a/Sources/DotNetGraph/Core/DotElement.cs +++ b/Sources/DotNetGraph/Core/DotElement.cs @@ -107,7 +107,7 @@ public bool RemoveAttribute(string name) return Attributes.Remove(name); } - public async Task CompileAttributesAsync(CompilationContext context) + protected async Task CompileAttributesAsync(CompilationContext context) { foreach (var attributePair in Attributes) { From 30387643bd36c2782471325ceb321fb939ad6af0 Mon Sep 17 00:00:00 2001 From: Valentin Date: Tue, 8 Aug 2023 12:19:59 +0200 Subject: [PATCH 15/15] Add logo --- README.md | 9 ++++++++- Resources/icon_128.png | Bin 0 -> 2295 bytes Resources/icon_64.png | Bin 0 -> 1351 bytes Sources/DotNetGraph/DotNetGraph.nuspec | 4 +++- 4 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 Resources/icon_128.png create mode 100644 Resources/icon_64.png diff --git a/README.md b/README.md index a480818..9df852b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # DotNetGraph +![Logo](Resources/icon_64.png) + Create **GraphViz DOT graph** with **dotnet**. Available on NuGet: [![#](https://img.shields.io/nuget/v/DotNetGraph.svg)](https://www.nuget.org/packages/DotNetGraph/) @@ -89,4 +91,9 @@ var result = writer.GetStringBuilder().ToString(); // Save it to a file File.WriteAllText("graph.dot", result); -``` \ No newline at end of file +``` +
+ +### Credits + +Logo: https://www.flaticon.com/free-icon/flow-chart_4411911 \ No newline at end of file diff --git a/Resources/icon_128.png b/Resources/icon_128.png new file mode 100644 index 0000000000000000000000000000000000000000..7ead69454eda95e345c6adaea3d89df48bf50ba0 GIT binary patch literal 2295 zcmb7GX*kqt8~@J?V~%w!CHt0)Y=d6KSOz0TWId)g>)6M!n+y)e6qO}Xlq_SZ5E`;( zEh3ar$Sy;1tl1;W81HmGocDb{ydU1@y6)$Ge!nmG{rv9xzOFmb`m!kxrzj@?06bVT zj4jKPe;N$Rx;ymoy)4HTW`wneu}(D1Gl7MF2{!v@7yv-3ei~>eZWYTSMTjO>h;~8V zL=ryK3m}n5s)WGb!aVT7UaCQ%J~?Z;q5uFRVljsH5xJ{VF?Z~7BG8QmJyLk))Sq%U zWiw3n&4u~T-gJIHs=;lj-}Iu>oob1E^w7<}uFhfLk?)|WiKV%UOsSb1flFng^W@h( zA|NXX&z%^0AH(nWxEJ5^xg5xD^Cmn)TpHdd9x~q<842x?rdP)Zr0ct(Oj9Wi^@5la zaRy!}W7tJAkcL~4bA*2e*Rfd$#1`nrg2WZrgL8%2LJDJfHyZaeXESaqz@D*L!*>~L zs)xeKs{0Gcl_b}8AC4!)w?13Uu=`gYb(GD%Zc${7AW$$j1ssN@&^529Dl^=*^HV)wU2;$eRbMGq+BqSl24h?wLn+Bwu^2 zKH6H@u#N`)#LrjBXs}DaMY&8hZgtm(IoZ|K@2VnQ>M3%gb3!v06v?wsfz)*Hh0B~Q zfQFjSCarSIEZzru7F>}4(rPJk-Md(j#@My)$6?aCfhbd6XZ+i{W}v`=D)&u4_!P$s zTiSVH7*V6YEvZDyvO-%Z%L@FYtjc|$2FR-um-Cqu`76bLtMXqG{SCxH=o@109UsG~ zZp8$QeRi_pbHjHJQ=2uX)_D>o5>u2J*cIBV{Q*eE^9}GYg7ZoZD@i-t3)RR|YRx_H@Vb0Ty-z->pu7T&pSa-4~q^ zJH=3!2dS12wlEoW6oJG@@4BpXt>#qb6eXx)h!)c2;#lMM$Z3H#3=ZAW6ahKX#> zW?bR5#!H9C&3B`T;CFA<;Xw3`MF1AX`MT&)3BgF}iN_$qLSiM!r)g45096d_X5xuw zW&}SeQkP1F4YZFvwNPIVmP3&-f^DaOysQY^Q4KYCZ+enbpR&ZncA!YYZ)?ZbmAse1 zn=UV+lKlKoq0GsKumye1)5V$w4>Z2COQ3K}jZy8#zHjcBN&y3(M9!O)+?FJ`9J;7# z_B8+Jbo_5swrWDOHaz@x+mlM2Z>uR|%sZMJPuUAVGQcJO*s~R29h3B8~Uz~H)TCaR= zkwrUQLWbMdjy$CKQC(M+^m#UZh#)sr(3z+HB52 z`7<0&E%u*DD<7~1J;d1ko*(rNQ-Ap7zsr(-3PcGn4TX!w4lVPcajTW((p^CzJ2wP0 z6Jl|lF%FEXP?wQW6@l}o-5ZJmAml@COmeodHPiO&ac{HMEnMA5%ssLt0FK3l@a1mk z2DMjUNlcX-3W7Vp@g_re4?yxyOwz=erGX>NCN;qq?2X!cfOSR8YehQa&}RG_=K97p zyF^((om8uA@%grKm7VRjF<8ea{0||B*SFHqGTzatp~)Bo(82AUgy8-DSV>Hi&tI%K z(G{?U5B4}JV#R)MzEU{J)!t$vKA}jC4w4|Zg3 z-hy8eF~-I-mkx>mC?UA(WpiT}I%~R8ZzDNUku0+rSN9Tpt~>Njo7!R#Q2extd)L(} z#j1A55>}1obb~2n`=B7e9_(R9q5<^CH)f}oYd(6`@%}^5L|E|9z+HL;T+C&8 z=Ofdca+=(`#CFh?R71zr3-NM{=kATI=9VkpGi=G|l8lnil>18E`KTTdsp|8cO;C+c z_N;VuX*ZM;iAksXp&;a5`KmV*!;@wp?)?HQA3bvHI1L@28E)a!FX@>g)Ry*Sb{(tX zL46Cmx|A2o7R{mxGAc(v7k(o!wwsHU^#zFcSkydWI5T09pX>l}0$kNwR(QStC?J^kZI7=ZL~-hKjeE=q zFIt2^ft6>g<{QbhtK%0M4+0Kw6bHm^j~Fy zr0PA!%EKY{CqySix%a{ryw;TTgUWFUp literal 0 HcmV?d00001 diff --git a/Resources/icon_64.png b/Resources/icon_64.png new file mode 100644 index 0000000000000000000000000000000000000000..7f6c543e474aed0396037585388d7bb596580f75 GIT binary patch literal 1351 zcmV-N1-SZ&P)1K~#90?VD|E6jc<4-*ac_mTp_xCJH4cDn*Nk_G@bzWNQVa zSlAFvS_}p?ibjpWfG9DIZv=nN@ZbgeFRnw>;kv0|W zlD2fWJNNj*EPiBnnUC$v)b8`|&bjBDci)|RXEM73q?z52-2(o}gFm*p$3pTI0`8jb zUJQ(?5O2DsyOAEoLh5#a_OM0$T#%K*qF&k{y4%Wj43s#_07+IaNph9}Heh%Us9pKN zJq%Qnl#0<4u%!n4FV?Xc9AyBLR4r~9b(8^MI%#b`oN&}`ex`E$hrVFTFayh` zyO&@Z&CGBea+Co8aN4`R6+o+1{hYM~Y#?ob-2&_;ZGhbZ?1mm4YO5j^ZxAC-Ym)lA zx=@DH!q`|@;QC(76=T=SV?tlpt!!&5cpwxveth*jgx&ALf`_62MnSyGMUp-Rut?8? zNKv3b6#VNsNU^4TMumG)y#!!a+;}8oCx9n(NHGV~EdroLmNf)GgrX#2OSJ$fn)Q1? z+5o!+*iG61y9L-y+5o!+*iG61y9L;d01&paA#;*`Qba720svtFP?LoXB{3aI7$rUe zKw74T_;ae~!%D`byj6nKd0KMDKMQS+4oCg5vHQNPS2IiJ4r<92pbH-ruI*1YhmZR2 zgpfoF55ntr_`5OD#Vywi**9gG90 zr6u2V8%g#B1J45VJ~W=W#1!!4QT?&o>Jr|53xHoRBE}#dfSxpxxS}`U2j~EFEL$e_ zkA>vHWOKw{qAW#szncET*~HWcW1IHl)jff_M8O$x6;LNV&jDCqyaMe`6qykQkmLq4 z`AqOupFMhOyqM*e!BfG-8*A@>ej@-xmEsg>jFYFFn1mnws}Vm^tpH(DEgaofRGia2^1d$TNpBi<2fy0EluvTxMUU5EtVe zwcLP;r58KfJDz?-Pma&k(gI+eiMCUUD{?Ac!0}4}0Ep;glO>uv%N`ny7nl(Sbd}dN z5yR+Xw}=9MEm2SaJY=x2K@9XGVo2El;5Xf=Oj|p>{(;2tfzk~C-T}1#N5}+y0Bxcr z=YBPk> DotNetGraph - 3.0.0 DotNetGraph + 3.0.0 VFRZ VFRZ + icon.png https://github.com/vfrz/DotNetGraph Create Graphviz DOT graph with dotnet @@ -23,5 +24,6 @@ + \ No newline at end of file