Skip to content

Commit 411a89c

Browse files
committed
Add tests
1 parent a83b74a commit 411a89c

5 files changed

Lines changed: 185 additions & 10 deletions

File tree

src/Speckle.Sdk/Models/Attributes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public DetachPropertyAttribute()
1919
}
2020

2121
[Obsolete("detachable = false is no longer supported")]
22-
public DetachPropertyAttribute(bool detachable = true)
22+
public DetachPropertyAttribute(bool detachable)
2323
{
2424
Detachable = detachable;
2525
}

src/Speckle.Sdk/Pipelines/Send/EfficientJson.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Buffers;
2+
using System.Text;
23
using Speckle.Sdk.Dependencies;
34

45
namespace Speckle.Sdk.Pipelines.Send;
@@ -11,10 +12,14 @@ public sealed class EfficientJson : IDisposable
1112

1213
public ReadOnlyMemory<byte> WrittenMemory => _value.WrittenMemory;
1314

14-
#if !NET5_0_OR_GREATER
15+
#if NET5_0_OR_GREATER
16+
public string ToJsonString() => Encoding.UTF8.GetString(WrittenSpan);
17+
#else
1518
public byte[] GetInternalBuffer() => _value.InternalBuffer;
1619

1720
public void CheckAndResizeBuffer(int sizeHint) => _value.CheckAndResizeBuffer(sizeHint);
21+
22+
public string ToJsonString() => Encoding.UTF8.GetString(_value.InternalBuffer, 0, _value.WrittenCount);
1823
#endif
1924

2025
public int WrittenCount => _value.WrittenCount;

src/Speckle.Sdk/Pipelines/Send/Serializer.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public IEnumerable<UploadItem> Serialize(Base root)
2929
yield break;
3030
}
3131

32+
//TODO: can we remove the EfficientJson from here?
3233
var detachedObjects = new List<(Id, EfficientJson, Dictionary<string, int>, Base, string)>();
3334
var rootClosures = new Dictionary<string, int>();
3435

@@ -122,16 +123,15 @@ private IEnumerable<PropertyInfo> ExtractProperties(Base baseObj)
122123
// It's also (debatably) important that the bytes we hash are the full json object (minus id and closures obviously)
123124
// For this, we are manually writing the closing } bracket without calling Buffer.Advance
124125
// Such that, the buffer can continue to write the id, and closures later in this function.
125-
var bytes = efficientJson.Buffer.GetSpan(efficientJson.WrittenCount + 1);
126-
bytes[^1] = (byte)'}';
127-
string id = IdGenerator.ComputeId(bytes);
126+
// var bytes = efficientJson.Buffer.GetSpan(1);
127+
// bytes[0] = (byte)'}';
128+
string id = IdGenerator.ComputeId(efficientJson.WrittenSpan);
129+
string str = Encoding.UTF8.GetString(efficientJson.WrittenSpan);
128130
#else
129-
efficientJson.CheckAndResizeBuffer(efficientJson.WrittenCount + 1);
130-
var bytes = efficientJson.GetInternalBuffer();
131-
bytes[efficientJson.WrittenCount] = (byte)'}';
132-
string id = IdGenerator.ComputeId(bytes, 0, efficientJson.WrittenCount);
131+
132+
string id = IdGenerator.ComputeId(efficientJson.GetInternalBuffer(), 0, efficientJson.WrittenCount);
133+
string str = Encoding.UTF8.GetString(efficientJson.GetInternalBuffer());
133134
#endif
134-
string str = Encoding.UTF8.GetString(bytes);
135135
jsonWriter.WriteString("id", id);
136136

