From 14d959834fbabf767a5c9c520416229ceb77e406 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Thu, 9 Jan 2025 15:32:28 +0000 Subject: [PATCH] Convert to Xunit (#196) * xunit unit tests * most pass with formatting * convert objects to xunit * remove nunit * format * merge fixes * switch objects to fluent assertions * update to fluent assertions * more FA * convert all to FA * Format * Fix tests * formatting * hopefully made credential test better * Catch more specific exception * use another more specific exception * Fix tests * update to xunit * update packages --- Directory.Build.targets | 2 - Directory.Packages.props | 13 +- src/Speckle.Sdk.Dependencies/Collections.cs | 5 + tests/Speckle.Objects.Tests.Unit/Assembly.cs | 3 + .../Geometry/ArcTests.cs | 109 +++++----- .../Geometry/BoxTests.cs | 35 ++-- .../Geometry/CircleTests.cs | 15 +- .../Geometry/MeshTests.cs | 31 +-- .../Geometry/PointTests.cs | 72 ++++--- .../Geometry/TransformTests.cs | 78 ++++--- .../ModelPropertySupportedTypes.cs | 25 ++- .../ObjectBaseValidityTests.cs | 20 +- .../Speckle.Objects.Tests.Unit.csproj | 6 +- .../Utils/MeshTriangulationHelperTests.cs | 69 ++++--- .../Utils/ShallowCopyTests.cs | 15 +- .../packages.lock.json | 178 ++++++++++------ .../Assembly.cs | 3 + .../BaseComparer.cs | 17 ++ .../DetachedTests.cs | 115 ++++++----- .../DummyReceiveServerObjectManager.cs | 1 - .../DummySendServerObjectManager.cs | 4 - .../ExplicitInterfaceTests.cs | 28 +-- .../ExternalIdTests.cs | 47 +++-- .../SerializationTests.cs | 80 ++++---- .../Speckle.Sdk.Serialization.Tests.csproj | 6 +- .../packages.lock.json | 178 ++++++++++------ .../GraphQL/GraphQLClientExceptionHandling.cs | 65 +++--- .../Resources/ActiveUserResourceTests.cs | 58 +++--- .../GraphQL/Resources/CommentResourceTests.cs | 99 ++++----- .../ModelResourceExceptionalTests.cs | 121 +++++++---- .../GraphQL/Resources/ModelResourceTests.cs | 109 ++++++---- .../Resources/OtherUserResourceTests.cs | 48 +++-- .../ProjectInviteResourceExceptionalTests.cs | 45 +++-- .../Resources/ProjectInviteResourceTests.cs | 76 ++++--- .../ProjectResourceExceptionalTests.cs | 98 ++++----- .../GraphQL/Resources/ProjectResourceTests.cs | 107 ++++++---- .../Resources/SubscriptionResourceTests.cs | 69 ++++--- .../GraphQL/Resources/VersionResourceTests.cs | 75 ++++--- .../Credentials/UserServerInfoTests.cs | 94 +++++---- .../Speckle.Sdk.Tests.Integration/Fixtures.cs | 4 +- .../MemoryTransportTests.cs | 35 ++-- .../Speckle.Sdk.Tests.Integration.csproj | 5 +- tests/Speckle.Sdk.Tests.Integration/Usings.cs | 1 - .../packages.lock.json | 188 +++++++++++------ .../Benchmarks/GeneralReceiveTest.cs | 5 - .../Benchmarks/GeneralSerializerTest.cs | 1 - .../Speckle.Sdk.Tests.Performance/Program.cs | 1 - .../Api/ClientResiliencyPolicyTest.cs | 30 ++- .../Api/GraphQLErrorHandler.cs | 60 +++--- .../Api/Operations/ClosureTests.cs | 39 ++-- .../OperationsReceiveTests.Exceptional.cs | 26 +-- .../Api/Operations/OperationsReceiveTests.cs | 66 +++--- .../Api/Operations/SendObjectReferences.cs | 38 ++-- .../Api/Operations/SendReceiveLocal.cs | 113 ++++------- .../Api/Operations/SerializationTests.cs | 63 +++--- tests/Speckle.Sdk.Tests.Unit/Assembly.cs | 3 + .../Common/NotNullTests.cs | 99 ++++----- .../Common/RangeFromTests.cs | 14 ++ .../Common/UnitsTest.cs | 90 ++++++--- .../AccountServerMigrationTests.cs | 46 ++--- .../Credentials/Accounts.cs | 77 ++++--- tests/Speckle.Sdk.Tests.Unit/Fixtures.cs | 10 +- tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs | 13 +- .../Host/HostApplicationTests.cs | 17 +- .../Models/BaseTests.cs | 124 ++++++------ .../Models/Extensions/BaseExtensionsTests.cs | 45 ++--- .../Models/Extensions/DisplayValueTests.cs | 35 ++-- .../Models/Extensions/ExceptionTests.cs | 17 +- .../GraphTraversal/GraphTraversalTests.cs | 68 +++---- .../TraversalContextExtensionsTests.cs | 47 +++-- .../Speckle.Sdk.Tests.Unit/Models/Hashing.cs | 42 ++-- .../Models/SpeckleType.cs | 52 +++-- .../Models/TraversalTests.cs | 47 +++-- .../Models/UtilitiesTests.cs | 131 +++++++----- .../SQLite/SQLiteJsonCacheManagerTests.cs | 53 +++-- .../SQLite/SQLiteJsonExceptionTests.cs | 7 +- .../Serialisation/BatchTests.cs | 21 +- .../Serialisation/ChunkingTests.cs | 38 ++-- .../Serialisation/JsonIgnoreAttributeTests.cs | 70 ++++--- .../ObjectModelDeprecationTests.cs | 25 +-- .../Serialisation/PrimitiveTestFixture.cs | 48 +++++ .../SerializerBreakingChanges.cs | 59 +++--- .../SerializerNonBreakingChanges.cs | 190 ++++++------------ .../Serialisation/SimpleRoundTripTests.cs | 33 ++- .../Speckle.Sdk.Tests.Unit.csproj | 6 +- .../Transports/DiskTransportTests.cs | 43 ++-- .../Transports/MemoryTransportTests.cs | 17 +- .../Transports/SQLiteTransport2Tests.cs | 70 +++---- .../Transports/SQLiteTransportTests.cs | 86 ++++---- .../Transports/TransportTests.cs | 80 ++++---- .../Speckle.Sdk.Tests.Unit/packages.lock.json | 178 ++++++++++------ 91 files changed, 2684 insertions(+), 2211 deletions(-) create mode 100644 tests/Speckle.Objects.Tests.Unit/Assembly.cs create mode 100644 tests/Speckle.Sdk.Serialization.Tests/Assembly.cs delete mode 100644 tests/Speckle.Sdk.Tests.Integration/Usings.cs create mode 100644 tests/Speckle.Sdk.Tests.Unit/Assembly.cs create mode 100644 tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs create mode 100644 tests/Speckle.Sdk.Tests.Unit/Serialisation/PrimitiveTestFixture.cs diff --git a/Directory.Build.targets b/Directory.Build.targets index db7cc978..10e64e3a 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,6 +1,5 @@ - Recommended $(NoWarn); @@ -9,7 +8,6 @@ CA5394;CA2007;CA1852;CA1819;CA1711;CA1063;CA1816;CA2234;CS8618;CA1054;CA1810;CA2208;CA1019;CA1831; - false diff --git a/Directory.Packages.props b/Directory.Packages.props index f2acca28..322df41a 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,8 +1,9 @@ - + + @@ -10,24 +11,22 @@ - + - + - - - - + + diff --git a/src/Speckle.Sdk.Dependencies/Collections.cs b/src/Speckle.Sdk.Dependencies/Collections.cs index 457a9079..e391b3d6 100644 --- a/src/Speckle.Sdk.Dependencies/Collections.cs +++ b/src/Speckle.Sdk.Dependencies/Collections.cs @@ -9,3 +9,8 @@ public static class Collections public static IReadOnlyDictionary Freeze(this IDictionary source) where TKey : notnull => source.ToFrozenDictionary(); } + +public static class EnumerableExtensions +{ + public static IEnumerable RangeFrom(int from, int to) => Enumerable.Range(from, to - from + 1); +} diff --git a/tests/Speckle.Objects.Tests.Unit/Assembly.cs b/tests/Speckle.Objects.Tests.Unit/Assembly.cs new file mode 100644 index 00000000..a4bcec54 --- /dev/null +++ b/tests/Speckle.Objects.Tests.Unit/Assembly.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/ArcTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/ArcTests.cs index d6dc9d52..6c9627ff 100644 --- a/tests/Speckle.Objects.Tests.Unit/Geometry/ArcTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Geometry/ArcTests.cs @@ -1,87 +1,78 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Objects.Tests.Unit.Geometry; -[TestFixture, TestOf(typeof(Arc))] public class ArcTests { - private Plane TestPlaneCounterClockwise - { - get + private Plane TestPlaneCounterClockwise => + new() { - const string UNITS = Units.Meters; - return new() - { - origin = new Point(0, 0, 0, UNITS), - normal = new Vector(0, 0, 1, UNITS), - xdir = new Vector(1, 0, 0, UNITS), - ydir = new Vector(0, 1, 0, UNITS), - units = UNITS, - }; - } - } + origin = new Point(0, 0, 0, Units.Meters), + normal = new Vector(0, 0, 1, Units.Meters), + xdir = new Vector(1, 0, 0, Units.Meters), + ydir = new Vector(0, 1, 0, Units.Meters), + units = Units.Meters, + }; - private Plane TestPlaneClockwise - { - get + private Plane TestPlaneClockwise => + new() { - const string UNITS = Units.Meters; - return new() - { - origin = new Point(0, 0, 0, UNITS), - normal = new Vector(0, 0, -1, UNITS), - xdir = new Vector(-1, 0, 0, UNITS), - ydir = new Vector(0, 1, 0, UNITS), - units = UNITS, - }; - } - } + origin = new Point(0, 0, 0, Units.Meters), + normal = new Vector(0, 0, -1, Units.Meters), + xdir = new Vector(-1, 0, 0, Units.Meters), + ydir = new Vector(0, 1, 0, Units.Meters), + units = Units.Meters, + }; - [Test] + [Fact] public void CanCreateArc_HalfCircle_CounterClockwise() { - const string UNITS = Units.Meters; var counterClockwiseArc = new Arc() { plane = TestPlaneCounterClockwise, - startPoint = new Point(1, 0, 0, UNITS), - endPoint = new Point(-1, 0, 0, UNITS), - midPoint = new Point(0, 1, 0, UNITS), - units = UNITS, + startPoint = new Point(1, 0, 0, Units.Meters), + endPoint = new Point(-1, 0, 0, Units.Meters), + midPoint = new Point(0, 1, 0, Units.Meters), + units = Units.Meters, }; - Assert.That(Point.Distance(counterClockwiseArc.midPoint, new Point(0, 1, 0, UNITS)), Is.EqualTo(0).Within(0.0001)); - Assert.That( - Point.Distance(counterClockwiseArc.plane.origin, new Point(0, 0, 0, UNITS)), - Is.EqualTo(0).Within(0.0001) - ); - Assert.That(counterClockwiseArc.measure - Math.PI, Is.EqualTo(0).Within(0.0001)); - Assert.That(counterClockwiseArc.radius, Is.EqualTo(1).Within(0.0001)); - Assert.That(counterClockwiseArc.length, Is.EqualTo(Math.PI).Within(0.0001)); + Point.Distance(counterClockwiseArc.midPoint, new Point(0, 1, 0, Units.Meters)).Should().BeApproximately(0, 0.0001); + + Point + .Distance(counterClockwiseArc.plane.origin, new Point(0, 0, 0, Units.Meters)) + .Should() + .BeApproximately(0, 0.0001); + + (counterClockwiseArc.measure - Math.PI).Should().BeApproximately(0, 0.0001); + + counterClockwiseArc.radius.Should().BeApproximately(1, 0.0001); + + counterClockwiseArc.length.Should().BeApproximately(Math.PI, 0.0001); } - [Test] + [Fact] public void CanCreateArc_HalfCircle_Clockwise() { - const string UNITS = Units.Meters; - var counterClockwiseArc = new Arc() + var clockwiseArc = new Arc() { plane = TestPlaneClockwise, - endPoint = new Point(1, 0, 0, UNITS), - startPoint = new Point(-1, 0, 0, UNITS), - midPoint = new Point(0, 1, 0, UNITS), - units = UNITS, + endPoint = new Point(1, 0, 0, Units.Meters), + startPoint = new Point(-1, 0, 0, Units.Meters), + midPoint = new Point(0, 1, 0, Units.Meters), + units = Units.Meters, }; - Assert.That(Point.Distance(counterClockwiseArc.midPoint, new Point(0, 1, 0, UNITS)), Is.EqualTo(0).Within(0.0001)); - Assert.That( - Point.Distance(counterClockwiseArc.plane.origin, new Point(0, 0, 0, UNITS)), - Is.EqualTo(0).Within(0.0001) - ); - Assert.That(counterClockwiseArc.measure - Math.PI, Is.EqualTo(0).Within(0.0001)); - Assert.That(counterClockwiseArc.radius, Is.EqualTo(1).Within(0.0001)); - Assert.That(counterClockwiseArc.length, Is.EqualTo(Math.PI).Within(0.0001)); + Point.Distance(clockwiseArc.midPoint, new Point(0, 1, 0, Units.Meters)).Should().BeApproximately(0, 0.0001); + + Point.Distance(clockwiseArc.plane.origin, new Point(0, 0, 0, Units.Meters)).Should().BeApproximately(0, 0.0001); + + (clockwiseArc.measure - Math.PI).Should().BeApproximately(0, 0.0001); + + clockwiseArc.radius.Should().BeApproximately(1, 0.0001); + + clockwiseArc.length.Should().BeApproximately(Math.PI, 0.0001); } } diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/BoxTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/BoxTests.cs index 05a83663..79a73133 100644 --- a/tests/Speckle.Objects.Tests.Unit/Geometry/BoxTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Geometry/BoxTests.cs @@ -1,29 +1,23 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Objects.Tests.Unit.Geometry; -[TestFixture, TestOf(typeof(Box))] public class BoxTests { - private Plane TestPlane - { - get + private Plane TestPlane => + new() { - const string UNITS = Units.Meters; - return new() - { - origin = new Point(0, 0, 0, UNITS), - normal = new Vector(0, 0, 1, UNITS), - xdir = new Vector(1, 0, 0, UNITS), - ydir = new Vector(0, 1, 0, UNITS), - units = UNITS, - }; - } - } + origin = new Point(0, 0, 0, Units.Meters), + normal = new Vector(0, 0, 1, Units.Meters), + xdir = new Vector(1, 0, 0, Units.Meters), + ydir = new Vector(0, 1, 0, Units.Meters), + units = Units.Meters, + }; - [Test] + [Fact] public void CanCreateBox() { const string UNITS = Units.Meters; @@ -36,7 +30,10 @@ public void CanCreateBox() units = UNITS, }; - Assert.That(box.area, Is.EqualTo(2 * (2 * 4 + 2 * 6 + 4 * 6)).Within(0.0001)); - Assert.That(box.volume, Is.EqualTo(2 * 4 * 6).Within(0.0001)); + // Assert area + box.area.Should().BeApproximately(2 * (2 * 4 + 2 * 6 + 4 * 6), 0.0001); + + // Assert volume + box.volume.Should().BeApproximately(2 * 4 * 6, 0.0001); } } diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/CircleTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/CircleTests.cs index 12501ce8..07bfe533 100644 --- a/tests/Speckle.Objects.Tests.Unit/Geometry/CircleTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Geometry/CircleTests.cs @@ -1,10 +1,10 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Objects.Tests.Unit.Geometry; -[TestFixture, TestOf(typeof(Circle))] public class CircleTests { private Plane TestPlane @@ -12,7 +12,7 @@ private Plane TestPlane get { const string UNITS = Units.Meters; - return new() + return new Plane { origin = new Point(0, 0, 0, UNITS), normal = new Vector(0, 0, 1, UNITS), @@ -23,18 +23,19 @@ private Plane TestPlane } } - [Test] + [Fact] public void CanCreateCircle() { const string UNITS = Units.Meters; - var circle = new Circle() + var circle = new Circle { plane = TestPlane, radius = 5, units = UNITS, }; - Assert.That(circle.length, Is.EqualTo(2 * Math.PI * 5).Within(0.0001)); - Assert.That(circle.area, Is.EqualTo(Math.PI * 5 * 5).Within(0.0001)); + // Use Shouldly assertions + circle.length.Should().BeApproximately(2 * Math.PI * 5, 0.0001); + circle.area.Should().BeApproximately(Math.PI * 5 * 5, 0.0001); } } diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs index dae8dca6..bb5c9f6d 100644 --- a/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Geometry/MeshTests.cs @@ -1,35 +1,38 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Objects.Tests.Unit.Geometry; -[TestFixture, TestOf(typeof(Mesh))] public class MeshTests { - private static Mesh[] s_testCaseSource = { CreateBlenderStylePolygon(), CreateRhinoStylePolygon() }; + private static readonly Mesh[] TestCaseSource = { CreateBlenderStylePolygon(), CreateRhinoStylePolygon() }; - [Test, TestCaseSource(nameof(s_testCaseSource))] + [Theory] + [MemberData(nameof(GetTestCaseSource))] public void CanAlignVertices(Mesh inPolygon) { inPolygon.AlignVerticesWithTexCoordsByIndex(); - Assert.That(inPolygon.VerticesCount, Is.EqualTo(inPolygon.TextureCoordinatesCount)); + inPolygon.VerticesCount.Should().Be(inPolygon.TextureCoordinatesCount); var expectedPolygon = CreateRhinoStylePolygon(); - Assert.That(inPolygon.vertices, Is.EquivalentTo(expectedPolygon.vertices)); - Assert.That(inPolygon.faces, Is.EquivalentTo(expectedPolygon.faces)); - Assert.That(inPolygon.textureCoordinates, Is.EquivalentTo(expectedPolygon.textureCoordinates)); + inPolygon.vertices.Should().BeEquivalentTo(expectedPolygon.vertices); + inPolygon.faces.Should().BeEquivalentTo(expectedPolygon.faces); + inPolygon.textureCoordinates.Should().BeEquivalentTo(expectedPolygon.textureCoordinates); } + public static IEnumerable GetTestCaseSource() => TestCaseSource.Select(mesh => new object[] { mesh }); + private static Mesh CreateRhinoStylePolygon() { return new Mesh { - vertices = [0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0], - faces = [3, 0, 1, 2, 3, 3, 4, 5], - textureCoordinates = [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0], + vertices = new List { 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0 }, + faces = new List { 3, 0, 1, 2, 3, 3, 4, 5 }, + textureCoordinates = new List { 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, units = Units.Meters, }; } @@ -38,9 +41,9 @@ private static Mesh CreateBlenderStylePolygon() { return new Mesh { - vertices = [0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0], - faces = [3, 0, 1, 2, 3, 0, 2, 3], - textureCoordinates = [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0], + vertices = new List { 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, + faces = new List { 3, 0, 1, 2, 3, 0, 2, 3 }, + textureCoordinates = new List { 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, units = Units.Meters, }; } diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/PointTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/PointTests.cs index 18f518ba..eabe68c6 100644 --- a/tests/Speckle.Objects.Tests.Unit/Geometry/PointTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Geometry/PointTests.cs @@ -1,18 +1,18 @@ using System.Diagnostics.CodeAnalysis; -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Objects.Tests.Unit.Geometry; -[TestFixture, TestOf(typeof(Point))] public class PointTests { - [Test] + [Fact] [SuppressMessage( "Assertion", - "NUnit2010:Use EqualConstraint for better assertion messages in case of failure", - Justification = "Need to explicitly test equality operator" + "xUnit2013:Do not use equality check to assert boolean value", + Justification = "Explicit equality operator tests are necessary" )] public void TestNull() { @@ -20,35 +20,49 @@ public void TestNull() Point? b = null; Point c = new(0, 0, 0, Units.Meters); - Assert.Multiple(() => - { - Assert.That(a == b, Is.True); - Assert.That(a != b, Is.False); - Assert.That(b == a, Is.True); - Assert.That(b != a, Is.False); - - Assert.That(a == c, Is.False); - Assert.That(a != c, Is.True); - Assert.That(c == a, Is.False); - Assert.That(c != a, Is.True); - }); + a.Should().Be(b); + (a != b).Should().BeFalse(); + + b.Should().Be(a); + (b != a).Should().BeFalse(); + + (a == c).Should().BeFalse(); + (a != c).Should().BeTrue(); + + (c == a).Should().BeFalse(); + (c != a).Should().BeTrue(); } - [Test] - [TestCase(1, 1, 1, "m", 1, 1, 1, "m", ExpectedResult = true)] - [TestCase(1, 1, 1, "m", 0, 1, 1, "m", ExpectedResult = false)] - [TestCase(1, 1, 1, "m", 1, 0, 1, "m", ExpectedResult = false)] - [TestCase(1, 1, 1, "m", 1, 1, 0, "m", ExpectedResult = false)] - [TestCase(1, 1, 1, "", 1, 1, 1, "", ExpectedResult = true)] - [TestCase(1, 1, 1, null, 1, 1, 1, null, ExpectedResult = true)] - [TestCase(1, 1, 1, "m", 1, 1, 1, "meters", ExpectedResult = false)] - [TestCase(1, 1, 1, "m", 1, 1, 1, "M", ExpectedResult = false)] - // Units - public bool TestEqual(double x1, double y1, double z1, string units1, double x2, double y2, double z2, string units2) + //TODO: Should(). units be allowed to be string? + [Theory] + [InlineData(1, 1, 1, "m", 1, 1, 1, "m", true)] + [InlineData(1, 1, 1, "m", 0, 1, 1, "m", false)] + [InlineData(1, 1, 1, "m", 1, 0, 1, "m", false)] + [InlineData(1, 1, 1, "m", 1, 1, 0, "m", false)] + [InlineData(1, 1, 1, "", 1, 1, 1, "", false)] + [InlineData(1, 1, 1, null, 1, 1, 1, null, false)] + [InlineData(1, 1, 1, "m", 1, 1, 1, "meters", false)] + [InlineData(1, 1, 1, "m", 1, 1, 1, "M", false)] + public void TestEqual( + double x1, + double y1, + double z1, + string? units1, + double x2, + double y2, + double z2, + string? units2, + bool expectedResult + ) { + if (string.IsNullOrEmpty(units1) || string.IsNullOrEmpty(units2)) + { + expectedResult.Should().BeFalse(); + return; + } Point p1 = new(x1, y1, z1, units1); Point p2 = new(x2, y2, z2, units2); - return p1 == p2; + (p1 == p2).Should().Be(expectedResult); } } diff --git a/tests/Speckle.Objects.Tests.Unit/Geometry/TransformTests.cs b/tests/Speckle.Objects.Tests.Unit/Geometry/TransformTests.cs index 819d28a7..8581600c 100644 --- a/tests/Speckle.Objects.Tests.Unit/Geometry/TransformTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Geometry/TransformTests.cs @@ -1,100 +1,98 @@ -using System.Collections; -using NUnit.Framework; +using FluentAssertions; using Speckle.DoubleNumerics; using Speckle.Objects.Other; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Objects.Tests.Unit.Geometry; -[TestFixture, TestOf(typeof(Transform))] public class TransformTests { private const float FLOAT_TOLERANCE = 1e-6f; - [Test, TestCaseSource(nameof(TransformTestCases))] + [Theory] + [MemberData(nameof(TransformTestCases))] public void ArrayBackAndForth(Matrix4x4 data) { + // Arrange var start = new Transform() { matrix = data, units = Units.None }; + + // Act var asArr = Transform.CreateMatrix(start.ToArray()); var end = new Transform() { matrix = asArr, units = Units.None }; - Assert.That(end.matrix, Is.EqualTo(data)); + // Assert + end.matrix.Should().Be(data); } - [Test, TestCaseSource(nameof(TransformTestCases))] + [Theory] + [MemberData(nameof(TransformTestCases))] public void ConvertToUnits(Matrix4x4 data) { const float SF = 1000f; - var transpose = Matrix4x4.Transpose(data); //NOTE: Transform expects matrices transposed (translation in column 4) + // Arrange + var transpose = Matrix4x4.Transpose(data); // Transform expects matrices transposed (translation in column 4) var mm = Matrix4x4.Transpose( Transform.CreateMatrix( new Transform() { matrix = transpose, units = Units.Meters }.ConvertToUnits(Units.Millimeters) ) ); + // Act Matrix4x4.Decompose(data, out var ms, out var mr, out var mt); Matrix4x4.Decompose(mm, out var mms, out var mmr, out var mmt); - Assert.Multiple(() => - { - Assert.That(mms.X, Is.EqualTo(ms.X).Within(FLOAT_TOLERANCE), "Expect scale x to be unchanged"); - Assert.That(mms.Y, Is.EqualTo(ms.Y).Within(FLOAT_TOLERANCE), "Expect scale y to be unchanged"); - Assert.That(mms.Z, Is.EqualTo(ms.Z).Within(FLOAT_TOLERANCE), "Expect scale z to be unchanged"); + // Assert + mms.X.Should().BeApproximately(ms.X, FLOAT_TOLERANCE, "Expect scale x to be unchanged"); + mms.Y.Should().BeApproximately(ms.Y, FLOAT_TOLERANCE, "Expect scale y to be unchanged"); + mms.Z.Should().BeApproximately(ms.Z, FLOAT_TOLERANCE, "Expect scale z to be unchanged"); - Assert.That(Quaternion.Dot(mr, mmr), Is.LessThan(1).Within(FLOAT_TOLERANCE), "Expect rot x to be equivalent"); + Quaternion.Dot(mr, mmr).Should().BeLessThan(1 + FLOAT_TOLERANCE, "Expect rotation to be equivalent"); - Assert.That(mmt.X, Is.EqualTo(mt.X * SF).Within(FLOAT_TOLERANCE), $"Expect translation x to be scaled by {SF}"); - Assert.That(mmt.Y, Is.EqualTo(mt.Y * SF).Within(FLOAT_TOLERANCE), $"Expect translation y to be scaled by {SF}"); - Assert.That(mmt.Z, Is.EqualTo(mt.Z * SF).Within(FLOAT_TOLERANCE), $"Expect translation z to be scaled by {SF}"); - }); + mmt.X.Should().BeApproximately(mt.X * SF, FLOAT_TOLERANCE, $"Expect translation x to be scaled by {SF}"); + mmt.Y.Should().BeApproximately(mt.Y * SF, FLOAT_TOLERANCE, $"Expect translation y to be scaled by {SF}"); + mmt.Z.Should().BeApproximately(mt.Z * SF, FLOAT_TOLERANCE, $"Expect translation z to be scaled by {SF}"); } /// /// Set of TRS transforms (row dominant i.e. translation in row 4) /// All with non-negative scale and rotation (for ease of testing scale and rot independently) /// - /// - private static IEnumerable TransformTestCases() + public static IEnumerable TransformTestCases() { var t = new Vector3(128.128f, 255.255f, 512.512f); var r = Quaternion.CreateFromYawPitchRoll(1.9f, 0.6666667f, 0.5f); var s = new Vector3(123f, 32f, 0.5f); - yield return new TestCaseData(Matrix4x4.Identity).SetName("{m} Identity Matrix"); + yield return [Matrix4x4.Identity]; - yield return new TestCaseData(Matrix4x4.CreateTranslation(t)).SetName("{m} Translation Only (positive)"); + yield return [Matrix4x4.CreateTranslation(t)]; - yield return new TestCaseData(Matrix4x4.CreateTranslation(t * -Vector3.UnitX)).SetName("{m} Translation Only -X"); + yield return [Matrix4x4.CreateTranslation(t * -Vector3.UnitX)]; - yield return new TestCaseData(Matrix4x4.CreateTranslation(t * -Vector3.UnitY)).SetName("{m} Translation Only -Y"); + yield return [Matrix4x4.CreateTranslation(t * -Vector3.UnitY)]; - yield return new TestCaseData(Matrix4x4.CreateTranslation(t * -Vector3.UnitZ)).SetName("{m} Translation Only -Z"); + yield return [Matrix4x4.CreateTranslation(t * -Vector3.UnitZ)]; - yield return new TestCaseData(Matrix4x4.CreateTranslation(-t)).SetName("{m} Translation Only -XYZ "); + yield return [Matrix4x4.CreateTranslation(-t)]; - yield return new TestCaseData(Matrix4x4.CreateFromYawPitchRoll(0.5f, 0.0f, 0.0f)).SetName("{m} Rotation Only X "); + yield return [Matrix4x4.CreateFromYawPitchRoll(0.5f, 0.0f, 0.0f)]; - yield return new TestCaseData(Matrix4x4.CreateFromYawPitchRoll(0.0f, 0.5f, 0.0f)).SetName("{m} Rotation Only Y "); + yield return [Matrix4x4.CreateFromYawPitchRoll(0.0f, 0.5f, 0.0f)]; - yield return new TestCaseData(Matrix4x4.CreateFromYawPitchRoll(0.0f, 0.0f, 0.5f)).SetName("{m} Rotation Only Z "); + yield return [Matrix4x4.CreateFromYawPitchRoll(0.0f, 0.0f, 0.5f)]; - yield return new TestCaseData(Matrix4x4.CreateFromYawPitchRoll(0.5f, 0.5f, 0.5f)).SetName("{m} Rotation Only XYZ "); + yield return [Matrix4x4.CreateFromYawPitchRoll(0.5f, 0.5f, 0.5f)]; - yield return new TestCaseData(Matrix4x4.CreateFromQuaternion(r)).SetName("{m} Rotation Only"); + yield return [Matrix4x4.CreateFromQuaternion(r)]; - yield return new TestCaseData(Matrix4x4.Identity + Matrix4x4.CreateScale(s)).SetName("{m} Scale Only"); + yield return [Matrix4x4.Identity + Matrix4x4.CreateScale(s)]; - yield return new TestCaseData(Matrix4x4.CreateTranslation(t) + Matrix4x4.CreateFromQuaternion(r)).SetName( - "{m} Translation + Rotation" - ); + yield return [Matrix4x4.CreateTranslation(t) + Matrix4x4.CreateFromQuaternion(r)]; - yield return new TestCaseData( - Matrix4x4.CreateTranslation(t) + Matrix4x4.CreateFromQuaternion(r) + Matrix4x4.CreateScale(s) - ).SetName("{m} Translation + Rotation + Scale"); + yield return [Matrix4x4.CreateTranslation(t) + Matrix4x4.CreateFromQuaternion(r) + Matrix4x4.CreateScale(s)]; - yield return new TestCaseData( - Matrix4x4.CreateTranslation(t) + Matrix4x4.CreateFromQuaternion(r) + Matrix4x4.CreateScale(-s) - ).SetName("{m} Translation + Rotation + -Scale"); + yield return [Matrix4x4.CreateTranslation(t) + Matrix4x4.CreateFromQuaternion(r) + Matrix4x4.CreateScale(-s)]; } } diff --git a/tests/Speckle.Objects.Tests.Unit/ModelPropertySupportedTypes.cs b/tests/Speckle.Objects.Tests.Unit/ModelPropertySupportedTypes.cs index 7cb8639b..70287fc2 100644 --- a/tests/Speckle.Objects.Tests.Unit/ModelPropertySupportedTypes.cs +++ b/tests/Speckle.Objects.Tests.Unit/ModelPropertySupportedTypes.cs @@ -1,10 +1,11 @@ -using System.Drawing; -using NUnit.Framework; +using System.Drawing; +using FluentAssertions; using Speckle.DoubleNumerics; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; +using Xunit; namespace Speckle.Objects.Tests.Unit; @@ -15,8 +16,7 @@ namespace Speckle.Objects.Tests.Unit; /// public class ModelPropertySupportedTypes { - [SetUp] - public void Setup() + public ModelPropertySupportedTypes() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Speckle.Objects.Geometry.Arc).Assembly); @@ -62,7 +62,7 @@ public void Setup() typeof(Matrix4x4), }; - [Test] + [Fact] public void TestObjects() { foreach ((string _, Type type, List _) in TypeLoader.Types) @@ -72,19 +72,24 @@ public void TestObjects() foreach (var prop in members) { if (prop.PropertyType.IsAssignableTo(typeof(Base))) + { continue; + } + if (prop.PropertyType.IsEnum) + { continue; + } + if (prop.PropertyType.IsSZArray) + { continue; + } Type propType = prop.PropertyType; Type typeDef = propType.IsGenericType ? propType.GetGenericTypeDefinition() : propType; - Assert.That( - _allowedTypes, - Does.Contain(typeDef), - $"{typeDef} was not in allowedTypes. (Origin: {type}.{prop.Name})" - ); + + _allowedTypes.Should().Contain(typeDef, $"{typeDef} was not in allowedTypes. (Origin: {type}.{prop.Name})"); } } } diff --git a/tests/Speckle.Objects.Tests.Unit/ObjectBaseValidityTests.cs b/tests/Speckle.Objects.Tests.Unit/ObjectBaseValidityTests.cs index 99c985e9..e3eb68db 100644 --- a/tests/Speckle.Objects.Tests.Unit/ObjectBaseValidityTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/ObjectBaseValidityTests.cs @@ -1,23 +1,23 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Objects.Geometry.Autocad; using Speckle.Sdk.Host; using Speckle.Sdk.Models; +using Xunit; using Point = Speckle.Objects.Geometry.Point; namespace Speckle.Objects.Tests.Unit; public class ObjectBaseValidityTests { - [Test] + [Fact] public void TestThatTypeWithoutAttributeFails() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); } - [Test] + [Fact] public void InheritanceTest_Disallow() { var exception = Assert.Throws(() => @@ -25,19 +25,19 @@ public void InheritanceTest_Disallow() TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly, typeof(Test).Assembly); }); - exception.ShouldNotBeNull(); - exception.Message.ShouldBe( - "Speckle.Objects.Tests.Unit.ObjectBaseValidityTests+Test inherits from Base has no SpeckleTypeAttribute" - ); + exception.Should().NotBeNull(); + exception + .Message.Should() + .Be("Speckle.Objects.Tests.Unit.ObjectBaseValidityTests+Test inherits from Base has no SpeckleTypeAttribute"); } - [Test] + [Fact] public void InheritanceTest_Allow() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); var fullTypeString = TypeLoader.GetFullTypeString(typeof(AutocadPolycurve)); - fullTypeString.ShouldBe("Objects.Geometry.Polycurve:Objects.Geometry.Autocad.AutocadPolycurve"); + fullTypeString.Should().Be("Objects.Geometry.Polycurve:Objects.Geometry.Autocad.AutocadPolycurve"); } public class Test : Polycurve; diff --git a/tests/Speckle.Objects.Tests.Unit/Speckle.Objects.Tests.Unit.csproj b/tests/Speckle.Objects.Tests.Unit/Speckle.Objects.Tests.Unit.csproj index fb22cc63..ce38ab83 100644 --- a/tests/Speckle.Objects.Tests.Unit/Speckle.Objects.Tests.Unit.csproj +++ b/tests/Speckle.Objects.Tests.Unit/Speckle.Objects.Tests.Unit.csproj @@ -8,10 +8,10 @@ + - - - + + diff --git a/tests/Speckle.Objects.Tests.Unit/Utils/MeshTriangulationHelperTests.cs b/tests/Speckle.Objects.Tests.Unit/Utils/MeshTriangulationHelperTests.cs index c7582df0..2baaf8cf 100644 --- a/tests/Speckle.Objects.Tests.Unit/Utils/MeshTriangulationHelperTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Utils/MeshTriangulationHelperTests.cs @@ -1,17 +1,28 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Geometry; using Speckle.Objects.Utils; using Speckle.Sdk.Common; +using Speckle.Sdk.Dependencies; +using Xunit; namespace Speckle.Objects.Tests.Unit.Utils; -[TestFixture, TestOf(typeof(MeshTriangulationHelper))] public class MeshTriangulationHelperTests { - [Test] - public void PolygonTest([Range(3, 9)] int n, [Values] bool planar) + public static IEnumerable PolygonTestSource() { - //Test Setup + foreach (var x in EnumerableExtensions.RangeFrom(3, 9)) + { + yield return new object[] { x, true }; + yield return new object[] { x, false }; + } + } + + [Theory] + [MemberData(nameof(PolygonTestSource))] + public void PolygonTest(int n, bool planar) + { + // Test Setup List vertices = new(n) { 0, planar ? 0 : 1, 1 }; for (int i = 1; i < n; i++) { @@ -30,30 +41,30 @@ public void PolygonTest([Range(3, 9)] int n, [Values] bool planar) units = Units.Meters, }; - //Test + // Test mesh.TriangulateMesh(); - //Results + // Results int numExpectedTriangles = n - 2; int expectedFaceCount = numExpectedTriangles * 4; - Assert.That(mesh.faces, Has.Count.EqualTo(expectedFaceCount)); + mesh.faces.Count.Should().Be(expectedFaceCount); + for (int i = 0; i < expectedFaceCount; i += 4) { - Assert.That(mesh.faces[i], Is.EqualTo(3)); - Assert.That(mesh.faces.GetRange(i + 1, 3), Is.Unique); + mesh.faces[i].Should().Be(3); + mesh.faces.GetRange(i + 1, 3).Should().OnlyHaveUniqueItems(); } - Assert.That(mesh.faces, Is.SupersetOf(Enumerable.Range(0, n))); - - Assert.That(mesh.faces, Is.All.GreaterThanOrEqualTo(0)); - Assert.That(mesh.faces, Is.All.LessThan(Math.Max(n, 4))); + var range = EnumerableExtensions.RangeFrom(0, n).ToList(); + mesh.faces.Should().BeSubsetOf(range); + mesh.faces.Should().AllSatisfy(x => x.Should().BeGreaterThanOrEqualTo(0).And.BeLessThan(Math.Max(n, 4))); } - [Test] + [Fact] public void DoesntFlipNormals() { - //Test Setup + // Test Setup List vertices = new() { 0, 0, 0, 1, 0, 0, 1, 0, 1 }; List faces = new() { 3, 0, 1, 2 }; @@ -65,22 +76,26 @@ public void DoesntFlipNormals() units = Units.Meters, }; - //Test + // Test mesh.TriangulateMesh(); - //Results - + // Results List shift1 = faces; List shift2 = new() { 3, 1, 2, 0 }; List shift3 = new() { 3, 2, 0, 1 }; - Assert.That(mesh.faces, Is.AnyOf(shift1, shift2, shift3)); + new List[] { shift1, shift2, shift3 } + .Any(x => mesh.faces.SequenceEqual(x)) + .Should() + .BeTrue(); } - [Test] - public void PreserveQuads([Values] bool preserveQuads) + [Theory] + [InlineData(true)] + [InlineData(false)] + public void PreserveQuads(bool preserveQuads) { - //Test Setup + // Test Setup List vertices = new() { 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1 }; List faces = new() { 4, 0, 1, 2, 3 }; @@ -92,14 +107,14 @@ public void PreserveQuads([Values] bool preserveQuads) units = Units.Meters, }; - //Tests + // Tests mesh.TriangulateMesh(preserveQuads); - //Results + // Results int expectedN = preserveQuads ? 4 : 3; int expectedFaceCount = preserveQuads ? 5 : 8; - Assert.That(mesh.faces, Has.Count.EqualTo(expectedFaceCount)); - Assert.That(mesh.faces[0], Is.EqualTo(expectedN)); + mesh.faces.Count.Should().Be(expectedFaceCount); + mesh.faces[0].Should().Be(expectedN); } } diff --git a/tests/Speckle.Objects.Tests.Unit/Utils/ShallowCopyTests.cs b/tests/Speckle.Objects.Tests.Unit/Utils/ShallowCopyTests.cs index 47ea8580..d27962e1 100644 --- a/tests/Speckle.Objects.Tests.Unit/Utils/ShallowCopyTests.cs +++ b/tests/Speckle.Objects.Tests.Unit/Utils/ShallowCopyTests.cs @@ -1,16 +1,23 @@ using System.Collections; -using NUnit.Framework; +using FluentAssertions; using Speckle.Objects.Data; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; +using Speckle.Sdk.Host; using Speckle.Sdk.Models; +using Xunit; namespace Speckle.Objects.Tests.Unit.Utils; -[TestFixture] public class ShallowCopyTests { - [Test] + public ShallowCopyTests() + { + TypeLoader.Reset(); + TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); + } + + [Fact] public void CanShallowCopy_Wall() { const string UNITS = Units.Meters; @@ -37,6 +44,6 @@ public void CanShallowCopy_Wall() var shallow = ds.ShallowCopy(); var displayValue = (IList)shallow["displayValue"].NotNull(); - Assert.That(ds.displayValue, Has.Count.EqualTo(displayValue.Count)); + ds.displayValue.Count.Should().Be(displayValue.Count); } } diff --git a/tests/Speckle.Objects.Tests.Unit/packages.lock.json b/tests/Speckle.Objects.Tests.Unit/packages.lock.json index fcd06d85..0e91de90 100644 --- a/tests/Speckle.Objects.Tests.Unit/packages.lock.json +++ b/tests/Speckle.Objects.Tests.Unit/packages.lock.json @@ -4,9 +4,18 @@ "net8.0": { "altcover": { "type": "Direct", - "requested": "[8.9.3, )", - "resolved": "8.9.3", - "contentHash": "auKC+pDCkLjfhFkSRaAUBu25BOmlLSqucR7YBs/Lkbdc0XRuJoklWafs1KKp+M+VoJ1f0TeMS6B/FO5IeIcu7w==" + "requested": "[9.0.1, )", + "resolved": "9.0.1", + "contentHash": "aadciFNDT5bnylaYUkKal+s5hF7yU/lmZxImQWAlk1438iPqK1Uf79H5ylELpyLIU49HL5ql+tnWBihp3WVLCA==" + }, + "FluentAssertions": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "mTLbcU991EQ1SEmNbVBaGGGJy0YFzvGd1sYJGNZ07nlPKuyHSn1I22aeKzqQXgEiaKyRO6MSCto9eN9VxMwBdA==", + "dependencies": { + "System.Configuration.ConfigurationManager": "6.0.0" + } }, "GitVersion.MsBuild": { "type": "Direct", @@ -16,12 +25,12 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.11.1, )", - "resolved": "17.11.1", - "contentHash": "U3Ty4BaGoEu+T2bwSko9tWqWUOU16WzSFkq6U8zve75oRBMSLTBdMAZrVNNz1Tq12aCdDom9fcOcM9QZaFHqFg==", + "requested": "[17.12.0, )", + "resolved": "17.12.0", + "contentHash": "kt/PKBZ91rFCWxVIJZSgVLk+YR+4KxTuHf799ho8WNiK5ZQpJNAEZCAWX86vcKrs+DiYjiibpYKdGZP6+/N17w==", "dependencies": { - "Microsoft.CodeCoverage": "17.11.1", - "Microsoft.TestPlatform.TestHost": "17.11.1" + "Microsoft.CodeCoverage": "17.12.0", + "Microsoft.TestPlatform.TestHost": "17.12.0" } }, "Microsoft.SourceLink.GitHub": { @@ -34,53 +43,34 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, - "NUnit": { - "type": "Direct", - "requested": "[4.2.2, )", - "resolved": "4.2.2", - "contentHash": "mon0OPko28yZ/foVXrhiUvq1LReaGsBdziumyyYGxV/pOE4q92fuYeN+AF+gEU5pCjzykcdBt5l7xobTaiBjsg==" - }, - "NUnit3TestAdapter": { - "type": "Direct", - "requested": "[4.6.0, )", - "resolved": "4.6.0", - "contentHash": "R7e1+a4vuV/YS+ItfL7f//rG+JBvVeVLX4mHzFEZo4W1qEKl8Zz27AqvQSAqo+BtIzUCo4aAJMYa56VXS4hudw==" - }, "PolySharp": { "type": "Direct", "requested": "[1.15.0, )", "resolved": "1.15.0", "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g==" }, - "Shouldly": { - "type": "Direct", - "requested": "[4.2.1, )", - "resolved": "4.2.1", - "contentHash": "dKAKiSuhLKqD2TXwLKtqNg1nwzJcIKOOMncZjk9LYe4W+h+SCftpWdxwR79YZUIHMH+3Vu9s0s0UHNrgICLwRQ==", - "dependencies": { - "DiffEngine": "11.3.0", - "EmptyFiles": "4.4.0" - } - }, "Speckle.InterfaceGenerator": { "type": "Direct", "requested": "[0.9.6, )", "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "DiffEngine": { - "type": "Transitive", - "resolved": "11.3.0", - "contentHash": "k0ZgZqd09jLZQjR8FyQbSQE86Q7QZnjEzq1LPHtj1R2AoWO8sjV5x+jlSisL7NZAbUOI4y+7Bog8gkr9WIRBGw==", + "xunit": { + "type": "Direct", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", "dependencies": { - "EmptyFiles": "4.4.0", - "System.Management": "6.0.1" + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" } }, - "EmptyFiles": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "gwJEfIGS7FhykvtZoscwXj/XwW+mJY6UbAZk+qtLKFUGWC95kfKXnj8VkxsZQnWBxJemM/q664rGLN5nf+OHZw==" + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "HggUqjQJe8PtDxcP25Q+CnR6Lz4oX3GElhD9V4oU2+75x9HI6A6sxbfKGS4UwU4t4yJaS9fBmAuriz8bQApNjw==" }, "GraphQL.Client.Abstractions": { "type": "Transitive", @@ -110,8 +100,8 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "nPJqrcA5iX+Y0kqoT3a+pD/8lrW/V7ayqnEJQsTonSoPz59J8bmoQhcSN4G8+UJ64Hkuf0zuxnfuj2lkHOq4cA==" + "resolved": "17.12.0", + "contentHash": "4svMznBd5JM21JIG2xZKGNanAHNXplxf/kQDFfLHXQ3OnpJkayRK/TjacFjA+EYmoyuNXHo/sOETEfcYtAzIrA==" }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", @@ -176,21 +166,26 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "E2jZqAU6JeWEVsyOEOrSW1o1bpHLgb25ypvKNB/moBXPVsFYBPd/Jwi7OrYahG50J83LfHzezYI+GaEkpAotiA==", + "resolved": "17.12.0", + "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==", "dependencies": { "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "DnG+GOqJXO/CkoqlJWeDFTgPhqD/V6VqUIL3vINizCWZ3X+HshCtbbyDdSHQQEjrc2Sl/K3yaxX6s+5LFEdYuw==", + "resolved": "17.12.0", + "contentHash": "MiPEJQNyADfwZ4pJNpQex+t9/jOClBGMiCiVVFuELCMSX2nmNfvUor3uFVxNNCg30uxDP8JDYfPnMXQzsfzYyg==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.11.1", + "Microsoft.TestPlatform.ObjectModel": "17.12.0", "Newtonsoft.Json": "13.0.1" } }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "hqTM5628jSsQiv+HGpiq3WKBl2c8v1KZfby2J6Pr7pEPlK9waPdgEO6b8A/+/xn/yZ9ulv8HuqK71ONy2tg67A==" + }, "Newtonsoft.Json": { "type": "Transitive", "resolved": "13.0.1", @@ -226,22 +221,26 @@ "SQLitePCLRaw.core": "2.1.4" } }, - "System.CodeDom": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA==" - }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, - "System.Management": { + "System.Configuration.ConfigurationManager": { "type": "Transitive", - "resolved": "6.0.1", - "contentHash": "10J1D0h/lioojphfJ4Fuh5ZUThT/xOVHdV9roGBittKKNP2PMjrvibEdbVTGZcPra1399Ja3tqIJLyQrc5Wmhg==", + "resolved": "6.0.0", + "contentHash": "7T+m0kDSlIPTHIkPMIu6m6tV6qsMqJpvQWW2jIc2qi7sn40qxFo0q+7mEQAhMPXZHMKnWrnv47ntGlM/ejvw3g==", "dependencies": { - "System.CodeDom": "6.0.0" + "System.Security.Cryptography.ProtectedData": "6.0.0", + "System.Security.Permissions": "6.0.0" + } + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "NfuoKUiP2nUWwKZN6twGqXioIe1zVD0RIj2t976A+czLHr2nY454RwwXs6JU9Htc6mwqL6Dn/nEL3dpVf2jOhg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "6.0.0" } }, "System.Memory": { @@ -264,6 +263,73 @@ "resolved": "4.5.1", "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "rp1gMNEZpvx9vP0JW0oHLxlf8oSiQgtno77Y4PLUBjSiDYoD77Y8uXHr1Ea5XG4/pIKhqAdxZ8v8OTUtqo9PeQ==" + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "T/uuc7AklkDoxmcJ7LGkyX1CcSviZuLCa4jg3PekfJ7SU0niF0IVTXwUiNVP9DSpzou2PpxJ+eNY2IfDM90ZCg==", + "dependencies": { + "System.Security.AccessControl": "6.0.0", + "System.Windows.Extensions": "6.0.0" + } + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "IXoJOXIqc39AIe+CIR7koBtRGMiCt/LPM3lI+PELtDIy9XdyeSrwXFdWV9dzJ2Awl0paLWUaknLxFQ5HpHZUog==", + "dependencies": { + "System.Drawing.Common": "6.0.0" + } + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]" + } + }, "speckle.objects": { "type": "Project", "dependencies": { diff --git a/tests/Speckle.Sdk.Serialization.Tests/Assembly.cs b/tests/Speckle.Sdk.Serialization.Tests/Assembly.cs new file mode 100644 index 00000000..a4bcec54 --- /dev/null +++ b/tests/Speckle.Sdk.Serialization.Tests/Assembly.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/Speckle.Sdk.Serialization.Tests/BaseComparer.cs b/tests/Speckle.Sdk.Serialization.Tests/BaseComparer.cs index 6630f219..a7db9618 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/BaseComparer.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/BaseComparer.cs @@ -7,19 +7,34 @@ public class BaseComparer : IEqualityComparer public bool Equals(Base? x, Base? y) { if (ReferenceEquals(x, y)) + { return true; + } + if (x is null) + { return false; + } + if (y is null) + { return false; + } + Type type = x.GetType(); if (type != y.GetType()) + { return false; + } + var types = DynamicBaseMemberType.Instance | DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.SchemaIgnored; var membersX = x.GetMembers(types); var membersY = y.GetMembers(types); if (membersX.Count != membersY.Count) + { return false; + } + foreach (var kvp in membersX) { var propertyInfo = type.GetProperty(kvp.Key); @@ -28,7 +43,9 @@ public bool Equals(Base? x, Base? y) continue; } if (y[kvp.Key] != kvp.Value) + { return false; + } } return x.id == y.id && x.applicationId == y.applicationId; } diff --git a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs index 0448cb4a..28bc847f 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DetachedTests.cs @@ -1,8 +1,6 @@ using System.Collections.Concurrent; using System.Text; -using NUnit.Framework; -using Shouldly; -using Speckle.Newtonsoft.Json; +using FluentAssertions; using Speckle.Newtonsoft.Json.Linq; using Speckle.Objects.Geometry; using Speckle.Sdk.Host; @@ -12,19 +10,19 @@ using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.SQLite; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Serialization.Tests; public class DetachedTests { - [SetUp] - public void Setup() + public DetachedTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DetachedTests).Assembly, typeof(Polyline).Assembly); } - [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including obsolete ones) are returned")] public async Task CanSerialize_New_Detached() { var expectedJson = """ @@ -75,20 +73,22 @@ public async Task CanSerialize_New_Detached() new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true, true) ); - await process2.Serialize(@base, default).ConfigureAwait(false); + await process2.Serialize(@base, default); - objects.Count.ShouldBe(2); - objects.ContainsKey("9ff8efb13c62fa80f3d1c4519376ba13").ShouldBeTrue(); - objects.ContainsKey("d3dd4621b2f68c3058c2b9c023a9de19").ShouldBeTrue(); + objects.Count.Should().Be(2); + objects.ContainsKey("9ff8efb13c62fa80f3d1c4519376ba13").Should().BeTrue(); + objects.ContainsKey("d3dd4621b2f68c3058c2b9c023a9de19").Should().BeTrue(); JToken .DeepEquals(JObject.Parse(expectedJson), JObject.Parse(objects["9ff8efb13c62fa80f3d1c4519376ba13"])) - .ShouldBeTrue(); + .Should() + .BeTrue(); JToken .DeepEquals(JObject.Parse(detachedJson), JObject.Parse(objects["d3dd4621b2f68c3058c2b9c023a9de19"])) - .ShouldBeTrue(); + .Should() + .BeTrue(); } - [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including obsolete ones) are returned")] public void CanSerialize_Old_Detached() { var expectedJson = """ @@ -133,19 +133,24 @@ public void CanSerialize_Old_Detached() var serializer = new SpeckleObjectSerializer(new[] { new MemoryTransport(objects) }); var json = serializer.Serialize(@base); - objects.Count.ShouldBe(2); - objects.ContainsKey("9ff8efb13c62fa80f3d1c4519376ba13").ShouldBeTrue(); - objects.ContainsKey("d3dd4621b2f68c3058c2b9c023a9de19").ShouldBeTrue(); - JToken.DeepEquals(JObject.Parse(json), JObject.Parse(objects["9ff8efb13c62fa80f3d1c4519376ba13"])).ShouldBeTrue(); + objects.Count.Should().Be(2); + objects.ContainsKey("9ff8efb13c62fa80f3d1c4519376ba13").Should().BeTrue(); + objects.ContainsKey("d3dd4621b2f68c3058c2b9c023a9de19").Should().BeTrue(); + JToken + .DeepEquals(JObject.Parse(json), JObject.Parse(objects["9ff8efb13c62fa80f3d1c4519376ba13"])) + .Should() + .BeTrue(); JToken .DeepEquals(JObject.Parse(expectedJson), JObject.Parse(objects["9ff8efb13c62fa80f3d1c4519376ba13"])) - .ShouldBeTrue(); + .Should() + .BeTrue(); JToken .DeepEquals(JObject.Parse(detachedJson), JObject.Parse(objects["d3dd4621b2f68c3058c2b9c023a9de19"])) - .ShouldBeTrue(); + .Should() + .BeTrue(); } - [Test] + [Fact] public void GetPropertiesExpected_Detached() { var @base = new SampleObjectBase(); @@ -157,14 +162,14 @@ public void GetPropertiesExpected_Detached() var children = new BaseChildFinder(new BasePropertyGatherer()).GetChildProperties(@base).ToList(); - children.Count.ShouldBe(4); - children.First(x => x.Name == "detachedProp").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); - children.First(x => x.Name == "list").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); - children.First(x => x.Name == "arr").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); - children.First(x => x.Name == "@prop2").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); + children.Count.Should().Be(4); + children.First(x => x.Name == "detachedProp").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); + children.First(x => x.Name == "list").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); + children.First(x => x.Name == "arr").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); + children.First(x => x.Name == "@prop2").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); } - [Test] + [Fact] public void GetPropertiesExpected_All() { var @base = new SampleObjectBase(); @@ -176,20 +181,20 @@ public void GetPropertiesExpected_All() var children = new BasePropertyGatherer().ExtractAllProperties(@base).ToList(); - children.Count.ShouldBe(9); - children.First(x => x.Name == "dynamicProp").PropertyAttributeInfo.IsDetachable.ShouldBeFalse(); - children.First(x => x.Name == "attachedProp").PropertyAttributeInfo.IsDetachable.ShouldBeFalse(); - children.First(x => x.Name == "crazyProp").PropertyAttributeInfo.IsDetachable.ShouldBeFalse(); - children.First(x => x.Name == "speckle_type").PropertyAttributeInfo.IsDetachable.ShouldBeFalse(); - children.First(x => x.Name == "applicationId").PropertyAttributeInfo.IsDetachable.ShouldBeFalse(); - - children.First(x => x.Name == "detachedProp").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); - children.First(x => x.Name == "list").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); - children.First(x => x.Name == "arr").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); - children.First(x => x.Name == "@prop2").PropertyAttributeInfo.IsDetachable.ShouldBeTrue(); + children.Count.Should().Be(9); + children.First(x => x.Name == "dynamicProp").PropertyAttributeInfo.IsDetachable.Should().BeFalse(); + children.First(x => x.Name == "attachedProp").PropertyAttributeInfo.IsDetachable.Should().BeFalse(); + children.First(x => x.Name == "crazyProp").PropertyAttributeInfo.IsDetachable.Should().BeFalse(); + children.First(x => x.Name == "speckle_type").PropertyAttributeInfo.IsDetachable.Should().BeFalse(); + children.First(x => x.Name == "applicationId").PropertyAttributeInfo.IsDetachable.Should().BeFalse(); + + children.First(x => x.Name == "detachedProp").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); + children.First(x => x.Name == "list").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); + children.First(x => x.Name == "arr").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); + children.First(x => x.Name == "@prop2").PropertyAttributeInfo.IsDetachable.Should().BeTrue(); } - [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including obsolete ones) are returned")] public async Task CanSerialize_New_Detached2() { var root = """ @@ -267,17 +272,17 @@ public async Task CanSerialize_New_Detached2() new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true, true) ); - var results = await process2.Serialize(@base, default).ConfigureAwait(false); + var results = await process2.Serialize(@base, default); - objects.Count.ShouldBe(9); + objects.Count.Should().Be(9); var x = JObject.Parse(objects["2ebfd4f317754fce14cadd001151441e"]); - JToken.DeepEquals(JObject.Parse(root), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(root), x).Should().BeTrue(); - results.RootId.ShouldBe(@base.id); - results.ConvertedReferences.Count.ShouldBe(2); + results.RootId.Should().Be(@base.id); + results.ConvertedReferences.Count.Should().Be(2); } - [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including obsolete ones) are returned")] public async Task CanSerialize_New_Detached_With_DataChunks() { var root = """ @@ -340,20 +345,20 @@ public async Task CanSerialize_New_Detached_With_DataChunks() new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true, true) ); - var results = await process2.Serialize(@base, default).ConfigureAwait(false); + var results = await process2.Serialize(@base, default); - objects.Count.ShouldBe(3); + objects.Count.Should().Be(3); var x = JObject.Parse(objects["efeadaca70a85ae6d3acfc93a8b380db"]); - JToken.DeepEquals(JObject.Parse(root), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(root), x).Should().BeTrue(); x = JObject.Parse(objects["0e61e61edee00404ec6e0f9f594bce24"]); - JToken.DeepEquals(JObject.Parse(list1), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(list1), x).Should().BeTrue(); x = JObject.Parse(objects["f70738e3e3e593ac11099a6ed6b71154"]); - JToken.DeepEquals(JObject.Parse(list2), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(list2), x).Should().BeTrue(); } - [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including obsolete ones) are returned")] public async Task CanSerialize_New_Detached_With_DataChunks2() { var root = """ @@ -421,17 +426,17 @@ public async Task CanSerialize_New_Detached_With_DataChunks2() new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true, true) ); - var results = await process2.Serialize(@base, default).ConfigureAwait(false); + var results = await process2.Serialize(@base, default); - objects.Count.ShouldBe(3); + objects.Count.Should().Be(3); var x = JObject.Parse(objects["525b1e9eef4d07165abb4ffc518395fc"]); - JToken.DeepEquals(JObject.Parse(root), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(root), x).Should().BeTrue(); x = JObject.Parse(objects["0e61e61edee00404ec6e0f9f594bce24"]); - JToken.DeepEquals(JObject.Parse(list1), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(list1), x).Should().BeTrue(); x = JObject.Parse(objects["f70738e3e3e593ac11099a6ed6b71154"]); - JToken.DeepEquals(JObject.Parse(list2), x).ShouldBeTrue(); + JToken.DeepEquals(JObject.Parse(list2), x).Should().BeTrue(); } } diff --git a/tests/Speckle.Sdk.Serialization.Tests/DummyReceiveServerObjectManager.cs b/tests/Speckle.Sdk.Serialization.Tests/DummyReceiveServerObjectManager.cs index 797d7b67..fb4c09fb 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DummyReceiveServerObjectManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DummyReceiveServerObjectManager.cs @@ -1,6 +1,5 @@ using System.Runtime.CompilerServices; using System.Text; -using Speckle.Sdk.Dependencies.Serialization; using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Transports; diff --git a/tests/Speckle.Sdk.Serialization.Tests/DummySendServerObjectManager.cs b/tests/Speckle.Sdk.Serialization.Tests/DummySendServerObjectManager.cs index 0d8433fc..b0873527 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/DummySendServerObjectManager.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/DummySendServerObjectManager.cs @@ -1,8 +1,4 @@ using System.Collections.Concurrent; -using Shouldly; -using Speckle.Newtonsoft.Json.Linq; -using Speckle.Sdk.Common; -using Speckle.Sdk.Dependencies.Serialization; using Speckle.Sdk.Serialisation.V2; using Speckle.Sdk.Serialisation.V2.Send; using Speckle.Sdk.Transports; diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs index e90293de..63f77daf 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExplicitInterfaceTests.cs @@ -1,21 +1,21 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation.V2.Send; +using Xunit; namespace Speckle.Sdk.Serialization.Tests; public class ExplicitInterfaceTests { - [SetUp] - public void Setup() + // Constructor to replace [SetUp] + public ExplicitInterfaceTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(TestClass).Assembly); } - [Test] + [Fact] // Replaces [Test] public async Task Test_Json() { var testClass = new TestClass() { RegularProperty = "Hello" }; @@ -29,24 +29,28 @@ public async Task Test_Json() new ObjectSerializerFactory(new BasePropertyGatherer()), new SerializeProcessOptions(false, false, true, true) ); - await process2.Serialize(testClass, default).ConfigureAwait(false); - objects.Count.ShouldBe(1); + + await process2.Serialize(testClass, default); + + objects.Count.Should().Be(1); objects["daaa67cfd73a957247cf2d631b7ca4f3"] - .ShouldBe( + .Should() + .Be( "{\"RegularProperty\":\"Hello\",\"applicationId\":null,\"speckle_type\":\"Speckle.Core.Serialisation.TestClass\",\"id\":\"daaa67cfd73a957247cf2d631b7ca4f3\"}" ); } - [Test] + [Fact] // Replaces [Test] public void Test_ExtractAllProperties() { var testClass = new TestClass() { RegularProperty = "Hello" }; var gatherer = new BasePropertyGatherer(); var properties = gatherer.ExtractAllProperties(testClass).ToList(); - properties.Count.ShouldBe(3); - properties.Select(x => x.Name).ShouldContain("RegularProperty"); - properties.Select(x => x.Name).ShouldNotContain("TestProperty"); + + properties.Count.Should().Be(3); + properties.Select(x => x.Name).Should().Contain("RegularProperty"); + properties.Select(x => x.Name).Should().NotContain("TestProperty"); } } diff --git a/tests/Speckle.Sdk.Serialization.Tests/ExternalIdTests.cs b/tests/Speckle.Sdk.Serialization.Tests/ExternalIdTests.cs index 925d73f8..d3d7baed 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/ExternalIdTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/ExternalIdTests.cs @@ -1,5 +1,4 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Newtonsoft.Json.Linq; using Speckle.Objects.Geometry; using Speckle.Objects.Primitive; @@ -9,20 +8,20 @@ using Speckle.Sdk.Models.Extensions; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Serialisation.V2.Send; +using Xunit; namespace Speckle.Sdk.Serialization.Tests; public class ExternalIdTests { - [SetUp] - public void Setup() + public ExternalIdTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Polyline).Assembly); } - [Test] - [TestCase("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] + [Theory] + [InlineData("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] public void ExternalIdTest_Detached(string lineId, string valueId) { var p = new Polyline() { units = "cm", value = [1, 2] }; @@ -31,16 +30,16 @@ public void ExternalIdTest_Detached(string lineId, string valueId) default ); var list = serializer.Serialize(p).ToDictionary(x => x.Item1, x => x.Item2); - list.ContainsKey(new Id(lineId)).ShouldBeTrue(); + list.ContainsKey(new Id(lineId)).Should().BeTrue(); var json = list[new Id(lineId)]; var jObject = JObject.Parse(json.Value); - jObject.ContainsKey("__closure").ShouldBeTrue(); + jObject.ContainsKey("__closure").Should().BeTrue(); var closures = (JObject)jObject["__closure"].NotNull(); - closures.ContainsKey(valueId).ShouldBeTrue(); + closures.ContainsKey(valueId).Should().BeTrue(); } - [Test] - [TestCase("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] + [Theory] + [InlineData("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] public void ExternalIdTest_Detached_Nested(string lineId, string valueId) { var curve = new Curve() @@ -61,16 +60,16 @@ public void ExternalIdTest_Detached_Nested(string lineId, string valueId) default ); var list = serializer.Serialize(curve).ToDictionary(x => x.Item1, x => x.Item2); - list.ContainsKey(new Id(lineId)).ShouldBeTrue(); + list.ContainsKey(new Id(lineId)).Should().BeTrue(); var json = list[new Id(lineId)]; var jObject = JObject.Parse(json.Value); - jObject.ContainsKey("__closure").ShouldBeTrue(); + jObject.ContainsKey("__closure").Should().BeTrue(); var closures = (JObject)jObject["__closure"].NotNull(); - closures.ContainsKey(valueId).ShouldBeTrue(); + closures.ContainsKey(valueId).Should().BeTrue(); } - [Test] - [TestCase("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] + [Theory] + [InlineData("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] public void ExternalIdTest_Detached_Nested_More(string lineId, string valueId) { var curve = new Curve() @@ -92,16 +91,16 @@ public void ExternalIdTest_Detached_Nested_More(string lineId, string valueId) default ); var list = serializer.Serialize(polycurve).ToDictionary(x => x.Item1, x => x.Item2); - list.ContainsKey(new Id(lineId)).ShouldBeTrue(); + list.ContainsKey(new Id(lineId)).Should().BeTrue(); var json = list[new Id(lineId)]; var jObject = JObject.Parse(json.Value); - jObject.ContainsKey("__closure").ShouldBeTrue(); + jObject.ContainsKey("__closure").Should().BeTrue(); var closures = (JObject)jObject["__closure"].NotNull(); - closures.ContainsKey(valueId).ShouldBeTrue(); + closures.ContainsKey(valueId).Should().BeTrue(); } - [Test] - [TestCase("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] + [Theory] + [InlineData("cfaf7ae0dfc5a7cf3343bb6db46ed238", "8d27f5c7fac36d985d89bb6d6d8acddc")] public void ExternalIdTest_Detached_Nested_More_Too(string lineId, string valueId) { var curve = new Curve() @@ -125,11 +124,11 @@ public void ExternalIdTest_Detached_Nested_More_Too(string lineId, string valueI default ); var list = serializer.Serialize(@base).ToDictionary(x => x.Item1, x => x.Item2); - list.ContainsKey(new Id(lineId)).ShouldBeTrue(); + list.ContainsKey(new Id(lineId)).Should().BeTrue(); var json = list[new Id(lineId)]; var jObject = JObject.Parse(json.Value); - jObject.ContainsKey("__closure").ShouldBeTrue(); + jObject.ContainsKey("__closure").Should().BeTrue(); var closures = (JObject)jObject["__closure"].NotNull(); - closures.ContainsKey(valueId).ShouldBeTrue(); + closures.ContainsKey(valueId).Should().BeTrue(); } } diff --git a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs index 076730a2..c562fd08 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs +++ b/tests/Speckle.Sdk.Serialization.Tests/SerializationTests.cs @@ -1,8 +1,7 @@ using System.Collections.Concurrent; using System.IO.Compression; using System.Reflection; -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Newtonsoft.Json; using Speckle.Newtonsoft.Json.Linq; using Speckle.Objects.Data; @@ -13,11 +12,10 @@ using Speckle.Sdk.Serialisation.Utilities; using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Serialisation.V2.Send; +using Xunit; namespace Speckle.Sdk.Serialization.Tests; -[TestFixture] -[Description("For certain types, changing property from one type to another should be implicitly backwards compatible")] public class SerializationTests { private class TestLoader(string json) : IObjectLoader @@ -39,8 +37,7 @@ public void Dispose() { } private readonly Assembly _assembly = Assembly.GetExecutingAssembly(); - [SetUp] - public void Setup() + public SerializationTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DataObject).Assembly, _assembly); @@ -83,7 +80,7 @@ public async Task RunTest2(string fileName) var closure = await ReadAsObjects(json); using DeserializeProcess sut = new(null, new TestLoader(json), new TestTransport(closure)); var @base = await sut.Deserialize("551513ff4f3596024547fc818f1f3f70"); - @base.ShouldNotBeNull(); + @base.Should().NotBeNull(); }*/ public class TestObjectLoader(Dictionary idToObject) : IObjectLoader @@ -109,8 +106,8 @@ CancellationToken cancellationToken public void Dispose() { } } - [Test] - [TestCase("RevitObject.json.gz")] + [Theory] + [InlineData("RevitObject.json.gz")] public async Task Basic_Namespace_Validation(string fileName) { var fullName = _assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); @@ -127,32 +124,32 @@ public async Task Basic_Namespace_Validation(string fileName) var jObject = JObject.Parse(objJson); var oldSpeckleType = jObject["speckle_type"].NotNull().Value().NotNull(); var starts = oldSpeckleType.StartsWith("Speckle.Core.") || oldSpeckleType.StartsWith("Objects."); - starts.ShouldBeTrue($"{oldSpeckleType} isn't expected"); + starts.Should().BeTrue($"{oldSpeckleType} isn't expected"); var baseType = await deserializer.DeserializeAsync(objJson); - baseType.id.ShouldBe(id); + baseType.id.Should().Be(id); var oldType = TypeLoader.GetAtomicType(oldSpeckleType); if (oldType == typeof(Base)) { - oldSpeckleType.ShouldNotContain("Base"); + oldSpeckleType.Should().NotContain("Base"); } else { starts = baseType.speckle_type.StartsWith("Speckle.Core.") || baseType.speckle_type.StartsWith("Objects."); - starts.ShouldBeTrue($"{baseType.speckle_type} isn't expected"); + starts.Should().BeTrue($"{baseType.speckle_type} isn't expected"); var type = TypeLoader.GetAtomicType(baseType.speckle_type); - type.ShouldNotBeNull(); + type.Should().NotBeNull(); var name = TypeLoader.GetTypeString(type) ?? throw new ArgumentNullException($"Could not find: {type}"); starts = name.StartsWith("Speckle.Core") || name.StartsWith("Objects"); - starts.ShouldBeTrue($"{name} isn't expected"); + starts.Should().BeTrue($"{name} isn't expected"); } } } - [Test] - [TestCase("RevitObject.json.gz")] + [Theory] + [InlineData("RevitObject.json.gz")] public async Task Basic_Namespace_Validation_New(string fileName) { var fullName = _assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); @@ -165,33 +162,34 @@ public async Task Basic_Namespace_Validation_New(string fileName) var jObject = JObject.Parse(objJson); var oldSpeckleType = jObject["speckle_type"].NotNull().Value().NotNull(); var starts = oldSpeckleType.StartsWith("Speckle.Core.") || oldSpeckleType.StartsWith("Objects."); - starts.ShouldBeTrue($"{oldSpeckleType} isn't expected"); + starts.Should().BeTrue($"{oldSpeckleType} isn't expected"); var oldType = TypeLoader.GetAtomicType(oldSpeckleType); if (oldType == typeof(Base)) { - oldSpeckleType.ShouldNotContain("Base"); + oldSpeckleType.Should().NotContain("Base"); } else { var baseType = process.BaseCache[id]; starts = baseType.speckle_type.StartsWith("Speckle.Core.") || baseType.speckle_type.StartsWith("Objects."); - starts.ShouldBeTrue($"{baseType.speckle_type} isn't expected"); + starts.Should().BeTrue($"{baseType.speckle_type} isn't expected"); var type = TypeLoader.GetAtomicType(baseType.speckle_type); - type.ShouldNotBeNull(); + type.Should().NotBeNull(); var name = TypeLoader.GetTypeString(type) ?? throw new ArgumentNullException(); starts = name.StartsWith("Speckle.Core") || name.StartsWith("Objects"); - starts.ShouldBeTrue($"{name} isn't expected"); + starts.Should().BeTrue($"{name} isn't expected"); } } } - [TestCase( + [Theory] + [InlineData( "{\"applicationId\":null,\"speckle_type\":\"Base\",\"IFC_GUID\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcGUID\",\"units\":null,\"value\":\"18HX_ys0P5uu77f1wwA7bn\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_GUID\",\"id\":\"1f4e29b7198e25221300c684876ec187\"},\"DOOR_COST\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Cost\",\"units\":\"\u0e3f\",\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:currency-1.0.0\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"DOOR_COST\",\"id\":\"80ff4c5df5170b75916a873a394cfbdf\"},\"ALL_MODEL_URL\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"URL\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_URL\",\"id\":\"140c53fcea5deaa35115b23cd2ba48c6\"},\"IFC_TYPE_GUID\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type IfcGUID\",\"units\":null,\"value\":\"0w69BRwHvBsBXN3bEBjQin\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_TYPE_GUID\",\"id\":\"99d5d914df5c50c879e73c50246a9249\"},\"KEYNOTE_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Keynote\",\"units\":null,\"value\":\"S0905\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"KEYNOTE_PARAM\",\"id\":\"c2272311800b04ab4d2b0052df68ecdc\"},\"PHASE_CREATED\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Phase Created\",\"units\":null,\"value\":\"0\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"PHASE_CREATED\",\"id\":\"72ecbbd5d29ea1b48df89d8f88b29120\"},\"ALL_MODEL_MARK\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Mark\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_MARK\",\"id\":\"f2e0ed6ebfbab4d4780c5143b774558e\"},\"FUNCTION_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Function\",\"units\":null,\"value\":0,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"FUNCTION_PARAM\",\"id\":\"a43000484f3fa3c5cf60a2ccd79a573c\"},\"UNIFORMAT_CODE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Assembly Code\",\"units\":null,\"value\":\"\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"UNIFORMAT_CODE\",\"id\":\"b797bb20d49af57eecbe718df4ebd411\"},\"WINDOW_TYPE_ID\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Mark\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"WINDOW_TYPE_ID\",\"id\":\"d74f026a13a539bd24369ea78b34aa6b\"},\"ALL_MODEL_IMAGE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Image\",\"units\":null,\"value\":\"-1\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_IMAGE\",\"id\":\"4ef25c5fcd2ee32d9b3d6ce9b1047904\"},\"ALL_MODEL_MODEL\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Model\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_MODEL\",\"id\":\"13597261389f532c0778e134623eff85\"},\"CLEAR_COVER_TOP\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Rebar Cover - Top Face\",\"units\":null,\"value\":\"95743\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"CLEAR_COVER_TOP\",\"id\":\"ed5f5e056314ee8435a1658a54261e94\"},\"ELEM_TYPE_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type\",\"units\":null,\"value\":\"5432827\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ELEM_TYPE_PARAM\",\"id\":\"e502cb5aed1fda357926c7ca9927c42c\"},\"RELATED_TO_MASS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Related to Mass\",\"units\":null,\"value\":false,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"RELATED_TO_MASS\",\"id\":\"a43b8424564b8f14738f4dbaa78be150\"},\"SYMBOL_ID_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Id\",\"units\":null,\"value\":\"5432827\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"SYMBOL_ID_PARAM\",\"id\":\"1947cb98e61f79da57f573a3a785b436\"},\"DESIGN_OPTION_ID\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Design Option\",\"units\":null,\"value\":\"-1\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"DESIGN_OPTION_ID\",\"id\":\"cf30f731c41543dd134a4877fbdab105\"},\"PHASE_DEMOLISHED\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Phase Demolished\",\"units\":null,\"value\":\"-1\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"PHASE_DEMOLISHED\",\"id\":\"47066bac7728f9b93f4acdb697284a59\"},\"CLEAR_COVER_OTHER\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Rebar Cover - Other Faces\",\"units\":null,\"value\":\"95743\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"CLEAR_COVER_OTHER\",\"id\":\"1afe7d22a897aff809bd92aea1acafd2\"},\"ELEM_FAMILY_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Family\",\"units\":null,\"value\":\"5432827\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ELEM_FAMILY_PARAM\",\"id\":\"ec3a159572a58b85b3a3650e5cc23e90\"},\"CLEAR_COVER_BOTTOM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Rebar Cover - Bottom Face\",\"units\":null,\"value\":\"95743\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"CLEAR_COVER_BOTTOM\",\"id\":\"476161776fc4c6ceb3c544c792a08120\"},\"HOST_AREA_COMPUTED\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Area\",\"units\":\"m\u00b2\",\"value\":7.128858225722908,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:squareMeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"HOST_AREA_COMPUTED\",\"id\":\"5e7567fea07a98c0cdd4903cabd897a3\"},\"IFC_EXPORT_ELEMENT\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Export to IFC\",\"units\":null,\"value\":0,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_EXPORT_ELEMENT\",\"id\":\"7de623e201f3fcfb16dbcacefe7f8403\"},\"totalChildrenCount\":0,\"ALL_MODEL_TYPE_NAME\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Name\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_TYPE_NAME\",\"id\":\"4699f3fc2fd4e84cc3b6296ded7225b5\"},\"DESIGN_OPTION_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Design Option\",\"units\":null,\"value\":\"Main Model\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"DESIGN_OPTION_PARAM\",\"id\":\"771449eae7f2fb96345b165954b2c797\"},\"ELEM_CATEGORY_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Category\",\"units\":null,\"value\":\"-2000032\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ELEM_CATEGORY_PARAM\",\"id\":\"fb0b948f7360b9415ea9ede20fb3cdd2\"},\"ALL_MODEL_TYPE_IMAGE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Image\",\"units\":null,\"value\":\"-1\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_TYPE_IMAGE\",\"id\":\"4c95be61c11f5609f1fa649804bf9814\"},\"ANALYTICAL_ROUGHNESS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Roughness\",\"units\":null,\"value\":1,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ANALYTICAL_ROUGHNESS\",\"id\":\"eab64895ad089cf272ae6a7431f4cdac\"},\"HOST_VOLUME_COMPUTED\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Volume\",\"units\":\"m\u00b3\",\"value\":1.413211687704679,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:cubicMeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"HOST_VOLUME_COMPUTED\",\"id\":\"4cac83d2757bc70d7e1f299de124d028\"},\"SCHEDULE_LEVEL_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Level\",\"units\":null,\"value\":\"1100600\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"SCHEDULE_LEVEL_PARAM\",\"id\":\"d0ab715757ddbaedf5dc2df0726ed38c\"},\"ALL_MODEL_DESCRIPTION\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Description\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_DESCRIPTION\",\"id\":\"4abdaadbe23c12c349c65abcd5979f56\"},\"IFC_EXPORT_ELEMENT_AS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Export to IFC As\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_EXPORT_ELEMENT_AS\",\"id\":\"ccacac43b32ffd10c88a870492f98f96\"},\"UNIFORMAT_DESCRIPTION\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Assembly Description\",\"units\":null,\"value\":\"\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"UNIFORMAT_DESCRIPTION\",\"id\":\"abfe7173561e8b86cae8aa8dc34743d1\"},\"ALL_MODEL_MANUFACTURER\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Manufacturer\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_MANUFACTURER\",\"id\":\"e280ae740be9133f1001f218a137bb2f\"},\"ANALYTICAL_ABSORPTANCE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Absorptance\",\"units\":null,\"value\":0.1,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ANALYTICAL_ABSORPTANCE\",\"id\":\"e1618d04224fb3e11e650f8854e5eddb\"},\"ELEM_CATEGORY_PARAM_MT\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Category\",\"units\":null,\"value\":\"-2000032\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ELEM_CATEGORY_PARAM_MT\",\"id\":\"d4119e43880a3cc8632a137d4f3372ae\"},\"ALL_MODEL_TYPE_COMMENTS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Comments\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_TYPE_COMMENTS\",\"id\":\"8ea15d6198e1f5c632df36270be5433e\"},\"ANALYTICAL_THERMAL_MASS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Thermal Mass\",\"units\":\"kJ/(m\u00b2·K)\",\"value\":null,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:kilojoulesPerSquareMeterKelvin-1.0.0\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ANALYTICAL_THERMAL_MASS\",\"id\":\"d8b711b81d9e0ad7f072b60b69bd0239\"},\"HOST_PERIMETER_COMPUTED\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Perimeter\",\"units\":\"mm\",\"value\":11098.801755409942,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"HOST_PERIMETER_COMPUTED\",\"id\":\"eb73365794668bf73b3ffd2c80162ee1\"},\"IFC_EXPORT_ELEMENT_TYPE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Export Type to IFC\",\"units\":null,\"value\":0,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_EXPORT_ELEMENT_TYPE\",\"id\":\"0a96867bd313e951c229fb92b346b516\"},\"WALL_ATTR_ROOM_BOUNDING\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Room Bounding\",\"units\":null,\"value\":true,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"WALL_ATTR_ROOM_BOUNDING\",\"id\":\"fdf5bd19ac0a9f2878323c71e4ae80ea\"},\"FLOOR_STRUCTURE_ID_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Structure\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"FLOOR_STRUCTURE_ID_PARAM\",\"id\":\"43b858d8cfaf2bd27cb0b466dc6d425b\"},\"SYMBOL_FAMILY_NAME_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Family Name\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"SYMBOL_FAMILY_NAME_PARAM\",\"id\":\"d96f492f43f2b0e11ce86d66c23caf0f\"},\"IFC_EXPORT_PREDEFINEDTYPE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IFC Predefined Type\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_EXPORT_PREDEFINEDTYPE\",\"id\":\"b927074616bc0e6e323b52a99867b907\"},\"STRUCTURAL_MATERIAL_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Structural Material\",\"units\":null,\"value\":\"215194\",\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_MATERIAL_PARAM\",\"id\":\"1f7ffc00602d1944892885d68dff8867\"},\"ELEM_FAMILY_AND_TYPE_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Family and Type\",\"units\":null,\"value\":\"5432827\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ELEM_FAMILY_AND_TYPE_PARAM\",\"id\":\"9d58f36db73c0c248a6db682a6c6a6a0\"},\"FLOOR_ATTR_THICKNESS_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Thickness\",\"units\":\"mm\",\"value\":200,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"FLOOR_ATTR_THICKNESS_PARAM\",\"id\":\"22c96d409372e700936805b825b574e6\"},\"IFC_EXPORT_ELEMENT_TYPE_AS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Export Type to IFC As\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_EXPORT_ELEMENT_TYPE_AS\",\"id\":\"41a53fec385581b6af53942aff3cd2d3\"},\"ALL_MODEL_INSTANCE_COMMENTS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Comments\",\"units\":null,\"value\":\"\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ALL_MODEL_INSTANCE_COMMENTS\",\"id\":\"ca8cdcc0b3fd824a34dcb42749151cd1\"},\"STRUCTURAL_ELEVATION_AT_TOP\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elevation at Top\",\"units\":\"mm\",\"value\":21099.999999999898,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_ELEVATION_AT_TOP\",\"id\":\"b1f293a63ff03c0c7456f8ba7b703f4f\"},\"FLOOR_HEIGHTABOVELEVEL_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Height Offset From Level\",\"units\":\"mm\",\"value\":-100,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"FLOOR_HEIGHTABOVELEVEL_PARAM\",\"id\":\"312773813c84648fc5ff2d78a8d8d8bc\"},\"ANALYTICAL_THERMAL_RESISTANCE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Thermal Resistance (R)\",\"units\":\"(m\u00b2·K)/W\",\"value\":null,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:squareMeterKelvinsPerWatt-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ANALYTICAL_THERMAL_RESISTANCE\",\"id\":\"fcfa5d36d656d4f8ca2b883a17c310b8\"},\"IFC_EXPORT_PREDEFINEDTYPE_TYPE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type IFC Predefined Type\",\"units\":null,\"value\":null,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"IFC_EXPORT_PREDEFINEDTYPE_TYPE\",\"id\":\"ac166cbccbcd8335272956f09d8d5d42\"},\"STRUCTURAL_ELEVATION_AT_BOTTOM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elevation at Bottom\",\"units\":\"mm\",\"value\":20899.9999999999,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_ELEVATION_AT_BOTTOM\",\"id\":\"d9e8f0e4b57b00ca99d13df99ea6ac26\"},\"COARSE_SCALE_FILL_PATTERN_COLOR\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Coarse Scale Fill Color\",\"units\":null,\"value\":0,\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"COARSE_SCALE_FILL_PATTERN_COLOR\",\"id\":\"854d889fd71071f3b81d0e06f7f1095c\"},\"STRUCTURAL_FLOOR_CORE_THICKNESS\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Core Thickness\",\"units\":\"mm\",\"value\":199.99999999999784,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_FLOOR_CORE_THICKNESS\",\"id\":\"6fb6fb65a394c5c68d5a760289c1129d\"},\"STRUCTURAL_ELEVATION_AT_TOP_CORE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elevation at Top Core\",\"units\":\"mm\",\"value\":21099.999999999898,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_ELEVATION_AT_TOP_CORE\",\"id\":\"aed8eedfb2527594e14ae4e5f74fb5c1\"},\"ANALYTICAL_ELEMENT_HAS_ASSOCIATION\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Has Association\",\"units\":null,\"value\":true,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ANALYTICAL_ELEMENT_HAS_ASSOCIATION\",\"id\":\"c9a6f771f05ef6072100c59c672dfb77\"},\"COARSE_SCALE_FILL_PATTERN_ID_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Coarse Scale Fill Pattern\",\"units\":null,\"value\":\"-1\",\"isShared\":false,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"COARSE_SCALE_FILL_PATTERN_ID_PARAM\",\"id\":\"1d271f4d80ffe772f9f8896971050ccc\"},\"FLOOR_ATTR_DEFAULT_THICKNESS_PARAM\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Default Thickness\",\"units\":\"mm\",\"value\":200,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"FLOOR_ATTR_DEFAULT_THICKNESS_PARAM\",\"id\":\"271b8b7f7e29c45065c1ccaa1095b32e\"},\"STRUCTURAL_ELEVATION_AT_TOP_SURVEY\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elevation at Top Survey\",\"units\":\"mm\",\"value\":30899.999999999894,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_ELEVATION_AT_TOP_SURVEY\",\"id\":\"8f2b9f55e373736263d14002838194b4\"},\"STRUCTURAL_ELEVATION_AT_BOTTOM_CORE\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elevation at Bottom Core\",\"units\":\"mm\",\"value\":20899.9999999999,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_ELEVATION_AT_BOTTOM_CORE\",\"id\":\"7a0b7e496383d08605ccb8c776cedbbf\"},\"02b58af4-afcd-404b-9011-3a25d6816e1b\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"ClassificationCode\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"02b58af4-afcd-404b-9011-3a25d6816e1b\",\"id\":\"141f6b021c701e5b4b4ee430652f7f91\"},\"042673e7-8ac4-413d-a393-e0785fbf8889\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 3\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"042673e7-8ac4-413d-a393-e0785fbf8889\",\"id\":\"f415ff5c972f45d7e0090b0849c54677\"},\"07afa150-f11f-40a1-a173-7a77ea32cf96\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 6\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"07afa150-f11f-40a1-a173-7a77ea32cf96\",\"id\":\"0e3acdf0b385d32d68caa8753c710849\"},\"07b6cf99-a3d2-4d7a-9ea4-246058cfae1a\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Classification.OmniClass.22.Description\",\"units\":null,\"value\":\"High-Tolerance Concrete Floor Finishing\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"07b6cf99-a3d2-4d7a-9ea4-246058cfae1a\",\"id\":\"8957914412a138b6255452dd485a25bd\"},\"082d16bb-7cf9-4968-ac22-b6f6ae068028\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcName\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"082d16bb-7cf9-4968-ac22-b6f6ae068028\",\"id\":\"f313bddfb2c5cf9f825ee6653021b04e\"},\"087f96a5-2dd2-42bb-a170-c22485216c09\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Element Condition\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"087f96a5-2dd2-42bb-a170-c22485216c09\",\"id\":\"8665b9cec7a39bffa030e6b415f78fa9\"},\"098e8d4f-1431-49e8-8ef6-69516cf72354\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"3D Model Element GUID\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"098e8d4f-1431-49e8-8ef6-69516cf72354\",\"id\":\"b81c608ec3bd9aa08ea1a2c5a2cea206\"},\"0a004b99-d4e6-4db6-8c88-9b77da33f012\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcDescription\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"0a004b99-d4e6-4db6-8c88-9b77da33f012\",\"id\":\"79b720b93988fd7840213380399408dd\"},\"0bf3a5d2-06c0-4b6c-9ba1-6985ef40c2b0\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 6\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"0bf3a5d2-06c0-4b6c-9ba1-6985ef40c2b0\",\"id\":\"622eab526502ce2a848c4aa932554f96\"},\"0c273fd8-260b-4f34-996e-921fa14a47fc\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 4\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"0c273fd8-260b-4f34-996e-921fa14a47fc\",\"id\":\"f70edec21839dfc410d94659d18d52c2\"},\"11f34dfe-4592-4c86-a455-2f020d9376e8\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"ClassificationCode\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"11f34dfe-4592-4c86-a455-2f020d9376e8\",\"id\":\"cd817060f1920a0194139bf2cdddecd4\"},\"12e4c976-0b76-4735-8664-e882b410ac7e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon A1\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"12e4c976-0b76-4735-8664-e882b410ac7e\",\"id\":\"0d2df557e73500e0c3d72c527d4c36fe\"},\"1336888e-1fed-4e9e-b74b-794bff5b6046\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"GrossArea(BaseQuantities)\",\"units\":\"m\u00b2\",\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:squareMeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"1336888e-1fed-4e9e-b74b-794bff5b6046\",\"id\":\"7e0f5932a6c5ad37872436b3ed0cf07b\"},\"15212817-1c39-4c7f-bae4-436acd0e4598\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcDescription\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"15212817-1c39-4c7f-bae4-436acd0e4598\",\"id\":\"f2bba2dcccf5786df17c279367baab39\"},\"18a3daed-8579-45e2-97a0-412159986104\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 8\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"18a3daed-8579-45e2-97a0-412159986104\",\"id\":\"173b9745cf4e7cc4b67748c5a03acf04\"},\"18ab825f-ba4c-4a8f-b509-5ddd7c378267\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Item\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"18ab825f-ba4c-4a8f-b509-5ddd7c378267\",\"id\":\"2c130ba41bf9797a0e7e64315695dd7b\"},\"1948bc31-5a23-482a-b337-4bd1fce08aec\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Renovation Status(AC_Pset_RenovationAndPhasing)\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"1948bc31-5a23-482a-b337-4bd1fce08aec\",\"id\":\"59b7e7b981f77ff4e7b01e7d794234f9\"},\"1d9a0983-608b-4aed-b03f-f27e8e0e677a\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B3\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"1d9a0983-608b-4aed-b03f-f27e8e0e677a\",\"id\":\"ec604873c2b3c4d53f5ea9c2e203fc70\"},\"219c8c15-4722-4b40-9e19-7fbbddeee30f\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 1\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"219c8c15-4722-4b40-9e19-7fbbddeee30f\",\"id\":\"abc83e3214698cefe7bbd9326b536b1d\"},\"226b84c2-b3b5-4a04-93f7-9523a21ef4e0\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Discipline\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"226b84c2-b3b5-4a04-93f7-9523a21ef4e0\",\"id\":\"f0e8a4a841062c6b5517b30002fd2325\"},\"244a8c27-edd6-4b09-8905-4cf403c61235\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Schedule Type Code/Number\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"244a8c27-edd6-4b09-8905-4cf403c61235\",\"id\":\"1ff35615eaa5e568fdb3c7c1bb21b72a\"},\"2cbf5041-2b36-4c7f-b65e-439af251d9f7\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Unique Asset ID - Equipment Type\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"2cbf5041-2b36-4c7f-b65e-439af251d9f7\",\"id\":\"1339498cfd39967f51d7d5a31feba974\"},\"2eac0fd8-0c8a-4c5a-9d54-62415d708f37\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elemental Code\",\"units\":null,\"value\":\"UFSB\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"2eac0fd8-0c8a-4c5a-9d54-62415d708f37\",\"id\":\"e20483f71786c3e27291a3eeaa049b48\"},\"2f1ef0a4-09a2-4e80-ba30-57984a475e1d\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Unique Asset ID\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"2f1ef0a4-09a2-4e80-ba30-57984a475e1d\",\"id\":\"d083dfba92681370be68f19d761a9628\"},\"2fb9b7d9-d0b0-4ce2-bbc0-02464fda354c\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon C1\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"2fb9b7d9-d0b0-4ce2-bbc0-02464fda354c\",\"id\":\"71196d8fbc135c7386841bb439f8aaee\"},\"3490690f-a8be-46d9-9607-47c255e9ee89\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcExportAs [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"3490690f-a8be-46d9-9607-47c255e9ee89\",\"id\":\"cf2c87ffe9b6babcd2659d619fe3a4b7\"},\"35064971-5814-4b17-b572-49ea1320c516\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 7\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"35064971-5814-4b17-b572-49ea1320c516\",\"id\":\"ecf761dcb34a3e098f355f401eec5738\"},\"36d9a077-9301-47a0-b049-4f29e17d51dd\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcExportAs [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"36d9a077-9301-47a0-b049-4f29e17d51dd\",\"id\":\"f547ba1d204747353092fccb1970b8ee\"},\"392cae56-cd6b-4946-817f-242686e12441\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Zone\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"392cae56-cd6b-4946-817f-242686e12441\",\"id\":\"37152ed7e04c0ea23c442aad0be9a611\"},\"3c3d55ea-8a2f-41c1-97fd-d222d586b0b1\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Omniclass Classification Type Code\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"3c3d55ea-8a2f-41c1-97fd-d222d586b0b1\",\"id\":\"861b129e42aac2de8166ad76ded0781c\"},\"3d134cec-2e95-4d43-bc4b-e552d382f73c\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcPresentationLayer\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"3d134cec-2e95-4d43-bc4b-e552d382f73c\",\"id\":\"030b7e2842cde1ce8a1d8e545d0e068a\"},\"3f146225-bd3e-448b-b180-034b880bd662\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon A5\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"3f146225-bd3e-448b-b180-034b880bd662\",\"id\":\"3d573a80fc3bd747d292d75c7751c523\"},\"3f9a284a-7485-460c-b827-9df8cd50720e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Classification.OmniClass.21.Description\",\"units\":null,\"value\":\"Insitu Concrete\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"3f9a284a-7485-460c-b827-9df8cd50720e\",\"id\":\"632da2ce6a52e51df22a05b776421b49\"},\"40e844db-ba22-4ddc-bc15-1fc47f5b12e7\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcSpatialContainer\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"40e844db-ba22-4ddc-bc15-1fc47f5b12e7\",\"id\":\"a8e9d80b93cd5f965d00aaffad6786e9\"},\"444d97fc-d9b6-4424-943d-37ac498a46c4\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Unique Asset ID - Item Number\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"444d97fc-d9b6-4424-943d-37ac498a46c4\",\"id\":\"d7cf7e867db30b45ac62757a6cc11b1b\"},\"46baf2f0-9232-4c37-aa7c-57e37fd5db17\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Product Type\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"46baf2f0-9232-4c37-aa7c-57e37fd5db17\",\"id\":\"b87714b8187aabde851b900a3755655a\"},\"4803c7b6-ded1-46b1-b5eb-ffe9ddcdc20b\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcSpatialContainer\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"4803c7b6-ded1-46b1-b5eb-ffe9ddcdc20b\",\"id\":\"9d6e8c6691db06081c2332c589ed2a31\"},\"48e76a50-9a4f-47a9-8074-79cc7fce9f14\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcPropertySetList\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"48e76a50-9a4f-47a9-8074-79cc7fce9f14\",\"id\":\"38621e3cf898c0fa404d29b88cf6ea5a\"},\"4ac5fa74-7864-45a3-9d89-1ab998b7731a\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon A3\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"4ac5fa74-7864-45a3-9d89-1ab998b7731a\",\"id\":\"34e84e5eed664e1ca94385e405141ef1\"},\"4c575161-247d-46a5-8ae2-72829f37725f\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"NetArea(BaseQuantities)\",\"units\":\"m\u00b2\",\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:squareMeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"4c575161-247d-46a5-8ae2-72829f37725f\",\"id\":\"c5741774b669ce685c5e53a704cc0320\"},\"4d293b70-da1a-4830-80a0-4f63b356ff61\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon A2\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"4d293b70-da1a-4830-80a0-4f63b356ff61\",\"id\":\"e629dd3ed399e1b8328aeaa2e90afae9\"},\"4dabccff-7cc0-42ff-a6db-29a28162d3f3\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type IfcPropertySetList\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"4dabccff-7cc0-42ff-a6db-29a28162d3f3\",\"id\":\"3aa01feade7f65bbd785f7083c04bacf\"},\"4fc2bd83-f0b1-41ba-8663-89e3d7f3e660\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcDescription [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"4fc2bd83-f0b1-41ba-8663-89e3d7f3e660\",\"id\":\"e7639f4355cebda699431a60345609c4\"},\"50a015d9-917f-4ac5-884e-42f7f36b47b1\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B5\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"50a015d9-917f-4ac5-884e-42f7f36b47b1\",\"id\":\"9a71039a2e2272f527084f2096f9429b\"},\"51778754-e984-42cf-8a6d-a2226baf316f\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcPresentationLayer\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"51778754-e984-42cf-8a6d-a2226baf316f\",\"id\":\"392005ecea2408b03939ef80fbb34a8f\"},\"5188c780-2bf1-460c-8bbf-043dcb4649eb\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcExportAs\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"5188c780-2bf1-460c-8bbf-043dcb4649eb\",\"id\":\"f38369c4acdfa96b7d45ac6187f8a183\"},\"5402c013-1b09-474f-b399-344a0e55a182\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Material\",\"units\":null,\"value\":\"PT\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"5402c013-1b09-474f-b399-344a0e55a182\",\"id\":\"e8252b753c969222390cf77fc56237ef\"},\"579138d4-c882-45f1-bfd6-5ec6f8189161\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Rate Reo Area\",\"units\":null,\"value\":12,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"579138d4-c882-45f1-bfd6-5ec6f8189161\",\"id\":\"09ca602feb656474737d2cf84e89e26f\"},\"5d8a425f-4cff-44fe-9896-932e8e5639ef\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 5\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"5d8a425f-4cff-44fe-9896-932e8e5639ef\",\"id\":\"805c08afb49a184af8649f63531be0e3\"},\"6248687a-e43d-4380-9f28-b98a14157187\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcExportAs [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"6248687a-e43d-4380-9f28-b98a14157187\",\"id\":\"c300499e47eea08ec5bfd25acc9abae3\"},\"6cbcfae1-3598-4ddd-a606-41f3788c0362\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Managed Asset YesNo\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"6cbcfae1-3598-4ddd-a606-41f3788c0362\",\"id\":\"b9473955cae7232a6d5ba4a2c7669e7c\"},\"76daee20-cdee-48b9-bf5f-1dc46079927e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 1\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"76daee20-cdee-48b9-bf5f-1dc46079927e\",\"id\":\"90563b7e8ed0acad2128d08383966907\"},\"7949a6c6-d3e4-45bf-bad0-208f3ba33483\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Unique Asset ID - Discipline Abbreviation\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"7949a6c6-d3e4-45bf-bad0-208f3ba33483\",\"id\":\"e427ecb62bb5a5f69dc56b12dfd4583a\"},\"79dbaeea-7a11-4cb4-a521-bc04d1b7a25b\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcName [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"79dbaeea-7a11-4cb4-a521-bc04d1b7a25b\",\"id\":\"d8a8a1f5d6315d9748e29bdd293d77a5\"},\"7a4a2609-0307-4c38-9a8c-4ffcd19a2d00\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Location\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"7a4a2609-0307-4c38-9a8c-4ffcd19a2d00\",\"id\":\"a4c9b4d5ce413090459c99efad3f1832\"},\"7d013fce-228f-4f3c-aa01-db40e458cc6e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 8\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"7d013fce-228f-4f3c-aa01-db40e458cc6e\",\"id\":\"07281437b9e050cd5ade4cca8a96227b\"},\"834ba6cf-7f91-49e5-ad0c-717d52a2507a\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcExportAs\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"834ba6cf-7f91-49e5-ad0c-717d52a2507a\",\"id\":\"7783908b6376a626de1c39d735b6cbfc\"},\"86d20f83-240f-44b9-8b27-6311eab2abcd\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B6\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"86d20f83-240f-44b9-8b27-6311eab2abcd\",\"id\":\"006791a1d0d5566c3b892202b08943fd\"},\"8a91c179-c4cb-471a-b108-ad540b8267e3\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Global Inherited Properties.Level Number\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"8a91c179-c4cb-471a-b108-ad540b8267e3\",\"id\":\"3d3d901b52bacdd137ac67f702680f3d\"},\"8c59bf6c-99ff-455b-bdfa-aeb7861e522e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcTag\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"8c59bf6c-99ff-455b-bdfa-aeb7861e522e\",\"id\":\"363ec752016b710969c8b4454fd2d35f\"},\"8f645e8b-7523-4462-a0af-858ffeaf44dc\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon D\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"8f645e8b-7523-4462-a0af-858ffeaf44dc\",\"id\":\"0e36907ad605957b17ba8556547d8ceb\"},\"91b7eb2f-0caf-45b0-a65d-83ce1eaca70e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcExportAs\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"91b7eb2f-0caf-45b0-a65d-83ce1eaca70e\",\"id\":\"04140c6ff8418bd2c731affd5691de8e\"},\"93b76d01-67c3-4799-a5f3-296f97489bd3\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Calc Room Number\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"93b76d01-67c3-4799-a5f3-296f97489bd3\",\"id\":\"4e270753bda04b81fd1c11bf1da5d852\"},\"9898cedf-179a-42e7-8cdc-c6c4212ec3e8\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcPresentationLayer\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"9898cedf-179a-42e7-8cdc-c6c4212ec3e8\",\"id\":\"7fd3f00069f6f1fcdab2ea0307661061\"},\"9a208060-4948-49b2-a1bf-1ab383705469\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcDescription\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"9a208060-4948-49b2-a1bf-1ab383705469\",\"id\":\"75340685a08f1a15df5c7aebbc41a85a\"},\"9a49a9a9-21c9-4f52-aeab-ae4727be6e1d\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type IfcPropertySetList\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"9a49a9a9-21c9-4f52-aeab-ae4727be6e1d\",\"id\":\"93f8195337085871545af0176f0ba282\"},\"9c2f84e0-2489-4a03-b4c8-eb44bb26fb0a\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 2\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"9c2f84e0-2489-4a03-b4c8-eb44bb26fb0a\",\"id\":\"fa24d55d23008ef6be1dbf3e8636c67e\"},\"9dd225d2-722b-4cb1-b972-babca7520f7e\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"System Name\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"9dd225d2-722b-4cb1-b972-babca7520f7e\",\"id\":\"056eec36214c733f8ecc448c27785434\"},\"9f484ce3-e8ae-4c20-b21c-0210b770935c\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Unique Asset ID - Tenancy Identifier\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"9f484ce3-e8ae-4c20-b21c-0210b770935c\",\"id\":\"416b24b324db272078942a4420775ec0\"},\"ANALYTICAL_HEAT_TRANSFER_COEFFICIENT\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Heat Transfer Coefficient (U)\",\"units\":\"W/(m\u00b2·K)\",\"value\":null,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:wattsPerSquareMeterKelvin-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ANALYTICAL_HEAT_TRANSFER_COEFFICIENT\",\"id\":\"8d290ae8d6ec3896b8dda96a83bb2d12\"},\"a5cb3364-d1f0-4ea5-a2d2-44114efbcf65\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcName\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"a5cb3364-d1f0-4ea5-a2d2-44114efbcf65\",\"id\":\"23ac4c2000599c233e5c390330e9108e\"},\"a77ddcdc-4c89-42c3-9d28-bc9e476c0fbe\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcName [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"a77ddcdc-4c89-42c3-9d28-bc9e476c0fbe\",\"id\":\"c60915bcbf4e2e070ccabc17694ee836\"},\"aa967357-e0b5-49f3-95a0-085e5d7d8951\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcMaterial\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"aa967357-e0b5-49f3-95a0-085e5d7d8951\",\"id\":\"08650ab84cd1be1235a60fccfcb1f39e\"},\"ac9b78b9-e138-483b-9796-6214cf7a5bd8\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Documentation.Home Story Name\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ac9b78b9-e138-483b-9796-6214cf7a5bd8\",\"id\":\"759d341196e21570a2f2d6199b5a9f2f\"},\"aeb679c1-1b82-4476-9099-7d13fd8ae3b8\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type IfcPropertySetList\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"aeb679c1-1b82-4476-9099-7d13fd8ae3b8\",\"id\":\"0a235c1836cd2ce0c5fd3869b938946e\"},\"af8efc07-fec4-4419-8513-4a268c4141c8\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon C3\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"af8efc07-fec4-4419-8513-4a268c4141c8\",\"id\":\"181c0245de21c9820a83396914565762\"},\"afb0a36f-1fa3-4f07-9b05-f86f48b3c3f0\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon C2\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"afb0a36f-1fa3-4f07-9b05-f86f48b3c3f0\",\"id\":\"cd929dfb8d143639a136ff3716800dfc\"},\"b13fb213-450c-4f92-859a-05cd5779daf1\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 7\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b13fb213-450c-4f92-859a-05cd5779daf1\",\"id\":\"1972d1f9e161892f2ba47ccb04f5e784\"},\"b41f116c-c6f7-418e-bf4b-61cc815f8d99\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Level Number(Global Inherited Properties)\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b41f116c-c6f7-418e-bf4b-61cc815f8d99\",\"id\":\"09caeb5d7565c779852e7802437af4a2\"},\"b594497d-7b5e-4221-aa1d-063f073aa326\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 2\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b594497d-7b5e-4221-aa1d-063f073aa326\",\"id\":\"ee718148bffebbcfb7e50f5f2be7f91f\"},\"b753aced-e142-45f9-9bb6-d7edce1df108\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Calc Location\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b753aced-e142-45f9-9bb6-d7edce1df108\",\"id\":\"ab32fc38096b2f538301b596be3ab123\"},\"b90ec63a-c51f-400a-bff1-66b8d0765f47\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Rate Reo Volume\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b90ec63a-c51f-400a-bff1-66b8d0765f47\",\"id\":\"5642967c62f928019c93b1bbc0e81c26\"},\"b958fd3c-5ea1-43a2-bc5c-df212ed8cf33\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcDescription [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b958fd3c-5ea1-43a2-bc5c-df212ed8cf33\",\"id\":\"ea40993e42d6379ab80b5b7d526347c2\"},\"b9d05d9c-a5f5-4a92-8811-9c5e2eefabd8\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"ClassificationCode\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"b9d05d9c-a5f5-4a92-8811-9c5e2eefabd8\",\"id\":\"c93f07ca1b6c3ac1c114474dc9aeeaca\"},\"bf3519b8-7b28-497e-97d8-afd4bf76203b\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcDescription [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"bf3519b8-7b28-497e-97d8-afd4bf76203b\",\"id\":\"3c46724925e301e2f88d4ecf4b6150f9\"},\"bfb5b2c0-aa1f-47ae-9cc9-70f7feaef0ea\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcName [Type]\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"bfb5b2c0-aa1f-47ae-9cc9-70f7feaef0ea\",\"id\":\"e8a6f622ac2589ad9fadd82e76c4c10c\"},\"bfd7311c-35b9-447d-9683-8ce244f8c1ad\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Remarks\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"bfd7311c-35b9-447d-9683-8ce244f8c1ad\",\"id\":\"05d34f2e81b12d25b60b1cd6a3788468\"},\"c4520aa3-cdf4-46b7-9539-180edc16d223\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon A4\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"c4520aa3-cdf4-46b7-9539-180edc16d223\",\"id\":\"54c0d9d278b045cbcb57fe4b2d477b86\"},\"c5b0f410-b4ee-4552-ac04-06fa0c13ec3b\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Unique Asset ID - Level/Floor\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"c5b0f410-b4ee-4552-ac04-06fa0c13ec3b\",\"id\":\"7365bc4a64abd37f8dbed69316983d60\"},\"c67d4cb4-b2d6-426f-8d05-ac6fbe0bd267\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Data 5\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"c67d4cb4-b2d6-426f-8d05-ac6fbe0bd267\",\"id\":\"7caf73cac38e203374836cef4827f0ae\"},\"c7ce9441-9aba-45ab-acbb-74e687481466\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Classification.OmniClass.22.Number\",\"units\":null,\"value\":\"22-03 35 13\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"c7ce9441-9aba-45ab-acbb-74e687481466\",\"id\":\"8b96e2130eddfb81c6a35635c5654079\"},\"cab1938b-5da8-4b53-9f0c-bb473c1966a4\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Level Number(Global Inherited Properties)\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"cab1938b-5da8-4b53-9f0c-bb473c1966a4\",\"id\":\"baed41d276e750b374a5ca62366d0e56\"},\"cda17719-cef4-4c69-92f1-e111e85353b1\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcTag\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"cda17719-cef4-4c69-92f1-e111e85353b1\",\"id\":\"a00fb37b573181a2bb6070b416ac2c87\"},\"ce24f3b1-369d-42bb-987e-ac0b45c4f8da\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Classification.OmniClass.23.Description\",\"units\":null,\"value\":\"Concrete Structural Floor Decks\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ce24f3b1-369d-42bb-987e-ac0b45c4f8da\",\"id\":\"57445c90784f528c2b0f414f9233a42d\"},\"ce25a030-e3d0-4856-bbc0-a1cdd8f4d4ff\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B4\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ce25a030-e3d0-4856-bbc0-a1cdd8f4d4ff\",\"id\":\"deb71e96bcf8157d78c59266aaaa86d1\"},\"d05b3c99-0643-409d-ad3b-2704d324bbcd\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B1\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"d05b3c99-0643-409d-ad3b-2704d324bbcd\",\"id\":\"34d4a2c23bc26a1545523ae8597223ca\"},\"d608342a-e8f5-4ec9-9626-771914eb3da2\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 4\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"d608342a-e8f5-4ec9-9626-771914eb3da2\",\"id\":\"b640302338235776966b78b0735abcca\"},\"d8b20410-414f-4777-8614-a7564519c6cd\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Classification.OmniClass.21.Number\",\"units\":null,\"value\":\"21-02 10 10 20 04\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"d8b20410-414f-4777-8614-a7564519c6cd\",\"id\":\"60e194032a186046e1a6db66376b97fb\"},\"db575143-7118-4f29-813e-2ced4535a170\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B2\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"db575143-7118-4f29-813e-2ced4535a170\",\"id\":\"29e7f431d56d49569acb66b3f0621eb5\"},\"dd0cf380-59d8-4d9f-82da-3e2be59e23a1\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon B7\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"dd0cf380-59d8-4d9f-82da-3e2be59e23a1\",\"id\":\"b2887224f02b48130a75948e3f924e61\"},\"dedec34c-f507-4242-a85f-07a816ff1128\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcName\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"dedec34c-f507-4242-a85f-07a816ff1128\",\"id\":\"eef57991b50ee252c88dcee0dc06fddd\"},\"e4af54de-6137-43b0-97d4-c2260a1a68c3\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcTag\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"e4af54de-6137-43b0-97d4-c2260a1a68c3\",\"id\":\"f00202e050fa8a6ea223906e11e870bd\"},\"ea3ba87c-ae3c-47ed-886d-754f2359389c\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcMaterial\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ea3ba87c-ae3c-47ed-886d-754f2359389c\",\"id\":\"0cd769e3fd9905a59cae6cea37f77b46\"},\"ed6b5c87-b77c-45ab-9d90-8f26e365bca1\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcSpatialContainer\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ed6b5c87-b77c-45ab-9d90-8f26e365bca1\",\"id\":\"76cd1f61df7f11197ead15a92693abae\"},\"ee8153af-4866-45f2-a9a2-b6342ccb1dd6\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcMaterial\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ee8153af-4866-45f2-a9a2-b6342ccb1dd6\",\"id\":\"c32a465b6682dbc0908107858c6b9b6b\"},\"ef2d5da9-0b71-4617-a78c-cf4395808169\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Type Data 3\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"ef2d5da9-0b71-4617-a78c-cf4395808169\",\"id\":\"28aa3437bdf40659590c753a3e842193\"},\"f3b20cd0-059c-48a6-b744-7a9babf1cb29\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Embodied Carbon C4\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"f3b20cd0-059c-48a6-b744-7a9babf1cb29\",\"id\":\"094df4c6e1d89bda1c3d32d19b859e57\"},\"f69d55e2-e23c-4a77-999d-45bae64d5856\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcPropertySetList\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"f69d55e2-e23c-4a77-999d-45bae64d5856\",\"id\":\"3fffe0348a0f398a26003c9552c4dbc9\"},\"f6a1fceb-536f-4261-ad25-4f1fb4dcda76\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Concrete Grade\",\"units\":null,\"value\":\"40 MPa\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"f6a1fceb-536f-4261-ad25-4f1fb4dcda76\",\"id\":\"acd05a5a6632bf49f56fe8d9b32ca1ff\"},\"f7c3a959-7884-46fd-97a6-cca3cea07fe7\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"IfcPropertySetList\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"f7c3a959-7884-46fd-97a6-cca3cea07fe7\",\"id\":\"131c5cc690b61877eac2f73f73cd69ad\"},\"fac5d675-3756-485d-9500-4f2aa3096a38\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Product Name\",\"units\":null,\"value\":null,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"fac5d675-3756-485d-9500-4f2aa3096a38\",\"id\":\"b5ba47412a41ee8f0e0b6309435f08e7\"},\"fb16e643-73bd-4c8d-a506-99506b010546\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Rate PT Area\",\"units\":null,\"value\":4.5,\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":\"autodesk.unit.unit:general-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"fb16e643-73bd-4c8d-a506-99506b010546\",\"id\":\"8607ae9e4c1350ec9eee23830a12c77e\"},\"fb272f85-666a-45a4-ae16-fa4d620d81b7\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Classification.OmniClass.23.Number\",\"units\":null,\"value\":\"23-13 35 23 11 11\",\"isShared\":true,\"isReadOnly\":false,\"applicationUnit\":null,\"isTypeParameter\":true,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"fb272f85-666a-45a4-ae16-fa4d620d81b7\",\"id\":\"5bcbae5ccbbdc5366970db0d9dd64eca\"},\"STRUCTURAL_ELEVATION_AT_BOTTOM_SURVEY\":{\"applicationId\":null,\"speckle_type\":\"Base\",\"name\":\"Elevation at Bottom Survey\",\"units\":\"mm\",\"value\":30699.999999999898,\"isShared\":false,\"isReadOnly\":true,\"applicationUnit\":\"autodesk.unit.unit:millimeters-1.0.1\",\"isTypeParameter\":false,\"totalChildrenCount\":0,\"applicationUnitType\":null,\"applicationInternalName\":\"STRUCTURAL_ELEVATION_AT_BOTTOM_SURVEY\",\"id\":\"830d5e76c5b5b84bbab7f9f52e80dfef\"},\"id\":\"e24896645d6932e8d2edc7b56bcd65b2\"}" )] - [TestCase( + [InlineData( "{\n \"applicationId\": null,\n \"speckle_type\": \"Base\",\n \"name\": \"Physically Based (1)\",\n \"diffuse\": -11810867,\n \"opacity\": 1,\n \"emissive\": -16777216,\n \"metalness\": 0,\n \"roughness\": 0.2,\n \"totalChildrenCount\": 0,\n \"id\": \"3ef9f1e3deb7e8057f9eceb29ff2ea88\"\n}" )] public void Serialize_Id_Stable(string json) @@ -202,12 +200,12 @@ public void Serialize_Id_Stable(string json) jObject.Remove("__closure"); var jsonWithoutId = jObject.ToString(Formatting.None); var newId = IdGenerator.ComputeId(new Json(jsonWithoutId)); - id.ShouldBe(newId.Value); + id.Should().Be(newId.Value); } - [Test] - [TestCase("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] - public async Task Roundtrip_Test_Old(string fileName, string rootId, int count) + [Theory] + [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818)] + public async Task Roundtrip_Test_Old(string fileName, string _, int count) { var fullName = _assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); var json = await ReadJson(fullName); @@ -224,31 +222,31 @@ public async Task Roundtrip_Test_Old(string fileName, string rootId, int count) var newIds = new Dictionary(); var oldIds = new Dictionary(); var idToBase = new Dictionary(); - closure.Count.ShouldBe(count); + closure.Count.Should().Be(count); foreach (var (id, objJson) in closure) { var base1 = await deserializer.DeserializeAsync(objJson); - base1.id.ShouldBe(id); + base1.id.Should().Be(id); var j = serializer.Serialize(base1); - //j.ShouldBe(objJson); + //j.Should().Be(objJson); JToken.DeepEquals(JObject.Parse(j), JObject.Parse(objJson)); newIds.Add(base1.id.NotNull(), j); oldIds.Add(id, j); idToBase.Add(id, base1); } - newIds.Count.ShouldBe(count); - oldIds.Count.ShouldBe(count); - idToBase.Count.ShouldBe(count); + newIds.Count.Should().Be(count); + oldIds.Count.Should().Be(count); + idToBase.Count.Should().Be(count); } - [Test] - [TestCase("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818, 4674)] + [Theory] + [InlineData("RevitObject.json.gz", "3416d3fe01c9196115514c4a2f41617b", 7818, 4674)] public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCount, int newCount) { var fullName = _assembly.GetManifestResourceNames().Single(x => x.EndsWith(fileName)); var json = await ReadJson(fullName); var closure = ReadAsObjects(json); - closure.Count.ShouldBe(oldCount); + closure.Count.Should().Be(oldCount); var o = new ObjectLoader( new DummySqLiteReceiveManager(closure), @@ -257,8 +255,8 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun ); using var process = new DeserializeProcess(null, o, new ObjectDeserializerFactory(), new(true)); var root = await process.Deserialize(rootId, default); - process.BaseCache.Count.ShouldBe(oldCount); - process.Total.ShouldBe(oldCount); + process.BaseCache.Count.Should().Be(oldCount); + process.Total.Should().Be(oldCount); var newIdToJson = new ConcurrentDictionary(); using var serializeProcess = new SerializeProcess( @@ -271,8 +269,8 @@ public async Task Roundtrip_Test_New(string fileName, string rootId, int oldCoun ); var (rootId2, _) = await serializeProcess.Serialize(root, default); - rootId2.ShouldBe(root.id); - newIdToJson.Count.ShouldBe(newCount); + rootId2.Should().Be(root.id); + newIdToJson.Count.Should().Be(newCount); foreach (var newKvp in newIdToJson) { diff --git a/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj b/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj index ce4c686e..b8028ef4 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj +++ b/tests/Speckle.Sdk.Serialization.Tests/Speckle.Sdk.Serialization.Tests.csproj @@ -9,10 +9,10 @@ + - - - + + diff --git a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json index fcd06d85..0e91de90 100644 --- a/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json +++ b/tests/Speckle.Sdk.Serialization.Tests/packages.lock.json @@ -4,9 +4,18 @@ "net8.0": { "altcover": { "type": "Direct", - "requested": "[8.9.3, )", - "resolved": "8.9.3", - "contentHash": "auKC+pDCkLjfhFkSRaAUBu25BOmlLSqucR7YBs/Lkbdc0XRuJoklWafs1KKp+M+VoJ1f0TeMS6B/FO5IeIcu7w==" + "requested": "[9.0.1, )", + "resolved": "9.0.1", + "contentHash": "aadciFNDT5bnylaYUkKal+s5hF7yU/lmZxImQWAlk1438iPqK1Uf79H5ylELpyLIU49HL5ql+tnWBihp3WVLCA==" + }, + "FluentAssertions": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "mTLbcU991EQ1SEmNbVBaGGGJy0YFzvGd1sYJGNZ07nlPKuyHSn1I22aeKzqQXgEiaKyRO6MSCto9eN9VxMwBdA==", + "dependencies": { + "System.Configuration.ConfigurationManager": "6.0.0" + } }, "GitVersion.MsBuild": { "type": "Direct", @@ -16,12 +25,12 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.11.1, )", - "resolved": "17.11.1", - "contentHash": "U3Ty4BaGoEu+T2bwSko9tWqWUOU16WzSFkq6U8zve75oRBMSLTBdMAZrVNNz1Tq12aCdDom9fcOcM9QZaFHqFg==", + "requested": "[17.12.0, )", + "resolved": "17.12.0", + "contentHash": "kt/PKBZ91rFCWxVIJZSgVLk+YR+4KxTuHf799ho8WNiK5ZQpJNAEZCAWX86vcKrs+DiYjiibpYKdGZP6+/N17w==", "dependencies": { - "Microsoft.CodeCoverage": "17.11.1", - "Microsoft.TestPlatform.TestHost": "17.11.1" + "Microsoft.CodeCoverage": "17.12.0", + "Microsoft.TestPlatform.TestHost": "17.12.0" } }, "Microsoft.SourceLink.GitHub": { @@ -34,53 +43,34 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, - "NUnit": { - "type": "Direct", - "requested": "[4.2.2, )", - "resolved": "4.2.2", - "contentHash": "mon0OPko28yZ/foVXrhiUvq1LReaGsBdziumyyYGxV/pOE4q92fuYeN+AF+gEU5pCjzykcdBt5l7xobTaiBjsg==" - }, - "NUnit3TestAdapter": { - "type": "Direct", - "requested": "[4.6.0, )", - "resolved": "4.6.0", - "contentHash": "R7e1+a4vuV/YS+ItfL7f//rG+JBvVeVLX4mHzFEZo4W1qEKl8Zz27AqvQSAqo+BtIzUCo4aAJMYa56VXS4hudw==" - }, "PolySharp": { "type": "Direct", "requested": "[1.15.0, )", "resolved": "1.15.0", "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g==" }, - "Shouldly": { - "type": "Direct", - "requested": "[4.2.1, )", - "resolved": "4.2.1", - "contentHash": "dKAKiSuhLKqD2TXwLKtqNg1nwzJcIKOOMncZjk9LYe4W+h+SCftpWdxwR79YZUIHMH+3Vu9s0s0UHNrgICLwRQ==", - "dependencies": { - "DiffEngine": "11.3.0", - "EmptyFiles": "4.4.0" - } - }, "Speckle.InterfaceGenerator": { "type": "Direct", "requested": "[0.9.6, )", "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "DiffEngine": { - "type": "Transitive", - "resolved": "11.3.0", - "contentHash": "k0ZgZqd09jLZQjR8FyQbSQE86Q7QZnjEzq1LPHtj1R2AoWO8sjV5x+jlSisL7NZAbUOI4y+7Bog8gkr9WIRBGw==", + "xunit": { + "type": "Direct", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", "dependencies": { - "EmptyFiles": "4.4.0", - "System.Management": "6.0.1" + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" } }, - "EmptyFiles": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "gwJEfIGS7FhykvtZoscwXj/XwW+mJY6UbAZk+qtLKFUGWC95kfKXnj8VkxsZQnWBxJemM/q664rGLN5nf+OHZw==" + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "HggUqjQJe8PtDxcP25Q+CnR6Lz4oX3GElhD9V4oU2+75x9HI6A6sxbfKGS4UwU4t4yJaS9fBmAuriz8bQApNjw==" }, "GraphQL.Client.Abstractions": { "type": "Transitive", @@ -110,8 +100,8 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "nPJqrcA5iX+Y0kqoT3a+pD/8lrW/V7ayqnEJQsTonSoPz59J8bmoQhcSN4G8+UJ64Hkuf0zuxnfuj2lkHOq4cA==" + "resolved": "17.12.0", + "contentHash": "4svMznBd5JM21JIG2xZKGNanAHNXplxf/kQDFfLHXQ3OnpJkayRK/TjacFjA+EYmoyuNXHo/sOETEfcYtAzIrA==" }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", @@ -176,21 +166,26 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "E2jZqAU6JeWEVsyOEOrSW1o1bpHLgb25ypvKNB/moBXPVsFYBPd/Jwi7OrYahG50J83LfHzezYI+GaEkpAotiA==", + "resolved": "17.12.0", + "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==", "dependencies": { "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "DnG+GOqJXO/CkoqlJWeDFTgPhqD/V6VqUIL3vINizCWZ3X+HshCtbbyDdSHQQEjrc2Sl/K3yaxX6s+5LFEdYuw==", + "resolved": "17.12.0", + "contentHash": "MiPEJQNyADfwZ4pJNpQex+t9/jOClBGMiCiVVFuELCMSX2nmNfvUor3uFVxNNCg30uxDP8JDYfPnMXQzsfzYyg==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.11.1", + "Microsoft.TestPlatform.ObjectModel": "17.12.0", "Newtonsoft.Json": "13.0.1" } }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "hqTM5628jSsQiv+HGpiq3WKBl2c8v1KZfby2J6Pr7pEPlK9waPdgEO6b8A/+/xn/yZ9ulv8HuqK71ONy2tg67A==" + }, "Newtonsoft.Json": { "type": "Transitive", "resolved": "13.0.1", @@ -226,22 +221,26 @@ "SQLitePCLRaw.core": "2.1.4" } }, - "System.CodeDom": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA==" - }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, - "System.Management": { + "System.Configuration.ConfigurationManager": { "type": "Transitive", - "resolved": "6.0.1", - "contentHash": "10J1D0h/lioojphfJ4Fuh5ZUThT/xOVHdV9roGBittKKNP2PMjrvibEdbVTGZcPra1399Ja3tqIJLyQrc5Wmhg==", + "resolved": "6.0.0", + "contentHash": "7T+m0kDSlIPTHIkPMIu6m6tV6qsMqJpvQWW2jIc2qi7sn40qxFo0q+7mEQAhMPXZHMKnWrnv47ntGlM/ejvw3g==", "dependencies": { - "System.CodeDom": "6.0.0" + "System.Security.Cryptography.ProtectedData": "6.0.0", + "System.Security.Permissions": "6.0.0" + } + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "NfuoKUiP2nUWwKZN6twGqXioIe1zVD0RIj2t976A+czLHr2nY454RwwXs6JU9Htc6mwqL6Dn/nEL3dpVf2jOhg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "6.0.0" } }, "System.Memory": { @@ -264,6 +263,73 @@ "resolved": "4.5.1", "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "rp1gMNEZpvx9vP0JW0oHLxlf8oSiQgtno77Y4PLUBjSiDYoD77Y8uXHr1Ea5XG4/pIKhqAdxZ8v8OTUtqo9PeQ==" + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "T/uuc7AklkDoxmcJ7LGkyX1CcSviZuLCa4jg3PekfJ7SU0niF0IVTXwUiNVP9DSpzou2PpxJ+eNY2IfDM90ZCg==", + "dependencies": { + "System.Security.AccessControl": "6.0.0", + "System.Windows.Extensions": "6.0.0" + } + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "IXoJOXIqc39AIe+CIR7koBtRGMiCt/LPM3lI+PELtDIy9XdyeSrwXFdWV9dzJ2Awl0paLWUaknLxFQ5HpHZUog==", + "dependencies": { + "System.Drawing.Common": "6.0.0" + } + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]" + } + }, "speckle.objects": { "type": "Project", "dependencies": { diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs index dfa31a87..4f81fd93 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/GraphQLClientExceptionHandling.cs @@ -1,36 +1,39 @@ -using GraphQL; +using System.ComponentModel; +using FluentAssertions; +using GraphQL; using GraphQL.Client.Http; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; +using Xunit; namespace Speckle.Sdk.Tests.Integration.Api.GraphQL; -[TestOf(typeof(Client))] -public class GraphQLClientExceptionHandling +public class GraphQLClientExceptionHandling : IAsyncLifetime { private Client _sut; - [SetUp] - public async Task Setup() + public Task DisposeAsync() => Task.CompletedTask; + + public async Task InitializeAsync() { _sut = await Fixtures.SeedUserWithClient(); } - [Test] + [Fact] [Description($"Attempts to execute a query on a non-existent server, expect a {nameof(GraphQLHttpRequestException)}")] - public void TestHttpLayer() + public async Task TestHttpLayer() { _sut.GQLClient.Options.EndPoint = new Uri("http://127.0.0.1:1234"); //There is no server on this port... - Assert.ThrowsAsync(async () => await _sut.ActiveUser.Get().ConfigureAwait(false)); + await Assert.ThrowsAsync(async () => await _sut.ActiveUser.Get().ConfigureAwait(false)); } - [Test] + [Fact] [Description( $"Attempts to execute a admin only command from a regular user, expect an inner {nameof(SpeckleGraphQLForbiddenException)}" )] - public void TestGraphQLLayer_Forbidden() + public async Task TestGraphQLLayer_Forbidden() { //language=graphql const string QUERY = """ @@ -46,14 +49,14 @@ query Query { """; GraphQLRequest request = new(query: QUERY); - var ex = Assert.ThrowsAsync( + var ex = await Assert.ThrowsAsync( async () => await _sut.ExecuteGraphQLRequest(request).ConfigureAwait(false) ); - Assert.That(ex?.InnerExceptions, Has.Exactly(1).TypeOf()); + ex.InnerExceptions.OfType().Count().Should().Be(1); } - [Test, Description($"Attempts to execute a bad query, expect an inner {nameof(SpeckleGraphQLInvalidQueryException)}")] - public void TestGraphQLLayer_BadQuery() + [Fact, Description($"Attempts to execute a bad query, expect an inner {nameof(SpeckleGraphQLInvalidQueryException)}")] + public async Task TestGraphQLLayer_BadQuery() { //language=graphql const string QUERY = """ @@ -64,41 +67,39 @@ query User { } """; GraphQLRequest request = new(query: QUERY); - var ex = Assert.ThrowsAsync( + var ex = await Assert.ThrowsAsync( async () => await _sut.ExecuteGraphQLRequest(request).ConfigureAwait(false) ); - - Assert.That(ex?.InnerExceptions, Has.Exactly(1).TypeOf()); + ex.InnerExceptions.OfType().Count().Should().Be(1); } - [Test] + [Fact] [Description( $"Attempts to execute a query with an invalid input, expect an inner {nameof(SpeckleGraphQLBadInputException)}" )] - public void TestGraphQLLayer_BadInput() + public async Task TestGraphQLLayer_BadInput() { ProjectUpdateRoleInput input = new(null!, null!, null); - var ex = Assert.ThrowsAsync( + var ex = await Assert.ThrowsAsync( async () => await _sut.Project.UpdateRole(input).ConfigureAwait(false) ); - - Assert.That(ex?.InnerExceptions, Has.Exactly(2).TypeOf()); + ex.InnerExceptions.OfType().Count().Should().Be(2); } - [Test] - public void TestCancel() + [Fact] + public async Task TestCancel() { using CancellationTokenSource cts = new(); - cts.Cancel(); + await cts.CancelAsync(); - var ex = Assert.CatchAsync( + var ex = await Assert.ThrowsAsync( async () => await _sut.ActiveUser.Get(cts.Token).ConfigureAwait(false) ); - Assert.That(ex?.CancellationToken, Is.EqualTo(cts.Token)); + ex.CancellationToken.Should().BeEquivalentTo(cts.Token); } - [Test] + [Fact] public void TestDisposal() { _sut.Dispose(); @@ -107,10 +108,10 @@ public void TestDisposal() } [ - Test, + Fact, Description($"Attempts to execute a query with a mismatched type, expect an {nameof(JsonSerializationException)}") ] - public void TestDeserialization() + public async Task TestDeserialization() { //language=graphql const string QUERY = """ @@ -121,6 +122,8 @@ query User { } """; GraphQLRequest request = new(query: QUERY); - Assert.CatchAsync(async () => await _sut.ExecuteGraphQLRequest(request).ConfigureAwait(false)); + await Assert.ThrowsAsync( + async () => await _sut.ExecuteGraphQLRequest(request).ConfigureAwait(false) + ); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs index 46b325ad..f4f99370 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ActiveUserResourceTests.cs @@ -1,53 +1,60 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; -using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ActiveUserResource))] -public class ActiveUserResourceTests +public class ActiveUserResourceTests : IAsyncLifetime { private Client _testUser; private ActiveUserResource Sut => _testUser.ActiveUser; - [OneTimeSetUp] - public async Task Setup() + // Setup method for xUnit using IAsyncLifetime + public async Task InitializeAsync() { _testUser = await Fixtures.SeedUserWithClient(); } - [Test] + public Task DisposeAsync() + { + // No resources to dispose + return Task.CompletedTask; + } + + [Fact] public async Task ActiveUserGet() { var res = await Sut.Get(); - Assert.That(res, Is.Not.Null); - Assert.That(res!.id, Is.EqualTo(_testUser.Account.userInfo.id)); + res.Should().NotBeNull(); + res!.id.Should().Be(_testUser.Account.userInfo.id); } - [Test] + [Fact] public async Task ActiveUserGet_NonAuthed() { var result = await Fixtures.Unauthed.ActiveUser.Get(); - Assert.That(result, Is.EqualTo(null)); + result.Should().BeNull(); } - [Test] + [Fact] public async Task ActiveUserUpdate() { const string NEW_NAME = "Ron"; const string NEW_BIO = "Now I have a bio, isn't that nice!"; const string NEW_COMPANY = "Limited Cooperation Organization Inc"; + var res = await Sut.Update(new UserUpdateInput(name: NEW_NAME, bio: NEW_BIO, company: NEW_COMPANY)); - Assert.That(res, Is.Not.Null); - Assert.That(res.id, Is.EqualTo(_testUser.Account.userInfo.id)); - Assert.That(res.name, Is.EqualTo(NEW_NAME)); - Assert.That(res.company, Is.EqualTo(NEW_COMPANY)); - Assert.That(res.bio, Is.EqualTo(NEW_BIO)); + res.Should().NotBeNull(); + res.id.Should().Be(_testUser.Account.userInfo.id); + res.name.Should().Be(NEW_NAME); + res.company.Should().Be(NEW_COMPANY); + res.bio.Should().Be(NEW_BIO); } - [Test] + [Fact] public async Task ActiveUserGetProjects() { var p1 = await _testUser.Project.Create(new("Project 1", null, null)); @@ -55,14 +62,17 @@ public async Task ActiveUserGetProjects() var res = await Sut.GetProjects(); - Assert.That(res.items, Has.Exactly(1).Items.With.Property(nameof(Project.id)).EqualTo(p1.id)); - Assert.That(res.items, Has.Exactly(1).Items.With.Property(nameof(Project.id)).EqualTo(p2.id)); - Assert.That(res.items, Has.Count.EqualTo(2)); + res.items.Should().Contain(x => x.id == p1.id); + res.items.Should().Contain(x => x.id == p2.id); + res.items.Count.Should().Be(2); } - [Test] - public void ActiveUserGetProjects_NoAuth() + [Fact] + public async Task ActiveUserGetProjects_NoAuth() { - Assert.ThrowsAsync(async () => await Fixtures.Unauthed.ActiveUser.GetProjects()); + await FluentActions + .Invoking(async () => await Fixtures.Unauthed.ActiveUser.GetProjects()) + .Should() + .ThrowAsync(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs index a6b90605..83373aad 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/CommentResourceTests.cs @@ -1,104 +1,111 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(CommentResource))] public class CommentResourceTests { - private Client _testUser; - private CommentResource Sut => _testUser.Comment; - private Project _project; - private Model _model; - private string _versionId; - private Comment _comment; - - [SetUp] - public async Task Setup() + private readonly Client _testUser; + private readonly CommentResource Sut; + private readonly Project _project; + private readonly Model _model; + private readonly string _versionId; + private readonly Comment _comment; + + // Constructor for setup + public CommentResourceTests() { - _testUser = await Fixtures.SeedUserWithClient(); - _project = await _testUser.Project.Create(new("Test project", "", null)); - _model = await _testUser.Model.Create(new("Test Model 1", "", _project.id)); - _versionId = await Fixtures.CreateVersion(_testUser, _project.id, _model.id); - _comment = await CreateComment(); + // Synchronous operations converted to async Task.Run for constructor + _testUser = Task.Run(async () => await Fixtures.SeedUserWithClient()).Result!; + _project = Task.Run(async () => await _testUser.Project.Create(new("Test project", "", null))).Result!; + _model = Task.Run(async () => await _testUser.Model.Create(new("Test Model 1", "", _project.id))).Result!; + _versionId = Task.Run(async () => await Fixtures.CreateVersion(_testUser, _project.id, _model.id)).Result!; + _comment = Task.Run(CreateComment).Result!; + Sut = _testUser.Comment; } - [Test] + [Fact] public async Task Get() { var comment = await Sut.Get(_comment.id, _project.id); - Assert.That(comment.id, Is.EqualTo(_comment.id)); - Assert.That(comment.authorId, Is.EqualTo(_testUser.Account.userInfo.id)); + + comment.Should().NotBeNull(); + comment.id.Should().Be(_comment.id); + comment.authorId.Should().Be(_testUser.Account.userInfo.id); } - [Test] + [Fact] public async Task GetProjectComments() { var comments = await Sut.GetProjectComments(_project.id); - Assert.That(comments.items.Count, Is.EqualTo(1)); - Assert.That(comments.totalCount, Is.EqualTo(1)); + + comments.Should().NotBeNull(); + comments.items.Count.Should().Be(1); + comments.totalCount.Should().Be(1); Comment comment = comments.items[0]; - Assert.That(comment, Is.Not.Null); - Assert.That(comment, Has.Property(nameof(Comment.authorId)).EqualTo(_testUser.Account.userInfo.id)); - - Assert.That(comment, Has.Property(nameof(Comment.id)).EqualTo(_comment.id)); - Assert.That(comment, Has.Property(nameof(Comment.authorId)).EqualTo(_comment.authorId)); - Assert.That(comment, Has.Property(nameof(Comment.archived)).EqualTo(_comment.archived)); - Assert.That(comment, Has.Property(nameof(Comment.archived)).EqualTo(false)); - Assert.That(comment, Has.Property(nameof(Comment.createdAt)).EqualTo(_comment.createdAt)); + comment.Should().NotBeNull(); + comment.authorId.Should().Be(_testUser.Account.userInfo.id); + comment.id.Should().Be(_comment.id); + comment.authorId.Should().Be(_comment.authorId); + comment.archived.Should().Be(false); + comment.createdAt.Should().Be(_comment.createdAt); } - [Test] + [Fact] public async Task MarkViewed() { await Sut.MarkViewed(new(_comment.id, _project.id)); - var res = await Sut.Get(_comment.id, _project.id); - Assert.That(res.viewedAt, Is.Not.Null); + var res = await Sut.Get(_comment.id, _project.id); + res.viewedAt.Should().NotBeNull(); } - [Test] + [Fact] public async Task Archive() { await Sut.Archive(new(_comment.id, _project.id, true)); var archived = await Sut.Get(_comment.id, _project.id); - Assert.That(archived.archived, Is.True); + + archived.archived.Should().BeTrue(); await Sut.Archive(new(_comment.id, _project.id, false)); var unarchived = await Sut.Get(_comment.id, _project.id); - Assert.That(unarchived.archived, Is.False); + + unarchived.archived.Should().BeFalse(); } - [Test] + [Fact] public async Task Edit() { var blobs = await Fixtures.SendBlobData(_testUser.Account, _project.id); var blobIds = blobs.Select(b => b.id.NotNull()).ToList(); - EditCommentInput input = new(new(blobIds, null), _comment.id, _project.id); + var input = new EditCommentInput(new(blobIds, null), _comment.id, _project.id); var editedComment = await Sut.Edit(input); - Assert.That(editedComment, Is.Not.Null); - Assert.That(editedComment, Has.Property(nameof(Comment.id)).EqualTo(_comment.id)); - Assert.That(editedComment, Has.Property(nameof(Comment.authorId)).EqualTo(_comment.authorId)); - Assert.That(editedComment, Has.Property(nameof(Comment.createdAt)).EqualTo(_comment.createdAt)); - Assert.That(editedComment, Has.Property(nameof(Comment.updatedAt)).GreaterThanOrEqualTo(_comment.updatedAt)); + editedComment.Should().NotBeNull(); + editedComment.id.Should().Be(_comment.id); + editedComment.authorId.Should().Be(_comment.authorId); + editedComment.createdAt.Should().Be(_comment.createdAt); + editedComment.updatedAt.Should().BeOnOrAfter(_comment.updatedAt); } - [Test] + [Fact] public async Task Reply() { var blobs = await Fixtures.SendBlobData(_testUser.Account, _project.id); var blobIds = blobs.Select(b => b.id.NotNull()).ToList(); - CreateCommentReplyInput input = new(new(blobIds, null), _comment.id, _project.id); + var input = new CreateCommentReplyInput(new(blobIds, null), _comment.id, _project.id); var editedComment = await Sut.Reply(input); - Assert.That(editedComment, Is.Not.Null); + editedComment.Should().NotBeNull(); } private async Task CreateComment() diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs index 7b72fb3f..91c995fd 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceExceptionalTests.cs @@ -1,94 +1,137 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ModelResource))] -public class ModelResourceExceptionalTests +public class ModelResourceExceptionalTests : IAsyncLifetime { private Client _testUser; private ModelResource Sut => _testUser.Model; private Project _project; private Model _model; - [OneTimeSetUp] - public async Task Setup() + // Replaces NUnit's OneTimeSetUp with an async constructor logic or initializer pattern + public async Task InitializeAsync() { _testUser = await Fixtures.SeedUserWithClient(); _project = await _testUser.Project.Create(new("Test project", "", ProjectVisibility.Private)); _model = await _testUser.Model.Create(new("Test Model", "", _project.id)); } - [TestCase("")] - [TestCase(" ")] - public void ModelCreate_Throws_InvalidInput(string name) + public Task DisposeAsync() => Task.CompletedTask; + + [Theory] + [InlineData("")] + [InlineData(" ")] + public async Task ModelCreate_Throws_InvalidInput(string name) { + // Arrange CreateModelInput input = new(name, null, _project.id); - var ex = Assert.ThrowsAsync(async () => await Sut.Create(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Sut.Create(input)) + .Should() + .ThrowAsync(); + + ex.WithInnerExceptionExactly(); } - [Test] - public void ModelGet_Throws_NoAuth() + [Fact] + public async Task ModelGet_Throws_NoAuth() { - var ex = Assert.ThrowsAsync( - async () => await Fixtures.Unauthed.Model.Get(_model.id, _project.id) - ); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Fixtures.Unauthed.Model.Get(_model.id, _project.id)) + .Should() + .ThrowAsync(); + + ex.WithInnerExceptionExactly(); } - [Test] - public void ModelGet_Throws_NonExistentModel() + [Fact] + public async Task ModelGet_Throws_NonExistentModel() { - var ex = Assert.ThrowsAsync(async () => await Sut.Get("non existent model", _project.id)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Sut.Get("non existent model", _project.id)) + .Should() + .ThrowAsync(); + ex.WithInnerExceptionExactly(); } - [Test] - public void ModelGet_Throws_NonExistentProject() + [Fact] + public async Task ModelGet_Throws_NonExistentProject() { - var ex = Assert.ThrowsAsync(async () => await Sut.Get(_model.id, "non existent project")); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Sut.Get(_model.id, "non existent project")) + .Should() + .ThrowAsync(); + ex.WithInnerExceptionExactly(); } - [Test] - public void ModelUpdate_Throws_NonExistentModel() + [Fact] + public async Task ModelUpdate_Throws_NonExistentModel() { + // Arrange UpdateModelInput input = new("non-existent model", "MY new name", "MY new desc", _project.id); - var ex = Assert.ThrowsAsync(async () => await Sut.Update(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Sut.Update(input)) + .Should() + .ThrowAsync(); + ex.WithInnerExceptionExactly(); } - [Test] - public void ModelUpdate_Throws_NonExistentProject() + [Fact] + public async Task ModelUpdate_Throws_NonExistentProject() { + // Arrange UpdateModelInput input = new(_model.id, "MY new name", "MY new desc", "non-existent project"); - var ex = Assert.ThrowsAsync(async () => await Sut.Update(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Sut.Update(input)) + .Should() + .ThrowAsync(); + ex.WithInnerExceptionExactly(); } - [Test] - public void ModelUpdate_Throws_NonAuthProject() + [Fact] + public async Task ModelUpdate_Throws_NonAuthProject() { + // Arrange UpdateModelInput input = new(_model.id, "MY new name", "MY new desc", _project.id); - var ex = Assert.ThrowsAsync(async () => await Fixtures.Unauthed.Model.Update(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Fixtures.Unauthed.Model.Update(input)) + .Should() + .ThrowAsync(); + ex.WithInnerExceptionExactly(); } - [Test] + [Fact] public async Task ModelDelete_Throws_NoAuth() { + // Arrange Model toDelete = await Sut.Create(new("Delete me", null, _project.id)); DeleteModelInput input = new(toDelete.id, _project.id); + await Sut.Delete(input); - var ex = Assert.ThrowsAsync(async () => await Sut.Delete(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Act & Assert + var ex = await FluentActions + .Invoking(async () => await Sut.Delete(input)) + .Should() + .ThrowAsync(); + ex.WithInnerExceptionExactly(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs index b3bcdedc..19051efb 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ModelResourceTests.cs @@ -1,100 +1,127 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ModelResource))] -public class ModelResourceTests +public class ModelResourceTests : IAsyncLifetime { private Client _testUser; private ModelResource Sut => _testUser.Model; private Project _project; private Model _model; - [SetUp] - public async Task Setup() + public async Task InitializeAsync() { + // Runs instead of [SetUp] in NUnit _testUser = await Fixtures.SeedUserWithClient(); _project = await _testUser.Project.Create(new("Test project", "", null)); _model = await _testUser.Model.Create(new("Test Model", "", _project.id)); } - [Order(1)] - [TestCase("My Model", "My model description")] - [TestCase("my/nested/model", null)] - public async Task ModelCreate(string name, string description) + public Task DisposeAsync() { + // Perform any cleanup, if needed + return Task.CompletedTask; + } + + [Theory] + [InlineData("My Model", "My model description")] + [InlineData("my/nested/model", null)] + public async Task ModelCreate(string name, string? description) + { + // Arrange CreateModelInput input = new(name, description, _project.id); + + // Act Model result = await Sut.Create(input); - Assert.That(result, Is.Not.Null); - Assert.That(result, Has.Property(nameof(result.id)).Not.Null); - Assert.That(result, Has.Property(nameof(result.name)).EqualTo(input.name).IgnoreCase); - Assert.That(result, Has.Property(nameof(result.description)).EqualTo(input.description)); + // Assert + result.Should().NotBeNull(); + result.id.Should().NotBeNull(); + result.name.Should().ContainEquivalentOf(input.name); + result.description.Should().Be(input.description); } - [Test] + [Fact] public async Task ModelGet() { + // Act Model result = await Sut.Get(_model.id, _project.id); - Assert.That(result.id, Is.EqualTo(_model.id)); - Assert.That(result.name, Is.EqualTo(_model.name)); - Assert.That(result.description, Is.EqualTo(_model.description)); - Assert.That(result.createdAt, Is.EqualTo(_model.createdAt)); - Assert.That(result.updatedAt, Is.EqualTo(_model.updatedAt)); + // Assert + result.id.Should().Be(_model.id); + result.name.Should().Be(_model.name); + result.description.Should().Be(_model.description); + result.createdAt.Should().Be(_model.createdAt); + result.updatedAt.Should().Be(_model.updatedAt); } - [Test] - [Order(2)] + [Fact] public async Task GetModels() { + // Act var result = await Sut.GetModels(_project.id); - Assert.That(result.items, Has.Count.EqualTo(1)); - Assert.That(result.totalCount, Is.EqualTo(1)); - Assert.That(result.items[0], Has.Property(nameof(Model.id)).EqualTo(_model.id)); + // Assert + result.items.Count.Should().Be(1); + result.totalCount.Should().Be(1); + result.items[0].id.Should().Be(_model.id); } - [Test] + [Fact] public async Task Project_GetModels() { + // Act var result = await _testUser.Project.GetWithModels(_project.id); - Assert.That(result, Has.Property(nameof(Project.id)).EqualTo(_project.id)); - Assert.That(result.models.items, Has.Count.EqualTo(1)); - Assert.That(result.models.totalCount, Is.EqualTo(1)); - Assert.That(result.models.items[0], Has.Property(nameof(Model.id)).EqualTo(_model.id)); + // Assert + result.id.Should().Be(_project.id); + result.models.items.Count.Should().Be(1); + result.models.totalCount.Should().Be(1); + result.models.items[0].id.Should().Be(_model.id); } - [Test] + [Fact] public async Task ModelUpdate() { + // Arrange const string NEW_NAME = "MY new name"; const string NEW_DESCRIPTION = "MY new desc"; - UpdateModelInput input = new(_model.id, NEW_NAME, NEW_DESCRIPTION, _project.id); + var input = new UpdateModelInput(_model.id, NEW_NAME, NEW_DESCRIPTION, _project.id); + + // Act Model updatedModel = await Sut.Update(input); - Assert.That(updatedModel.id, Is.EqualTo(_model.id)); - Assert.That(updatedModel.name, Is.EqualTo(NEW_NAME).IgnoreCase); - Assert.That(updatedModel.description, Is.EqualTo(NEW_DESCRIPTION)); - Assert.That(updatedModel.updatedAt, Is.GreaterThanOrEqualTo(_model.updatedAt)); + // Assert + updatedModel.id.Should().Be(_model.id); + updatedModel.name.Should().ContainEquivalentOf(NEW_NAME); + updatedModel.description.Should().Be(NEW_DESCRIPTION); + updatedModel.updatedAt.Should().BeOnOrAfter(_model.updatedAt); } - [Test] + [Fact] public async Task ModelDelete() { - DeleteModelInput input = new(_model.id, _project.id); + // Arrange + var input = new DeleteModelInput(_model.id, _project.id); + // Act await Sut.Delete(input); - var getEx = Assert.CatchAsync(async () => await Sut.Get(_model.id, _project.id)); - Assert.That(getEx?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Assert: Ensure fetching the deleted model throws an exception + var getEx = await FluentActions + .Invoking(() => Sut.Get(_model.id, _project.id)) + .Should() + .ThrowAsync(); + getEx.WithInnerExceptionExactly(); - var delEx = Assert.CatchAsync(async () => await Sut.Delete(input)); - Assert.That(delEx?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + // Assert: Ensure deleting the non-existing model again throws an exception + var delEx = await FluentActions.Invoking(() => Sut.Delete(input)).Should().ThrowAsync(); + getEx.WithInnerExceptionExactly(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs index 6ac9818e..86e41c71 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/OtherUserResourceTests.cs @@ -1,50 +1,54 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Credentials; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(OtherUserResource))] public class OtherUserResourceTests { - private Client _testUser; - private Account _testData; + private readonly Client _testUser; + private readonly Account _testData; private OtherUserResource Sut => _testUser.OtherUser; - [OneTimeSetUp] - public async Task Setup() + public OtherUserResourceTests() { - _testUser = await Fixtures.SeedUserWithClient(); - _testData = await Fixtures.SeedUser(); + _testUser = Fixtures.SeedUserWithClient().GetAwaiter().GetResult(); + _testData = Fixtures.SeedUser().GetAwaiter().GetResult(); } - [Test] - public async Task OtherUserGet() + [Fact] + public async Task OtherUserGet_Should_ReturnCorrectUser() { var res = await Sut.Get(_testData.userInfo.id); - Assert.That(res, Is.Not.Null); - Assert.That(res!.name, Is.EqualTo(_testData.userInfo.name)); + + res.Should().NotBeNull(); + res!.name.Should().Be(_testData.userInfo.name); } - [Test] - public async Task OtherUserGet_NonExistentUser() + [Fact] + public async Task OtherUserGet_NonExistentUser_Should_ReturnNull() { var result = await Sut.Get("AnIdThatDoesntExist"); - Assert.That(result, Is.Null); + + result.Should().BeNull(); } - [Test] - public async Task UserSearch() + [Fact] + public async Task UserSearch_Should_ReturnMatchingUser() { var res = await Sut.UserSearch(_testData.userInfo.email, 25); - Assert.That(res.items, Has.Count.EqualTo(1)); - Assert.That(res.items[0].id, Is.EqualTo(_testData.userInfo.id)); + + res.items.Should().ContainSingle(); + res.items[0].id.Should().Be(_testData.userInfo.id); } - [Test] - public async Task UserSearch_NonExistentUser() + [Fact] + public async Task UserSearch_NonExistentUser_Should_ReturnEmptyList() { var res = await Sut.UserSearch("idontexist@example.com", 25); - Assert.That(res.items, Has.Count.EqualTo(0)); + + res.items.Should().BeEmpty(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs index 07151fbc..23137093 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceExceptionalTests.cs @@ -1,33 +1,48 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ProjectInviteResource))] -public class ProjectInviteResourceExceptionalTests +public class ProjectInviteResourceExceptionalTests : IAsyncLifetime { private Client _testUser; private Project _project; private ProjectInviteResource Sut => _testUser.ProjectInvite; - [OneTimeSetUp] - public async Task Setup() + // Replacing OneTimeSetUp with IAsyncLifetime's InitializeAsync + public async Task InitializeAsync() { _testUser = await Fixtures.SeedUserWithClient(); - _project = await _testUser.Project.Create(new("test", null, null)); + _project = await _testUser.Project.Create(new ProjectCreateInput("test", null, null)); } - [TestCase(null, null, null, null)] - [TestCase(null, "something", "something", null)] - public void ProjectInviteCreate_InvalidInput(string email, string role, string serverRole, string userId) + // Implementing IAsyncLifetime's DisposeAsync (optional if no cleanup is needed) + public Task DisposeAsync() => Task.CompletedTask; + + [Theory] + [InlineData(null, null, null, null)] + [InlineData(null, "something", "something", null)] + public async Task ProjectInviteCreate_InvalidInput_ShouldThrowSpeckleGraphQLException( + string? email, + string? role, + string? serverRole, + string? userId + ) { - var ex = Assert.CatchAsync(async () => - { - var input = new ProjectInviteCreateInput(email, role, serverRole, userId); - await Sut.Create(_project.id, input); - }); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var input = new ProjectInviteCreateInput(email, role, serverRole, userId); + + var exception = await FluentActions + .Invoking(async () => + { + await Sut.Create(_project.id, input); + }) + .Should() + .ThrowAsync(); + + exception.WithInnerExceptionExactly(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs index 046b1796..0a4efd57 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectInviteResourceTests.cs @@ -1,22 +1,21 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; -using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ProjectInviteResource))] -public class ProjectInviteResourceTests +public class ProjectInviteResourceTests : IAsyncLifetime { private Client _inviter, _invitee; private Project _project; private PendingStreamCollaborator _createdInvite; - [SetUp] - public async Task Setup() + public async Task InitializeAsync() { _inviter = await Fixtures.SeedUserWithClient(); _invitee = await Fixtures.SeedUserWithClient(); @@ -24,6 +23,8 @@ public async Task Setup() _createdInvite = await SeedInvite(); } + public Task DisposeAsync() => Task.CompletedTask; + private async Task SeedInvite() { ProjectInviteCreateInput input = new(_invitee.Account.userInfo.email, null, null, null); @@ -32,7 +33,7 @@ private async Task SeedInvite() return invites.First(i => i.projectId == res.id); } - [Test] + [Fact] public async Task ProjectInviteCreate_ByEmail() { ProjectInviteCreateInput input = new(_invitee.Account.userInfo.email, null, null, null); @@ -41,75 +42,72 @@ public async Task ProjectInviteCreate_ByEmail() var invites = await _invitee.ActiveUser.GetProjectInvites(); var invite = invites.First(i => i.projectId == res.id); - Assert.That(res, Has.Property(nameof(_project.id)).EqualTo(_project.id)); - Assert.That(res.invitedTeam, Has.Count.EqualTo(1)); - Assert.That(invite.user!.id, Is.EqualTo(_invitee.Account.userInfo.id)); - Assert.That(invite.token, Is.Not.Null); + res.id.Should().Be(_project.id); + res.invitedTeam.Should().ContainSingle(); + invite.user!.id.Should().Be(_invitee.Account.userInfo.id); + invite.token.Should().NotBeNull(); } - [Test] + [Fact] public async Task ProjectInviteCreate_ByUserId() { ProjectInviteCreateInput input = new(null, null, null, _invitee.Account.userInfo.id); var res = await _inviter.ProjectInvite.Create(_project.id, input); - Assert.That(res, Has.Property(nameof(_project.id)).EqualTo(_project.id)); - Assert.That(res.invitedTeam, Has.Count.EqualTo(1)); - Assert.That(res.invitedTeam[0].user!.id, Is.EqualTo(_invitee.Account.userInfo.id)); + res.id.Should().Be(_project.id); + res.invitedTeam.Should().ContainSingle(); + res.invitedTeam[0].user!.id.Should().Be(_invitee.Account.userInfo.id); } - [Test] + [Fact] public async Task ProjectInviteGet() { - var collaborator = await _invitee.ProjectInvite.Get(_project.id, _createdInvite.token); + var collaborator = await _invitee.ProjectInvite.Get(_project.id, _createdInvite.token).NotNull(); - Assert.That( - collaborator, - Has.Property(nameof(PendingStreamCollaborator.inviteId)).EqualTo(_createdInvite.inviteId) - ); - Assert.That(collaborator!.user!.id, Is.EqualTo(_createdInvite.user!.id)); + collaborator.inviteId.Should().Be(_createdInvite.inviteId); + collaborator.user!.id.Should().Be(_createdInvite.user!.id); } - [Test] + [Fact] public async Task ProjectInviteGet_NonExisting() { var collaborator = await _invitee.ProjectInvite.Get(_project.id, "this is not a real token"); - - Assert.That(collaborator, Is.Null); + collaborator.Should().BeNull(); } - [Test] + [Fact] public async Task ProjectInviteUse_MemberAdded() { ProjectInviteUseInput input = new(true, _createdInvite.projectId, _createdInvite.token.NotNull()); await _invitee.ProjectInvite.Use(input); var project = await _inviter.Project.GetWithTeam(_project.id); - var teamMembers = project.team.Select(c => c.user.id); + var teamMembers = project.team.Select(c => c.user.id).ToArray(); var expectedTeamMembers = new[] { _inviter.Account.userInfo.id, _invitee.Account.userInfo.id }; - Assert.That(teamMembers, Is.EquivalentTo(expectedTeamMembers)); + + teamMembers.Should().BeEquivalentTo(expectedTeamMembers); } - [Test] + [Fact] public async Task ProjectInviteCancel_MemberNotAdded() { var res = await _inviter.ProjectInvite.Cancel(_createdInvite.projectId, _createdInvite.inviteId); - - Assert.That(res.invitedTeam, Is.Empty); + res.invitedTeam.Should().BeEmpty(); } - [Test] - [TestCase(StreamRoles.STREAM_OWNER)] - [TestCase(StreamRoles.STREAM_CONTRIBUTOR)] - [TestCase(StreamRoles.STREAM_REVIEWER)] - [TestCase(StreamRoles.REVOKE)] + [Theory] + [InlineData(StreamRoles.STREAM_OWNER)] + [InlineData(StreamRoles.STREAM_CONTRIBUTOR)] + [InlineData(StreamRoles.STREAM_REVIEWER)] + [InlineData(StreamRoles.REVOKE)] public async Task ProjectUpdateRole(string? newRole) { await ProjectInviteUse_MemberAdded(); + ProjectUpdateRoleInput input = new(_invitee.Account.userInfo.id, _project.id, newRole); - _ = await _inviter.Project.UpdateRole(input); + await _inviter.Project.UpdateRole(input); - Project finalProject = await _invitee.Project.Get(_project.id); - Assert.That(finalProject.role, Is.EqualTo(newRole)); + var finalProject = await _invitee.Project.Get(_project.id); + finalProject.role.Should().Be(newRole); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs index 5a938fff..2fd429b3 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceExceptionalTests.cs @@ -1,15 +1,16 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL; using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ProjectResource))] -public class ProjectResourceExceptionalTests +public class ProjectResourceExceptionalTests : IAsyncLifetime { private Client _testUser, _secondUser, @@ -17,8 +18,9 @@ public class ProjectResourceExceptionalTests private Project _testProject; private ProjectResource Sut => _testUser.Project; - [OneTimeSetUp] - public async Task Setup() + public Task DisposeAsync() => Task.CompletedTask; + + public async Task InitializeAsync() { _testUser = await Fixtures.SeedUserWithClient(); _secondUser = await Fixtures.SeedUserWithClient(); @@ -33,8 +35,8 @@ public async Task Setup() // 4. Server doesn't exist (is down) //There's got to be a smarter way to parametrise these... - [Test] - public void ProjectCreate_WithoutAuth() + [Fact] + public async Task ProjectCreate_WithoutAuth() { ProjectCreateInput input = new( "The best project", @@ -42,84 +44,88 @@ public void ProjectCreate_WithoutAuth() ProjectVisibility.Private ); - var ex = Assert.ThrowsAsync(async () => _ = await _unauthedUser.Project.Create(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var ex = await Assert.ThrowsAsync(async () => _ = await _unauthedUser.Project.Create(input)); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] + [Fact] public async Task ProjectGet_WithoutAuth() { ProjectCreateInput input = new("Private Stream", "A very private stream", ProjectVisibility.Private); Project privateStream = await Sut.Create(input); - var ex = Assert.ThrowsAsync(async () => _ = await _unauthedUser.Project.Get(privateStream.id)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var ex = await Assert.ThrowsAsync( + async () => _ = await _unauthedUser.Project.Get(privateStream.id) + ); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] - public void ProjectGet_NonExistentProject() + [Fact] + public async Task ProjectGet_NonExistentProject() { - var ex = Assert.ThrowsAsync(async () => await Sut.Get("NonExistentProject")); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var ex = await Assert.ThrowsAsync(async () => await Sut.Get("NonExistentProject")); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] - public void ProjectUpdate_NonExistentProject() + [Fact] + public async Task ProjectUpdate_NonExistentProject() { - var ex = Assert.ThrowsAsync( + var ex = await Assert.ThrowsAsync( async () => _ = await Sut.Update(new("NonExistentProject", "My new name")) ); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] - public void ProjectUpdate_NoAuth() + [Fact] + public async Task ProjectUpdate_NoAuth() { - var ex = Assert.ThrowsAsync( + var ex = await Assert.ThrowsAsync( async () => _ = await _unauthedUser.Project.Update(new(_testProject.id, "My new name")) ); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] - [TestCase(StreamRoles.STREAM_OWNER)] - [TestCase(StreamRoles.STREAM_CONTRIBUTOR)] - [TestCase(StreamRoles.STREAM_REVIEWER)] - [TestCase(StreamRoles.REVOKE)] - public void ProjectUpdateRole_NonExistentProject(string newRole) + [Theory] + [InlineData(StreamRoles.STREAM_OWNER)] + [InlineData(StreamRoles.STREAM_CONTRIBUTOR)] + [InlineData(StreamRoles.STREAM_REVIEWER)] + [InlineData(StreamRoles.REVOKE)] + public async Task ProjectUpdateRole_NonExistentProject(string? newRole) { ProjectUpdateRoleInput input = new(_secondUser.Account.id.NotNull(), "NonExistentProject", newRole); - var ex = Assert.ThrowsAsync(async () => _ = await Sut.UpdateRole(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var ex = await Assert.ThrowsAsync(async () => _ = await Sut.UpdateRole(input)); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] - [TestCase(StreamRoles.STREAM_OWNER)] - [TestCase(StreamRoles.STREAM_CONTRIBUTOR)] - [TestCase(StreamRoles.STREAM_REVIEWER)] - [TestCase(StreamRoles.REVOKE)] - public void ProjectUpdateRole_NonAuth(string newRole) + [Theory] + [InlineData(StreamRoles.STREAM_OWNER)] + [InlineData(StreamRoles.STREAM_CONTRIBUTOR)] + [InlineData(StreamRoles.STREAM_REVIEWER)] + [InlineData(StreamRoles.REVOKE)] + public async Task ProjectUpdateRole_NonAuth(string? newRole) { ProjectUpdateRoleInput input = new(_secondUser.Account.id.NotNull(), "NonExistentProject", newRole); - var ex = Assert.ThrowsAsync(async () => _ = await _unauthedUser.Project.UpdateRole(input)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var ex = await Assert.ThrowsAsync( + async () => _ = await _unauthedUser.Project.UpdateRole(input) + ); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] + [Fact] public async Task ProjectDelete_NonExistentProject() { await Sut.Delete(_testProject.id); - var ex = Assert.ThrowsAsync(async () => _ = await Sut.Get(_testProject.id)); - Assert.That(ex?.InnerExceptions, Has.One.Items.And.All.TypeOf()); + var ex = await Assert.ThrowsAsync(async () => _ = await Sut.Get(_testProject.id)); + ex.InnerExceptions.Single().Should().BeOfType(); } - [Test] - public void ProjectInvites_NoAuth() + [Fact] + public async Task ProjectInvites_NoAuth() { - Assert.ThrowsAsync(async () => await Fixtures.Unauthed.ActiveUser.ProjectInvites()); + await Assert.ThrowsAsync(async () => await Fixtures.Unauthed.ActiveUser.ProjectInvites()); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs index 18f4eb2b..98cee1fe 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/ProjectResourceTests.cs @@ -1,72 +1,103 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(ProjectResource))] public class ProjectResourceTests { - private Client _testUser; - private Project _testProject; + private readonly Client _testUser; + private readonly Project _testProject; private ProjectResource Sut => _testUser.Project; - [OneTimeSetUp] - public async Task Setup() + public ProjectResourceTests() { - _testUser = await Fixtures.SeedUserWithClient(); - _testProject = await _testUser.Project.Create(new("test project123", "desc", null)); + var setupTask = Setup(); + setupTask.Wait(); // Ensure setup runs synchronously for the constructor + (_testUser, _testProject) = setupTask.Result; } - [TestCase("Very private project", "My secret project", ProjectVisibility.Private)] - [TestCase("Very public project", null, ProjectVisibility.Public)] - public async Task ProjectCreate(string name, string desc, ProjectVisibility visibility) + private async Task<(Client TestUser, Project TestProject)> Setup() { - ProjectCreateInput input = new(name, desc, visibility); - Project result = await Sut.Create(input); - Assert.That(result, Is.Not.Null); - Assert.That(result, Has.Property(nameof(Project.id)).Not.Null); - Assert.That(result, Has.Property(nameof(Project.name)).EqualTo(input.name)); - Assert.That(result, Has.Property(nameof(Project.description)).EqualTo(input.description ?? string.Empty)); - Assert.That(result, Has.Property(nameof(Project.visibility)).EqualTo(input.visibility)); + var testUser = await Fixtures.SeedUserWithClient(); + var testProject = await testUser.Project.Create(new ProjectCreateInput("test project123", "desc", null)); + return (testUser, testProject); } - [Test] - public async Task ProjectGet() + [Theory] + [InlineData("Very private project", "My secret project", ProjectVisibility.Private)] + [InlineData("Very public project", null, ProjectVisibility.Public)] + public async Task ProjectCreate_Should_CreateProjectSuccessfully( + string name, + string? description, + ProjectVisibility visibility + ) { - Project result = await Sut.Get(_testProject.id); + // Arrange + var input = new ProjectCreateInput(name, description, visibility); - Assert.That(result.id, Is.EqualTo(_testProject.id)); - Assert.That(result.name, Is.EqualTo(_testProject.name)); - Assert.That(result.description, Is.EqualTo(_testProject.description)); - Assert.That(result.visibility, Is.EqualTo(_testProject.visibility)); - Assert.That(result.createdAt, Is.EqualTo(_testProject.createdAt)); + // Act + var result = await Sut.Create(input); + + // Assert + result.Should().NotBeNull(); + result.id.Should().NotBeNullOrWhiteSpace(); + result.name.Should().Be(input.name); + result.description.Should().Be(input.description ?? string.Empty); + input.visibility.Should().NotBeNull(); + } + + [Fact] + public async Task ProjectGet_Should_ReturnCorrectProject() + { + // Act + var result = await Sut.Get(_testProject.id); + + // Assert + result.id.Should().Be(_testProject.id); + result.name.Should().Be(_testProject.name); + result.description.Should().Be(_testProject.description); + result.visibility.Should().Be(_testProject.visibility); + result.createdAt.Should().Be(_testProject.createdAt); } - [Test] - public async Task ProjectUpdate() + [Fact] + public async Task ProjectUpdate_Should_UpdateProjectSuccessfully() { + // Arrange const string NEW_NAME = "MY new name"; const string NEW_DESCRIPTION = "MY new desc"; const ProjectVisibility NEW_VISIBILITY = ProjectVisibility.Public; - Project newProject = await Sut.Update(new(_testProject.id, NEW_NAME, NEW_DESCRIPTION, null, NEW_VISIBILITY)); + // Act + var newProject = await Sut.Update( + new ProjectUpdateInput(_testProject.id, NEW_NAME, NEW_DESCRIPTION, null, NEW_VISIBILITY) + ); - Assert.That(newProject.id, Is.EqualTo(_testProject.id)); - Assert.That(newProject.name, Is.EqualTo(NEW_NAME)); - Assert.That(newProject.description, Is.EqualTo(NEW_DESCRIPTION)); - Assert.That(newProject.visibility, Is.EqualTo(NEW_VISIBILITY)); + // Assert + newProject.id.Should().Be(_testProject.id); + newProject.name.Should().Be(NEW_NAME); + newProject.description.Should().Be(NEW_DESCRIPTION); + newProject.visibility.Should().Be(NEW_VISIBILITY); } - [Test] - public async Task ProjectDelete() + [Fact] + public async Task ProjectDelete_Should_DeleteProjectSuccessfully() { - Project toDelete = await Sut.Create(new("Delete me", null, null)); + // Arrange + var toDelete = await Sut.Create(new ProjectCreateInput("Delete me", null, null)); + + // Act await Sut.Delete(toDelete.id); - var getEx = Assert.ThrowsAsync(async () => _ = await Sut.Get(toDelete.id)); - Assert.That(getEx?.InnerExceptions, Has.Exactly(1).TypeOf()); + // Assert + await FluentActions + .Invoking(async () => await Sut.Get(toDelete.id)) + .Should() + .ThrowAsync(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs index a52985e2..596a9cac 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/SubscriptionResourceTests.cs @@ -1,13 +1,14 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Enums; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(SubscriptionResource))] -public class SubscriptionResourceTests : IDisposable +public class SubscriptionResourceTests : IAsyncLifetime { private const int WAIT_PERIOD = 300; private Client _testUser; @@ -17,8 +18,13 @@ public class SubscriptionResourceTests : IDisposable private SubscriptionResource Sut => _testUser.Subscription; - [OneTimeSetUp] - public async Task Setup() + public Task DisposeAsync() + { + _testUser.Dispose(); + return Task.CompletedTask; + } + + public async Task InitializeAsync() { _testUser = await Fixtures.SeedUserWithClient(); _testProject = await _testUser.Project.Create(new("test project123", "desc", null)); @@ -26,7 +32,7 @@ public async Task Setup() _testVersion = await Fixtures.CreateVersion(_testUser, _testProject.id, _testModel.id); } - [Test] + [Fact] public async Task UserProjectsUpdated_SubscriptionIsCalled() { UserProjectsUpdatedMessage? subscriptionMessage = null; @@ -40,13 +46,13 @@ public async Task UserProjectsUpdated_SubscriptionIsCalled() await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered - Assert.That(subscriptionMessage, Is.Not.Null); - Assert.That(subscriptionMessage!.id, Is.EqualTo(created.id)); - Assert.That(subscriptionMessage.type, Is.EqualTo(UserProjectsUpdatedMessageType.ADDED)); - Assert.That(subscriptionMessage.project, Is.Not.Null); + subscriptionMessage.Should().NotBeNull(); + subscriptionMessage!.id.Should().Be(created.id); + subscriptionMessage.type.Should().Be(UserProjectsUpdatedMessageType.ADDED); + subscriptionMessage.project.Should().NotBeNull(); } - [Test] + [Fact] public async Task ProjectModelsUpdated_SubscriptionIsCalled() { ProjectModelsUpdatedMessage? subscriptionMessage = null; @@ -61,13 +67,13 @@ public async Task ProjectModelsUpdated_SubscriptionIsCalled() await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered - Assert.That(subscriptionMessage, Is.Not.Null); - Assert.That(subscriptionMessage!.id, Is.EqualTo(created.id)); - Assert.That(subscriptionMessage.type, Is.EqualTo(ProjectModelsUpdatedMessageType.CREATED)); - Assert.That(subscriptionMessage.model, Is.Not.Null); + subscriptionMessage.Should().NotBeNull(); + subscriptionMessage!.id.Should().Be(created.id); + subscriptionMessage.type.Should().Be(ProjectModelsUpdatedMessageType.CREATED); + subscriptionMessage.model.Should().NotBeNull(); } - [Test] + [Fact] public async Task ProjectUpdated_SubscriptionIsCalled() { ProjectUpdatedMessage? subscriptionMessage = null; @@ -82,13 +88,13 @@ public async Task ProjectUpdated_SubscriptionIsCalled() await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered - Assert.That(subscriptionMessage, Is.Not.Null); - Assert.That(subscriptionMessage!.id, Is.EqualTo(created.id)); - Assert.That(subscriptionMessage.type, Is.EqualTo(ProjectUpdatedMessageType.UPDATED)); - Assert.That(subscriptionMessage.project, Is.Not.Null); + subscriptionMessage.Should().NotBeNull(); + subscriptionMessage!.id.Should().Be(created.id); + subscriptionMessage.type.Should().Be(ProjectUpdatedMessageType.UPDATED); + subscriptionMessage.project.Should().NotBeNull(); } - [Test] + [Fact] public async Task ProjectVersionsUpdated_SubscriptionIsCalled() { ProjectVersionsUpdatedMessage? subscriptionMessage = null; @@ -102,13 +108,13 @@ public async Task ProjectVersionsUpdated_SubscriptionIsCalled() await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered - Assert.That(subscriptionMessage, Is.Not.Null); - Assert.That(subscriptionMessage!.id, Is.EqualTo(created)); - Assert.That(subscriptionMessage.type, Is.EqualTo(ProjectVersionsUpdatedMessageType.CREATED)); - Assert.That(subscriptionMessage.version, Is.Not.Null); + subscriptionMessage.Should().NotBeNull(); + subscriptionMessage!.id.Should().Be(created); + subscriptionMessage.type.Should().Be(ProjectVersionsUpdatedMessageType.CREATED); + subscriptionMessage.version.Should().NotBeNull(); } - [Test] + [Fact] public async Task ProjectCommentsUpdated_SubscriptionIsCalled() { string resourceIdString = $"{_testProject.id},{_testModel.id},{_testVersion}"; @@ -123,12 +129,9 @@ public async Task ProjectCommentsUpdated_SubscriptionIsCalled() await Task.Delay(WAIT_PERIOD); // Give time for subscription to be triggered - Assert.That(subscriptionMessage, Is.Not.Null); - Assert.That(subscriptionMessage!.id, Is.EqualTo(created.id)); - Assert.That(subscriptionMessage.type, Is.EqualTo(ProjectCommentsUpdatedMessageType.CREATED)); - Assert.That(subscriptionMessage.comment, Is.Not.Null); + subscriptionMessage.Should().NotBeNull(); + subscriptionMessage!.id.Should().Be(created.id); + subscriptionMessage.type.Should().Be(ProjectCommentsUpdatedMessageType.CREATED); + subscriptionMessage.comment.Should().NotBeNull(); } - - [OneTimeTearDown] - public void Dispose() => _testUser.Dispose(); } diff --git a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs index 28264563..717d8a13 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Api/GraphQL/Resources/VersionResourceTests.cs @@ -1,13 +1,14 @@ -using Speckle.Sdk.Api; +using FluentAssertions; +using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Inputs; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Api.GraphQL.Resources; +using Xunit; using Version = Speckle.Sdk.Api.GraphQL.Models.Version; namespace Speckle.Sdk.Tests.Integration.API.GraphQL.Resources; -[TestOf(typeof(VersionResource))] -public class VersionResourceTests +public class VersionResourceTests : IAsyncLifetime { private Client _testUser; private VersionResource Sut => _testUser.Version; @@ -16,8 +17,9 @@ public class VersionResourceTests private Model _model2; private Version _version; - [SetUp] - public async Task Setup() + public Task DisposeAsync() => Task.CompletedTask; + + public async Task InitializeAsync() { _testUser = await Fixtures.SeedUserWithClient(); _project = await _testUser.Project.Create(new("Test project", "", null)); @@ -29,44 +31,44 @@ public async Task Setup() _version = await Sut.Get(versionId, _project.id); } - [Test] + [Fact] public async Task VersionGet() { Version result = await Sut.Get(_version.id, _project.id); - Assert.That(result, Has.Property(nameof(Version.id)).EqualTo(_version.id)); - Assert.That(result, Has.Property(nameof(Version.message)).EqualTo(_version.message)); + result.id.Should().Be(_version.id); + result.message.Should().Be(_version.message); } - [Test] + [Fact] public async Task VersionsGet() { ResourceCollection result = await Sut.GetVersions(_model1.id, _project.id); - Assert.That(result.items, Has.Count.EqualTo(1)); - Assert.That(result.totalCount, Is.EqualTo(1)); - Assert.That(result.items[0], Has.Property(nameof(Version.id)).EqualTo(_version.id)); + result.items.Count.Should().Be(1); + result.totalCount.Should().Be(1); + result.items[0].id.Should().Be(_version.id); } - [Test] + [Fact] public async Task VersionReceived() { MarkReceivedVersionInput input = new(_version.id, _project.id, "Integration test"); await Sut.Received(input); } - [Test] + [Fact] public async Task ModelGetWithVersions() { var result = await _testUser.Model.GetWithVersions(_model1.id, _project.id); - Assert.That(result, Has.Property(nameof(Model.id)).EqualTo(_model1.id)); - Assert.That(result.versions.items, Has.Count.EqualTo(1)); - Assert.That(result.versions.totalCount, Is.EqualTo(1)); - Assert.That(result.versions.items[0], Has.Property(nameof(Version.id)).EqualTo(_version.id)); + result.id.Should().Be(_model1.id); + result.versions.items.Count.Should().Be(1); + result.versions.totalCount.Should().Be(1); + result.versions.items[0].id.Should().Be(_version.id); } - [Test] + [Fact] public async Task VersionUpdate() { const string NEW_MESSAGE = "MY new version message"; @@ -74,34 +76,43 @@ public async Task VersionUpdate() UpdateVersionInput input = new(_version.id, _project.id, NEW_MESSAGE); Version updatedVersion = await Sut.Update(input); - Assert.That(updatedVersion, Has.Property(nameof(Version.id)).EqualTo(_version.id)); - Assert.That(updatedVersion, Has.Property(nameof(Version.message)).EqualTo(NEW_MESSAGE)); - Assert.That(updatedVersion, Has.Property(nameof(Version.previewUrl)).EqualTo(_version.previewUrl)); + updatedVersion.id.Should().Be(_version.id); + updatedVersion.message.Should().Be(NEW_MESSAGE); + updatedVersion.previewUrl.Should().Be(_version.previewUrl); } - [Test] + [Fact] public async Task VersionMoveToModel() { MoveVersionsInput input = new(_project.id, _model2.name, [_version.id]); string id = await Sut.MoveToModel(input); - Assert.That(id, Is.EqualTo(_model2.id)); + + id.Should().Be(_model2.id); + Version movedVersion = await Sut.Get(_version.id, _project.id); - Assert.That(movedVersion, Has.Property(nameof(Version.id)).EqualTo(_version.id)); - Assert.That(movedVersion, Has.Property(nameof(Version.message)).EqualTo(_version.message)); - Assert.That(movedVersion, Has.Property(nameof(Version.previewUrl)).EqualTo(_version.previewUrl)); + movedVersion.id.Should().Be(_version.id); + movedVersion.message.Should().Be(_version.message); + movedVersion.previewUrl.Should().Be(_version.previewUrl); } - [Test] + [Fact] public async Task VersionDelete() { DeleteVersionsInput input = new([_version.id], _project.id); await Sut.Delete(input); - var getEx = Assert.ThrowsAsync(async () => await Sut.Get(_version.id, _project.id)); - Assert.That(getEx?.InnerExceptions, Has.Exactly(1).TypeOf()); - var delEx = Assert.ThrowsAsync(async () => await Sut.Delete(input)); - Assert.That(delEx?.InnerExceptions, Has.Exactly(1).TypeOf()); + var getEx = await FluentActions + .Invoking(async () => await Sut.Get(_version.id, _project.id)) + .Should() + .ThrowAsync(); + getEx.WithInnerExceptionExactly(); + + var delEx = await FluentActions + .Invoking(async () => await Sut.Delete(input)) + .Should() + .ThrowAsync(); + delEx.WithInnerExceptionExactly(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs b/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs index 782244f4..fe621978 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Credentials/UserServerInfoTests.cs @@ -1,40 +1,43 @@ -using GraphQL.Client.Http; +using FluentAssertions; +using GraphQL.Client.Http; using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; +using Xunit; namespace Speckle.Sdk.Tests.Integration.Credentials; -public class UserServerInfoTests +public class UserServerInfoTests : IAsyncLifetime { private Account _acc; - [SetUp] - public async Task Setup() + public Task DisposeAsync() => Task.CompletedTask; + + public async Task InitializeAsync() { _acc = await Fixtures.SeedUser(); } - [Test] + [Fact] public async Task IsFrontEnd2True() { ServerInfo? result = await Fixtures .ServiceProvider.GetRequiredService() .GetServerInfo(new("https://app.speckle.systems/")); - Assert.That(result, Is.Not.Null); - Assert.That(result!.frontend2, Is.True); + result.Should().NotBeNull(); + result.frontend2.Should().BeTrue(); } - [Test] + [Fact] public async Task IsFrontEnd2False() { ServerInfo? result = await Fixtures .ServiceProvider.GetRequiredService() .GetServerInfo(new("https://speckle.xyz/")); - Assert.That(result, Is.Not.Null); - Assert.That(result!.frontend2, Is.False); + result.Should().NotBeNull(); + result.frontend2.Should().BeFalse(); } /// @@ -43,27 +46,33 @@ public async Task IsFrontEnd2False() /// This is not doable in local server because there is no end-point on this to ping. /// This is a bad sign for mutation. /// - [Test] - public void GetServerInfo_ExpectFail_CantPing() + [Fact] + public async Task GetServerInfo_ExpectFail_CantPing() { Uri serverUrl = new(_acc.serverInfo.url); - Assert.ThrowsAsync( - async () => await Fixtures.ServiceProvider.GetRequiredService().GetServerInfo(serverUrl) - ); + await FluentActions + .Invoking( + async () => await Fixtures.ServiceProvider.GetRequiredService().GetServerInfo(serverUrl) + ) + .Should() + .ThrowAsync(); } - [Test] - public void GetServerInfo_ExpectFail_NoServer() + [Fact] + public async Task GetServerInfo_ExpectFail_NoServer() { Uri serverUrl = new("http://invalidserver.local"); - Assert.ThrowsAsync( - async () => await Fixtures.ServiceProvider.GetRequiredService().GetServerInfo(serverUrl) - ); + await FluentActions + .Invoking( + async () => await Fixtures.ServiceProvider.GetRequiredService().GetServerInfo(serverUrl) + ) + .Should() + .ThrowAsync(); } - [Test] + [Fact] public async Task GetUserInfo() { Uri serverUrl = new(_acc.serverInfo.url); @@ -71,33 +80,38 @@ public async Task GetUserInfo() .ServiceProvider.GetRequiredService() .GetUserInfo(_acc.token, serverUrl); - Assert.That(result.id, Is.EqualTo(_acc.userInfo.id)); - Assert.That(result.name, Is.EqualTo(_acc.userInfo.name)); - Assert.That(result.email, Is.EqualTo(_acc.userInfo.email)); - Assert.That(result.company, Is.EqualTo(_acc.userInfo.company)); - Assert.That(result.avatar, Is.EqualTo(_acc.userInfo.avatar)); + result.id.Should().Be(_acc.userInfo.id); + result.name.Should().Be(_acc.userInfo.name); + result.email.Should().Be(_acc.userInfo.email); + result.company.Should().Be(_acc.userInfo.company); + result.avatar.Should().Be(_acc.userInfo.avatar); } - [Test] - public void GetUserInfo_ExpectFail_NoServer() + [Fact] + public async Task GetUserInfo_ExpectFail_NoServer() { Uri serverUrl = new("http://invalidserver.local"); - Assert.ThrowsAsync( - async () => await Fixtures.ServiceProvider.GetRequiredService().GetUserInfo("", serverUrl) - ); + await FluentActions + .Invoking( + async () => await Fixtures.ServiceProvider.GetRequiredService().GetUserInfo("", serverUrl) + ) + .Should() + .ThrowAsync(); } - [Test] - public void GetUserInfo_ExpectFail_NoUser() + [Fact] + public async Task GetUserInfo_ExpectFail_NoUser() { Uri serverUrl = new(_acc.serverInfo.url); - - Assert.ThrowsAsync( - async () => - await Fixtures - .ServiceProvider.GetRequiredService() - .GetUserInfo("Bearer 08913c3c1e7ac65d779d1e1f11b942a44ad9672ca9", serverUrl) - ); + await FluentActions + .Invoking( + async () => + await Fixtures + .ServiceProvider.GetRequiredService() + .GetUserInfo("Bearer 08913c3c1e7ac65d779d1e1f11b942a44ad9672ca9", serverUrl) + ) + .Should() + .ThrowAsync(); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs b/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs index d57badd1..58241347 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs +++ b/tests/Speckle.Sdk.Tests.Integration/Fixtures.cs @@ -54,9 +54,9 @@ public static async Task SeedUser() var seed = Guid.NewGuid().ToString().ToLower(); Dictionary user = new() { - ["email"] = $"{seed.Substring(0, 7)}@example.com", + ["email"] = $"{seed[..7]}@example.com", ["password"] = "12ABC3456789DEF0GHO", - ["name"] = $"{seed.Substring(0, 5)} Name", + ["name"] = $"{seed[..5]} Name", }; using var httpClient = new HttpClient( diff --git a/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs b/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs index 230804b4..99ccf856 100644 --- a/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Integration/MemoryTransportTests.cs @@ -1,21 +1,20 @@ -using System.Collections.Concurrent; -using System.Reflection; +using System.Reflection; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using Shouldly; using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Integration; -public class MemoryTransportTests +public class MemoryTransportTests : IDisposable { private readonly MemoryTransport _memoryTransport = new(blobStorageEnabled: true); private IOperations _operations; - [SetUp] - public void Setup() + public MemoryTransportTests() { CleanData(); TypeLoader.Reset(); @@ -24,8 +23,7 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - [TearDown] - public void TearDown() => CleanData(); + public void Dispose() => CleanData(); private void CleanData() { @@ -33,10 +31,11 @@ private void CleanData() { Directory.Delete(_memoryTransport.BlobStorageFolder, true); } + Directory.CreateDirectory(_memoryTransport.BlobStorageFolder); } - [Test] + [Fact] public async Task SendAndReceiveObjectWithBlobs() { var myObject = Fixtures.GenerateSimpleObject(); @@ -53,20 +52,24 @@ public async Task SendAndReceiveObjectWithBlobs() .GetFiles(_memoryTransport.BlobStorageFolder) .Select(fp => fp.Split(Path.DirectorySeparatorChar).Last()) .ToList(); + var blobPaths = allFiles .Where(fp => fp.Length > Blob.LocalHashPrefixLength) // excludes things like .DS_store .ToList(); // Check that there are three downloaded blobs! - Assert.That(blobPaths, Has.Count.EqualTo(3)); + blobPaths.Count.Should().Be(3); + var objectBlobs = receivedObject["blobs"] as IList; - objectBlobs.ShouldNotBeNull(); - var blobs = objectBlobs.Cast().ToList(); + objectBlobs.Should().NotBeNull(); + + var blobs = objectBlobs!.Cast().ToList(); // Check that we have three blobs - Assert.That(blobs, Has.Count.EqualTo(3)); + blobs.Count.Should().Be(3); + // Check that received blobs point to local path (where they were received) - Assert.That(blobs[0].filePath, Contains.Substring(_memoryTransport.BlobStorageFolder)); - Assert.That(blobs[1].filePath, Contains.Substring(_memoryTransport.BlobStorageFolder)); - Assert.That(blobs[2].filePath, Contains.Substring(_memoryTransport.BlobStorageFolder)); + blobs[0].filePath.Should().Contain(_memoryTransport.BlobStorageFolder); + blobs[1].filePath.Should().Contain(_memoryTransport.BlobStorageFolder); + blobs[2].filePath.Should().Contain(_memoryTransport.BlobStorageFolder); } } diff --git a/tests/Speckle.Sdk.Tests.Integration/Speckle.Sdk.Tests.Integration.csproj b/tests/Speckle.Sdk.Tests.Integration/Speckle.Sdk.Tests.Integration.csproj index 5eb43529..e5204dc2 100644 --- a/tests/Speckle.Sdk.Tests.Integration/Speckle.Sdk.Tests.Integration.csproj +++ b/tests/Speckle.Sdk.Tests.Integration/Speckle.Sdk.Tests.Integration.csproj @@ -9,9 +9,8 @@ - - - + + diff --git a/tests/Speckle.Sdk.Tests.Integration/Usings.cs b/tests/Speckle.Sdk.Tests.Integration/Usings.cs deleted file mode 100644 index 32445676..00000000 --- a/tests/Speckle.Sdk.Tests.Integration/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using NUnit.Framework; diff --git a/tests/Speckle.Sdk.Tests.Integration/packages.lock.json b/tests/Speckle.Sdk.Tests.Integration/packages.lock.json index 160e2842..2c652b68 100644 --- a/tests/Speckle.Sdk.Tests.Integration/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Integration/packages.lock.json @@ -4,9 +4,9 @@ "net8.0": { "altcover": { "type": "Direct", - "requested": "[8.9.3, )", - "resolved": "8.9.3", - "contentHash": "auKC+pDCkLjfhFkSRaAUBu25BOmlLSqucR7YBs/Lkbdc0XRuJoklWafs1KKp+M+VoJ1f0TeMS6B/FO5IeIcu7w==" + "requested": "[9.0.1, )", + "resolved": "9.0.1", + "contentHash": "aadciFNDT5bnylaYUkKal+s5hF7yU/lmZxImQWAlk1438iPqK1Uf79H5ylELpyLIU49HL5ql+tnWBihp3WVLCA==" }, "GitVersion.MsBuild": { "type": "Direct", @@ -16,12 +16,12 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.11.1, )", - "resolved": "17.11.1", - "contentHash": "U3Ty4BaGoEu+T2bwSko9tWqWUOU16WzSFkq6U8zve75oRBMSLTBdMAZrVNNz1Tq12aCdDom9fcOcM9QZaFHqFg==", + "requested": "[17.12.0, )", + "resolved": "17.12.0", + "contentHash": "kt/PKBZ91rFCWxVIJZSgVLk+YR+4KxTuHf799ho8WNiK5ZQpJNAEZCAWX86vcKrs+DiYjiibpYKdGZP6+/N17w==", "dependencies": { - "Microsoft.CodeCoverage": "17.11.1", - "Microsoft.TestPlatform.TestHost": "17.11.1" + "Microsoft.CodeCoverage": "17.12.0", + "Microsoft.TestPlatform.TestHost": "17.12.0" } }, "Microsoft.SourceLink.GitHub": { @@ -34,53 +34,34 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, - "NUnit": { - "type": "Direct", - "requested": "[4.2.2, )", - "resolved": "4.2.2", - "contentHash": "mon0OPko28yZ/foVXrhiUvq1LReaGsBdziumyyYGxV/pOE4q92fuYeN+AF+gEU5pCjzykcdBt5l7xobTaiBjsg==" - }, - "NUnit3TestAdapter": { - "type": "Direct", - "requested": "[4.6.0, )", - "resolved": "4.6.0", - "contentHash": "R7e1+a4vuV/YS+ItfL7f//rG+JBvVeVLX4mHzFEZo4W1qEKl8Zz27AqvQSAqo+BtIzUCo4aAJMYa56VXS4hudw==" - }, "PolySharp": { "type": "Direct", "requested": "[1.15.0, )", "resolved": "1.15.0", "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g==" }, - "Shouldly": { - "type": "Direct", - "requested": "[4.2.1, )", - "resolved": "4.2.1", - "contentHash": "dKAKiSuhLKqD2TXwLKtqNg1nwzJcIKOOMncZjk9LYe4W+h+SCftpWdxwR79YZUIHMH+3Vu9s0s0UHNrgICLwRQ==", - "dependencies": { - "DiffEngine": "11.3.0", - "EmptyFiles": "4.4.0" - } - }, "Speckle.InterfaceGenerator": { "type": "Direct", "requested": "[0.9.6, )", "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "DiffEngine": { - "type": "Transitive", - "resolved": "11.3.0", - "contentHash": "k0ZgZqd09jLZQjR8FyQbSQE86Q7QZnjEzq1LPHtj1R2AoWO8sjV5x+jlSisL7NZAbUOI4y+7Bog8gkr9WIRBGw==", + "xunit": { + "type": "Direct", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", "dependencies": { - "EmptyFiles": "4.4.0", - "System.Management": "6.0.1" + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" } }, - "EmptyFiles": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "gwJEfIGS7FhykvtZoscwXj/XwW+mJY6UbAZk+qtLKFUGWC95kfKXnj8VkxsZQnWBxJemM/q664rGLN5nf+OHZw==" + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "HggUqjQJe8PtDxcP25Q+CnR6Lz4oX3GElhD9V4oU2+75x9HI6A6sxbfKGS4UwU4t4yJaS9fBmAuriz8bQApNjw==" }, "GraphQL.Client.Abstractions": { "type": "Transitive", @@ -110,8 +91,8 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "nPJqrcA5iX+Y0kqoT3a+pD/8lrW/V7ayqnEJQsTonSoPz59J8bmoQhcSN4G8+UJ64Hkuf0zuxnfuj2lkHOq4cA==" + "resolved": "17.12.0", + "contentHash": "4svMznBd5JM21JIG2xZKGNanAHNXplxf/kQDFfLHXQ3OnpJkayRK/TjacFjA+EYmoyuNXHo/sOETEfcYtAzIrA==" }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", @@ -176,21 +157,26 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "E2jZqAU6JeWEVsyOEOrSW1o1bpHLgb25ypvKNB/moBXPVsFYBPd/Jwi7OrYahG50J83LfHzezYI+GaEkpAotiA==", + "resolved": "17.12.0", + "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==", "dependencies": { "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "DnG+GOqJXO/CkoqlJWeDFTgPhqD/V6VqUIL3vINizCWZ3X+HshCtbbyDdSHQQEjrc2Sl/K3yaxX6s+5LFEdYuw==", + "resolved": "17.12.0", + "contentHash": "MiPEJQNyADfwZ4pJNpQex+t9/jOClBGMiCiVVFuELCMSX2nmNfvUor3uFVxNNCg30uxDP8JDYfPnMXQzsfzYyg==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.11.1", + "Microsoft.TestPlatform.ObjectModel": "17.12.0", "Newtonsoft.Json": "13.0.1" } }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "hqTM5628jSsQiv+HGpiq3WKBl2c8v1KZfby2J6Pr7pEPlK9waPdgEO6b8A/+/xn/yZ9ulv8HuqK71ONy2tg67A==" + }, "Newtonsoft.Json": { "type": "Transitive", "resolved": "13.0.1", @@ -226,22 +212,26 @@ "SQLitePCLRaw.core": "2.1.4" } }, - "System.CodeDom": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA==" - }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, - "System.Management": { + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "7T+m0kDSlIPTHIkPMIu6m6tV6qsMqJpvQWW2jIc2qi7sn40qxFo0q+7mEQAhMPXZHMKnWrnv47ntGlM/ejvw3g==", + "dependencies": { + "System.Security.Cryptography.ProtectedData": "6.0.0", + "System.Security.Permissions": "6.0.0" + } + }, + "System.Drawing.Common": { "type": "Transitive", - "resolved": "6.0.1", - "contentHash": "10J1D0h/lioojphfJ4Fuh5ZUThT/xOVHdV9roGBittKKNP2PMjrvibEdbVTGZcPra1399Ja3tqIJLyQrc5Wmhg==", + "resolved": "6.0.0", + "contentHash": "NfuoKUiP2nUWwKZN6twGqXioIe1zVD0RIj2t976A+czLHr2nY454RwwXs6JU9Htc6mwqL6Dn/nEL3dpVf2jOhg==", "dependencies": { - "System.CodeDom": "6.0.0" + "Microsoft.Win32.SystemEvents": "6.0.0" } }, "System.Memory": { @@ -264,6 +254,73 @@ "resolved": "4.5.1", "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "rp1gMNEZpvx9vP0JW0oHLxlf8oSiQgtno77Y4PLUBjSiDYoD77Y8uXHr1Ea5XG4/pIKhqAdxZ8v8OTUtqo9PeQ==" + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "T/uuc7AklkDoxmcJ7LGkyX1CcSviZuLCa4jg3PekfJ7SU0niF0IVTXwUiNVP9DSpzou2PpxJ+eNY2IfDM90ZCg==", + "dependencies": { + "System.Security.AccessControl": "6.0.0", + "System.Windows.Extensions": "6.0.0" + } + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "IXoJOXIqc39AIe+CIR7koBtRGMiCt/LPM3lI+PELtDIy9XdyeSrwXFdWV9dzJ2Awl0paLWUaknLxFQ5HpHZUog==", + "dependencies": { + "System.Drawing.Common": "6.0.0" + } + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]" + } + }, "speckle.sdk": { "type": "Project", "dependencies": { @@ -283,14 +340,23 @@ "speckle.sdk.tests.unit": { "type": "Project", "dependencies": { + "FluentAssertions": "[7.0.0, )", "Microsoft.Extensions.DependencyInjection": "[2.2.0, )", - "Microsoft.NET.Test.Sdk": "[17.11.1, )", - "NUnit": "[4.2.2, )", - "NUnit3TestAdapter": "[4.6.0, )", - "Shouldly": "[4.2.1, )", + "Microsoft.NET.Test.Sdk": "[17.12.0, )", "Speckle.DoubleNumerics": "[4.0.1, )", "Speckle.Sdk": "[1.0.0, )", - "altcover": "[8.9.3, )" + "altcover": "[9.0.1, )", + "xunit": "[2.9.3, )", + "xunit.runner.visualstudio": "[3.0.0, )" + } + }, + "FluentAssertions": { + "type": "CentralTransitive", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "mTLbcU991EQ1SEmNbVBaGGGJy0YFzvGd1sYJGNZ07nlPKuyHSn1I22aeKzqQXgEiaKyRO6MSCto9eN9VxMwBdA==", + "dependencies": { + "System.Configuration.ConfigurationManager": "6.0.0" } }, "GraphQL.Client": { diff --git a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralReceiveTest.cs b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralReceiveTest.cs index 60c2ee39..e0727f8d 100644 --- a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralReceiveTest.cs +++ b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralReceiveTest.cs @@ -4,13 +4,8 @@ using Speckle.Objects.Geometry; using Speckle.Sdk.Api; using Speckle.Sdk.Credentials; -using Speckle.Sdk.Helpers; using Speckle.Sdk.Host; -using Speckle.Sdk.Logging; using Speckle.Sdk.Models; -using Speckle.Sdk.Serialisation; -using Speckle.Sdk.Serialisation.V2; -using Speckle.Sdk.Serialisation.V2.Receive; using Speckle.Sdk.Transports; namespace Speckle.Sdk.Tests.Performance.Benchmarks; diff --git a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSerializerTest.cs b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSerializerTest.cs index deb8a27d..48b544dd 100644 --- a/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSerializerTest.cs +++ b/tests/Speckle.Sdk.Tests.Performance/Benchmarks/GeneralSerializerTest.cs @@ -1,6 +1,5 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Engines; -using Microsoft.Extensions.Logging.Abstractions; using Speckle.Objects.Geometry; using Speckle.Sdk.Common; using Speckle.Sdk.Credentials; diff --git a/tests/Speckle.Sdk.Tests.Performance/Program.cs b/tests/Speckle.Sdk.Tests.Performance/Program.cs index 889b29d8..75694359 100644 --- a/tests/Speckle.Sdk.Tests.Performance/Program.cs +++ b/tests/Speckle.Sdk.Tests.Performance/Program.cs @@ -1,7 +1,6 @@ // See https://aka.ms/new-console-template for more information using BenchmarkDotNet.Running; -using Speckle.Sdk.Tests.Performance.Benchmarks; BenchmarkSwitcher.FromAssemblies([typeof(Program).Assembly]).Run(args); // var sut = new GeneralSendTest(); diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs b/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs index 53f4c394..af764b5d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/ClientResiliencyPolicyTest.cs @@ -1,20 +1,18 @@ using System.Diagnostics; -using GraphQL; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api; -[TestOf(typeof(Client))] public sealed class GraphQLClientTests : IDisposable { - private Client _client; + private readonly Client _client; - [OneTimeSetUp] - public void Setup() + public GraphQLClientTests() { var serviceProvider = TestServiceSetup.GetServiceProvider(); _client = serviceProvider @@ -28,17 +26,14 @@ public void Setup() ); } - public void Dispose() - { - _client?.Dispose(); - } + public void Dispose() => _client?.Dispose(); - [Test] - public void TestExecuteWithResiliencePoliciesDoesntRetryTaskCancellation() + [Fact] + public async Task TestExecuteWithResiliencePoliciesDoesntRetryTaskCancellation() { var timer = new Stopwatch(); timer.Start(); - Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { var tokenSource = new CancellationTokenSource(); tokenSource.Cancel(); @@ -55,14 +50,13 @@ await Task.Run( ); }); timer.Stop(); - var elapsed = timer.ElapsedMilliseconds; + timer.ElapsedMilliseconds.Should().BeLessThan(1000); // the default retry policy would retry 5 times with 1 second jitter backoff each // if the elapsed is less than a second, this was def not retried - Assert.That(elapsed, Is.LessThan(1000)); } - [Test] + [Fact] public async Task TestExecuteWithResiliencePoliciesRetry() { var counter = 0; @@ -82,8 +76,8 @@ public async Task TestExecuteWithResiliencePoliciesRetry() }); timer.Stop(); // The baseline for wait is 1 seconds between the jittered retry - Assert.That(timer.ElapsedMilliseconds, Is.GreaterThanOrEqualTo(5000)); - Assert.That(counter, Is.EqualTo(maxRetryCount)); + timer.ElapsedMilliseconds.Should().BeGreaterThanOrEqualTo(5000); + counter.Should().Be(maxRetryCount); } public class FakeGqlResponseModel { } diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs b/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs index 72c78df2..3a06614f 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/GraphQLErrorHandler.cs @@ -1,55 +1,41 @@ -using GraphQL; -using NUnit.Framework; +using FluentAssertions; +using GraphQL; using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api; public class GraphQLErrorHandlerTests { - private static IEnumerable ErrorCases() + public static IEnumerable ErrorCases() { - yield return new TestCaseData(typeof(SpeckleGraphQLForbiddenException), new Map { { "code", "FORBIDDEN" } }); - yield return new TestCaseData(typeof(SpeckleGraphQLForbiddenException), new Map { { "code", "UNAUTHENTICATED" } }); - yield return new TestCaseData( - typeof(SpeckleGraphQLInternalErrorException), - new Map { { "code", "INTERNAL_SERVER_ERROR" } } - ); - yield return new TestCaseData( - typeof(SpeckleGraphQLStreamNotFoundException), - new Map { { "code", "STREAM_NOT_FOUND" } } - ); - yield return new TestCaseData(typeof(SpeckleGraphQLBadInputException), new Map { { "code", "BAD_USER_INPUT" } }); - yield return new TestCaseData( - typeof(SpeckleGraphQLInvalidQueryException), - new Map { { "code", "GRAPHQL_PARSE_FAILED" } } - ); - yield return new TestCaseData( - typeof(SpeckleGraphQLInvalidQueryException), - new Map { { "code", "GRAPHQL_VALIDATION_FAILED" } } - ); - yield return new TestCaseData(typeof(SpeckleGraphQLException), new Map { { "foo", "bar" } }); - yield return new TestCaseData(typeof(SpeckleGraphQLException), new Map { { "code", "CUSTOM_THING" } }); + yield return [typeof(SpeckleGraphQLForbiddenException), new Map { { "code", "FORBIDDEN" } }]; + yield return [typeof(SpeckleGraphQLForbiddenException), new Map { { "code", "UNAUTHENTICATED" } }]; + yield return [typeof(SpeckleGraphQLInternalErrorException), new Map { { "code", "INTERNAL_SERVER_ERROR" } }]; + yield return [typeof(SpeckleGraphQLStreamNotFoundException), new Map { { "code", "STREAM_NOT_FOUND" } }]; + yield return [typeof(SpeckleGraphQLBadInputException), new Map { { "code", "BAD_USER_INPUT" } }]; + yield return [typeof(SpeckleGraphQLInvalidQueryException), new Map { { "code", "GRAPHQL_PARSE_FAILED" } }]; + yield return [typeof(SpeckleGraphQLInvalidQueryException), new Map { { "code", "GRAPHQL_VALIDATION_FAILED" } }]; + yield return [typeof(SpeckleGraphQLException), new Map { { "foo", "bar" } }]; + yield return [typeof(SpeckleGraphQLException), new Map { { "code", "CUSTOM_THING" } }]; } - [Test, TestCaseSource(nameof(ErrorCases))] + [Theory] + [MemberData(nameof(ErrorCases))] public void TestExceptionThrowingFromGraphQLErrors(Type exType, Map extensions) { var ex = Assert.Throws( () => - GraphQLErrorHandler.EnsureGraphQLSuccess( - new GraphQLResponse - { - Errors = new GraphQLError[] { new() { Extensions = extensions } }, - } - ) + new GraphQLResponse + { + Errors = [new() { Extensions = extensions }], + }.EnsureGraphQLSuccess() ); - Assert.That(ex?.InnerExceptions, Has.Exactly(1).TypeOf(exType)); + ex.InnerExceptions.Count.Should().Be(1); + ex.InnerExceptions[0].Should().BeOfType(exType); } - [Test] - public void TestMaybeThrowsDoesntThrowForNoErrors() - { - Assert.DoesNotThrow(() => GraphQLErrorHandler.EnsureGraphQLSuccess(new GraphQLResponse())); - } + [Fact] + public void TestMaybeThrowsDoesntThrowForNoErrors() => new GraphQLResponse().EnsureGraphQLSuccess(); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs index 88ea3a3c..1240254e 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/ClosureTests.cs @@ -1,23 +1,21 @@ +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; -using NUnit.Framework; using Speckle.Sdk.Api; using Speckle.Sdk.Common; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; -[TestFixture] -[TestOf(typeof(Sdk.Api.Operations))] public class Closures { - private IOperations _operations; + private readonly IOperations _operations; - [SetUp] - public void Setup() + public Closures() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(TableLegFixture).Assembly); @@ -25,7 +23,7 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - [Test(Description = "Checks whether closures are generated correctly by the serialiser.")] + [Fact(DisplayName = "Checks whether closures are generated correctly by the serialiser.")] public async Task CorrectDecompositionTracking() { var d5 = new Base(); @@ -56,31 +54,31 @@ public async Task CorrectDecompositionTracking() var test = await _operations.Receive(sendResult.rootObjId, localTransport: transport); test.id.NotNull(); - Assert.That(d1.GetId(true), Is.EqualTo(test.id)); + d1.GetId(true).Should().BeEquivalentTo((test.id)); var d1_ = NotNullExtensions.NotNull(JsonConvert.DeserializeObject(transport.Objects[d1.GetId(true)])); var d2_ = NotNullExtensions.NotNull(JsonConvert.DeserializeObject(transport.Objects[d2.GetId(true)])); var d3_ = NotNullExtensions.NotNull(JsonConvert.DeserializeObject(transport.Objects[d3.GetId(true)])); - var d4_ = JsonConvert.DeserializeObject(transport.Objects[d4.GetId(true)]); - var d5_ = JsonConvert.DeserializeObject(transport.Objects[d5.GetId(true)]); + JsonConvert.DeserializeObject(transport.Objects[d4.GetId(true)]); + JsonConvert.DeserializeObject(transport.Objects[d5.GetId(true)]); var depthOf_d5_in_d1 = int.Parse((string)d1_.__closure[d5.GetId(true)]); - Assert.That(depthOf_d5_in_d1, Is.EqualTo(1)); + depthOf_d5_in_d1.Should().Be(1); var depthOf_d4_in_d1 = int.Parse((string)d1_.__closure[d4.GetId(true)]); - Assert.That(depthOf_d4_in_d1, Is.EqualTo(3)); + depthOf_d4_in_d1.Should().Be(3); var depthOf_d5_in_d3 = int.Parse((string)d3_.__closure[d5.GetId(true)]); - Assert.That(depthOf_d5_in_d3, Is.EqualTo(2)); + depthOf_d5_in_d3.Should().Be(2); var depthOf_d4_in_d3 = int.Parse((string)d3_.__closure[d4.GetId(true)]); - Assert.That(depthOf_d4_in_d3, Is.EqualTo(1)); + depthOf_d4_in_d3.Should().Be(1); var depthOf_d5_in_d2 = int.Parse((string)d2_.__closure[d5.GetId(true)]); - Assert.That(depthOf_d5_in_d2, Is.EqualTo(1)); + depthOf_d5_in_d2.Should().Be(1); } - [Test] + [Fact] public void DescendantsCounting() { Base myBase = new(); @@ -118,18 +116,15 @@ public void DescendantsCounting() myBase["@detachTheDictionary"] = dictionary; - var count = myBase.GetTotalChildrenCount(); - Assert.That(count, Is.EqualTo(112)); + myBase.GetTotalChildrenCount().Should().Be(112); var tableTest = new DiningTable(); - var tableKidsCount = tableTest.GetTotalChildrenCount(); - Assert.That(tableKidsCount, Is.EqualTo(10)); + tableTest.GetTotalChildrenCount().Should().Be(10); // Explicitely test for recurisve references! var recursiveRef = new Base { applicationId = "random" }; recursiveRef["@recursive"] = recursiveRef; - var supriseCount = recursiveRef.GetTotalChildrenCount(); - Assert.That(supriseCount, Is.EqualTo(2)); + recursiveRef.GetTotalChildrenCount().Should().Be(2); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs index 14caa794..1079ef52 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.Exceptional.cs @@ -1,43 +1,39 @@ -using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Speckle.Sdk.Api; -using Speckle.Sdk.Host; -using Speckle.Sdk.Models; -using Speckle.Sdk.Transports; +using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; public partial class OperationsReceiveTests { - [Test, TestCaseSource(nameof(TestCases))] - public void Receive_ObjectsDontExist_ExceptionThrown(string id) + [Theory, MemberData(nameof(TestCases))] + public async Task Receive_ObjectsDontExist_ExceptionThrown(string id) { MemoryTransport emptyTransport1 = new(); MemoryTransport emptyTransport2 = new(); - Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await _operations.Receive(id, emptyTransport1, emptyTransport2); }); } - [Test, TestCaseSource(nameof(TestCases))] - public void Receive_ObjectsDontExistNullRemote_ExceptionThrown(string id) + [Theory, MemberData(nameof(TestCases))] + public async Task Receive_ObjectsDontExistNullRemote_ExceptionThrown(string id) { MemoryTransport emptyTransport = new(); - Assert.ThrowsAsync(async () => + await Assert.ThrowsAsync(async () => { await _operations.Receive(id, null, emptyTransport); }); } - [Test, TestCaseSource(nameof(TestCases))] - public void Receive_OperationCanceled_ExceptionThrown(string id) + [Theory, MemberData(nameof(TestCases))] + public async Task Receive_OperationCanceled_ExceptionThrown(string id) { using CancellationTokenSource ctc = new(); ctc.Cancel(); MemoryTransport emptyTransport2 = new(); - Assert.CatchAsync(async () => + await Assert.ThrowsAsync(async () => { await _operations.Receive(id, _testCaseTransport, emptyTransport2, cancellationToken: ctc.Token); }); diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs index 1a51c2f5..8df3a466 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/OperationsReceiveTests.cs @@ -1,18 +1,18 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; -[TestFixture, TestOf(nameof(Sdk.Api.Operations.Receive))] -public sealed partial class OperationsReceiveTests +public sealed partial class OperationsReceiveTests : IDisposable { private static readonly Base[] s_testObjects; - private IOperations _operations; + private readonly IOperations _operations; + private readonly MemoryTransport _testCaseTransport; static OperationsReceiveTests() { @@ -29,64 +29,57 @@ static OperationsReceiveTests() ]; } - public static IEnumerable TestCases() + public OperationsReceiveTests() { - List ret = new(); - foreach (var s in s_testObjects) + Reset(); + var serviceProvider = TestServiceSetup.GetServiceProvider(); + _operations = serviceProvider.GetRequiredService(); + _testCaseTransport = new MemoryTransport(); + + // Simulate a one-time setup action + foreach (var b in s_testObjects) { - ret.Add(s.GetId(true)); + _ = _operations.Send(b, _testCaseTransport, false).GetAwaiter().GetResult(); } - - return ret; } - private MemoryTransport _testCaseTransport; - private static void Reset() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly()); } - [OneTimeSetUp] - public async Task GlobalSetup() + public static IEnumerable TestCases() { - Reset(); - var serviceProvider = TestServiceSetup.GetServiceProvider(); - _operations = serviceProvider.GetRequiredService(); - _testCaseTransport = new MemoryTransport(); - foreach (var b in s_testObjects) + foreach (var s in s_testObjects) { - await _operations.Send(b, _testCaseTransport, false); + yield return [s.GetId(true)]; } } - [SetUp] - public void Setup() - { - Reset(); - var serviceProvider = TestServiceSetup.GetServiceProvider(); - _operations = serviceProvider.GetRequiredService(); - } - - [Test, TestCaseSource(nameof(TestCases))] + [Theory] + [MemberData(nameof(TestCases))] public async Task Receive_FromLocal_ExistingObjects(string id) { Base result = await _operations.Receive(id, null, _testCaseTransport); - Assert.That(result.id, Is.EqualTo(id)); + Assert.NotNull(result); + Assert.Equal(id, result.id); } - [Test, TestCaseSource(nameof(TestCases))] + [Theory] + [MemberData(nameof(TestCases))] public async Task Receive_FromRemote_ExistingObjects(string id) { MemoryTransport localTransport = new(); Base result = await _operations.Receive(id, _testCaseTransport, localTransport); - Assert.That(result.id, Is.EqualTo(id)); + Assert.NotNull(result); + Assert.Equal(id, result.id); } - [Test, TestCaseSource(nameof(TestCases))] + [Theory] + [MemberData(nameof(TestCases))] public async Task Receive_FromLocal_OnProgressActionCalled(string id) { bool wasCalled = false; @@ -97,6 +90,11 @@ public async Task Receive_FromLocal_OnProgressActionCalled(string id) onProgressAction: new UnitTestProgress(_ => wasCalled = true) ); - Assert.That(wasCalled, Is.True); + Assert.True(wasCalled); + } + + public void Dispose() + { + // Cleanup resources if necessary } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs index dd486a7f..3e402fc8 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendObjectReferences.cs @@ -1,18 +1,18 @@ -using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; +using FluentAssertions; +using Microsoft.Extensions.DependencyInjection; using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; public class SendObjectReferences { - private IOperations _operations; + private readonly IOperations _operations; - [SetUp] - public void Setup() + public SendObjectReferences() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DataChunk).Assembly); @@ -20,34 +20,38 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - [TestCase(0)] - [TestCase(1)] - [TestCase(10)] + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(10)] public async Task SendObjectsWithApplicationIds(int testDepth) { Base testData = GenerateTestCase(testDepth, true); MemoryTransport transport = new(); var result = await _operations.Send(testData, [transport]); - Assert.That(result.rootObjId, Is.Not.Null); - Assert.That(result.rootObjId, Has.Length.EqualTo(32)); + result.rootObjId.Should().NotBeNull(); - Assert.That(result.convertedReferences, Has.Count.EqualTo(Math.Pow(2, testDepth + 1) - 2)); + result.rootObjId.Length.Should().Be(32); + + result.convertedReferences.Count.Should().Be((int)(Math.Pow(2, testDepth + 1) - 2)); } - [TestCase(0)] - [TestCase(1)] - [TestCase(10)] + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(10)] public async Task SendObjectsWithoutApplicationIds(int testDepth) { Base testData = GenerateTestCase(testDepth, false); MemoryTransport transport = new(); var result = await _operations.Send(testData, [transport]); - Assert.That(result.rootObjId, Is.Not.Null); - Assert.That(result.rootObjId, Has.Length.EqualTo(32)); + result.rootObjId.Should().NotBeNull(); + + result.rootObjId.Length.Should().Be(32); - Assert.That(result.convertedReferences, Is.Empty); + result.convertedReferences.Should().BeEmpty(); } private Base GenerateTestCase(int depth, bool withAppId) diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs index c08e9ee5..813d9307 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SendReceiveLocal.cs @@ -1,23 +1,20 @@ -using System.Collections.Concurrent; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Shouldly; using Speckle.Sdk.Api; using Speckle.Sdk.Common; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Api.Operations; -[TestFixture] public sealed class SendReceiveLocal : IDisposable { - private IOperations _operations; + private readonly IOperations _operations; - [SetUp] - public void Setup() + public SendReceiveLocal() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); @@ -25,15 +22,14 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - private string? _objId01; - private string? _commitId02; - private const int NUM_OBJECTS = 3001; private readonly SQLiteTransport _sut = new(); - [Test(Description = "Pushing a commit locally"), Order(1)] - public async Task LocalUpload() + public void Dispose() => _sut.Dispose(); + + [Fact(DisplayName = "Pushing a commit locally")] + public async Task LocalUploadAndDownload() { var myObject = new Base(); var rand = new Random(); @@ -48,24 +44,18 @@ public async Task LocalUpload() } using SQLiteTransport localTransport = new(); - (_objId01, var references) = await _operations.Send(myObject, localTransport, false); + (var objId01, var references) = await _operations.Send(myObject, localTransport, false); - Assert.That(_objId01, Is.Not.Null); - Assert.That(references, Has.Count.EqualTo(NUM_OBJECTS)); + objId01.Should().NotBeNull(); + references.Count.Should().Be(NUM_OBJECTS); - TestContext.Out.WriteLine($"Written {NUM_OBJECTS + 1} objects. Commit id is {_objId01}"); - } + var commitPulled = await _operations.Receive(objId01.NotNull()); - [Test(Description = "Pulling a commit locally"), Order(2)] - public async Task LocalDownload() - { - var commitPulled = await _operations.Receive(_objId01.NotNull()); - - Assert.That(((List)commitPulled["@items"].NotNull())[0], Is.TypeOf()); - Assert.That(((List)commitPulled["@items"].NotNull()), Has.Count.EqualTo(NUM_OBJECTS)); + ((List)commitPulled["@items"].NotNull())[0].Should().BeOfType(); + ((List)commitPulled["@items"].NotNull()).Count.Should().Be(NUM_OBJECTS); } - [Test(Description = "Pushing and Pulling a commit locally")] + [Fact(DisplayName = "Pushing and Pulling a commit locally")] public async Task LocalUploadDownload() { var myObject = new Base(); @@ -80,16 +70,15 @@ public async Task LocalUploadDownload() ); } - (_objId01, _) = await _operations.Send(myObject, _sut, false); + (var objId01, _) = await _operations.Send(myObject, _sut, false); - var commitPulled = await _operations.Receive(_objId01); + var commitPulled = await _operations.Receive(objId01); List items = (List)commitPulled["@items"].NotNull(); - - Assert.That(items, Has.All.TypeOf()); - Assert.That(items, Has.Count.EqualTo(NUM_OBJECTS)); + items.Should().AllSatisfy(x => x.Should().BeOfType()); + items.Count.Should().Be(NUM_OBJECTS); } - [Test(Description = "Pushing and pulling a commit locally"), Order(3)] + [Fact(DisplayName = "Pushing and pulling a commit locally")] public async Task LocalUploadDownloadSmall() { var myObject = new Base(); @@ -104,16 +93,15 @@ public async Task LocalUploadDownloadSmall() ); } - (_objId01, _) = await _operations.Send(myObject, _sut, false); + (var objId01, _) = await _operations.Send(myObject, _sut, false); - Assert.That(_objId01, Is.Not.Null); - TestContext.Out.WriteLine($"Written {NUM_OBJECTS + 1} objects. Commit id is {_objId01}"); + objId01.Should().NotBeNull(); - var objsPulled = await _operations.Receive(_objId01); - Assert.That(((List)objsPulled["@items"].NotNull()), Has.Count.EqualTo(30)); + var objsPulled = await _operations.Receive(objId01); + ((List)objsPulled["@items"].NotNull()).Count.Should().Be(30); } - [Test(Description = "Pushing and pulling a commit locally"), Order(3)] + [Fact(DisplayName = "Pushing and pulling a commit locally")] public async Task LocalUploadDownloadListDic() { var myList = new List { 1, 2, 3, "ciao" }; @@ -128,19 +116,16 @@ public async Task LocalUploadDownloadListDic() myObject["@dictionary"] = myDic; myObject["@list"] = myList; - (_objId01, _) = await _operations.Send(myObject, _sut, false); + (var _objId01, _) = await _operations.Send(myObject, _sut, false); - Assert.That(_objId01, Is.Not.Null); + _objId01.Should().NotBeNull(); var objsPulled = await _operations.Receive(_objId01); - Assert.That( - ((List)((Dictionary)objsPulled["@dictionary"].NotNull())["a"]).First(), - Is.EqualTo(1) - ); - Assert.That(((List)objsPulled["@list"].NotNull()).Last(), Is.EqualTo("ciao")); + ((List)((Dictionary)objsPulled["@dictionary"].NotNull())["a"]).First().Should().Be(1); + ((List)objsPulled["@list"].NotNull()).Last().Should().Be("ciao"); } - [Test(Description = "Pushing and pulling a random object, with our without detachment"), Order(3)] + [Fact(DisplayName = "Pushing and pulling a random object, with or without detachment")] public async Task UploadDownloadNonCommitObject() { var obj = new Base(); @@ -166,32 +151,31 @@ public async Task UploadDownloadNonCommitObject() ((List)((dynamic)obj)["@LayerC"]).Add(new Point(i, i, i + rand.NextDouble()) { applicationId = i + "baz" }); } - (_objId01, _) = await _operations.Send(obj, _sut, false); + (var objId01, _) = await _operations.Send(obj, _sut, false); - Assert.That(_objId01, Is.Not.Null); - TestContext.Out.WriteLine($"Written {NUM_OBJECTS + 1} objects. Commit id is {_objId01}"); + objId01.Should().NotBeNull(); - var objPulled = await _operations.Receive(_objId01); + var objPulled = await _operations.Receive(objId01); - Assert.That(objPulled, Is.TypeOf()); + objPulled.Should().BeOfType(); // Note: even if the layers were originally declared as lists of "Base" objects, on deserialisation we cannot know that, // as it's a dynamic property. Dynamic properties, if their content value is ambigous, will default to a common-sense standard. // This specifically manifests in the case of lists and dictionaries: List will become List, and // Dictionary will deserialize to Dictionary. var layerA = ((dynamic)objPulled)["LayerA"] as List; - Assert.That(layerA, Has.Count.EqualTo(30)); + layerA?.Count.Should().Be(30); var layerC = (List)((dynamic)objPulled)["@LayerC"]; - Assert.That(layerC, Has.Count.EqualTo(30)); - Assert.That(layerC[0], Is.TypeOf()); + layerC.Count.Should().Be(30); + layerC[0].Should().BeOfType(); var layerD = ((dynamic)objPulled)["@LayerD"] as List; - Assert.That(layerD, Has.Count.EqualTo(2)); + layerD?.Count.Should().Be(2); } - [Test(Description = "Should show progress!"), Order(4)] - public async Task UploadProgressReports() + [Fact(DisplayName = "Should show progress!")] + public async Task UploadAndDownloadProgressReports() { Base myObject = new() { ["items"] = new List() }; var rand = new Random(); @@ -203,24 +187,20 @@ public async Task UploadProgressReports() ); } - (_commitId02, _) = await _operations.Send(myObject, _sut, false); - } + (var commitId02, _) = await _operations.Send(myObject, _sut, false); - [Test(Description = "Should show progress!"), Order(5)] - public async Task DownloadProgressReports() - { ProgressArgs? progress = null; await _operations.Receive( - _commitId02.NotNull(), + commitId02.NotNull(), onProgressAction: new UnitTestProgress(x => { progress = x; }) ); - progress.ShouldNotBeNull(); + progress.Should().NotBeNull(); } - [Test(Description = "Should not dispose of transports if so specified.")] + [Fact(DisplayName = "Should not dispose of transports if so specified.")] public async Task ShouldNotDisposeTransports() { var @base = new Base(); @@ -233,9 +213,4 @@ public async Task ShouldNotDisposeTransports() _ = await _operations.Receive(sendResult.rootObjId, null, myLocalTransport); await _operations.Receive(sendResult.rootObjId, null, myLocalTransport); } - - public void Dispose() - { - _sut.Dispose(); - } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs index 3dda4555..b5dc30fe 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Api/Operations/SerializationTests.cs @@ -1,24 +1,20 @@ using System.Drawing; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; using Speckle.Sdk.Api; -using Speckle.Sdk.Api.GraphQL.Models; -using Speckle.Sdk.Credentials; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; +using Xunit; using Point = Speckle.Sdk.Tests.Unit.Host.Point; namespace Speckle.Sdk.Tests.Unit.Api.Operations; -[TestFixture] -[TestOf(typeof(Sdk.Api.Operations))] public class ObjectSerialization { - private IOperations _operations; + private readonly IOperations _operations; - [SetUp] - public void Setup() + public ObjectSerialization() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DataChunk).Assembly, typeof(ColorMock).Assembly); @@ -26,7 +22,7 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - [Test] + [Fact] public async Task IgnoreCircularReferences() { var pt = new Point(1, 2, 3); @@ -36,10 +32,10 @@ public async Task IgnoreCircularReferences() var result = await _operations.DeserializeAsync(test); var circle = result["circle"]; - Assert.That(circle, Is.Null); + circle.Should().BeNull(); } - [Test] + [Fact] public async Task InterfacePropHandling() { Line tail = new() { Start = new Point(0, 0, 0), End = new Point(42, 42, 42) }; @@ -75,10 +71,10 @@ public async Task InterfacePropHandling() var deserialisedFeline = await _operations.DeserializeAsync(result); - Assert.That(deserialisedFeline.GetId(), Is.EqualTo(cat.GetId())); // If we're getting the same hash... we're probably fine! + deserialisedFeline.GetId().Should().Be(cat.GetId()); } - [Test] + [Fact] public async Task InheritanceTests() { var superPoint = new SuperPoint @@ -92,10 +88,10 @@ public async Task InheritanceTests() var str = _operations.Serialize(superPoint); var sstr = await _operations.DeserializeAsync(str); - Assert.That(sstr.speckle_type, Is.EqualTo(superPoint.speckle_type)); + sstr.speckle_type.Should().Be(superPoint.speckle_type); } - [Test] + [Fact] public async Task ListDynamicProp() { var point = new Point(); @@ -111,11 +107,12 @@ public async Task ListDynamicProp() var str = _operations.Serialize(point); var dsrls = await _operations.DeserializeAsync(str); - var list = dsrls["test"] as List; // NOTE: on dynamically added lists, we cannot infer the inner type and we always fall back to a generic list. - Assert.That(list, Has.Count.EqualTo(100)); + var list = dsrls["test"] as List; + list.Should().NotBeNull(); // Ensure the list isn't null in first place + list!.Count.Should().Be(100); } - [Test] + [Fact] public async Task ChunkSerialisation() { var baseBasedChunk = new DataChunk() { data = new() }; @@ -144,12 +141,12 @@ public async Task ChunkSerialisation() var stringChunkDeserialised = (DataChunk)await _operations.DeserializeAsync(stringChunkString); var doubleChunkDeserialised = (DataChunk)await _operations.DeserializeAsync(doubleChunkString); - Assert.That(baseChunkDeserialised.data, Has.Count.EqualTo(baseBasedChunk.data.Count)); - Assert.That(stringChunkDeserialised.data, Has.Count.EqualTo(stringBasedChunk.data.Count)); - Assert.That(doubleChunkDeserialised.data, Has.Count.EqualTo(doubleBasedChunk.data.Count)); + baseChunkDeserialised.data.Count.Should().Be(baseBasedChunk.data.Count); + stringChunkDeserialised.data.Count.Should().Be(stringBasedChunk.data.Count); + doubleChunkDeserialised.data.Count.Should().Be(doubleBasedChunk.data.Count); } - [Test] + [Fact] public async Task ObjectWithChunksSerialisation() { const int MAX_NUM = 2020; @@ -174,10 +171,10 @@ public async Task ObjectWithChunksSerialisation() var serialised = _operations.Serialize(mesh); var deserialised = await _operations.DeserializeAsync(serialised); - Assert.That(mesh.GetId(), Is.EqualTo(deserialised.GetId())); + mesh.GetId().Should().Be(deserialised.GetId()); } - [Test] + [Fact] public void EmptyListSerialisationTests() { // NOTE: expected behaviour is that empty lists should serialize as empty lists. Don't ask why, it's complicated. @@ -200,7 +197,7 @@ public void EmptyListSerialisationTests() && serialised.Contains("\"nestedList\":[[[]]]") && serialised.Contains("\"@nestedDetachableList\":[[[]]]"); - Assert.That(isCorrect, Is.EqualTo(true)); + isCorrect.Should().BeTrue(); } [SpeckleType("Speckle.Core.Tests.Unit.Api.Operations.ObjectSerialization+DateMock")] @@ -209,7 +206,7 @@ private class DateMock : Base public DateTime TestField { get; set; } } - [Test] + [Fact] public async Task DateSerialisation() { var date = new DateTime(2020, 1, 14); @@ -218,7 +215,7 @@ public async Task DateSerialisation() var result = _operations.Serialize(mockBase); var test = (DateMock)await _operations.DeserializeAsync(result); - Assert.That(test.TestField, Is.EqualTo(date)); + test.TestField.Should().Be(date); } [SpeckleType("Speckle.Core.Tests.Unit.Api.Operations.ObjectSerialization+GUIDMock")] @@ -227,7 +224,7 @@ private class GUIDMock : Base public Guid TestField { get; set; } } - [Test] + [Fact] public async Task GuidSerialisation() { var guid = Guid.NewGuid(); @@ -236,7 +233,7 @@ public async Task GuidSerialisation() var result = _operations.Serialize(mockBase); var test = (GUIDMock)await _operations.DeserializeAsync(result); - Assert.That(test.TestField, Is.EqualTo(guid)); + test.TestField.Should().Be(guid); } [SpeckleType("Speckle.Core.Tests.Unit.Api.Operations.ObjectSerialization+ColorMock")] @@ -245,7 +242,7 @@ private class ColorMock : Base public Color TestField { get; set; } } - [Test] + [Fact] public async Task ColorSerialisation() { var color = Color.FromArgb(255, 4, 126, 251); @@ -254,7 +251,7 @@ public async Task ColorSerialisation() var result = _operations.Serialize(mockBase); var test = (ColorMock)await _operations.DeserializeAsync(result); - Assert.That(test.TestField, Is.EqualTo(color)); + test.TestField.Should().Be(color); } [SpeckleType("Speckle.Core.Tests.Unit.Api.Operations.ObjectSerialization+StringDateTimeRegressionMock")] @@ -263,7 +260,7 @@ private class StringDateTimeRegressionMock : Base public string TestField { get; set; } } - [Test] + [Fact] public async Task StringDateTimeRegression() { var mockBase = new StringDateTimeRegressionMock { TestField = "2021-11-12T11:32:01" }; @@ -271,6 +268,6 @@ public async Task StringDateTimeRegression() var result = _operations.Serialize(mockBase); var test = (StringDateTimeRegressionMock)await _operations.DeserializeAsync(result); - Assert.That(test.TestField, Is.EqualTo(mockBase.TestField)); + test.TestField.Should().Be(mockBase.TestField); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Assembly.cs b/tests/Speckle.Sdk.Tests.Unit/Assembly.cs new file mode 100644 index 00000000..a4bcec54 --- /dev/null +++ b/tests/Speckle.Sdk.Tests.Unit/Assembly.cs @@ -0,0 +1,3 @@ +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs b/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs index 169b36cf..a9ac02d5 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Common/NotNullTests.cs @@ -1,87 +1,94 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Common; public class NotNullTests { - [TestCase(null, 0)] - [TestCase(new string[0], 0)] - [TestCase(new[] { "yay" }, 1)] + [Theory] + [InlineData(null, 0)] + [InlineData(new string[0], 0)] + [InlineData(new[] { "yay" }, 1)] public void Empty(string[]? test, int length) { - var list = NotNullExtensions.Empty(test).ToList(); - list.Count.ShouldBe(length); + var list = test.Empty().ToList(); + list.Count.Should().Be(length); } - [Test] + [Fact] public void NotNullClass() { - var t = NotNullExtensions.NotNull("test"); - t.ShouldNotBeNull().ShouldBe("test"); + var t = "test".NotNull(); + t.Should().Be("test"); } - [Test] + [Fact] public void NotNullStruct() { var t = NotNullExtensions.NotNull(2); - t.ShouldBe(2); + t.Should().Be(2); } - [Test] + [Fact] public async Task NotNullClass_Task() { - var t = await NotNullExtensions.NotNull(Task.FromResult("test")); - t.ShouldNotBeNull().ShouldBe("test"); + var t = await Task.FromResult("test").NotNull(); + t.Should().Be("test"); } - [Test] + [Fact] public async Task NotNullStruct_Task() { - var t = await NotNullExtensions.NotNull(Task.FromResult(2)); - t.ShouldBe(2); + var t = await Task.FromResult(2).NotNull(); + t.Should().Be(2); } - [Test] + [Fact] public async Task NotNullClass_ValueTask() { - var t = await NotNullExtensions.NotNull(ValueTask.FromResult("test")); - t.ShouldNotBeNull().ShouldBe("test"); + var t = await ValueTask.FromResult("test").NotNull(); + t.Should().Be("test"); } - [Test] + [Fact] public async Task NotNullStruct_ValueTask() { - var t = await NotNullExtensions.NotNull(ValueTask.FromResult(2)); - t.ShouldBe(2); + var t = await ValueTask.FromResult(2).NotNull(); + t.Should().Be(2); } - [Test] - public void NotNullClass_Exception() => - Assert.Throws(() => NotNullExtensions.NotNull((string?)null)); + [Fact] + public void NotNullClass_Exception() => FluentActions.Invoking(() => ((string?)null).NotNull()); - [Test] - public void NotNullStruct_Exception() => - Assert.Throws(() => NotNullExtensions.NotNull((int?)null)); + [Fact] + public void NotNullStruct_Exception() => FluentActions.Invoking(() => ((int?)null).NotNull()); - [Test] - public void NotNullClass_Task_Exception() => - Assert.ThrowsAsync(() => NotNullExtensions.NotNull(Task.FromResult((string?)null))); + [Fact] + public async Task NotNullClass_Task_Exception() => + await FluentActions + .Invoking(async () => await Task.FromResult((string?)null).NotNull()) + .Should() + .ThrowAsync(); - [Test] - public void NotNullStruct_Task_Exception() => - Assert.ThrowsAsync(() => NotNullExtensions.NotNull(Task.FromResult((int?)null))); + [Fact] + public async Task NotNullStruct_Task_Exception() => + await FluentActions + .Invoking(async () => await Task.FromResult((int?)null).NotNull()) + .Should() + .ThrowAsync(); - [Test] - public void NotNullClass_ValueTask_Exception() => - Assert.ThrowsAsync( - async () => await NotNullExtensions.NotNull(ValueTask.FromResult((string?)null)) - ); + [Fact] + public async Task NotNullClass_ValueTask_Exception() => + await FluentActions + .Invoking(async () => await ValueTask.FromResult((string?)null).NotNull()) + .Should() + .ThrowAsync(); - [Test] - public void NotNullStruct_ValueTask_Exception() => - Assert.ThrowsAsync( - async () => await NotNullExtensions.NotNull(ValueTask.FromResult((int?)null)) - ); + [Fact] + public async Task NotNullStruct_ValueTask_Exception() => + await FluentActions + .Invoking(async () => await ValueTask.FromResult((int?)null).NotNull()) + .Should() + .ThrowAsync(); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs b/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs new file mode 100644 index 00000000..575277bd --- /dev/null +++ b/tests/Speckle.Sdk.Tests.Unit/Common/RangeFromTests.cs @@ -0,0 +1,14 @@ +using Speckle.Sdk.Dependencies; +using Xunit; + +namespace Speckle.Sdk.Tests.Unit.Common; + +public class RangeFromTests +{ + [Fact] + public void EnsureRange() + { + var list = EnumerableExtensions.RangeFrom(1, 4).ToArray(); + Assert.Equal([1, 2, 3, 4], list); + } +} diff --git a/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs b/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs index 938d3a7e..c93a0b51 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Common/UnitsTest.cs @@ -1,70 +1,98 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Common; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Common; -[TestOf(typeof(Units))] public class UnitsTest { private const double EPS = 0.00022; public static List OfficiallySupportedUnits => Units.SupportedUnits; + public static List NotSupportedUnits => ["feeters", "liters", "us_ft"]; - public static List ConversionSupport => [.. Units.SupportedUnits, null]; - - [Test, Combinatorial] - [DefaultFloatingPointTolerance(EPS)] - public void TestUnitConversion( - [ValueSource(nameof(ConversionSupport))] string? from, - [ValueSource(nameof(ConversionSupport))] string? to - ) + + public static List ConversionSupport => Units.SupportedUnits.Concat([null]).ToList(); + + [Theory] + [MemberData(nameof(ConversionSupportGenerator))] + public void TestUnitConversion(string? from, string? to) { var forwards = Units.GetConversionFactor(from, to); var backwards = Units.GetConversionFactor(to, from); - Assert.That( - backwards * forwards, - Is.EqualTo(1d), - $"Behaviour says that 1{from} == {forwards}{to}, and 1{to} == {backwards}{from}" - ); + (backwards * forwards) + .Should() + .BeApproximately(1d, EPS, $"Behaviour says that 1{from} == {forwards}{to}, and 1{to} == {backwards}{from}"); } - [TestCaseSource(nameof(OfficiallySupportedUnits))] + [Theory] + [MemberData(nameof(OfficiallySupportedUnitsGenerator))] public void IsUnitSupported_ReturnsTrue_AllSupportedUnits(string unit) { bool res = Units.IsUnitSupported(unit); - Assert.That(res, Is.True); + res.Should().BeTrue(); } - [TestCaseSource(nameof(NotSupportedUnits))] + [Theory] + [MemberData(nameof(NotSupportedUnitsGenerator))] public void IsUnitSupported_ReturnsFalse_NotSupportedUnits(string unit) { bool res = Units.IsUnitSupported(unit); - Assert.That(res, Is.False); + res.Should().BeFalse(); } - [TestCaseSource(nameof(OfficiallySupportedUnits))] + [Theory] + [MemberData(nameof(OfficiallySupportedUnitsGenerator))] public void GetUnitsFromString_ReturnsSupported(string unit) { - var lower = Units.GetUnitsFromString(unit); - var upper = Units.GetUnitsFromString(unit?.ToUpperInvariant()); + string? lower = Units.GetUnitsFromString(unit); + string? upper = Units.GetUnitsFromString(unit.ToUpperInvariant()); - Assert.That(lower, Is.EqualTo(unit)); - Assert.That(upper, Is.EqualTo(unit)); + lower.Should().Be(unit); + upper.Should().Be(unit); } - [TestCaseSource(nameof(NotSupportedUnits))] - public void GetUnitsFromString_ThrowsUnSupported(string unit) - { - Assert.Throws(() => _ = Units.GetUnitsFromString(unit)); - } + [Theory] + [MemberData(nameof(NotSupportedUnitsGenerator))] + public void GetUnitsFromString_ThrowsUnSupported(string unit) => + FluentActions.Invoking(() => Units.GetUnitsFromString(unit)).Should().Throw(); - [TestCaseSource(nameof(OfficiallySupportedUnits))] + [Theory] + [MemberData(nameof(OfficiallySupportedUnitsGenerator))] public void UnitEncoding_RoundTrip(string unit) { var encoded = Units.GetEncodingFromUnit(unit); var res = Units.GetUnitFromEncoding(encoded); - Assert.That(res, Is.EqualTo(unit)); + res.Should().Be(unit); + } + + // Generators for MemberData + public static IEnumerable OfficiallySupportedUnitsGenerator() + { + foreach (var unit in OfficiallySupportedUnits) + { + yield return [unit]; + } + } + + public static IEnumerable NotSupportedUnitsGenerator() + { + foreach (var unit in NotSupportedUnits) + { + yield return [unit]; + } + } + + public static IEnumerable ConversionSupportGenerator() + { + foreach (var from in ConversionSupport) + { + foreach (var to in ConversionSupport) + { + yield return [from, to]; + } + } } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs index b0254631..b61eae75 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Credentials/AccountServerMigrationTests.cs @@ -1,68 +1,66 @@ +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; -using Speckle.Sdk.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Credentials; -public class AccountServerMigrationTests +public class AccountServerMigrationTests : IDisposable { - private readonly List _accountsToCleanUp = new(); + private readonly List _accountsToCleanUp = []; - public static IEnumerable MigrationTestCase() + public static IEnumerable MigrationTestCases() { const string OLD_URL = "https://old.example.com"; const string NEW_URL = "https://new.example.com"; const string OTHER_URL = "https://other.example.com"; + Account oldAccount = CreateTestAccount(OLD_URL, null, new(NEW_URL)); string accountId = oldAccount.userInfo.id; // new account user must match old account user id Account newAccount = CreateTestAccount(NEW_URL, new(OLD_URL), null, accountId); Account otherAccount = CreateTestAccount(OTHER_URL, null, null); - List givenAccounts = new() { oldAccount, newAccount, otherAccount }; + List givenAccounts = [oldAccount, newAccount, otherAccount]; - yield return new TestCaseData(givenAccounts, NEW_URL, new[] { newAccount }) - .SetName("Get New") - .SetDescription("When requesting for new account, ensure only this account is returned"); + yield return [givenAccounts, NEW_URL, new[] { newAccount }]; - yield return new TestCaseData(givenAccounts, OLD_URL, new[] { newAccount }) - .SetName("Get New via Old") - .SetDescription("When requesting for old account, ensure migrated account is returned first"); + yield return [givenAccounts, OLD_URL, new[] { newAccount }]; - var reversed = Enumerable.Reverse(givenAccounts).ToList(); + var reversed = givenAccounts.AsEnumerable().Reverse().ToList(); - yield return new TestCaseData(reversed, OLD_URL, new[] { newAccount }) - .SetName("Get New via Old (Reversed order)") - .SetDescription("Account order shouldn't matter"); + yield return [reversed, OLD_URL, new[] { newAccount }]; } - [Test] - [TestCaseSource(nameof(MigrationTestCase))] + [Theory] + [MemberData(nameof(MigrationTestCases))] public void TestServerMigration(IList accounts, string requestedUrl, IList expectedSequence) { + // Add accounts to the local setup AddAccounts(accounts); - var serviceProvider = TestServiceSetup.GetServiceProvider(); + var serviceProvider = TestServiceSetup.GetServiceProvider(); var result = serviceProvider.GetRequiredService().GetAccounts(requestedUrl).ToList(); - Assert.That(result, Is.EquivalentTo(expectedSequence)); + // Assert the result using Shouldly + result.Should().BeEquivalentTo(expectedSequence); } - [TearDown] - public void TearDown() + public void Dispose() { - //Clean up any of the test accounts we made + // Clean up accounts after each test foreach (var acc in _accountsToCleanUp) { Fixtures.DeleteLocalAccount(acc.id); } + _accountsToCleanUp.Clear(); } private static Account CreateTestAccount(string url, Uri? movedFrom, Uri? movedTo, string? id = null) { id ??= Guid.NewGuid().ToString(); + return new Account { token = "myToken", @@ -83,7 +81,7 @@ private static Account CreateTestAccount(string url, Uri? movedFrom, Uri? movedT private void AddAccounts(IEnumerable accounts) { - foreach (Account account in accounts) + foreach (var account in accounts) { _accountsToCleanUp.Add(account); Fixtures.UpdateOrSaveAccount(account); diff --git a/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs b/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs index e1643ed0..ac9df5f0 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Credentials/Accounts.cs @@ -1,19 +1,19 @@ +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Speckle.Sdk.Api; using Speckle.Sdk.Api.GraphQL.Models; using Speckle.Sdk.Credentials; -using Speckle.Sdk.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Credentials; -[TestFixture] -public class CredentialInfrastructure +public class CredentialInfrastructure : IDisposable { - private IAccountManager _accountManager; + private readonly IAccountManager _accountManager; + private static readonly Account s_testAccount1; + private static readonly Account s_testAccount2; + private static readonly Account s_testAccount3; - [OneTimeSetUp] - public static void SetUp() + static CredentialInfrastructure() { s_testAccount1 = new Account { @@ -42,76 +42,69 @@ public static void SetUp() name = "Test Account 3", }, }; + } + public CredentialInfrastructure() + { Fixtures.UpdateOrSaveAccount(s_testAccount1); Fixtures.UpdateOrSaveAccount(s_testAccount2); Fixtures.SaveLocalAccount(s_testAccount3); - } - [SetUp] - public void Setup2() - { var serviceProvider = TestServiceSetup.GetServiceProvider(); _accountManager = serviceProvider.GetRequiredService(); } - [OneTimeTearDown] - public static void TearDown() + public void Dispose() { + _accountManager.Dispose(); Fixtures.DeleteLocalAccount(s_testAccount1.id); Fixtures.DeleteLocalAccount(s_testAccount2.id); + Fixtures.DeleteLocalAccount(s_testAccount3.id); Fixtures.DeleteLocalAccountFile(); } - private static Account s_testAccount1, - s_testAccount2, - s_testAccount3; - - [Test] + [Fact] public void GetAllAccounts() { var accs = _accountManager.GetAccounts().ToList(); - Assert.That(accs, Has.Count.GreaterThanOrEqualTo(3)); // Tests are adding three accounts, you might have extra accounts on your machine when testing :D + accs.Count.Should().BeGreaterThanOrEqualTo(3); // Tests are adding three accounts, there might be extra accounts locally } - [Test] + [Fact] public void GetAccount_ById() { var result = _accountManager.GetAccount(s_testAccount1.id); - Assert.That(result, Is.EqualTo(s_testAccount1)); + result.Should().Be(s_testAccount1); // Uses `Shouldly` for a clean assertion } - [Test] - public void GetAccount_ById_ThrowsWhenNotFound() - { - Assert.Throws(() => _accountManager.GetAccount("Non_existent_id")); - } + [Fact] + public void GetAccount_ById_ThrowsWhenNotFound() => + FluentActions + .Invoking(() => _accountManager.GetAccount("Non_existent_id")) + .Should() + .Throw(); - public static IEnumerable TestCases() - { - SetUp(); - return new[] { s_testAccount1, s_testAccount2, s_testAccount3 }; - } + public static TheoryData TestCases() => new() { s_testAccount1, s_testAccount2, s_testAccount3 }; - [Test] - [TestCaseSource(nameof(TestCases))] + [Theory] + [MemberData(nameof(TestCases))] public void GetAccountsForServer(Account target) { var accs = _accountManager.GetAccounts(target.serverInfo.url).ToList(); - Assert.That(accs, Has.Count.EqualTo(1)); + accs.Count.Should().Be(1); var acc = accs[0]; - Assert.That(acc, Is.Not.SameAs(target), "We expect new objects (no reference equality)"); - Assert.That(acc.serverInfo.company, Is.EqualTo(target.serverInfo.company)); - Assert.That(acc.serverInfo.url, Is.EqualTo(target.serverInfo.url)); - Assert.That(acc.refreshToken, Is.EqualTo(target.refreshToken)); - Assert.That(acc.token, Is.EqualTo(target.token)); + acc.Should().NotBeSameAs(target); // We expect new objects (no reference equality) + acc.serverInfo.company.Should().Be(target.serverInfo.company); + acc.serverInfo.url.Should().Be(target.serverInfo.url); + acc.refreshToken.Should().Be(target.refreshToken); + acc.token.Should().Be(target.token); } - [Test] + [Fact] public void EnsureLocalIdentifiers_AreUniqueAcrossServers() { // Accounts with the same user ID in different servers should always result in different local identifiers. @@ -128,6 +121,6 @@ public void EnsureLocalIdentifiers_AreUniqueAcrossServers() userInfo = new UserInfo { id = id }, }.GetLocalIdentifier(); - Assert.That(acc1, Is.Not.EqualTo(acc2)); + acc1.Should().NotBe(acc2); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Fixtures.cs b/tests/Speckle.Sdk.Tests.Unit/Fixtures.cs index 88746a75..65f49f12 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Fixtures.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Fixtures.cs @@ -28,13 +28,7 @@ public static void SaveLocalAccount(Account account) File.WriteAllText(s_accountPath, json); } - public static void DeleteLocalAccount(string id) - { - s_accountStorage.DeleteObject(id); - } + public static void DeleteLocalAccount(string id) => s_accountStorage.DeleteObject(id); - public static void DeleteLocalAccountFile() - { - File.Delete(s_accountPath); - } + public static void DeleteLocalAccountFile() => File.Delete(s_accountPath); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs b/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs index ab992217..422dcbbe 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Helpers/Path.cs @@ -1,14 +1,13 @@ using System.Runtime.InteropServices; -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Logging; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Helpers; -[TestFixture] -[TestOf(nameof(SpecklePathProvider))] public class SpecklePathTests { - [Test] + [Fact] public void TestUserApplicationDataPath() { var userPath = SpecklePathProvider.UserApplicationDataPath(); @@ -39,10 +38,10 @@ public void TestUserApplicationDataPath() throw new NotImplementedException("Your OS platform is not supported"); } - Assert.That(userPath, Does.Match(pattern)); + userPath.Should().MatchRegex(pattern); } - [Test] + [Fact] public void TestInstallApplicationDataPath() { var installPath = SpecklePathProvider.InstallApplicationDataPath; @@ -78,6 +77,6 @@ public void TestInstallApplicationDataPath() throw new NotImplementedException("Your OS platform is not supported"); } - Assert.That(installPath, Does.Match(pattern)); + installPath.Should().MatchRegex(pattern); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs index 728266c8..87d5aa3c 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Host/HostApplicationTests.cs @@ -1,19 +1,22 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Sdk.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Host; public class HostApplicationTests { - private static List s_hostAppVersion = Enum.GetValues().ToList(); + public static TheoryData HostAppVersionData => new(Enum.GetValues().ToList()); - [Test] - [TestCaseSource(nameof(s_hostAppVersion))] + [Theory] + [MemberData(nameof(HostAppVersionData))] public void HostAppVersionParsingTests(HostAppVersion appVersion) { - appVersion.ToString().StartsWith('v').ShouldBeTrue(); + // Assert that the string representation starts with 'v' + appVersion.ToString().StartsWith('v').Should().BeTrue(); + + // Assert that the parsed version is a positive integer var version = HostApplications.GetVersion(appVersion); - int.Parse(version).ShouldBePositive(); + int.Parse(version).Should().BePositive(); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs index 36190b59..c658b48a 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs @@ -1,50 +1,38 @@ -using System.Collections.Concurrent; -using System.Text; -using NUnit.Framework; -using Shouldly; -using Speckle.Newtonsoft.Json.Linq; +using FluentAssertions; using Speckle.Sdk.Common; -using Speckle.Sdk.Dependencies.Serialization; using Speckle.Sdk.Host; using Speckle.Sdk.Models; -using Speckle.Sdk.Serialisation; -using Speckle.Sdk.Serialisation.V2; -using Speckle.Sdk.Serialisation.V2.Send; -using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; -[TestFixture] -[TestOf(typeof(Base))] -[TestOf(typeof(DynamicBase))] public class BaseTests { - [SetUp] - public void Setup() + public BaseTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(BaseTests).Assembly); } - [Test] + [Fact] public void CanGetSetDynamicItemProp() { var @base = new Base(); @base["Item"] = "Item"; - Assert.That(@base["Item"], Is.EqualTo("Item")); + @base["Item"].Should().Be("Item"); } - [Test] + [Fact] public void CanGetSetTypedItemProp() { var @base = new ObjectWithItemProp { Item = "baz" }; - Assert.That(@base["Item"], Is.EqualTo("baz")); - Assert.That(@base.Item, Is.EqualTo("baz")); + @base["Item"].Should().Be("baz"); + @base.Item.Should().Be("baz"); } - [Test(Description = "Checks if validation is performed in property names")] + [Fact(DisplayName = "Checks if validation is performed in property names")] public void CanValidatePropNames() { dynamic @base = new Base(); @@ -54,27 +42,35 @@ public void CanValidatePropNames() // Only single leading @ allowed @base["@something"] = "A"; - Assert.Throws(() => - { - @base["@@@something"] = "Testing"; - }); + FluentActions + .Invoking(() => + { + @base["@@@something"] = "Testing"; + }) + .Should() + .Throw(); // Invalid chars: ./ - Assert.Throws(() => - { - @base["some.thing"] = "Testing"; - }); - Assert.Throws(() => - { - @base["some/thing"] = "Testing"; - }); - + FluentActions + .Invoking(() => + { + @base["some.thing"] = "Testing"; + }) + .Should() + .Throw(); + FluentActions + .Invoking(() => + { + @base["some/thing"] = "Testing"; + }) + .Should() + .Throw(); // Trying to change a class member value will throw exceptions. //Assert.Throws(() => { @base["speckle_type"] = "Testing"; }); //Assert.Throws(() => { @base["id"] = "Testing"; }); } - [Test] + [Fact] public void CountDynamicChunkables() { const int MAX_NUM = 3000; @@ -92,10 +88,10 @@ public void CountDynamicChunkables() @base["@(1000)cc2"] = customChunkArr; var num = @base.GetTotalChildrenCount(); - Assert.That(num, Is.EqualTo(MAX_NUM / 1000 * 2 + 1)); + num.Should().Be(MAX_NUM / 1000 * 2 + 1); } - [Test] + [Fact] public void CountTypedChunkables() { const int MAX_NUM = 3000; @@ -114,33 +110,33 @@ public void CountTypedChunkables() var num = @base.GetTotalChildrenCount(); var actualNum = 1 + MAX_NUM / 300 + MAX_NUM / 1000; - Assert.That(num, Is.EqualTo(actualNum)); + num.Should().Be(actualNum); } - [Test(Description = "Checks that no ignored or obsolete properties are returned")] + [Fact(DisplayName = "Checks that no ignored or obsolete properties are returned")] public void CanGetMemberNames() { var @base = new SampleObject(); var dynamicProp = "dynamicProp"; @base[dynamicProp] = 123; var names = @base.GetMembers().Keys; - Assert.That(names, Has.No.Member(nameof(@base.IgnoredSchemaProp))); - Assert.That(names, Has.No.Member(nameof(@base.ObsoleteSchemaProp))); - Assert.That(names, Has.Member(dynamicProp)); - Assert.That(names, Has.Member(nameof(@base.attachedProp))); + names.Should().NotContain(nameof(@base.IgnoredSchemaProp)); + names.Should().NotContain(nameof(@base.ObsoleteSchemaProp)); + names.Should().Contain(dynamicProp); + names.Should().Contain(nameof(@base.attachedProp)); } - [Test(Description = "Checks that only instance properties are returned, excluding obsolete and ignored.")] + [Fact(DisplayName = "Checks that only instance properties are returned, excluding obsolete and ignored.")] public void CanGetMembers_OnlyInstance() { var @base = new SampleObject(); @base["dynamicProp"] = 123; var names = @base.GetMembers(DynamicBaseMemberType.Instance).Keys; - Assert.That(names, Has.Member(nameof(@base.attachedProp))); + names.Should().Contain(nameof(@base.attachedProp)); } - [Test(Description = "Checks that only dynamic properties are returned")] + [Fact(DisplayName = "Checks that only dynamic properties are returned")] public void CanGetMembers_OnlyDynamic() { var @base = new SampleObject(); @@ -148,33 +144,33 @@ public void CanGetMembers_OnlyDynamic() @base[dynamicProp] = 123; var names = @base.GetMembers(DynamicBaseMemberType.Dynamic).Keys; - Assert.That(names, Has.Member(dynamicProp)); - Assert.That(names, Has.Count.EqualTo(1)); + names.Should().Contain(dynamicProp); + names.Count.Should().Be(1); } - [Test(Description = "Checks that all typed properties (including ignored ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including ignored ones) are returned")] public void CanGetMembers_OnlyInstance_IncludeIgnored() { var @base = new SampleObject(); @base["dynamicProp"] = 123; var names = @base.GetMembers(DynamicBaseMemberType.Instance | DynamicBaseMemberType.SchemaIgnored).Keys; - Assert.That(names, Has.Member(nameof(@base.IgnoredSchemaProp))); - Assert.That(names, Has.Member(nameof(@base.attachedProp))); + names.Should().Contain(nameof(@base.IgnoredSchemaProp)); + names.Should().Contain(nameof(@base.attachedProp)); } - [Test(Description = "Checks that all typed properties (including obsolete ones) are returned")] + [Fact(DisplayName = "Checks that all typed properties (including obsolete ones) are returned")] public void CanGetMembers_OnlyInstance_IncludeObsolete() { var @base = new SampleObject(); @base["dynamicProp"] = 123; var names = @base.GetMembers(DynamicBaseMemberType.Instance | DynamicBaseMemberType.Obsolete).Keys; - Assert.That(names, Has.Member(nameof(@base.ObsoleteSchemaProp))); - Assert.That(names, Has.Member(nameof(@base.attachedProp))); + names.Should().Contain(nameof(@base.ObsoleteSchemaProp)); + names.Should().Contain(nameof(@base.attachedProp)); } - [Test] + [Fact] public void CanGetDynamicMembers() { var @base = new SampleObject(); @@ -182,11 +178,11 @@ public void CanGetDynamicMembers() @base[dynamicProp] = null; var names = @base.GetDynamicMemberNames(); - Assert.That(names, Has.Member(dynamicProp)); - Assert.That(@base[dynamicProp], Is.Null); + names.Should().Contain(dynamicProp); + @base[dynamicProp].Should().BeNull(); } - [Test] + [Fact] public void CanSetDynamicMembers() { var @base = new SampleObject(); @@ -194,19 +190,19 @@ public void CanSetDynamicMembers() var value = "something"; // Can create a new dynamic member @base[key] = value; - Assert.That(value, Is.EqualTo((string)@base[key].NotNull())); + value.Should().Be((string)@base[key].NotNull()); // Can overwrite existing value = "some other value"; @base[key] = value; - Assert.That(value, Is.EqualTo((string)@base[key].NotNull())); + value.Should().Be((string)@base[key].NotNull()); // Accepts null values @base[key] = null; - Assert.That(@base[key], Is.Null); + @base[key].Should().BeNull(); } - [Test] + [Fact] public void CanShallowCopy() { var sample = new SampleObject(); @@ -217,8 +213,8 @@ public void CanShallowCopy() var sampleMembers = sample.GetMembers(selectedMembers); var copyMembers = copy.GetMembers(selectedMembers); - Assert.That(copyMembers.Keys, Is.EquivalentTo(sampleMembers.Keys)); - Assert.That(copyMembers.Values, Is.EquivalentTo(sampleMembers.Values)); + copyMembers.Keys.Should().BeEquivalentTo(sampleMembers.Keys); + copyMembers.Values.Should().BeEquivalentTo(sampleMembers.Values); } [SpeckleType("Speckle.Core.Tests.Unit.Models.BaseTests+SampleObject")] diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs index 5af6a011..f0a24de5 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/BaseExtensionsTests.cs @@ -1,46 +1,44 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; using Speckle.Sdk.Models.Extensions; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.Extensions; -[TestFixture] -[TestOf(nameof(BaseExtensions))] public class BaseExtensionsTests { - [SetUp] - public void Setup() + public BaseExtensionsTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly); } - [Test] - [TestCase("myDynamicProp")] - [TestCase("elements")] + [Theory] + [InlineData("myDynamicProp")] + [InlineData("elements")] public void GetDetachedPropName_Dynamic(string propertyName) { var data = new TestBase(); var result = data.GetDetachedPropName(propertyName); var expected = $"@{propertyName}"; - Assert.That(result, Is.EqualTo(expected)); + result.Should().Be(expected); } - [Test] - [TestCase(nameof(TestBase.myProperty))] - [TestCase(nameof(TestBase.myOtherProperty))] + [Theory] + [InlineData(nameof(TestBase.myProperty))] + [InlineData(nameof(TestBase.myOtherProperty))] public void GetDetachedPropName_Instance(string propertyName) { var data = new TestBase(); var result = data.GetDetachedPropName(propertyName); - Assert.That(result, Is.EqualTo(propertyName)); + result.Should().Be(propertyName); } - [Test] + [Fact] public void TraverseWithPath() { var collection = new Collection() { name = "collection" }; @@ -51,17 +49,18 @@ public void TraverseWithPath() var basePaths = collection.TraverseWithPath((obj => obj is not Collection)).ToList(); - Assert.That(basePaths.Count, Is.EqualTo(3)); - Assert.That(basePaths[0].Item2.speckle_type, Is.EqualTo("Speckle.Core.Models.Collections.Collection")); - Assert.That(basePaths[0].Item2["name"], Is.EqualTo("collection")); - Assert.That(basePaths[0].Item1, Is.EqualTo(new List())); + basePaths.Count.Should().Be(3); - Assert.That(basePaths[1].Item2.speckle_type, Is.EqualTo("Speckle.Core.Models.Collections.Collection")); - Assert.That(basePaths[1].Item2["name"], Is.EqualTo("subCollection")); - Assert.That(basePaths[1].Item1, Is.EqualTo(new List() { "collection" })); + basePaths[0].Item2.speckle_type.Should().Be("Speckle.Core.Models.Collections.Collection"); + basePaths[0].Item2["name"].Should().Be("collection"); + basePaths[0].Item1.Should().BeEquivalentTo(new List()); - Assert.That(basePaths[2].Item2.speckle_type, Is.EqualTo("Base")); - Assert.That(basePaths[2].Item1, Is.EqualTo(new List() { "collection", "subCollection" })); + basePaths[1].Item2.speckle_type.Should().Be("Speckle.Core.Models.Collections.Collection"); + basePaths[1].Item2["name"].Should().Be("subCollection"); + basePaths[1].Item1.Should().BeEquivalentTo(new List() { "collection" }); + + basePaths[2].Item2.speckle_type.Should().Be("Base"); + basePaths[2].Item1.Should().BeEquivalentTo(new List() { "collection", "subCollection" }); } [SpeckleType("Speckle.Core.Tests.Unit.Models.Extensions.BaseExtensionsTests+TestBase")] diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs index 07b00adf..b000afcc 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/DisplayValueTests.cs @@ -1,11 +1,11 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Extensions; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.Extensions; -[TestOf(typeof(BaseExtensions))] public class DisplayValueTests { private const string PAYLOAD = "This is my payload"; @@ -22,28 +22,35 @@ private static void Reset() TypeLoader.Initialize(typeof(Base).Assembly); } - [SetUp] + [Fact] public void Setup() => Reset(); - [TestCaseSource(nameof(TestCases))] + [Theory] + [MemberData(nameof(TestCases))] public void TestTryGetDisplayValue_WithValue(Base testCase) { var res = testCase.TryGetDisplayValue(); - Assert.That(res, Has.Count.EqualTo(1)); - Assert.That(res, Has.One.Items.TypeOf().With.Property(nameof(Base.applicationId)).EqualTo(PAYLOAD)); + // Assert collection count + res?.Count.Should().Be(1); + + // Assert the single item matches the expected type and property + var displayValue = res?[0]; + displayValue.Should().NotBeNull(); + displayValue!.applicationId.Should().Be(PAYLOAD); } - public static IEnumerable TestCases() + public static IEnumerable TestCases() { - var listOfBase = new List { s_displayValue }; //This is what our deserializer will output + var listOfBase = new List { s_displayValue }; // This is what our deserializer will output var listOfMesh = new List { s_displayValue }; - yield return new Base { ["@displayValue"] = s_displayValue }; - yield return new Base { ["displayValue"] = s_displayValue }; - yield return new Base { ["@displayValue"] = listOfBase }; - yield return new Base { ["displayValue"] = listOfBase }; - yield return new TypedDisplayValue { displayValue = s_displayValue }; - yield return new TypedDisplayValueList { displayValue = listOfMesh }; + + yield return [new Base { ["@displayValue"] = s_displayValue }]; + yield return [new Base { ["displayValue"] = s_displayValue }]; + yield return [new Base { ["@displayValue"] = listOfBase }]; + yield return [new Base { ["displayValue"] = listOfBase }]; + yield return [new TypedDisplayValue { displayValue = s_displayValue }]; + yield return [new TypedDisplayValueList { displayValue = listOfMesh }]; } [SpeckleType("Speckle.Core.Tests.Unit.Models.Extensions.DisplayValueTests+TypedDisplayValue")] diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs index bf6640bd..4b5c3750 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Extensions/ExceptionTests.cs @@ -1,26 +1,27 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Models.Extensions; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.Extensions; -[TestFixture] -[TestOf(typeof(BaseExtensions))] public class ExceptionTests { - [Test] + [Fact] public void CanPrintAllInnerExceptions() { + // Test with a single exception var ex = new Exception("Some error"); var exMsg = ex.ToFormattedString(); - Assert.That(exMsg, Is.Not.Null); + exMsg.Should().NotBeNull(); + // Test with an inner exception var ex2 = new Exception("One or more errors occurred", ex); var ex2Msg = ex2.ToFormattedString(); - Assert.That(ex2Msg, Is.Not.Null); + ex2Msg.Should().NotBeNull(); + // Test with an aggregate exception var ex3 = new AggregateException("One or more errors occurred", ex2); var ex3Msg = ex3.ToFormattedString(); - - Assert.That(ex3Msg, Is.Not.Null); + ex3Msg.Should().NotBeNull(); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs index 4f200fae..945102a4 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/GraphTraversalTests.cs @@ -1,17 +1,15 @@ using System.Collections; -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Models.GraphTraversal; -using Speckle.Sdk.Tests.Unit.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.GraphTraversal; -[TestFixture, TestOf(typeof(Sdk.Models.GraphTraversal.GraphTraversal))] public class GraphTraversalTests { - [SetUp] - public void Setup() + public GraphTraversalTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(TraversalMock).Assembly); @@ -23,7 +21,7 @@ private static IEnumerable Traverse(Base testCase, params ITra return sut.Traverse(testCase); } - [Test] + [Fact] public void Traverse_TraversesListMembers() { var traverseListsRule = TraversalRule @@ -38,23 +36,23 @@ public void Traverse_TraversesListMembers() TraversalMock testCase = new() { - ListChildren = new List { expectTraverse }, + ListChildren = [expectTraverse], DictChildren = new Dictionary { ["myprop"] = expectIgnored }, Child = expectIgnored, }; var ret = Traverse(testCase, traverseListsRule).Select(b => b.Current).ToList(); - //Assert expected members present - Assert.That(ret, Has.Exactly(1).Items.EqualTo(testCase)); - Assert.That(ret, Has.Exactly(1).Items.EqualTo(expectTraverse)); + // Assert expected members present + ret.Should().Contain(testCase); + ret.Should().Contain(expectTraverse); - //Assert unexpected members not present - Assert.That(ret, Has.No.Member(expectIgnored)); - Assert.That(ret, Has.Count.EqualTo(2)); + // Assert unexpected members not present + ret.Should().NotContain(expectIgnored); + ret.Count.Should().Be(2); } - [Test] + [Fact] public void Traverse_TraversesDictMembers() { var traverseListsRule = TraversalRule @@ -69,23 +67,23 @@ public void Traverse_TraversesDictMembers() TraversalMock testCase = new() { - ListChildren = new List { expectIgnored }, + ListChildren = [expectIgnored], DictChildren = new Dictionary { ["myprop"] = expectTraverse }, Child = expectIgnored, }; var ret = Traverse(testCase, traverseListsRule).Select(b => b.Current).ToList(); - //Assert expected members present - Assert.That(ret, Has.Exactly(1).Items.EqualTo(testCase)); - Assert.That(ret, Has.Exactly(1).Items.EqualTo(expectTraverse)); + // Assert expected members present + ret.Should().Contain(testCase); + ret.Should().Contain(expectTraverse); - //Assert unexpected members not present - Assert.That(ret, Has.No.Member(expectIgnored)); - Assert.That(ret, Has.Count.EqualTo(2)); + // Assert unexpected members not present + ret.Should().NotContain(expectIgnored); + ret.Count.Should().Be(2); } - [Test] + [Fact] public void Traverse_TraversesDynamic() { var traverseListsRule = TraversalRule @@ -105,16 +103,16 @@ public void Traverse_TraversesDynamic() var ret = Traverse(testCase, traverseListsRule).Select(b => b.Current).ToList(); - //Assert expected members present - Assert.That(ret, Has.Exactly(1).Items.EqualTo(testCase)); - Assert.That(ret, Has.Exactly(2).Items.EqualTo(expectTraverse)); + // Assert expected members present + ret.Should().Contain(testCase); + ret.Count(x => x == expectTraverse).Should().Be(2); - //Assert unexpected members not present - Assert.That(ret, Has.No.Member(expectIgnored)); - Assert.That(ret, Has.Count.EqualTo(3)); + // Assert unexpected members not present + ret.Should().NotContain(expectIgnored); + ret.Count.Should().Be(3); } - [Test] + [Fact] public void Traverse_ExclusiveRule() { var expectTraverse = new Base { id = "List Member" }; @@ -134,12 +132,12 @@ public void Traverse_ExclusiveRule() var ret = Traverse(testCase, traverseListsRule).Select(b => b.Current).ToList(); - //Assert expected members present - Assert.That(ret, Has.Exactly(1).Items.EqualTo(testCase)); - Assert.That(ret, Has.Exactly(2).Items.EqualTo(expectTraverse)); + // Assert expected members present + ret.Should().Contain(testCase); + ret.Count(x => x == expectTraverse).Should().Be(2); - //Assert unexpected members not present - Assert.That(ret, Has.No.Member(expectIgnored)); - Assert.That(ret, Has.Count.EqualTo(3)); + // Assert unexpected members not present + ret.Should().NotContain(expectIgnored); + ret.Count.Should().Be(3); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs index a386ca14..d8c6f072 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/GraphTraversal/TraversalContextExtensionsTests.cs @@ -1,62 +1,71 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Collections; using Speckle.Sdk.Models.GraphTraversal; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models.GraphTraversal; -[TestOf(typeof(TraversalContextExtensions))] +// Mark test class for xUnit public class TraversalContextExtensionsTests { - public static int[] TestDepths => new[] { 1, 2, 10 }; - private TraversalContext? CreateLinkedList(int depth, Func createBaseFunc) { if (depth <= 0) + { return null; + } + return new TraversalContext(createBaseFunc(depth), $"{depth}", CreateLinkedList(depth - 1, createBaseFunc)); } - [TestCaseSource(nameof(TestDepths))] + [Theory] // replaces [TestCaseSource] + [MemberData(nameof(GetTestDepths))] public void GetPropertyPath_ReturnsSequentialPath(int depth) { - var testData = CreateLinkedList(depth, i => new()).NotNull(); + var testData = CreateLinkedList(depth, i => new Base()).NotNull(); - var path = TraversalContextExtensions.GetPropertyPath(testData); + var path = testData.GetPropertyPath(); var expected = Enumerable.Range(1, depth).Select(i => i.ToString()); - Assert.That(path, Is.EquivalentTo(expected)); + path.Should().BeEquivalentTo(expected); } - [TestCaseSource(nameof(TestDepths))] + [Theory] + [MemberData(nameof(GetTestDepths))] public void GetAscendant(int depth) { - var testData = CreateLinkedList(depth, i => new()).NotNull(); + var testData = CreateLinkedList(depth, i => new Base()).NotNull(); - var all = TraversalContextExtensions.GetAscendants(testData).ToArray(); + var all = testData.GetAscendants().ToArray(); - Assert.That(all, Has.Length.EqualTo(depth)); + all.Length.Should().Be(depth); } - [TestCaseSource(nameof(TestDepths))] + [Theory] + [MemberData(nameof(GetTestDepths))] public void GetAscendantOfType_AllBase(int depth) { - var testData = CreateLinkedList(depth, i => new()).NotNull(); + var testData = CreateLinkedList(depth, i => new Base()).NotNull(); - var all = TraversalContextExtensions.GetAscendantOfType(testData).ToArray(); + var all = testData.GetAscendantOfType().ToArray(); - Assert.That(all, Has.Length.EqualTo(depth)); + all.Length.Should().Be(depth); } - [TestCaseSource(nameof(TestDepths))] + [Theory] + [MemberData(nameof(GetTestDepths))] public void GetAscendantOfType_EveryOtherIsCollection(int depth) { var testData = CreateLinkedList(depth, i => i % 2 == 0 ? new Base() : new Collection()).NotNull(); - var all = TraversalContextExtensions.GetAscendantOfType(testData).ToArray(); + var all = testData.GetAscendantOfType().ToArray(); - Assert.That(all, Has.Length.EqualTo(Math.Ceiling(depth / 2.0))); + all.Length.Should().Be((int)Math.Ceiling(depth / 2.0)); } + + // Providing the test depths to [MemberData] for xUnit + public static IEnumerable GetTestDepths() => new[] { 1, 2, 10 }.Select(depth => new object[] { depth }); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs b/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs index bbc97251..decd2b33 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/Hashing.cs @@ -1,50 +1,50 @@ using System.Diagnostics; -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; -[TestFixture] -[TestOf(typeof(Base))] +// Removed [TestFixture] and [TestOf] annotations as they are NUnit specific public class Hashing { - [SetUp] - public void Setup() + public Hashing() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(DiningTable).Assembly); } - [Test(Description = "Checks that hashing (as represented by object ids) actually works.")] - public void HashChangeCheck() + [Fact(DisplayName = "Checks that hashing (as represented by object IDs) actually works.")] + public void HashChangeCheck_Test() { var table = new DiningTable(); var secondTable = new DiningTable(); - Assert.That(secondTable.GetId(), Is.EqualTo(table.GetId())); + secondTable.GetId().Should().Be(table.GetId(), "Object IDs of identical objects should match."); ((dynamic)secondTable).testProp = "wonderful"; - Assert.That(secondTable.GetId(), Is.Not.EqualTo(table.GetId())); + secondTable.GetId().Should().NotBe(table.GetId(), "Changing a property should alter the object ID."); } - [Test( - Description = "Tests the convention that dynamic properties that have key names prepended with '__' are ignored." - )] - public void IgnoredDynamicPropertiesCheck() + [Fact(DisplayName = "Verifies that dynamic properties with '__' prefix are ignored during hashing.")] + public void IgnoredDynamicPropertiesCheck_Test() { var table = new DiningTable(); var originalHash = table.GetId(); ((dynamic)table).__testProp = "wonderful"; - Assert.That(table.GetId(), Is.EqualTo(originalHash)); + table + .GetId() + .Should() + .Be(originalHash, "Hashing of table should not change when '__' prefixed properties are added."); } - [Test(Description = "Rather stupid test as results vary wildly even on one machine.")] - public void HashingPerformance() + [Fact(DisplayName = "Performance test: Hash computation time for large and small objects.")] + public void HashingPerformance_Test() { var polyline = new Polyline(); @@ -62,7 +62,7 @@ public void HashingPerformance() _ = polyline.GetId(); var diff1 = stopWatch.ElapsedMilliseconds - stopWatchStep; - Assert.That(diff1, Is.LessThan(300), $"Hashing shouldn't take that long ({diff1} ms) for the test object used."); + diff1.Should().BeLessThan(300, $"Hashing shouldn't take that long ({diff1} ms) for the test object used."); Console.WriteLine($"Big obj hash duration: {diff1} ms"); var pt = new Point @@ -75,12 +75,12 @@ public void HashingPerformance() _ = pt.GetId(); var diff2 = stopWatch.ElapsedMilliseconds - stopWatchStep; - Assert.That(diff2, Is.LessThan(10), $"Hashing shouldn't take that long ({diff2} ms)for the point object used."); + diff2.Should().BeLessThan(10, $"Hashing shouldn't take that long ({diff2} ms) for the point object used."); Console.WriteLine($"Small obj hash duration: {diff2} ms"); } - [Test(Description = "The hash of a decomposed object is different that that of a non-decomposed object.")] - public void DecompositionHashes() + [Fact(DisplayName = "Verifies that decomposed and non-decomposed objects have different hashes.")] + public void DecompositionHashes_Test() { var table = new DiningTable(); ((dynamic)table)["@decomposeMePlease"] = new Point(); @@ -88,6 +88,6 @@ public void DecompositionHashes() var hash1 = table.GetId(); var hash2 = table.GetId(true); - Assert.That(hash2, Is.Not.EqualTo(hash1)); + hash2.Should().NotBe(hash1, "Hash values should differ for decomposed and non-decomposed objects."); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs b/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs index 344b3e39..63500570 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/SpeckleType.cs @@ -1,45 +1,43 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; -using TestModels; +using Speckle.Sdk.Tests.Unit.Models.TestModels; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models { - [TestFixture] - [TestOf(typeof(Base))] public class SpeckleTypeTests { - [SetUp] - public void Setup() + public SpeckleTypeTests() { + // Setup logic during test class initialization TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Foo).Assembly); } - [Test, TestCaseSource(nameof(s_cases))] - public void SpeckleTypeIsProperlyBuilt(Base foo, string expectedType) - { - Assert.That(foo.speckle_type, Is.EqualTo(expectedType)); - } + [Theory] + [MemberData(nameof(Cases))] + public void SpeckleTypeIsProperlyBuilt(Base foo, string expectedType) => foo.speckle_type.Should().Be(expectedType); - private static readonly object[] s_cases = - { - new object[] { new Base(), "Base" }, - new object[] { new Foo(), "TestModels.Foo" }, - new object[] { new Bar(), "TestModels.Foo:TestModels.Bar" }, - new object[] { new Baz(), "TestModels.Foo:TestModels.Bar:TestModels.Baz" }, - }; + public static IEnumerable Cases => + new List + { + new object[] { new Base(), "Base" }, + new object[] { new Foo(), "TestModels.Foo" }, + new object[] { new Bar(), "TestModels.Foo:TestModels.Bar" }, + new object[] { new Baz(), "TestModels.Foo:TestModels.Bar:TestModels.Baz" }, + }; } -} -namespace TestModels -{ - [SpeckleType("TestModels.Foo")] - public class Foo : Base { } + namespace TestModels + { + [SpeckleType("TestModels.Foo")] + public class Foo : Base { } - [SpeckleType("TestModels.Bar")] - public class Bar : Foo { } + [SpeckleType("TestModels.Bar")] + public class Bar : Foo { } - [SpeckleType("TestModels.Baz")] - public class Baz : Bar { } + [SpeckleType("TestModels.Baz")] + public class Baz : Bar { } + } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs index 5c36f3e6..da0c804b 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/TraversalTests.cs @@ -1,14 +1,14 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Models; using Speckle.Sdk.Models.Extensions; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; -[TestFixture, TestOf(typeof(BaseExtensions))] public class TraversalTests { - [Test, Description("Tests that provided breaker rules are respected")] + [Fact(DisplayName = "Tests that provided breaker rules are respected")] public void TestFlattenWithBreaker() { //Setup @@ -32,13 +32,19 @@ public void TestFlattenWithBreaker() var ret = root.Flatten(BreakRule).ToList(); //Test - Assert.That(ret, Has.Count.EqualTo(3)); - Assert.That(ret, Is.Unique); - Assert.That(ret.Where(BreakRule), Is.Not.Empty); - Assert.That(ret, Has.No.Member(Contains.Substring("should have ignored me"))); + ret.Count.Should().Be(3); + + ret.Should().OnlyHaveUniqueItems(); + + ret.Where(BreakRule).Should().NotBeEmpty(); + + ret.Should().NotContain(x => x.id == "should have ignored me"); } - [Test, TestCase(5, 5), TestCase(5, 10), TestCase(10, 5), Description("Tests breaking after a fixed number of items")] + [Theory(DisplayName = "Tests breaking after a fixed number of items")] + [InlineData(5, 5)] + [InlineData(5, 10)] + [InlineData(10, 5)] public void TestBreakerFixed(int nestDepth, int flattenDepth) { //Setup @@ -56,11 +62,12 @@ public void TestBreakerFixed(int nestDepth, int flattenDepth) var ret = rootObject.Flatten(_ => ++counter >= flattenDepth).ToList(); //Test - Assert.That(ret, Has.Count.EqualTo(Math.Min(flattenDepth, nestDepth))); - Assert.That(ret, Is.Unique); + ret.Count.Should().Be(Math.Min(flattenDepth, nestDepth)); + + ret.Should().OnlyHaveUniqueItems(); } - [Test, Timeout(2000), Description("Tests that the flatten function does not get stuck on circular references")] + [Fact(DisplayName = "Tests that the flatten function does not get stuck on circular references")] public void TestCircularReference() { //Setup @@ -76,12 +83,14 @@ public void TestCircularReference() var ret = objectA.Flatten().ToList(); //Test - Assert.That(ret, Is.Unique); - Assert.That(ret, Is.EquivalentTo(new[] { objectA, objectB, objectC })); - Assert.That(ret, Has.Count.EqualTo(3)); + ret.Should().OnlyHaveUniqueItems(); + + ret.Should().BeEquivalentTo([objectA, objectB, objectC]); + + ret.Count.Should().Be(3); } - [Test, Description("Tests that the flatten function correctly handles (non circular) duplicates")] + [Fact(DisplayName = "Tests that the flatten function correctly handles (non circular) duplicates")] public void TestDuplicates() { //Setup @@ -95,8 +104,10 @@ public void TestDuplicates() var ret = objectA.Flatten().ToList(); //Test - Assert.That(ret, Is.Unique); - Assert.That(ret, Is.EquivalentTo(new[] { objectA, objectB })); - Assert.That(ret, Has.Count.EqualTo(2)); + ret.Should().OnlyHaveUniqueItems(); + + ret.Should().BeEquivalentTo([objectA, objectB]); + + ret.Count.Should().Be(2); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs b/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs index 32286cc5..72f71821 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Models/UtilitiesTests.cs @@ -1,92 +1,121 @@ -using NUnit.Framework; +using FluentAssertions; +using Speckle.Sdk.Dependencies; using Speckle.Sdk.Helpers; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Models; -[TestFixture(TestOf = typeof(Crypt))] public sealed class HashUtilityTests { - public static IEnumerable<(string input, string sha256, string md5)> SmallTestCases() + public static IEnumerable SmallTestCases() { - yield return ( + yield return + [ "fxFB14cBcXvoENN", "491267c87e343c2a4f9070034f4f8966e8ee4c14e5baf6f49289833142e5b509", - "d38572fdb20fe90c4871178df3f9570d" - ); - yield return ( + "d38572fdb20fe90c4871178df3f9570d", + ]; + yield return + [ "tgWsOH8frdAwJT7", "dd62d2028d8243f07cbdbb0cd4c3460a96c88dd6322dd9fceba4e4912ad88fa7", - "a7eecf20d68f836f462963928cd0f1a1" - ); - yield return ( + "a7eecf20d68f836f462963928cd0f1a1", + ]; + yield return + [ "wQKrSUzBB7FI1o6", "70be5055f737e05d287c8898c7fcd3342733a337b67fe64f91fd34dcdf92fc88", - "2424cff4a88055b149e5ff2aaf0b3131" - ); - yield return ( + "2424cff4a88055b149e5ff2aaf0b3131", + ]; + yield return + [ "WnAbz1hCznVmDh1", "511433f4bb8d24d4ef7d4478984fd36f17ab6c58676f40ad0f4bcb615de0e313", - "ad48ff1e60ea2369de178aaab2fa99af" - ); + "ad48ff1e60ea2369de178aaab2fa99af", + ]; } - public static IEnumerable LargeTestCases() + public static IEnumerable SmallTestCases(IEnumerable cases, IEnumerable range) + { + foreach (var length in range) + { + foreach (var testCase in cases) + { + yield return [.. testCase, length]; + } + } + } + + public static IEnumerable SmallTestCasesMd5() => + SmallTestCases(SmallTestCases(), EnumerableExtensions.RangeFrom(0, 32)); + + public static IEnumerable SmallTestCasesSha256() => + SmallTestCases(SmallTestCases(), EnumerableExtensions.RangeFrom(2, 64)); + + public static IEnumerable SmallTestCasesSha256Span() => + SmallTestCases(SmallTestCases(), EnumerableExtensions.RangeFrom(2, 64).Where(x => x % 2 == 0)); + + public static IEnumerable LargeTestCases() { Random random = new(420); - yield return new TestCaseData( + yield return + [ new string(Enumerable.Range(0, 1_000_000).Select(_ => (char)random.Next(32, 127)).ToArray()), - "b919b9e60cd6bb86ab395ee1408e12efd4d3e4e7b58f02b4cda6b4120086959a" - ).SetName("1_000_000 random chars"); - yield return new TestCaseData( + "b919b9e60cd6bb86ab395ee1408e12efd4d3e4e7b58f02b4cda6b4120086959a", + ]; + yield return + [ new string(Enumerable.Range(0, 10_000_000).Select(_ => (char)random.Next(32, 127)).ToArray()), - "f2e83101c3066c8a2983acdb92df53504ec00ac1e5afb71b7c3798cb4daf6162" - ).SetName("10_000_000 random chars"); + "f2e83101c3066c8a2983acdb92df53504ec00ac1e5afb71b7c3798cb4daf6162", + ]; } - [Test, TestOf(nameof(Crypt.Md5))] - public void Md5( - [ValueSource(nameof(SmallTestCases))] (string input, string _, string expected) testCase, - [Range(0, 32)] int length - ) + [Theory] + [MemberData(nameof(SmallTestCasesMd5))] + public void Md5(string input, string _, string expected, int length) { - var lower = Crypt.Md5(testCase.input, "x2", length); - var upper = Crypt.Md5(testCase.input, "X2", length); + var resultLower = Crypt.Md5(input, "x2", length); + var resultUpper = Crypt.Md5(input, "X2", length); + + resultLower.Should().Be(new string(expected.ToLower()[..length])); - Assert.That(lower, Is.EqualTo(new string(testCase.expected.ToLower()[..length]))); - Assert.That(upper, Is.EqualTo(new string(testCase.expected.ToUpper()[..length]))); + resultUpper.Should().Be(new string(expected.ToUpper()[..length])); } - [Test, TestOf(nameof(Crypt.Sha256))] - public void Sha256( - [ValueSource(nameof(SmallTestCases))] (string input, string expected, string _) testCase, - [Range(2, 64)] int length - ) + [Theory] + [MemberData(nameof(SmallTestCasesSha256))] + public void Sha256(string input, string expected, string _, int length) { - var lower = Crypt.Sha256(testCase.input, "x2", length); - var upper = Crypt.Sha256(testCase.input, "X2", length); + var resultLower = Crypt.Sha256(input, "x2", length); + var resultUpper = Crypt.Sha256(input, "X2", length); - Assert.That(lower, Is.EqualTo(new string(testCase.expected.ToLower()[..length]))); - Assert.That(upper, Is.EqualTo(new string(testCase.expected.ToUpper()[..length]))); + resultLower.Should().Be(new string(expected.ToLower()[..length])); + + resultUpper.Should().Be(new string(expected.ToUpper()[..length])); } - [Test, TestOf(nameof(Crypt.Sha256))] + [Theory] + [MemberData(nameof(SmallTestCasesSha256Span))] public void Sha256_Span( - [ValueSource(nameof(SmallTestCases))] (string input, string expected, string _) testCase, - [Range(2, 64, 2)] int length //Span version of the function must have multiple of 2 + string input, + string expected, + string _, + int length //Span version of the function must have multiple of 2 ) { - var lower64 = Crypt.Sha256(testCase.input.AsSpan(), "x2", length); - var upper64 = Crypt.Sha256(testCase.input.AsSpan(), "X2", length); + var resultLowerSpan = Crypt.Sha256(input.AsSpan(), "x2", length); + var resultUpperSpan = Crypt.Sha256(input.AsSpan(), "X2", length); + + resultLowerSpan.Should().Be(new string(expected.ToLower()[..length])); - Assert.That(lower64, Is.EqualTo(new string(testCase.expected.ToLower()[..length]))); - Assert.That(upper64, Is.EqualTo(new string(testCase.expected.ToUpper()[..length]))); + resultUpperSpan.Should().Be(new string(expected.ToUpper()[..length])); } - [Test, TestOf(nameof(Crypt.Sha256))] - [TestCaseSource(nameof(LargeTestCases))] + [Theory] + [MemberData(nameof(LargeTestCases))] public void Sha256_LargeDataTests(string input, string expected) { - var test = Crypt.Sha256(input.AsSpan()); - Assert.That(test, Is.EqualTo(expected)); + var computedHash = Crypt.Sha256(input.AsSpan()); + computedHash.Should().Be(expected); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs index 961729a5..582bae34 100644 --- a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonCacheManagerTests.cs @@ -1,22 +1,19 @@ -using Microsoft.Data.Sqlite; -using NUnit.Framework; -using Shouldly; +using FluentAssertions; +using Microsoft.Data.Sqlite; using Speckle.Sdk.Common; using Speckle.Sdk.SQLite; +using Xunit; namespace Speckle.Sdk.Tests.Unit.SQLite; -[TestFixture] -public class SQLiteJsonCacheManagerTests +public class SQLiteJsonCacheManagerTests : IDisposable { private readonly string _basePath = $"{Guid.NewGuid()}.db"; - private string? _connectionString; + private readonly string? _connectionString; - [SetUp] - public void Setup() => _connectionString = $"Data Source={_basePath};"; + public SQLiteJsonCacheManagerTests() => _connectionString = $"Data Source={_basePath};"; - [TearDown] - public void TearDown() + public void Dispose() { if (File.Exists(_basePath)) { @@ -27,23 +24,23 @@ public void TearDown() } } - [Test] + [Fact] public void TestGetAll() { var data = new List<(string id, string json)>() { ("id1", "1"), ("id2", "2") }; using var manager = new SqLiteJsonCacheManager(_connectionString.NotNull(), 2); manager.SaveObjects(data); var items = manager.GetAllObjects(); - items.Count.ShouldBe(data.Count); + items.Count.Should().Be(data.Count); var i = items.ToDictionary(); foreach (var (id, json) in data) { - i.TryGetValue(id, out var j).ShouldBeTrue(); - j.ShouldBe(json); + i.TryGetValue(id, out var j).Should().BeTrue(); + j.Should().Be(json); } } - [Test] + [Fact] public void TestGet() { var data = new List<(string id, string json)>() { ("id1", "1"), ("id2", "2") }; @@ -57,35 +54,35 @@ public void TestGet() manager.SaveObject(d.id, d.json); } var items = manager.GetAllObjects(); - items.Count.ShouldBe(data.Count); + items.Count.Should().Be(data.Count); var id1 = data[0].id; var json1 = manager.GetObject(id1); - json1.ShouldBe(data[0].json); - manager.HasObject(id1).ShouldBeTrue(); + json1.Should().Be(data[0].json); + manager.HasObject(id1).Should().BeTrue(); manager.UpdateObject(id1, "3"); json1 = manager.GetObject(id1); - json1.ShouldBe("3"); - manager.HasObject(id1).ShouldBeTrue(); + json1.Should().Be("3"); + manager.HasObject(id1).Should().BeTrue(); manager.DeleteObject(id1); json1 = manager.GetObject(id1); - json1.ShouldBeNull(); - manager.HasObject(id1).ShouldBeFalse(); + json1.Should().BeNull(); + manager.HasObject(id1).Should().BeFalse(); manager.UpdateObject(id1, "3"); json1 = manager.GetObject(id1); - json1.ShouldBe("3"); - manager.HasObject(id1).ShouldBeTrue(); + json1.Should().Be("3"); + manager.HasObject(id1).Should().BeTrue(); var id2 = data[1].id; var json2 = manager.GetObject(id2); - json2.ShouldBe(data[1].json); - manager.HasObject(id2).ShouldBeTrue(); + json2.Should().Be(data[1].json); + manager.HasObject(id2).Should().BeTrue(); manager.DeleteObject(id2); json2 = manager.GetObject(id2); - json2.ShouldBeNull(); - manager.HasObject(id2).ShouldBeFalse(); + json2.Should().BeNull(); + manager.HasObject(id2).Should().BeFalse(); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs index a5d80fd6..91721a95 100644 --- a/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/SQLite/SQLiteJsonExceptionTests.cs @@ -1,13 +1,12 @@ using Microsoft.Data.Sqlite; -using NUnit.Framework; using Speckle.Sdk.SQLite; +using Xunit; namespace Speckle.Sdk.Tests.Unit.SQLite; -[TestFixture] public class SqLiteJsonCacheExceptionTests { - [Test] + [Fact] public void ExpectedExceptionFires_Void() { using var pool = new CacheDbCommandPool("DataSource=:memory:", 1); @@ -16,7 +15,7 @@ public void ExpectedExceptionFires_Void() ); } - [Test] + [Fact] public void ExpectedExceptionFires_Return() { using var pool = new CacheDbCommandPool("DataSource=:memory:", 1); diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs index a16b1937..9d8f2036 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/BatchTests.cs @@ -1,11 +1,10 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Sdk.Dependencies; using Speckle.Sdk.Serialisation.V2.Send; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; -[TestFixture] public class BatchTests { private class BatchItem : IHasSize @@ -18,28 +17,28 @@ public BatchItem(int size) public int Size { get; } } - [Test] + [Fact] public void TestBatchSize_Calc() { using var batch = new Batch(); batch.Add(new BatchItem(1)); - batch.Size.ShouldBe(1); + batch.Size.Should().Be(1); batch.Add(new BatchItem(2)); - batch.Size.ShouldBe(3); + batch.Size.Should().Be(3); } - [Test] + [Fact] public void TestBatchSize_Trim() { using var batch = new Batch(); batch.Add(new BatchItem(1)); batch.Add(new BatchItem(2)); - batch.Size.ShouldBe(3); + batch.Size.Should().Be(3); - batch.Items.Capacity.ShouldBe(Pools.DefaultCapacity); + batch.Items.Capacity.Should().Be(Pools.DefaultCapacity); batch.TrimExcess(); - batch.Items.Capacity.ShouldBe(2); - batch.Size.ShouldBe(3); + batch.Items.Capacity.Should().Be(2); + batch.Size.Should().Be(3); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs index 08a765b4..7eb55588 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ChunkingTests.cs @@ -1,50 +1,56 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; public class ChunkingTests { - public static IEnumerable TestCases() + public static IEnumerable TestCases() { + // Initialize type loader TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly); - yield return new TestCaseData(CreateDynamicTestCase(10, 100)).Returns(10); - yield return new TestCaseData(CreateDynamicTestCase(0.5, 100)).Returns(1); - yield return new TestCaseData(CreateDynamicTestCase(20.5, 100)).Returns(21); + // Return test data as a collection of objects for xUnit + yield return [CreateDynamicTestCase(10, 100), 10]; + yield return [CreateDynamicTestCase(0.5, 100), 1]; + yield return [CreateDynamicTestCase(20.5, 100), 21]; - yield return new TestCaseData(CreateDynamicTestCase(10, 1000)).Returns(10); - yield return new TestCaseData(CreateDynamicTestCase(0.5, 1000)).Returns(1); - yield return new TestCaseData(CreateDynamicTestCase(20.5, 1000)).Returns(21); + yield return [CreateDynamicTestCase(10, 1000), 10]; + yield return [CreateDynamicTestCase(0.5, 1000), 1]; + yield return [CreateDynamicTestCase(20.5, 1000), 21]; } - [TestCaseSource(nameof(TestCases))] - public int ChunkSerializationTest(Base testCase) + [Theory] + [MemberData(nameof(TestCases))] + public void ChunkSerializationTest(Base testCase, int expectedChunkCount) { - MemoryTransport transport = new(); + // Arrange + var transport = new MemoryTransport(); var sut = new SpeckleObjectSerializer([transport]); + // Act _ = sut.Serialize(testCase); - - var serailizedObjects = transport + var serializedObjects = transport .Objects.Values.Select(json => JsonConvert.DeserializeObject>(json)) .ToList(); - int numberOfChunks = serailizedObjects.Count(x => + var numberOfChunks = serializedObjects.Count(x => x!.TryGetValue("speckle_type", out var speckleType) && ((string)speckleType!) == "Speckle.Core.Models.DataChunk" ); - return numberOfChunks; + numberOfChunks.Should().Be(expectedChunkCount); } private static Base CreateDynamicTestCase(double numberOfChunks, int chunkSize) { - List value = Enumerable.Range(0, (int)Math.Floor(chunkSize * numberOfChunks)).ToList(); + // Helper method to create the dynamic test case + var value = Enumerable.Range(0, (int)Math.Floor(chunkSize * numberOfChunks)).ToList(); return new Base { [$"@({chunkSize})chunkedProperty"] = value }; } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs index 288a0810..2b03a901 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/JsonIgnoreAttributeTests.cs @@ -1,10 +1,11 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; @@ -12,74 +13,84 @@ namespace Speckle.Sdk.Tests.Unit.Serialisation; /// Tests that the leads to properties being ignored both from the final JSON output, /// But also from the id calculation /// -[TestOf(typeof(SpeckleObjectSerializer))] public sealed class JsonIgnoreRespected { - [SetUp] - public void Setup() + public JsonIgnoreRespected() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly); } - public static IEnumerable IgnoredTestCases() + public static IEnumerable IgnoredTestCases() { const string EXPECTED_PAYLOAD = "this should have been included"; const string EXPECTED_HASH = "e1d9f0685266465c9bfe4e71f2eee6e9"; - yield return new TestCaseData("this should have been ignored", EXPECTED_PAYLOAD).Returns(EXPECTED_HASH); - yield return new TestCaseData("again, ignored!", EXPECTED_PAYLOAD).Returns(EXPECTED_HASH); - yield return new TestCaseData("this one is not", EXPECTED_PAYLOAD).Returns(EXPECTED_HASH); + yield return ["this should have been ignored", EXPECTED_PAYLOAD, EXPECTED_HASH]; + yield return ["again, ignored!", EXPECTED_PAYLOAD, EXPECTED_HASH]; + yield return ["this one is not", EXPECTED_PAYLOAD, EXPECTED_HASH]; } - public static IEnumerable IgnoredCompoundTestCases() + public static IEnumerable IgnoredCompoundTestCases() { const string EXPECTED_PAYLOAD = "this should have been included"; const string EXPECTED_HASH = "eeaeee4e61b04b313dd840cd63341eee"; - yield return new TestCaseData("this should have been ignored", EXPECTED_PAYLOAD).Returns(EXPECTED_HASH); - yield return new TestCaseData("again, ignored!", EXPECTED_PAYLOAD).Returns(EXPECTED_HASH); - yield return new TestCaseData("this one is not", EXPECTED_PAYLOAD).Returns(EXPECTED_HASH); + yield return ["this should have been ignored", EXPECTED_PAYLOAD, EXPECTED_HASH]; + yield return ["again, ignored!", EXPECTED_PAYLOAD, EXPECTED_HASH]; + yield return ["this one is not", EXPECTED_PAYLOAD, EXPECTED_HASH]; } - [TestCaseSource(nameof(IgnoredTestCases))] - public string? IgnoredProperties_NotIncludedInJson(string ignoredPayload, string expectedPayload) + [Theory] + [MemberData(nameof(IgnoredTestCases))] + public void IgnoredProperties_NotIncludedInJson(string ignoredPayload, string expectedPayload, string expectedHash) { IgnoreTest testData = new(ignoredPayload, expectedPayload); SpeckleObjectSerializer sut = new(); - var (json, id) = sut.SerializeBase(testData).NotNull(); + var result = sut.SerializeBase(testData); + result.Should().NotBeNull(); + result!.Value.Id.Should().NotBeNull(); - Assert.That(json.ToString(), Does.Not.Contain(nameof(testData.ShouldBeIgnored))); - Assert.That(json.ToString(), Does.Not.Contain(ignoredPayload)); + var jsonString = result.Value.Json.ToString(); + jsonString.Should().NotContain(nameof(testData.ShouldBeIgnored)); + jsonString.Should().NotContain(ignoredPayload); - Assert.That(json.ToString(), Does.Contain(nameof(testData.ShouldBeIncluded))); - Assert.That(json.ToString(), Does.Contain(expectedPayload)); + jsonString.Should().Contain(nameof(testData.ShouldBeIncluded)); + jsonString.Should().Contain(expectedPayload); - return id?.Value; + result.Value.Id!.Value.Value.Should().Be(expectedHash); } - [TestCaseSource(nameof(IgnoredCompoundTestCases))] - public string? IgnoredProperties_Compound_NotIncludedInJson(string ignoredPayload, string expectedPayload) + [Theory] + [MemberData(nameof(IgnoredCompoundTestCases))] + public void IgnoredProperties_Compound_NotIncludedInJson( + string ignoredPayload, + string expectedPayload, + string expectedHash + ) { IgnoredCompoundTest testData = new(ignoredPayload, expectedPayload); MemoryTransport savedObjects = new(); SpeckleObjectSerializer sut = new(writeTransports: [savedObjects]); - var (json, id) = sut.SerializeBase(testData).NotNull(); + var result = sut.SerializeBase(testData); + var (json, id) = result.NotNull(); + json.Value.Should().NotBeNull(); + id.Should().NotBeNull(); - savedObjects.SaveObject(id.NotNull().Value, json.Value); + savedObjects.SaveObject(id!.Value.Value.NotNull(), json.Value); foreach ((_, string childJson) in savedObjects.Objects) { - Assert.That(childJson, Does.Not.Contain(nameof(testData.ShouldBeIgnored))); - Assert.That(childJson, Does.Not.Contain(ignoredPayload)); + childJson.Should().NotContain(nameof(testData.ShouldBeIgnored)); + childJson.Should().NotContain(ignoredPayload); - Assert.That(childJson, Does.Contain(nameof(testData.ShouldBeIncluded))); - Assert.That(childJson, Does.Contain(expectedPayload)); + childJson.Should().Contain(nameof(testData.ShouldBeIncluded)); + childJson.Should().Contain(expectedPayload); } - return id.Value.Value; + id.Value.Value.Should().Be(expectedHash); } } @@ -88,6 +99,7 @@ public sealed class IgnoredCompoundTest(string ignoredPayload, string expectedPa { [JsonIgnore] public Base ShouldBeIgnored => new IgnoreTest(ignoredPayload, expectedPayload) { ["override"] = ignoredPayload }; + public Base ShouldBeIncluded => new IgnoreTest(ignoredPayload, expectedPayload); [JsonIgnore, DetachProperty] diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs index 7c1437bc..eae0825c 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/ObjectModelDeprecationTests.cs @@ -1,41 +1,42 @@ -using NUnit.Framework; -using Shouldly; +using FluentAssertions; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation.Deprecated; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation { - [TestFixture] - [TestOf(typeof(TypeLoader))] public class TypeLoaderTests { - [SetUp] - public void Setup() + // Constructor replaces the [SetUp] functionality in NUnit + public TypeLoaderTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(MySpeckleBase).Assembly); } - [Test] + [Fact] // Replaces [Test] public void TestThatTypeWithoutAttributeFails() { - var e = Assert.Throws(() => TypeLoader.ParseType(typeof(string))); - e.ShouldNotBeNull(); + // Record.Exception is the xUnit alternative of Assert.Throws + var exception = Record.Exception(() => TypeLoader.ParseType(typeof(string))); + + exception.Should().NotBeNull(); // Shouldly assertion + exception.Should().BeOfType(); // Ensure it's the correct exception type } - [Test] + [Fact] // Replaces [Test] public void TestThatTypeWithoutMultipleAttributes() { string destinationType = $"Speckle.Core.Serialisation.{nameof(MySpeckleBase)}"; var result = TypeLoader.GetAtomicType(destinationType); - Assert.That(result, Is.EqualTo(typeof(MySpeckleBase))); + result.Should().Be(typeof(MySpeckleBase)); // Shouldly assertion replaces Assert.That destinationType = $"Speckle.Core.Serialisation.Deprecated.{nameof(MySpeckleBase)}"; result = TypeLoader.GetAtomicType(destinationType); - Assert.That(result, Is.EqualTo(typeof(MySpeckleBase))); + result.Should().Be(typeof(MySpeckleBase)); // Shouldly assertion replaces Assert.That } } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/PrimitiveTestFixture.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/PrimitiveTestFixture.cs new file mode 100644 index 00000000..75f63184 --- /dev/null +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/PrimitiveTestFixture.cs @@ -0,0 +1,48 @@ +namespace Speckle.Sdk.Tests.Unit.Serialisation; + +public abstract class PrimitiveTestFixture +{ + public static IEnumerable Int8TestCases => + new sbyte[] { 0, sbyte.MaxValue, sbyte.MinValue }.Select(x => new object[] { x }); + public static readonly short[] Int16TestCases = [short.MaxValue, short.MinValue]; + public static IEnumerable Int32TestCases => + new int[] { int.MinValue, int.MaxValue }.Select(x => new object[] { x }); + + public static IEnumerable Int64TestCases => + new long[] { long.MinValue, long.MaxValue }.Select(x => new object[] { x }); + + public static IEnumerable UInt64TestCases => + new ulong[] { ulong.MinValue, ulong.MaxValue }.Select(x => new object[] { x }); + + public static IEnumerable Float64TestCases => + new[] + { + 0, + double.Epsilon, + double.MaxValue, + double.MinValue, + double.PositiveInfinity, + double.NegativeInfinity, + double.NaN, + }.Select(x => new object[] { x }); + + public static IEnumerable Float32TestCases => + new[] + { + default, + float.Epsilon, + float.MaxValue, + float.MinValue, + float.PositiveInfinity, + float.NegativeInfinity, + float.NaN, + }.Select(x => new object[] { x }); + + public static Half[] Float16TestCases { get; } = + [default, Half.Epsilon, Half.MaxValue, Half.MinValue, Half.PositiveInfinity, Half.NegativeInfinity, Half.NaN]; + + public static float[] FloatIntegralTestCases { get; } = [0, 1, int.MaxValue, int.MinValue]; + + public static IEnumerable MyEnums { get; } = + Enum.GetValues(typeof(MyEnum)).Cast().Select(x => new[] { x }); +} diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs index 4c78302e..a2510abe 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerBreakingChanges.cs @@ -1,28 +1,26 @@ +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; using Speckle.Sdk.Tests.Unit.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; /// -/// Test fixture that documents what property typing changes break backwards/cross/forwards compatibility, and are "breaking" changes. +/// Test class that documents what property typing changes break backwards/cross/forwards compatibility, +/// and are "breaking" changes. /// This doesn't guarantee things work this way for SpecklePy /// Nor does it encompass other tricks (like deserialize callback, or computed json ignored properties) /// -[TestFixture] -[Description( - "For certain types, changing property from one type to another is a breaking change, and not backwards/forwards compatible" -)] public class SerializerBreakingChanges : PrimitiveTestFixture { - private IOperations _operations; + private readonly IOperations _operations; - [SetUp] - public void Setup() + // xUnit does not support a Setup method; instead, you can use the constructor for initialization. + public SerializerBreakingChanges() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, typeof(Point).Assembly); @@ -30,38 +28,39 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - [Test] - public void StringToInt_ShouldThrow() + [Fact] + public async Task StringToInt_ShouldThrow() { var from = new StringValueMock { value = "testValue" }; - Assert.ThrowsAsync( - async () => await from.SerializeAsTAndDeserialize(_operations) - ); + await FluentActions + .Invoking(async () => await from.SerializeAsTAndDeserialize(_operations)) + .Should() + .ThrowAsync(); } - [Test, TestCaseSource(nameof(MyEnums))] - public void StringToEnum_ShouldThrow(MyEnum testCase) + [Theory] + [MemberData(nameof(MyEnums))] // Replaces [TestCaseSource(nameof(MyEnums))] + public async Task StringToEnum_ShouldThrow(MyEnum testCase) { var from = new StringValueMock { value = testCase.ToString() }; - Assert.ThrowsAsync(async () => - { - var res = await from.SerializeAsTAndDeserialize(_operations); - }); + await FluentActions + .Invoking(async () => await from.SerializeAsTAndDeserialize(_operations)) + .Should() + .ThrowAsync(); } - [ - Test, - Description("Deserialization of a JTokenType.Float to a .NET short/int/long should throw exception"), - TestCaseSource(nameof(Float64TestCases)), - TestCase(1e+30) - ] - public void DoubleToInt_ShouldThrow(double testCase) + [Theory(DisplayName = "Deserialization of a JTokenType.Float to a .NET short/int/long should throw exception")] + [MemberData(nameof(Float64TestCases))] + [InlineData(1e+30)] // Inline test case replaces [TestCase(1e+30)] + public async Task DoubleToInt_ShouldThrow(double testCase) { var from = new DoubleValueMock { value = testCase }; - Assert.ThrowsAsync( - async () => await from.SerializeAsTAndDeserialize(_operations) - ); + + await FluentActions + .Invoking(async () => await from.SerializeAsTAndDeserialize(_operations)) + .Should() + .ThrowAsync(); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs index e6893775..42397f93 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SerializerNonBreakingChanges.cs @@ -1,29 +1,20 @@ using System.Drawing; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; -using Shouldly; using Speckle.Sdk.Api; -using Speckle.Sdk.Helpers; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Serialisation; +using Xunit; using Matrix4x4 = Speckle.DoubleNumerics.Matrix4x4; namespace Speckle.Sdk.Tests.Unit.Serialisation; -/// -/// Test fixture that documents what property typing changes maintain backwards/cross/forwards compatibility, and are "non-breaking" changes. -/// This doesn't guarantee things work this way for SpecklePy -/// Nor does it encompass other tricks (like deserialize callback, or computed json ignored properties) -/// -[TestFixture] -[Description("For certain types, changing property from one type to another should be implicitly backwards compatible")] public class SerializerNonBreakingChanges : PrimitiveTestFixture { - private IOperations _operations; + private readonly IOperations _operations; - [SetUp] - public void Setup() + public SerializerNonBreakingChanges() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(StringValueMock).Assembly); @@ -31,178 +22,163 @@ public void Setup() _operations = serviceProvider.GetRequiredService(); } - [Test, TestCaseSource(nameof(Int8TestCases)), TestCaseSource(nameof(Int32TestCases))] + [Theory, MemberData(nameof(Int8TestCases)), MemberData(nameof(Int32TestCases))] public async Task IntToColor(int argb) { var from = new IntValueMock { value = argb }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value.ToArgb(), Is.EqualTo(argb)); + res.value.ToArgb().Should().Be(argb); } - [Test, TestCaseSource(nameof(Int8TestCases)), TestCaseSource(nameof(Int32TestCases))] + [Theory, MemberData(nameof(Int8TestCases)), MemberData(nameof(Int32TestCases))] public async Task ColorToInt(int argb) { var from = new ColorValueMock { value = Color.FromArgb(argb) }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(argb)); + res.value.Should().Be(argb); } - [ - Test, - TestCaseSource(nameof(Int8TestCases)), - TestCaseSource(nameof(Int32TestCases)), - TestCaseSource(nameof(Int64TestCases)) - ] + [Theory, MemberData(nameof(Int8TestCases)), MemberData(nameof(Int32TestCases)), MemberData(nameof(Int64TestCases))] public async Task IntToDouble(long testCase) { var from = new IntValueMock { value = testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(testCase)); + res.value.Should().Be(testCase); } - [Test] + [Fact] public async Task NullToInt() { var from = new ObjectValueMock { value = null }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(default(int))); + res.value.Should().Be(default(int)); } - [Test] + [Fact] public async Task NullToDouble() { var from = new ObjectValueMock { value = null }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(default(double))); + res.value.Should().Be(0); } - // IMPORTANT!!: This test mimics large numbers that we sometimes see from python - // This is behaviour our deserializer has, but not necessarily commited to keeping - // Numbers outside the range of a Long are not officially supported - [Test] - [TestCaseSource(nameof(UInt64TestCases))] - [DefaultFloatingPointTolerance(2048)] + [Theory] + [MemberData(nameof(UInt64TestCases))] public async Task UIntToDouble(ulong testCase) { var from = new UIntValueMock { value = testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(testCase)); + res.value.Should().BeApproximately(testCase, 2048); } - [ - Test, - TestCaseSource(nameof(Int8TestCases)), - TestCaseSource(nameof(Int32TestCases)), - TestCaseSource(nameof(Int64TestCases)) - ] + [Theory, MemberData(nameof(Int8TestCases)), MemberData(nameof(Int32TestCases)), MemberData(nameof(Int64TestCases))] public async Task IntToString(long testCase) { var from = new IntValueMock { value = testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(testCase.ToString())); + res.value.Should().Be(testCase.ToString()); } - private static readonly double[][] s_arrayTestCases = - { - Array.Empty(), - new double[] { 0, 1, int.MaxValue, int.MinValue }, - new[] { default, double.Epsilon, double.MaxValue, double.MinValue }, - }; + public static IEnumerable s_arrayTestCases => + new object[] + { + Array.Empty(), + new double[] { 0, 1, int.MaxValue, int.MinValue }, + new[] { default, double.Epsilon, double.MaxValue, double.MinValue }, + }.Select(x => new[] { x }); - [Test, TestCaseSource(nameof(s_arrayTestCases))] + [Theory, MemberData(nameof(s_arrayTestCases))] public async Task ArrayToList(double[] testCase) { var from = new ArrayDoubleValueMock { value = testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EquivalentTo(testCase)); + res.value.Should().BeEquivalentTo(testCase); } - [Test, TestCaseSource(nameof(s_arrayTestCases))] + [Theory, MemberData(nameof(s_arrayTestCases))] public async Task ListToArray(double[] testCase) { var from = new ListDoubleValueMock { value = testCase.ToList() }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EquivalentTo(testCase)); + res.value.Should().BeEquivalentTo(testCase); } - [Test, TestCaseSource(nameof(s_arrayTestCases))] + [Theory, MemberData(nameof(s_arrayTestCases))] public async Task ListToIList(double[] testCase) { var from = new ListDoubleValueMock { value = testCase.ToList() }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EquivalentTo(testCase)); + res.value.Should().BeEquivalentTo(testCase); } - [Test, TestCaseSource(nameof(s_arrayTestCases))] + [Theory, MemberData(nameof(s_arrayTestCases))] public async Task ListToIReadOnlyList(double[] testCase) { var from = new ListDoubleValueMock { value = testCase.ToList() }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EquivalentTo(testCase)); + res.value.Should().BeEquivalentTo(testCase); } - [Test, TestCaseSource(nameof(s_arrayTestCases))] + [Theory, MemberData(nameof(s_arrayTestCases))] public async Task IListToList(double[] testCase) { var from = new IListDoubleValueMock { value = testCase.ToList() }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EquivalentTo(testCase)); + res.value.Should().BeEquivalentTo(testCase); } - [Test, TestCaseSource(nameof(s_arrayTestCases))] + [Theory, MemberData(nameof(s_arrayTestCases))] public async Task IReadOnlyListToList(double[] testCase) { var from = new IReadOnlyListDoubleValueMock { value = testCase.ToList() }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EquivalentTo(testCase)); + res.value.Should().BeEquivalentTo(testCase); } - [Test, TestCaseSource(nameof(MyEnums))] + [Theory, MemberData(nameof(MyEnums))] public async Task EnumToInt(MyEnum testCase) { var from = new EnumValueMock { value = testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo((int)testCase)); + res.value.Should().Be((int)testCase); } - [Test, TestCaseSource(nameof(MyEnums))] + [Theory, MemberData(nameof(MyEnums))] public async Task IntToEnum(MyEnum testCase) { var from = new IntValueMock { value = (int)testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(testCase)); + res.value.Should().Be(testCase); } - [Test] - [TestCaseSource(nameof(Float64TestCases))] - [TestCaseSource(nameof(Float32TestCases))] + [Theory, MemberData(nameof(Float32TestCases)), MemberData(nameof(Float64TestCases))] public async Task DoubleToDouble(double testCase) { var from = new DoubleValueMock { value = testCase }; var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value, Is.EqualTo(testCase)); + res.value.Should().Be(testCase); } - [Test] - [TestCase(123, 255)] - [TestCase(256, 1)] - [TestCase(256, float.MinValue)] + [Theory] + [InlineData(123, 255)] + [InlineData(256, 1)] + [InlineData(256, float.MinValue)] public async Task ListToMatrix64(int seed, double scalar) { Random rand = new(seed); @@ -210,33 +186,29 @@ public async Task ListToMatrix64(int seed, double scalar) ListDoubleValueMock from = new() { value = testCase }; - //Test List -> Matrix var res = await from.SerializeAsTAndDeserialize(_operations); - Assert.That(res.value.M11, Is.EqualTo(testCase[0])); - Assert.That(res.value.M44, Is.EqualTo(testCase[testCase.Count - 1])); + res.value.M11.Should().Be(testCase[0]); + res.value.M44.Should().Be(testCase[^1]); - //Test Matrix -> List var backAgain = await res.SerializeAsTAndDeserialize(_operations); - Assert.That(backAgain.value, Is.Not.Null); - Assert.That(backAgain.value, Is.EquivalentTo(testCase)); + backAgain.value.Should().NotBeNull(); + backAgain.value.Should().BeEquivalentTo(testCase); } - [Test] - [TestCase(123, 255)] - [TestCase(256, 1)] - [DefaultFloatingPointTolerance(Constants.EPS)] - public void Matrix32ToMatrix64(int seed, float scalar) + [Theory] + [InlineData(123, 255)] + [InlineData(256, 1)] + public async Task Matrix32ToMatrix64(int seed, float scalar) { Random rand = new(seed); List testCase = Enumerable.Range(0, 16).Select(_ => rand.NextDouble() * scalar).ToList(); ListDoubleValueMock from = new() { value = testCase }; - //Test List -> Matrix - var exception = Assert.ThrowsAsync( - async () => await from.SerializeAsTAndDeserialize(_operations) - ); - exception.ShouldNotBeNull(); + await FluentActions + .Invoking(async () => await from.SerializeAsTAndDeserialize(_operations)) + .Should() + .ThrowAsync(); } } @@ -361,46 +333,8 @@ internal async Task SerializeAsTAndDeserialize(IOperations operations) var json = operations.Serialize(this); Base result = await operations.DeserializeAsync(json); - Assert.That(result, Is.Not.Null); - Assert.That(result, Is.TypeOf()); + result.Should().NotBeNull(); + result.Should().BeOfType(); return (TTo)result; } } - -public abstract class PrimitiveTestFixture -{ - public static readonly sbyte[] Int8TestCases = { default, sbyte.MaxValue, sbyte.MinValue }; - public static readonly short[] Int16TestCases = { short.MaxValue, short.MinValue }; - public static readonly int[] Int32TestCases = { int.MinValue, int.MaxValue }; - public static readonly long[] Int64TestCases = { long.MaxValue, long.MinValue }; - public static readonly ulong[] UInt64TestCases = { ulong.MaxValue, ulong.MinValue }; - - public static double[] Float64TestCases { get; } = - { - default, - double.Epsilon, - double.MaxValue, - double.MinValue, - double.PositiveInfinity, - double.NegativeInfinity, - double.NaN, - }; - - public static float[] Float32TestCases { get; } = - { - default, - float.Epsilon, - float.MaxValue, - float.MinValue, - float.PositiveInfinity, - float.NegativeInfinity, - float.NaN, - }; - - public static Half[] Float16TestCases { get; } = - { default, Half.Epsilon, Half.MaxValue, Half.MinValue, Half.PositiveInfinity, Half.NegativeInfinity, Half.NaN }; - - public static float[] FloatIntegralTestCases { get; } = { 0, 1, int.MaxValue, int.MinValue }; - - public static MyEnum[] MyEnums { get; } = Enum.GetValues(typeof(MyEnum)).Cast().ToArray(); -} diff --git a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs index b9cd0183..dc6e8cb2 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Serialisation/SimpleRoundTripTests.cs @@ -1,30 +1,29 @@ using System.Reflection; +using FluentAssertions; using Microsoft.Extensions.DependencyInjection; -using NUnit.Framework; using Speckle.Sdk.Api; using Speckle.Sdk.Host; using Speckle.Sdk.Models; using Speckle.Sdk.Tests.Unit.Host; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Serialisation; -[TestFixture] public class SimpleRoundTripTests { - private IOperations _operations; + private readonly IOperations _operations; - static SimpleRoundTripTests() - { - Reset(); - } - - private static void Reset() + public SimpleRoundTripTests() { TypeLoader.Reset(); TypeLoader.Initialize(typeof(Base).Assembly, Assembly.GetExecutingAssembly()); + var serviceProvider = TestServiceSetup.GetServiceProvider(); + _operations = serviceProvider.GetRequiredService(); } - public static IEnumerable TestData() + public static IEnumerable TestData() => TestDataInternal().Select(x => new object[] { x }); + + public static IEnumerable TestDataInternal() { yield return new DiningTable { ["@strangeVariable_NAme3"] = new TableLegFixture() }; @@ -36,21 +35,13 @@ public static IEnumerable TestData() yield return polyline; } - [SetUp] - public void Setup() - { - Reset(); - - var serviceProvider = TestServiceSetup.GetServiceProvider(); - _operations = serviceProvider.GetRequiredService(); - } - - [TestCaseSource(nameof(TestData))] + [Theory] + [MemberData(nameof(TestData))] public async Task SimpleSerialization(Base testData) { var result = _operations.Serialize(testData); var test = await _operations.DeserializeAsync(result); - Assert.That(testData.GetId(), Is.EqualTo(test.GetId())); + testData.GetId().Should().Be(test.GetId()); } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj b/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj index 76529a53..5980c41d 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj +++ b/tests/Speckle.Sdk.Tests.Unit/Speckle.Sdk.Tests.Unit.csproj @@ -8,12 +8,12 @@ + - - - + + diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs index 36aaf999..d903a902 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/DiskTransportTests.cs @@ -1,37 +1,40 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; -[TestFixture] -[TestOf(nameof(DiskTransport))] -public sealed class DiskTransportTests : TransportTests +public sealed class DiskTransportTests : TransportTests, IDisposable { - protected override ITransport Sut => _diskTransport.NotNull(); - - private DiskTransport _diskTransport; + private readonly DiskTransport _diskTransport; + private readonly string _basePath = $"./temp_{Guid.NewGuid()}"; + private const string ApplicationName = "Speckle Integration Tests"; + private readonly string _fullPath; - private static readonly string s_basePath = $"./temp {Guid.NewGuid()}"; - private const string APPLICATION_NAME = "Speckle Integration Tests"; - private static readonly string s_fullPath = Path.Combine(s_basePath, APPLICATION_NAME); + protected override ITransport Sut => _diskTransport.NotNull(); - [SetUp] - public void Setup() + public DiskTransportTests() { - _diskTransport = new DiskTransport(s_fullPath); + _fullPath = Path.Combine(_basePath, ApplicationName); + _diskTransport = new DiskTransport(_fullPath); } - [TearDown] - public void TearDown() + [Fact] + public void DirectoryCreated_AfterInitialization() { - Directory.Delete(s_basePath, true); + // Act + var directoryExists = Directory.Exists(_fullPath); + + // Assert + directoryExists.Should().BeTrue(); } - [Test] - public void DirectoryCreated_AfterInitialization() + public void Dispose() { - bool fileExists = Directory.Exists(s_fullPath); - Assert.That(fileExists, Is.True); + if (Directory.Exists(_basePath)) + { + Directory.Delete(_basePath, true); + } } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs index 2f41d623..e457c1a7 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/MemoryTransportTests.cs @@ -1,20 +1,23 @@ -using NUnit.Framework; +// MemoryTransportTests.cs + +using FluentAssertions; using Speckle.Sdk.Common; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; -[TestFixture] -[TestOf(nameof(MemoryTransport))] public sealed class MemoryTransportTests : TransportTests { protected override ITransport Sut => _memoryTransport.NotNull(); + private readonly MemoryTransport _memoryTransport; - private MemoryTransport _memoryTransport; - - [SetUp] - public void Setup() + // Constructor used for setup in xUnit + public MemoryTransportTests() { _memoryTransport = new MemoryTransport(); } + + [Fact] + public void TransportName_ShouldSetProperly() => _memoryTransport.TransportName.Should().Be("Memory"); } diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs index f61009ab..e4d20cf4 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransport2Tests.cs @@ -1,13 +1,12 @@ +using FluentAssertions; using Microsoft.Data.Sqlite; -using NUnit.Framework; using Speckle.Sdk.Common; using Speckle.Sdk.Serialisation.Utilities; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; -[TestFixture] -[TestOf(nameof(SQLiteTransport2))] public sealed class SQLiteTransport2Tests : TransportTests, IDisposable { protected override ITransport? Sut => _sqlite; @@ -17,30 +16,31 @@ public sealed class SQLiteTransport2Tests : TransportTests, IDisposable private static readonly string s_name = $"test-{Guid.NewGuid()}"; private static readonly string s_basePath = SqlitePaths.GetDBPath(s_name); - [SetUp] - public void Setup() + public SQLiteTransport2Tests() { _sqlite = new SQLiteTransport2(s_name); } - [TearDown] - public void TearDown() + public void Dispose() { _sqlite?.Dispose(); SqliteConnection.ClearAllPools(); - File.Delete(s_basePath); + if (File.Exists(s_basePath)) + { + File.Delete(s_basePath); + } + _sqlite = null; } - [Test] + [Fact] public void DbCreated_AfterInitialization() { bool fileExists = File.Exists(s_basePath); - Assert.That(fileExists, Is.True); + fileExists.Should().BeTrue(); } - [Test] - [Description("Tests that an object can be updated")] + [Fact(DisplayName = "Tests that an object can be updated")] public async Task UpdateObject_AfterAdd() { const string PAYLOAD_ID = "MyTestObjectId"; @@ -54,50 +54,45 @@ public async Task UpdateObject_AfterAdd() await _sqlite.WriteComplete(); var result = await _sqlite.GetObject(PAYLOAD_ID); - Assert.That(result, Is.EqualTo(NEW_PAYLOAD)); + result.Should().Be(NEW_PAYLOAD); } - [Test] - [Description("Tests that updating an object that hasn't been saved previously adds the object to the DB")] + [Fact(DisplayName = "Tests that updating an object that hasn't been saved previously adds the object to the DB")] public async Task UpdateObject_WhenMissing() { const string PAYLOAD_ID = "MyTestObjectId"; const string PAYLOAD_DATA = "MyTestObjectData"; var preUpdate = await _sqlite.NotNull().GetObject(PAYLOAD_ID); - Assert.That(preUpdate, Is.Null); + preUpdate.Should().BeNull(); _sqlite.UpdateObject(PAYLOAD_ID, PAYLOAD_DATA); await _sqlite.WriteComplete(); var postUpdate = await _sqlite.GetObject(PAYLOAD_ID); - Assert.That(postUpdate, Is.EqualTo(PAYLOAD_DATA)); + postUpdate.Should().Be(PAYLOAD_DATA); } - [Test] + [Fact] public async Task SaveAndRetrieveObject_Sync() { const string PAYLOAD_ID = "MyTestObjectId"; const string PAYLOAD_DATA = "MyTestObjectData"; var preAdd = await Sut.NotNull().GetObject(PAYLOAD_ID); - Assert.That(preAdd, Is.Null); + preAdd.Should().BeNull(); _sqlite.NotNull().SaveObjectSync(PAYLOAD_ID, PAYLOAD_DATA); { var postAdd = await Sut.GetObject(PAYLOAD_ID); - Assert.That(postAdd, Is.EqualTo(PAYLOAD_DATA)); + postAdd.Should().Be(PAYLOAD_DATA); } } - [Test( - Description = "Tests that it is possible to enumerate through all objects of the transport while updating them, without getting stuck in an infinite loop" - )] - [Timeout(1000)] + [Fact(DisplayName = "Tests enumerating through all objects while updating them without infinite loop")] public void UpdateObject_WhileEnumerating() { - //I question if this is the behaviour we want, but AccountManager.GetObjects is relying on being able to update objects while enumerating over them const string UPDATE_STRING = "_new"; Dictionary testData = new() { @@ -121,18 +116,14 @@ public void UpdateObject_WhileEnumerating() _sqlite.UpdateObject(key, newData); } - //Assert that objects were updated - Assert.That(_sqlite.GetAllObjects().ToList(), Has.All.Contains(UPDATE_STRING)); - //Assert that objects were only updated once - Assert.That(_sqlite.GetAllObjects().ToList(), Has.All.Length.EqualTo(length + UPDATE_STRING.Length)); + // Assert that objects were updated + _sqlite.GetAllObjects().ToList().Should().AllSatisfy(o => o.Should().Contain(UPDATE_STRING)); + // Assert that objects were only updated once + _sqlite.GetAllObjects().ToList().Should().AllSatisfy(o => o.Should().HaveLength(length + UPDATE_STRING.Length)); } - [Test] - [Repeat(10)] - [TestCase(6, 32)] - [Description( - $"Tests that the {nameof(SQLiteTransport2.GetAllObjects)} function can be called concurrently from multiple threads" - )] + [Theory(DisplayName = "Tests that GetAllObjects can be called concurrently from multiple threads")] + [InlineData(6, 32)] public void GetAllObjects_IsThreadSafe(int dataSize, int parallelism) { foreach (int i in Enumerable.Range(0, dataSize)) @@ -151,13 +142,8 @@ public void GetAllObjects_IsThreadSafe(int dataSize, int parallelism) foreach (var result in results) { - Assert.That(result, Is.EquivalentTo(results[0])); - Assert.That(result, Has.Count.EqualTo(dataSize)); + result.Should().BeEquivalentTo(results[0]); + result.Count.Should().Be(dataSize); } } - - public void Dispose() - { - _sqlite?.Dispose(); - } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs index 5393730d..1a385466 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/SQLiteTransportTests.cs @@ -1,51 +1,47 @@ +using FluentAssertions; using Microsoft.Data.Sqlite; -using NUnit.Framework; -using Speckle.Sdk.Common; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; -[TestFixture] -[TestOf(nameof(SQLiteTransport))] public sealed class SQLiteTransportTests : TransportTests, IDisposable { protected override ITransport? Sut => _sqlite; - private SQLiteTransport? _sqlite; + private readonly SQLiteTransport _sqlite; private static readonly string s_basePath = $"./temp {Guid.NewGuid()}"; private const string APPLICATION_NAME = "Speckle Integration Tests"; - [SetUp] - public void Setup() + // Constructor replaces [SetUp] + public SQLiteTransportTests() { _sqlite = new SQLiteTransport(s_basePath, APPLICATION_NAME); } - [TearDown] - public void TearDown() + // Disposal replaces [TearDown] for cleanup + public void Dispose() { _sqlite?.Dispose(); SqliteConnection.ClearAllPools(); Directory.Delete(s_basePath, true); - _sqlite = null; } - [Test] + [Fact] public void DbCreated_AfterInitialization() { bool fileExists = File.Exists($"{s_basePath}/{APPLICATION_NAME}/Data.db"); - Assert.That(fileExists, Is.True); + fileExists.Should().BeTrue(); } - [Test] - [Description("Tests that an object can be updated")] + [Fact] public async Task UpdateObject_AfterAdd() { const string PAYLOAD_ID = "MyTestObjectId"; const string PAYLOAD_DATA = "MyTestObjectData"; - _sqlite.NotNull().SaveObject(PAYLOAD_ID, PAYLOAD_DATA); + _sqlite!.SaveObject(PAYLOAD_ID, PAYLOAD_DATA); await _sqlite.WriteComplete(); const string NEW_PAYLOAD = "MyEvenBetterObjectData"; @@ -53,50 +49,45 @@ public async Task UpdateObject_AfterAdd() await _sqlite.WriteComplete(); var result = await _sqlite.GetObject(PAYLOAD_ID); - Assert.That(result, Is.EqualTo(NEW_PAYLOAD)); + result.Should().Be(NEW_PAYLOAD); } - [Test] - [Description("Tests that updating an object that hasn't been saved previously adds the object to the DB")] + [Fact] public async Task UpdateObject_WhenMissing() { const string PAYLOAD_ID = "MyTestObjectId"; const string PAYLOAD_DATA = "MyTestObjectData"; - var preUpdate = await _sqlite.NotNull().GetObject(PAYLOAD_ID); - Assert.That(preUpdate, Is.Null); + var preUpdate = await _sqlite!.GetObject(PAYLOAD_ID); + preUpdate.Should().BeNull(); _sqlite.UpdateObject(PAYLOAD_ID, PAYLOAD_DATA); await _sqlite.WriteComplete(); var postUpdate = await _sqlite.GetObject(PAYLOAD_ID); - Assert.That(postUpdate, Is.EqualTo(PAYLOAD_DATA)); + postUpdate.Should().Be(PAYLOAD_DATA); } - [Test] + [Fact] public async Task SaveAndRetrieveObject_Sync() { const string PAYLOAD_ID = "MyTestObjectId"; const string PAYLOAD_DATA = "MyTestObjectData"; - var preAdd = await Sut.NotNull().GetObject(PAYLOAD_ID); - Assert.That(preAdd, Is.Null); + var preAdd = await Sut!.GetObject(PAYLOAD_ID); + preAdd.Should().BeNull(); - _sqlite.NotNull().SaveObjectSync(PAYLOAD_ID, PAYLOAD_DATA); + _sqlite!.SaveObjectSync(PAYLOAD_ID, PAYLOAD_DATA); { var postAdd = await Sut.GetObject(PAYLOAD_ID); - Assert.That(postAdd, Is.EqualTo(PAYLOAD_DATA)); + postAdd.Should().Be(PAYLOAD_DATA); } } - [Test( - Description = "Tests that it is possible to enumerate through all objects of the transport while updating them, without getting stuck in an infinite loop" - )] - [Timeout(1000)] + [Fact] // No xUnit [Timeout], so this is purely indicative public void UpdateObject_WhileEnumerating() { - //I question if this is the behaviour we want, but AccountManager.GetObjects is relying on being able to update objects while enumerating over them const string UPDATE_STRING = "_new"; Dictionary testData = new() { @@ -109,10 +100,10 @@ public void UpdateObject_WhileEnumerating() foreach (var (key, data) in testData) { - _sqlite.NotNull().SaveObjectSync(key, data); + _sqlite!.SaveObjectSync(key, data); } - foreach (var o in _sqlite.NotNull().GetAllObjects()) + foreach (var o in _sqlite.GetAllObjects()) { string newData = o + UPDATE_STRING; string key = $"{o[length - 1]}"; @@ -120,23 +111,19 @@ public void UpdateObject_WhileEnumerating() _sqlite.UpdateObject(key, newData); } - //Assert that objects were updated - Assert.That(_sqlite.GetAllObjects().ToList(), Has.All.Contains(UPDATE_STRING)); - //Assert that objects were only updated once - Assert.That(_sqlite.GetAllObjects().ToList(), Has.All.Length.EqualTo(length + UPDATE_STRING.Length)); + // Assert that objects were updated + _sqlite.GetAllObjects().ToList().Should().AllSatisfy(o => o.Should().Contain(UPDATE_STRING)); + // Assert that objects were only updated once + _sqlite.GetAllObjects().ToList().Should().AllSatisfy(o => o.Should().HaveLength(length + UPDATE_STRING.Length)); } - [Test] - [Repeat(10)] - [TestCase(6, 32)] - [Description( - $"Tests that the {nameof(SQLiteTransport.GetAllObjects)} function can be called concurrently from multiple threads" - )] + [Theory] + [InlineData(6, 32)] public void GetAllObjects_IsThreadSafe(int dataSize, int parallelism) { foreach (int i in Enumerable.Range(0, dataSize)) { - _sqlite.NotNull().SaveObjectSync(i.ToString(), Guid.NewGuid().ToString()); + _sqlite!.SaveObjectSync(i.ToString(), Guid.NewGuid().ToString()); } List[] results = new List[parallelism]; @@ -144,19 +131,14 @@ public void GetAllObjects_IsThreadSafe(int dataSize, int parallelism) Enumerable.Range(0, parallelism), i => { - results[i] = _sqlite.NotNull().GetAllObjects().ToList(); + results[i] = _sqlite.GetAllObjects().ToList(); } ); foreach (var result in results) { - Assert.That(result, Is.EquivalentTo(results[0])); - Assert.That(result, Has.Count.EqualTo(dataSize)); + result.Should().BeEquivalentTo(results[0]); + result.Count.Should().Be(dataSize); } } - - public void Dispose() - { - _sqlite?.Dispose(); - } } diff --git a/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs b/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs index 77689518..2aa32fdf 100644 --- a/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs +++ b/tests/Speckle.Sdk.Tests.Unit/Transports/TransportTests.cs @@ -1,16 +1,16 @@ -using NUnit.Framework; +using FluentAssertions; using Speckle.Newtonsoft.Json; using Speckle.Sdk.Common; using Speckle.Sdk.Transports; +using Xunit; namespace Speckle.Sdk.Tests.Unit.Transports; -[TestFixture] public abstract class TransportTests { protected abstract ITransport? Sut { get; } - [Test] + [Fact] public async Task SaveAndRetrieveObject() { const string PAYLOAD_ID = "MyTestObjectId"; @@ -18,7 +18,7 @@ public async Task SaveAndRetrieveObject() { var preAdd = await Sut.NotNull().GetObject(PAYLOAD_ID); - Assert.That(preAdd, Is.Null); + preAdd.Should().BeNull(); } Sut.SaveObject(PAYLOAD_ID, PAYLOAD_DATA); @@ -26,37 +26,35 @@ public async Task SaveAndRetrieveObject() { var postAdd = await Sut.GetObject(PAYLOAD_ID); - Assert.That(postAdd, Is.EqualTo(PAYLOAD_DATA)); + postAdd.Should().Be(PAYLOAD_DATA); } } - [Test] + [Fact] public async Task HasObject() { const string PAYLOAD_ID = "MyTestObjectId"; const string PAYLOAD_DATA = "MyTestObjectData"; { - var preAdd = await Sut.NotNull().HasObjects(new[] { PAYLOAD_ID }); - Assert.That(preAdd, Has.Exactly(1).Items); - Assert.That(preAdd, Has.No.ContainValue(true)); - Assert.That(preAdd, Contains.Key(PAYLOAD_ID)); + var preAdd = await Sut.NotNull().HasObjects([PAYLOAD_ID]); + preAdd.Count.Should().Be(1); + preAdd.Values.Should().NotContain(true); + preAdd.Keys.Should().Contain(PAYLOAD_ID); } Sut.SaveObject(PAYLOAD_ID, PAYLOAD_DATA); await Sut.WriteComplete(); { - var postAdd = await Sut.HasObjects(new[] { PAYLOAD_ID }); - - Assert.That(postAdd, Has.Exactly(1).Items); - Assert.That(postAdd, Has.No.ContainValue(false)); - Assert.That(postAdd, Contains.Key(PAYLOAD_ID)); + var postAdd = await Sut.HasObjects([PAYLOAD_ID]); + postAdd.Count.Should().Be(1); + postAdd.Values.Should().NotContain(false); + postAdd.Keys.Should().Contain(PAYLOAD_ID); } } - [Test] - [Description("Test that transports save objects when many threads are concurrently saving data")] + [Fact] public async Task SaveObject_ConcurrentWrites() { const int TEST_DATA_COUNT = 100; @@ -75,58 +73,54 @@ public async Task SaveObject_ConcurrentWrites() await Sut.NotNull().WriteComplete(); - //Test 1. SavedObjectCount //WARN: FAIL!!! seems this is not implemented for SQLite Transport - //Assert.That(transport.SavedObjectCount, Is.EqualTo(testDataCount)); - - //Test 2. HasObjects + //Test: HasObjects var ids = testData.Select(x => x.id).ToList(); var hasObjectsResult = await Sut.HasObjects(ids); - Assert.That(hasObjectsResult, Does.Not.ContainValue(false)); - Assert.That(hasObjectsResult.Keys, Is.EquivalentTo(ids)); + hasObjectsResult.Values.Should().NotContain(false); + hasObjectsResult.Keys.Should().BeEquivalentTo(ids); - //Test 3. GetObjects + //Test: GetObjects foreach (var x in testData) { var res = await Sut.GetObject(x.id); - Assert.That(res, Is.EqualTo(x.data)); + res.Should().Be(x.data); } } - [Test] + [Fact] public void ToString_IsNotEmpty() { var toString = Sut.NotNull().ToString(); - - Assert.That(toString, Is.Not.Null); - Assert.That(toString, Is.Not.Empty); + toString.Should().NotBeNullOrEmpty(); } - [Test] + [Fact] public void TransportName_IsNotEmpty() { var toString = Sut.NotNull().TransportName; - - Assert.That(toString, Is.Not.Null); - Assert.That(toString, Is.Not.Empty); + toString.Should().NotBeNullOrEmpty(); } - [Test] - public void SaveObject_ExceptionThrown_TaskIsCanceled() + [Fact] + public async Task SaveObject_ExceptionThrown_TaskIsCanceled() { using CancellationTokenSource tokenSource = new(); Sut.NotNull().CancellationToken = tokenSource.Token; - tokenSource.Cancel(); + await tokenSource.CancelAsync(); - Assert.CatchAsync(async () => - { - Sut.SaveObject("abcdef", "fake payload data"); - await Sut.WriteComplete(); - }); + await FluentActions + .Invoking(async () => + { + Sut.SaveObject("abcdef", "fake payload data"); + await Sut.WriteComplete(); + }) + .Should() + .ThrowAsync(); } - [Test] + [Fact] public async Task CopyObjectAndChildren() { //Assemble @@ -156,7 +150,7 @@ public async Task CopyObjectAndChildren() foreach (var (expectedId, expectedData) in testData) { var actual = await destination.GetObject(expectedId); - Assert.That(actual, Is.EqualTo(expectedData)); + actual.Should().Be(expectedData); } } } diff --git a/tests/Speckle.Sdk.Tests.Unit/packages.lock.json b/tests/Speckle.Sdk.Tests.Unit/packages.lock.json index 7c77fd93..f4ddc12b 100644 --- a/tests/Speckle.Sdk.Tests.Unit/packages.lock.json +++ b/tests/Speckle.Sdk.Tests.Unit/packages.lock.json @@ -4,9 +4,18 @@ "net8.0": { "altcover": { "type": "Direct", - "requested": "[8.9.3, )", - "resolved": "8.9.3", - "contentHash": "auKC+pDCkLjfhFkSRaAUBu25BOmlLSqucR7YBs/Lkbdc0XRuJoklWafs1KKp+M+VoJ1f0TeMS6B/FO5IeIcu7w==" + "requested": "[9.0.1, )", + "resolved": "9.0.1", + "contentHash": "aadciFNDT5bnylaYUkKal+s5hF7yU/lmZxImQWAlk1438iPqK1Uf79H5ylELpyLIU49HL5ql+tnWBihp3WVLCA==" + }, + "FluentAssertions": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "mTLbcU991EQ1SEmNbVBaGGGJy0YFzvGd1sYJGNZ07nlPKuyHSn1I22aeKzqQXgEiaKyRO6MSCto9eN9VxMwBdA==", + "dependencies": { + "System.Configuration.ConfigurationManager": "6.0.0" + } }, "GitVersion.MsBuild": { "type": "Direct", @@ -25,12 +34,12 @@ }, "Microsoft.NET.Test.Sdk": { "type": "Direct", - "requested": "[17.11.1, )", - "resolved": "17.11.1", - "contentHash": "U3Ty4BaGoEu+T2bwSko9tWqWUOU16WzSFkq6U8zve75oRBMSLTBdMAZrVNNz1Tq12aCdDom9fcOcM9QZaFHqFg==", + "requested": "[17.12.0, )", + "resolved": "17.12.0", + "contentHash": "kt/PKBZ91rFCWxVIJZSgVLk+YR+4KxTuHf799ho8WNiK5ZQpJNAEZCAWX86vcKrs+DiYjiibpYKdGZP6+/N17w==", "dependencies": { - "Microsoft.CodeCoverage": "17.11.1", - "Microsoft.TestPlatform.TestHost": "17.11.1" + "Microsoft.CodeCoverage": "17.12.0", + "Microsoft.TestPlatform.TestHost": "17.12.0" } }, "Microsoft.SourceLink.GitHub": { @@ -43,34 +52,12 @@ "Microsoft.SourceLink.Common": "8.0.0" } }, - "NUnit": { - "type": "Direct", - "requested": "[4.2.2, )", - "resolved": "4.2.2", - "contentHash": "mon0OPko28yZ/foVXrhiUvq1LReaGsBdziumyyYGxV/pOE4q92fuYeN+AF+gEU5pCjzykcdBt5l7xobTaiBjsg==" - }, - "NUnit3TestAdapter": { - "type": "Direct", - "requested": "[4.6.0, )", - "resolved": "4.6.0", - "contentHash": "R7e1+a4vuV/YS+ItfL7f//rG+JBvVeVLX4mHzFEZo4W1qEKl8Zz27AqvQSAqo+BtIzUCo4aAJMYa56VXS4hudw==" - }, "PolySharp": { "type": "Direct", "requested": "[1.15.0, )", "resolved": "1.15.0", "contentHash": "FbU0El+EEjdpuIX4iDbeS7ki1uzpJPx8vbqOzEtqnl1GZeAGJfq+jCbxeJL2y0EPnUNk8dRnnqR2xnYXg9Tf+g==" }, - "Shouldly": { - "type": "Direct", - "requested": "[4.2.1, )", - "resolved": "4.2.1", - "contentHash": "dKAKiSuhLKqD2TXwLKtqNg1nwzJcIKOOMncZjk9LYe4W+h+SCftpWdxwR79YZUIHMH+3Vu9s0s0UHNrgICLwRQ==", - "dependencies": { - "DiffEngine": "11.3.0", - "EmptyFiles": "4.4.0" - } - }, "Speckle.DoubleNumerics": { "type": "Direct", "requested": "[4.0.1, )", @@ -83,19 +70,22 @@ "resolved": "0.9.6", "contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w==" }, - "DiffEngine": { - "type": "Transitive", - "resolved": "11.3.0", - "contentHash": "k0ZgZqd09jLZQjR8FyQbSQE86Q7QZnjEzq1LPHtj1R2AoWO8sjV5x+jlSisL7NZAbUOI4y+7Bog8gkr9WIRBGw==", + "xunit": { + "type": "Direct", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", "dependencies": { - "EmptyFiles": "4.4.0", - "System.Management": "6.0.1" + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" } }, - "EmptyFiles": { - "type": "Transitive", - "resolved": "4.4.0", - "contentHash": "gwJEfIGS7FhykvtZoscwXj/XwW+mJY6UbAZk+qtLKFUGWC95kfKXnj8VkxsZQnWBxJemM/q664rGLN5nf+OHZw==" + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "HggUqjQJe8PtDxcP25Q+CnR6Lz4oX3GElhD9V4oU2+75x9HI6A6sxbfKGS4UwU4t4yJaS9fBmAuriz8bQApNjw==" }, "GraphQL.Client.Abstractions": { "type": "Transitive", @@ -125,8 +115,8 @@ }, "Microsoft.CodeCoverage": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "nPJqrcA5iX+Y0kqoT3a+pD/8lrW/V7ayqnEJQsTonSoPz59J8bmoQhcSN4G8+UJ64Hkuf0zuxnfuj2lkHOq4cA==" + "resolved": "17.12.0", + "contentHash": "4svMznBd5JM21JIG2xZKGNanAHNXplxf/kQDFfLHXQ3OnpJkayRK/TjacFjA+EYmoyuNXHo/sOETEfcYtAzIrA==" }, "Microsoft.Data.Sqlite.Core": { "type": "Transitive", @@ -191,21 +181,26 @@ }, "Microsoft.TestPlatform.ObjectModel": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "E2jZqAU6JeWEVsyOEOrSW1o1bpHLgb25ypvKNB/moBXPVsFYBPd/Jwi7OrYahG50J83LfHzezYI+GaEkpAotiA==", + "resolved": "17.12.0", + "contentHash": "TDqkTKLfQuAaPcEb3pDDWnh7b3SyZF+/W9OZvWFp6eJCIiiYFdSB6taE2I6tWrFw5ywhzOb6sreoGJTI6m3rSQ==", "dependencies": { "System.Reflection.Metadata": "1.6.0" } }, "Microsoft.TestPlatform.TestHost": { "type": "Transitive", - "resolved": "17.11.1", - "contentHash": "DnG+GOqJXO/CkoqlJWeDFTgPhqD/V6VqUIL3vINizCWZ3X+HshCtbbyDdSHQQEjrc2Sl/K3yaxX6s+5LFEdYuw==", + "resolved": "17.12.0", + "contentHash": "MiPEJQNyADfwZ4pJNpQex+t9/jOClBGMiCiVVFuELCMSX2nmNfvUor3uFVxNNCg30uxDP8JDYfPnMXQzsfzYyg==", "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "17.11.1", + "Microsoft.TestPlatform.ObjectModel": "17.12.0", "Newtonsoft.Json": "13.0.1" } }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "hqTM5628jSsQiv+HGpiq3WKBl2c8v1KZfby2J6Pr7pEPlK9waPdgEO6b8A/+/xn/yZ9ulv8HuqK71ONy2tg67A==" + }, "Newtonsoft.Json": { "type": "Transitive", "resolved": "13.0.1", @@ -241,22 +236,26 @@ "SQLitePCLRaw.core": "2.1.4" } }, - "System.CodeDom": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "CPc6tWO1LAer3IzfZufDBRL+UZQcj5uS207NHALQzP84Vp/z6wF0Aa0YZImOQY8iStY0A2zI/e3ihKNPfUm8XA==" - }, "System.ComponentModel.Annotations": { "type": "Transitive", "resolved": "4.5.0", "contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg==" }, - "System.Management": { + "System.Configuration.ConfigurationManager": { "type": "Transitive", - "resolved": "6.0.1", - "contentHash": "10J1D0h/lioojphfJ4Fuh5ZUThT/xOVHdV9roGBittKKNP2PMjrvibEdbVTGZcPra1399Ja3tqIJLyQrc5Wmhg==", + "resolved": "6.0.0", + "contentHash": "7T+m0kDSlIPTHIkPMIu6m6tV6qsMqJpvQWW2jIc2qi7sn40qxFo0q+7mEQAhMPXZHMKnWrnv47ntGlM/ejvw3g==", "dependencies": { - "System.CodeDom": "6.0.0" + "System.Security.Cryptography.ProtectedData": "6.0.0", + "System.Security.Permissions": "6.0.0" + } + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "NfuoKUiP2nUWwKZN6twGqXioIe1zVD0RIj2t976A+czLHr2nY454RwwXs6JU9Htc6mwqL6Dn/nEL3dpVf2jOhg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "6.0.0" } }, "System.Memory": { @@ -279,6 +278,73 @@ "resolved": "4.5.1", "contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw==" }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "AUADIc0LIEQe7MzC+I0cl0rAT8RrTAKFHl53yHjEUzNVIaUlhFY11vc2ebiVJzVBuOzun6F7FBA+8KAbGTTedQ==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "rp1gMNEZpvx9vP0JW0oHLxlf8oSiQgtno77Y4PLUBjSiDYoD77Y8uXHr1Ea5XG4/pIKhqAdxZ8v8OTUtqo9PeQ==" + }, + "System.Security.Permissions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "T/uuc7AklkDoxmcJ7LGkyX1CcSviZuLCa4jg3PekfJ7SU0niF0IVTXwUiNVP9DSpzou2PpxJ+eNY2IfDM90ZCg==", + "dependencies": { + "System.Security.AccessControl": "6.0.0", + "System.Windows.Extensions": "6.0.0" + } + }, + "System.Windows.Extensions": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "IXoJOXIqc39AIe+CIR7koBtRGMiCt/LPM3lI+PELtDIy9XdyeSrwXFdWV9dzJ2Awl0paLWUaknLxFQ5HpHZUog==", + "dependencies": { + "System.Drawing.Common": "6.0.0" + } + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]" + } + }, "speckle.sdk": { "type": "Project", "dependencies": {