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..9df852b 100644
--- a/README.md
+++ b/README.md
@@ -1,93 +1,99 @@
# DotNetGraph
-Create **GraphViz DOT graph** with **.NET**
+![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/)
-Compatible with **.NET Standard 2.0** and higher
+Compatible with **.NET Standard 2.0** and higher.
-# Documentation
+# Usage
## 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);
-```
\ No newline at end of file
+File.WriteAllText("graph.dot", result);
+```
+
+
+### 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 0000000..7ead694
Binary files /dev/null and b/Resources/icon_128.png differ
diff --git a/Resources/icon_64.png b/Resources/icon_64.png
new file mode 100644
index 0000000..7f6c543
Binary files /dev/null and b/Resources/icon_64.png differ
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
new file mode 100644
index 0000000..2f9403c
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotColorAttributeTests.cs
@@ -0,0 +1,53 @@
+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 CompileFromString()
+ {
+ 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 CompileFromColor()
+ {
+ 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\"");
+ }
+
+ [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
new file mode 100644
index 0000000..9cb1d54
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotDoubleAttributeTests.cs
@@ -0,0 +1,45 @@
+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 CompileWithDefaultFormat()
+ {
+ 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 CompileWithSpecifiedFormat()
+ {
+ 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");
+ }
+
+ [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
new file mode 100644
index 0000000..d8e6ddd
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeArrowTypeAttributeTests.cs
@@ -0,0 +1,53 @@
+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 CompileFromString()
+ {
+ 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 CompileFromEnum()
+ {
+ 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\"");
+ }
+
+ [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
new file mode 100644
index 0000000..f6d88b7
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotEdgeStyleAttributeTests.cs
@@ -0,0 +1,53 @@
+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 CompileFromString()
+ {
+ 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 CompileFromEnum()
+ {
+ 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\"");
+ }
+
+ [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
new file mode 100644
index 0000000..35b3fea
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotLabelAttributeTests.cs
@@ -0,0 +1,63 @@
+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 CompileDefault()
+ {
+ 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 CompileWithoutAutomaticEscapedCharactersFormat()
+ {
+ 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 CompileHtml()
+ {
+ 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!>");
+ }
+
+ [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
new file mode 100644
index 0000000..2195e68
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeShapeAttributeTests.cs
@@ -0,0 +1,53 @@
+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 CompileFromString()
+ {
+ 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 CompileFromEnum()
+ {
+ 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\"");
+ }
+
+ [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
new file mode 100644
index 0000000..faad002
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotNodeStyleAttributeTests.cs
@@ -0,0 +1,53 @@
+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 CompileFromString()
+ {
+ 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 CompileFromEnum()
+ {
+ 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\"");
+ }
+
+ [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
new file mode 100644
index 0000000..deaa6ce
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotPointAttributeTests.cs
@@ -0,0 +1,54 @@
+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 CompileFromString()
+ {
+ 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 CompileFromDotPoint()
+ {
+ 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!");
+ }
+
+ [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
new file mode 100644
index 0000000..9dde479
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Attributes/DotSubgraphStyleAttributeTests.cs
@@ -0,0 +1,53 @@
+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 CompileFromString()
+ {
+ 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 CompileFromEnum()
+ {
+ 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\"");
+ }
+
+ [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.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/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/DotEdgeTests.cs b/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs
new file mode 100644
index 0000000..4896c5e
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Core/DotEdgeTests.cs
@@ -0,0 +1,101 @@
+using System;
+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.Core;
+
+[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");
+ }
+
+ [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.Tests/Core/DotGraphTests.cs b/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs
new file mode 100644
index 0000000..9cbd341
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Core/DotGraphTests.cs
@@ -0,0 +1,73 @@
+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.Core;
+
+[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");
+ }
+
+ [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");
+ }
+
+ [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/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/Core/DotNodeTests.cs b/Sources/DotNetGraph.Tests/Core/DotNodeTests.cs
new file mode 100644
index 0000000..6a4bfec
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Core/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.Core;
+
+[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.Tests/Core/DotSubgraphTests.cs b/Sources/DotNetGraph.Tests/Core/DotSubgraphTests.cs
new file mode 100644
index 0000000..707e68b
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Core/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.Core;
+
+[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.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..e7a061c 100644
--- a/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj
+++ b/Sources/DotNetGraph.Tests/DotNetGraph.Tests.csproj
@@ -2,22 +2,17 @@
net6.0
-
false
+ enable
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
-
+
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/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..3422c6b
--- /dev/null
+++ b/Sources/DotNetGraph.Tests/Extensions/DotBaseGraphExtensionsTests.cs
@@ -0,0 +1,50 @@
+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 WithRankDir()
+ {
+ var graph = new DotGraph()
+ .WithRankDir(DotRankDir.TB);
+
+ graph.RankDir.Should().Be(DotRankDir.TB);
+ }
+
+ [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.Tests/Extensions/DotGraphExtensionsTests.cs b/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs
index 5388e03..f54570c 100644
--- a/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs
+++ b/Sources/DotNetGraph.Tests/Extensions/DotGraphExtensionsTests.cs
@@ -1,80 +1,28 @@
-using DotNetGraph.SubGraph;
-using DotNetGraph.Extensions;
-using System.Collections.Generic;
-using Xunit;
-using NFluent;
using DotNetGraph.Core;
-using DotNetGraph.Node;
-using DotNetGraph.Edge;
+using DotNetGraph.Extensions;
+using FluentAssertions;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
-namespace DotNetGraph.Tests.Extensions
+namespace DotNetGraph.Tests.Extensions;
+
+[TestClass]
+public class DotGraphExtensionsTests
{
- public class DotGraphExtensionsTests
+ [TestMethod]
+ public void Directed()
{
- public static IEnumerable