137137
baseObj.id = id;
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using AwesomeAssertions;
2+
using Speckle.Newtonsoft.Json;
3+
using Speckle.Sdk.Host;
4+
using Speckle.Sdk.Models;
5+
using Speckle.Sdk.Pipelines.Send;
6+
7+
namespace Speckle.Sdk.Tests.Unit.Pipelines.Send.Serialization;
8+
9+
/// <summary>
10+
/// Tests that the <see cref="JsonIgnoreAttribute"/> leads to properties being ignored both from the final JSON output,
11+
/// But also from the id calculation
12+
/// </summary>
13+
[Collection(nameof(RequiresTypeLoaderCollection))]
14+
public sealed class JsonIgnoreRespected
15+
{
16+
private readonly Serializer _sut = new();
17+
18+
public JsonIgnoreRespected()
19+
{
20+
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(IgnoreTest).Assembly);
21+
}
22+
23+
public static IEnumerable<object[]> IgnoredTestCases()
24+
{
25+
const string EXPECTED_PAYLOAD = "this should have been included";
26+
const string EXPECTED_HASH = "c24fe8fad993b1f500e65315e9284afd";
27+
yield return ["this should have been ignored", EXPECTED_PAYLOAD, EXPECTED_HASH];
28+
yield return ["again, ignored!", EXPECTED_PAYLOAD, EXPECTED_HASH];
29+
yield return ["this one is not", EXPECTED_PAYLOAD, EXPECTED_HASH];
30+
}
31+
32+
public static IEnumerable<object[]> IgnoredCompoundTestCases()
33+
{
34+
const string EXPECTED_PAYLOAD = "this should have been included";
35+
const string EXPECTED_HASH = "aa78478569795e0ed8df656e792a4ee8";
36+
yield return ["this should have been ignored", EXPECTED_PAYLOAD, EXPECTED_HASH];
37+
yield return ["again, ignored!", EXPECTED_PAYLOAD, EXPECTED_HASH];
38+
yield return ["this one is not", EXPECTED_PAYLOAD, EXPECTED_HASH];
39+
}
40+
41+
[Theory]
42+
[MemberData(nameof(IgnoredTestCases))]
43+
public void IgnoredProperties_NotIncludedInJson(string ignoredPayload, string expectedPayload, string expectedHash)
44+
{
45+
IgnoreTest testData = new(ignoredPayload, expectedPayload);
46+
47+
UploadItem result = _sut.Serialize(testData).ToArray().First();
48+
result.SpeckleType.Should().Be(testData.speckle_type);
49+
50+
string jsonString = result.Json.ToJsonString();
51+
jsonString.Should().NotContain(nameof(testData.ShouldBeIgnored));
52+
jsonString.Should().NotContain(ignoredPayload);
53+
54+
jsonString.Should().Contain(nameof(testData.ShouldBeIncluded));
55+
jsonString.Should().Contain(expectedPayload);
56+
57+
result.Id.Should().Be(expectedHash);
58+
}
59+
60+
[Theory]
61+
[MemberData(nameof(IgnoredCompoundTestCases))]
62+
public void IgnoredProperties_Compound_NotIncludedInJson(
63+
string ignoredPayload,
64+
string expectedPayload,
65+
string expectedHash
66+
)
67+
{
68+
IgnoredCompoundTest testData = new(ignoredPayload, expectedPayload);
69+
70+
UploadItem[] results = _sut.Serialize(testData).ToArray();
71+
UploadItem result = results[0];
72+
result.SpeckleType.Should().Be(testData.speckle_type);
73+
result.Reference.closure.Should().NotBeNull();
74+
75+
foreach (UploadItem child in results)
76+
{
77+
string jsonString = child.Json.ToJsonString();
78+
jsonString.Should().NotContain(nameof(testData.ShouldBeIgnored));
79+
jsonString.Should().NotContain(ignoredPayload);
80+
81+
jsonString.Should().Contain(nameof(testData.ShouldBeIncluded));
82+
jsonString.Should().Contain(expectedPayload);
83+
}
84+
85+
result.Id.Should().Be(expectedHash);
86+
}
87+
}
88+
89+
[SpeckleType("Speckle.Sdk.Test.Unit.Serialisation.IgnoredCompoundTest")]
90+
public sealed class IgnoredCompoundTest(string ignoredPayload, string expectedPayload) : Base
91+
{
92+
[JsonIgnore]
93+
public Base ShouldBeIgnored => new IgnoreTest(ignoredPayload, expectedPayload) { ["override"] = ignoredPayload };
94+
95+
public Base ShouldBeIncluded => new IgnoreTest(ignoredPayload, expectedPayload);
96+
97+
[JsonIgnore, DetachProperty]
98+
public Base ShouldBeIgnoredDetached => ShouldBeIgnored;
99+
100+
[DetachProperty]
101+
public Base ShouldBeIncludedDetached => ShouldBeIncluded;
102+
103+
[JsonIgnore]
104+
public List<Base> ShouldBeIgnoredList => [ShouldBeIgnored];
105+
106+
[JsonIgnore, DetachProperty]
107+
public List<Base> ShouldBeIgnoredDetachedList => ShouldBeIgnoredList;
108+
109+
public List<Base> ShouldBeIncludedList => [ShouldBeIncluded];
110+
111+
[DetachProperty]
112+
public List<Base> ShouldBeIncludedDetachedList => ShouldBeIncludedList;
113+
}
114+
115+
[SpeckleType("Speckle.Sdk.Tests.Unit.Serialisation.IgnoreTest")]
116+
public sealed class IgnoreTest(string shouldBeIgnoredPayload, string shouldBeIncludedPayload) : Base
117+
{
118+
[JsonIgnore]
119+
public string ShouldBeIgnored => shouldBeIgnoredPayload;
120+
121+
public string ShouldBeIncluded => shouldBeIncludedPayload;
122+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using AwesomeAssertions;
2+
using Speckle.Sdk.Host;
3+
using Speckle.Sdk.Models;
4+
using Speckle.Sdk.Serialisation.Deprecated;
5+
6+
namespace Speckle.Sdk.Tests.Unit.Pipelines.Send.Serialization
7+
{
8+
[Collection(nameof(RequiresTypeLoaderCollection))]
9+
public class TypeLoaderTests
10+
{
11+
// Constructor replaces the [SetUp] functionality in NUnit
12+
public TypeLoaderTests()
13+
{
14+
TypeLoader.ReInitialize(typeof(Base).Assembly, typeof(MySpeckleBase).Assembly);
15+
}
16+
17+
[Fact] // Replaces [Test]
18+
public void TestThatTypeWithoutAttributeFails()
19+
{
20+
// Record.Exception is the xUnit alternative of Assert.Throws
21+
var exception = Record.Exception(() => TypeLoader.ParseType(typeof(string)));
22+
23+
exception.Should().NotBeNull(); // Shouldly assertion
24+
exception.Should().BeOfType<InvalidOperationException>(); // Ensure it's the correct exception type
25+
}
26+
27+
[Fact] // Replaces [Test]
28+
public void TestThatTypeWithoutMultipleAttributes()
29+
{
30+
string destinationType = $"Speckle.Core.Serialisation.{nameof(MySpeckleBase)}";
31+
32+
var result = TypeLoader.GetAtomicType(destinationType);
33+
result.Should().Be<MySpeckleBase>(); // Shouldly assertion replaces Assert.That
34+
35+
destinationType = $"Speckle.Core.Serialisation.Deprecated.{nameof(MySpeckleBase)}";
36+
37+
result = TypeLoader.GetAtomicType(destinationType);
38+
result.Should().Be<MySpeckleBase>(); // Shouldly assertion replaces Assert.That
39+
}
40+
}
41+
}
42+
43+
namespace Speckle.Sdk.Tests.Unit.Pipelines.Send.Serialization.Deprecated
44+
{
45+
[SpeckleType("Speckle.Core.Serialisation.MySpeckleBase")]
46+
[DeprecatedSpeckleType("Speckle.Core.Serialisation.Deprecated.MySpeckleBase")]
47+
public class MySpeckleBase : Base { }
48+
}

0 commit comments

Comments
 (0)