Files
speckle-sharp-sdk/tests/Speckle.Sdk.Tests.Unit/Models/BaseTests.cs
T
Adam Hathcock 4cc78c4bc9 Serialize using a Channel (#146)
* Use a stack channel for deserialization

* multi-threaded

* add object dictionary pool

* more pooling

* adjust sqlite transport

* format

* Optimize IsPropNameValid

* object loader first pass

* save test

* add cache pre check

* save better deserialize

* mostly works

* uses tasks but slower at end

* rework to make more sense

* add check to avoid multi-deserialize

* modify max parallelism

* async enqueuing of tasks

* switch to more asyncenumerable

* fmt

* fmt

* cleanup sqlite

* make ServerObjectManager

* revert change

* add ability to skip cache check

* cache json to know what is loaded

* testing

* clean up usage

* clean up and added new op

* Fix exception handling

* fixing progress

* remove codejam

* Hides ObjectPool dependency

* fmt

* Use the 1.0 BCL async to try to be more compatible

* rename to dependencies

* Move Polly to internal dependencies

* format

* remove more old references

* remove stackchannel

* fixes for registration

* remove console writeline

* add cache check shortcut for root object

* start refactoring send

* recevie2 benchmark

* add test for deserialize new

* use channels for sending

* test and fixes

* Use same asyncinterfaces as Dynamo.  Merge fixes

* clean up

* fix download object progress

* put back from bad merge

* intermediate commit: separating get child function from serializer

* send didn't error

* add channels

* Use net48, netstandard2.1 and net8

* remove collection special case

* have to make a tree of tasks even though it may serialize things twice

* pre-id changing during serialize

* need AsyncInterfaces for net48 :(

* options changes

* revert to netstandard2.0 and net8.0

* fix totals

* revert httpcontext changes

* format

* clean up

* active tasks works when accounting for id not being stable

* add id tests

* more fixes

* works

* format

* Convert to BaseItem and use single SQLite checks to avoid locks

* use locks and batch sqlite operations

* hook up and handle null ids

* remove unused parameter

* remove progress from serializer itself

* invert has objects call

* readd object references

* format

* fix tests

* remove active tasks check

* bug fix for json cache

* remove locks from sqlite

* General Send test

* add childclosures

* redo extract all to be enumerable

* group tests in projects

* caching json does matter

* cache checking should be managed by channels

* format

* Merge pull request #152 from specklesystems/new-json-test

Uses a new objects test in Revit for serialization tests

* add skip

* add new roundtrip test

* fix finish

* clean up tests

* check happens in serialize...don't do it twice

* better progress reporting

* fix progress reporting

* only use detached properties when children gathering

* move detached tests

* add detached tests

* fix merge

* Fix progress change

* fix more tests

---------

Co-authored-by: Jedd Morgan <45512892+JR-Morgan@users.noreply.github.com>
Co-authored-by: Claire Kuang <kuang.claire@gmail.com>
2024-11-05 09:56:54 +00:00

258 lines
7.2 KiB
C#

using System.Collections.Concurrent;
using System.Text;
using NUnit.Framework;
using Shouldly;
using Speckle.Newtonsoft.Json.Linq;
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;
namespace Speckle.Sdk.Tests.Unit.Models;
[TestFixture]
[TestOf(typeof(Base))]
[TestOf(typeof(DynamicBase))]
public class BaseTests
{
[SetUp]
public void Setup()
{
TypeLoader.Reset();
TypeLoader.Initialize(typeof(Base).Assembly, typeof(BaseTests).Assembly);
}
[Test]
public void CanGetSetDynamicItemProp()
{
var @base = new Base();
@base["Item"] = "Item";
Assert.That(@base["Item"], Is.EqualTo("Item"));
}
[Test]
public void CanGetSetTypedItemProp()
{
var @base = new ObjectWithItemProp { Item = "baz" };
Assert.That(@base["Item"], Is.EqualTo("baz"));
Assert.That(@base.Item, Is.EqualTo("baz"));
}
[Test(Description = "Checks if validation is performed in property names")]
public void CanValidatePropNames()
{
dynamic @base = new Base();
// Word chars are OK
@base["something"] = "B";
// Only single leading @ allowed
@base["@something"] = "A";
Assert.Throws<InvalidPropNameException>(() =>
{
@base["@@@something"] = "Testing";
});
// Invalid chars: ./
Assert.Throws<InvalidPropNameException>(() =>
{
@base["some.thing"] = "Testing";
});
Assert.Throws<InvalidPropNameException>(() =>
{
@base["some/thing"] = "Testing";
});
// Trying to change a class member value will throw exceptions.
//Assert.Throws<Exception>(() => { @base["speckle_type"] = "Testing"; });
//Assert.Throws<Exception>(() => { @base["id"] = "Testing"; });
}
[Test]
public void CountDynamicChunkables()
{
const int MAX_NUM = 3000;
var @base = new Base();
var customChunk = new List<double>();
var customChunkArr = new double[MAX_NUM];
for (int i = 0; i < MAX_NUM; i++)
{
customChunk.Add(i / 2);
customChunkArr[i] = i;
}
@base["@(1000)cc1"] = customChunk;
@base["@(1000)cc2"] = customChunkArr;
var num = @base.GetTotalChildrenCount();
Assert.That(num, Is.EqualTo(MAX_NUM / 1000 * 2 + 1));
}
[Test]
public void CountTypedChunkables()
{
const int MAX_NUM = 3000;
var @base = new SampleObject();
var customChunk = new List<double>();
var customChunkArr = new double[MAX_NUM];
for (int i = 0; i < MAX_NUM; i++)
{
customChunk.Add(i / 2);
customChunkArr[i] = i;
}
@base.list = customChunk;
@base.arr = customChunkArr;
var num = @base.GetTotalChildrenCount();
var actualNum = 1 + MAX_NUM / 300 + MAX_NUM / 1000;
Assert.That(num, Is.EqualTo(actualNum));
}
[Test(Description = "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)));
}
[Test(Description = "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)));
}
[Test(Description = "Checks that only dynamic properties are returned")]
public void CanGetMembers_OnlyDynamic()
{
var @base = new SampleObject();
var dynamicProp = "dynamicProp";
@base[dynamicProp] = 123;
var names = @base.GetMembers(DynamicBaseMemberType.Dynamic).Keys;
Assert.That(names, Has.Member(dynamicProp));
Assert.That(names, Has.Count.EqualTo(1));
}
[Test(Description = "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)));
}
[Test(Description = "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)));
}
[Test]
public void CanGetDynamicMembers()
{
var @base = new SampleObject();
var dynamicProp = "dynamicProp";
@base[dynamicProp] = null;
var names = @base.GetDynamicMemberNames();
Assert.That(names, Has.Member(dynamicProp));
Assert.That(@base[dynamicProp], Is.Null);
}
[Test]
public void CanSetDynamicMembers()
{
var @base = new SampleObject();
var key = "dynamicProp";
var value = "something";
// Can create a new dynamic member
@base[key] = value;
Assert.That(value, Is.EqualTo((string)@base[key].NotNull()));
// Can overwrite existing
value = "some other value";
@base[key] = value;
Assert.That(value, Is.EqualTo((string)@base[key].NotNull()));
// Accepts null values
@base[key] = null;
Assert.That(@base[key], Is.Null);
}
[Test]
public void CanShallowCopy()
{
var sample = new SampleObject();
var copy = sample.ShallowCopy();
var selectedMembers =
DynamicBaseMemberType.Dynamic | DynamicBaseMemberType.Instance | DynamicBaseMemberType.SchemaIgnored;
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));
}
[SpeckleType("Speckle.Core.Tests.Unit.Models.BaseTests+SampleObject")]
public class SampleObject : Base
{
[Chunkable, DetachProperty]
public List<double> list { get; set; } = new();
[Chunkable(300), DetachProperty]
public double[] arr { get; set; }
[DetachProperty]
public SampleProp detachedProp { get; set; }
public SampleProp attachedProp { get; set; }
public string crazyProp { get; set; }
[SchemaIgnore]
public string IgnoredSchemaProp { get; set; }
[Obsolete("Use attached prop")]
public string ObsoleteSchemaProp { get; set; }
}
public class SampleProp
{
public string name { get; set; }
}
[SpeckleType("Speckle.Core.Tests.Unit.Models.BaseTests+ObjectWithItemProp")]
public class ObjectWithItemProp : Base
{
public string Item { get; set; } = "Item";
}
}