Merge branch 'master' into appveyor

This commit is contained in:
Paul Knopf 2018-07-21 20:51:34 -04:00 committed by GitHub
commit eaabc4e734
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 1 deletions

View file

@ -0,0 +1,90 @@
using Qml.Net.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Xunit;
using FluentAssertions;
using System.Threading;
namespace Qml.Net.Tests.Internal
{
public class ObjectTaggerTests : BaseTests
{
private static void SetMaxIdTo(UInt64 maxId)
{
var fieldInfo = typeof(ObjectId)
.GetField("MaxId", BindingFlags.NonPublic | BindingFlags.Static);
fieldInfo.SetValue(null, maxId);
}
private static void Reset()
{
var methodInfo = typeof(ObjectId)
.GetMethod("Reset", BindingFlags.NonPublic | BindingFlags.Static);
methodInfo.Invoke(null, new object[0]);
}
public ObjectTaggerTests()
{
Reset();
}
public override void Dispose()
{
Reset();
base.Dispose();
}
[Fact]
void Can_detect_id_overflow()
{
SetMaxIdTo(10);
List<object> handledObjects = new List<object>();
for(int i=0; i < 9; i++)
{
var obj = new object();
obj.GetOrCreateTag();
handledObjects.Add(obj);
}
var lastObj = new object();
Assert.Throws<Exception>(() => { lastObj.GetOrCreateTag(); });
}
[Fact]
void Can_handle_id_overflow_by_filling_spots()
{
SetMaxIdTo(10);
List<object> handledObjects = new List<object>();
for (int i = 0; i < 9; i++)
{
var obj = new object();
obj.GetOrCreateTag();
handledObjects.Add(obj);
}
//Ids are all used
handledObjects.Clear();
GC.Collect(2, GCCollectionMode.Forced, true);
Thread.Sleep(100);
//the next one is the already prepared next id
var obj10 = new object();
var tag10 = obj10.GetOrCreateTag();
tag10.Should().Be(10ul);
//the next after that will overflow
var obj1 = new object();
var tag1 = obj1.GetOrCreateTag();
tag1.Should().Be(1ul);
}
[Fact]
void Can_deliver_same_tag_for_same_instance()
{
var obj = new object();
var tag1 = obj.GetOrCreateTag();
var tag2 = obj.GetOrCreateTag();
tag1.Should().Be(tag2);
}
}
}

View file

@ -32,6 +32,17 @@ namespace Qml.Net.Internal
#region Id management
//set in unit tests
private static UInt64 MaxId = UInt64.MaxValue - 1;
//used in unit tests
private static void Reset()
{
MaxId = UInt64.MaxValue - 1;
NextId = 1;
UsedIds.Clear();
}
private static UInt64 NextId = 1;
private static HashSet<UInt64> UsedIds = new HashSet<UInt64>();
@ -48,7 +59,7 @@ namespace Qml.Net.Internal
bool firstPass = true;
while (UsedIds.Contains(nextId))
{
if(nextId == UInt64.MaxValue)
if(nextId >= MaxId)
{
if(!firstPass)
{
@ -75,6 +86,11 @@ namespace Qml.Net.Internal
FreeId(Id);
}
~ObjectId()
{
FreeId(Id);
}
#endregion
}