Browse Source

Merge branch 'master' into property-hotfix

pull/2270/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
f07384ee65
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      scripts/ReplaceNugetCache.ps1
  2. 7
      src/Avalonia.Remote.Protocol/MetsysBson.cs
  3. 6
      src/Avalonia.Remote.Protocol/TcpTransportBase.cs
  4. 62
      tests/Avalonia.DesignerSupport.Tests/Helpers.cs
  5. 171
      tests/Avalonia.DesignerSupport.Tests/RemoteProtocolTests.cs

3
scripts/ReplaceNugetCache.ps1

@ -1,6 +1,5 @@
copy ..\samples\ControlCatalog.Desktop\bin\Debug\net461\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\net461\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp2.0\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia.Gtk3.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia.Win32.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia.Skia.dll ~\.nuget\packages\avalonia.skia\$args\lib\netstandard2.0\
copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp2.0\Avalonia.Skia.dll ~\.nuget\packages\avalonia.direct2d1\$args\lib\netstandard2.0\

7
src/Avalonia.Remote.Protocol/MetsysBson.cs

@ -1190,10 +1190,6 @@ namespace Metsys.Bson
object container = null;
var property = typeHelper.FindProperty(name);
var propertyType = property != null ? property.Type : _typeMap.ContainsKey(storageType) ? _typeMap[storageType] : typeof(object);
if (property == null && typeHelper.Expando == null)
{
throw new BsonException(string.Format("Deserialization failed: type {0} does not have a property named {1}", type.FullName, name));
}
if (property != null && property.Setter == null)
{
container = property.Getter(instance);
@ -1201,7 +1197,8 @@ namespace Metsys.Bson
var value = isNull ? null : DeserializeValue(propertyType, storageType, container, options);
if (property == null)
{
((IDictionary<string, object>)typeHelper.Expando.Getter(instance))[name] = value;
if (typeHelper.Expando != null)
((IDictionary<string, object>)typeHelper.Expando.Getter(instance))[name] = value;
}
else if (container == null && value != null && !property.Ignored)
{

6
src/Avalonia.Remote.Protocol/TcpTransportBase.cs

@ -46,7 +46,7 @@ namespace Avalonia.Remote.Protocol
{
try
{
var cl = await server.AcceptTcpClientAsync();
var cl = await server.AcceptTcpClientAsync().ConfigureAwait(false);
AcceptNew();
await Task.Run(async () =>
{
@ -54,7 +54,7 @@ namespace Avalonia.Remote.Protocol
var t = CreateTransport(_resolver, cl.GetStream(), () => tcs.TrySetResult(0));
cb(t);
await tcs.Task;
});
}).ConfigureAwait(false);
}
catch
{
@ -69,7 +69,7 @@ namespace Avalonia.Remote.Protocol
public async Task<IAvaloniaRemoteTransportConnection> Connect(IPAddress address, int port)
{
var c = new TcpClient();
await c.ConnectAsync(address, port);
await c.ConnectAsync(address, port).ConfigureAwait(false);
return CreateTransport(_resolver, c.GetStream(), ((IDisposable)c).Dispose);
}
}

62
tests/Avalonia.DesignerSupport.Tests/Helpers.cs

@ -0,0 +1,62 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Avalonia.DesignerSupport.Tests
{
static class Helpers
{
public static void StructDiff(object parsed, object expected) => StructDiff(parsed, expected, "{root}");
static void StructDiff(object parsed, object expected, string path)
{
if (parsed == null && expected == null)
return;
if ((parsed == null && expected != null) || (parsed != null && expected == null))
throw new Exception(
$"{path}: Null mismatch: {(parsed == null ? "null" : "not-null")} {(expected == null ? "null" : "not-null")}");
if (parsed.GetType() != expected.GetType())
throw new Exception($"{path}: Type mismatch: {parsed.GetType()} {expected.GetType()}");
if (parsed is string || parsed.GetType().IsPrimitive)
{
if (!parsed.Equals(expected))
throw new Exception($"{path}: Not equal {parsed} {expected}");
}
else if (parsed is IDictionary dic)
{
var dic2 = (IDictionary) expected;
if (dic.Count != dic2.Count)
throw new Exception($"{path}: Dictionary count mismatch: {dic.Count} {dic2.Count}");
foreach (var k in dic.Keys.Cast<object>().OrderBy(o => o.ToString()))
{
var v1 = dic[k];
var v2 = dic2[k];
StructDiff(v1, v2, path + "['" + k + "']");
}
}
else if (parsed is IList col)
{
var col2 = (IList) expected;
if (col.Count != col2.Count)
throw new Exception($"{path}: Collection count mismatch: {col.Count} {col2.Count}");
for (var c = 0; c < col.Count; c++)
StructDiff(col[c], col2[c], path + "[" + c + "]");
}
else
{
foreach (var prop in parsed.GetType().GetProperties()
.Where(p => p.GetMethod != null && p.GetMethod.IsPublic))
{
StructDiff(prop.GetValue(parsed), prop.GetValue(expected), path + "." + prop.Name);
}
}
}
}
}

171
tests/Avalonia.DesignerSupport.Tests/RemoteProtocolTests.cs

@ -0,0 +1,171 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Viewport;
using Xunit;
namespace Avalonia.DesignerSupport.Tests
{
public class RemoteProtocolTests : IDisposable
{
private readonly List<IDisposable> _disposables = new List<IDisposable>();
private IAvaloniaRemoteTransportConnection _server;
private IAvaloniaRemoteTransportConnection _client;
private BlockingCollection<object> _serverMessages = new BlockingCollection<object>();
private BlockingCollection<object> _clientMessages = new BlockingCollection<object>();
private SynchronizationContext _originalContext;
class DisabledSyncContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
throw new InvalidCastException("Not allowed");
}
public override void Send(SendOrPostCallback d, object state)
{
throw new InvalidCastException("Not allowed");
}
}
void Init(IMessageTypeResolver clientResolver = null, IMessageTypeResolver serverResolver = null)
{
_originalContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(new DisabledSyncContext());
var clientTransport = new BsonTcpTransport(clientResolver ?? new DefaultMessageTypeResolver());
var serverTransport = new BsonTcpTransport(serverResolver ?? new DefaultMessageTypeResolver());
var tcpListener = new TcpListener(IPAddress.Loopback, 0);
tcpListener.Start();
var port = ((IPEndPoint)tcpListener.LocalEndpoint).Port;
tcpListener.Stop();
var tcs = new TaskCompletionSource<int>();
serverTransport.Listen(IPAddress.Loopback, port, connected =>
{
_server = connected;
tcs.SetResult(0);
});
_client = clientTransport.Connect(IPAddress.Loopback, port).Result;
_disposables.Add(_client);
_client.OnMessage += (_, m) => _clientMessages.Add(m);
tcs.Task.Wait();
_disposables.Add(_server);
_server.OnMessage += (_, m) => _serverMessages.Add(m);
}
object TakeServer()
{
var src = new CancellationTokenSource(200);
try
{
return _serverMessages.Take(src.Token);
}
finally
{
src.Dispose();
}
}
[Fact]
void EntitiesAreProperlySerializedAndDeserialized()
{
Init();
var rnd = new Random();
_server.OnMessage += (_, message) => { };
object GetRandomValue(Type t, string pathInfo)
{
if (t.IsArray)
{
var arr = Array.CreateInstance(t.GetElementType(), 1);
((IList)arr)[0] = GetRandomValue(t.GetElementType(), pathInfo);
return arr;
}
if (t == typeof(bool))
return true;
if (t == typeof(int) || t == typeof(long))
return rnd.Next();
if (t == typeof(byte))
return (byte)rnd.Next(255);
if (t == typeof(double))
return rnd.NextDouble();
if (t.IsEnum)
return ((IList)Enum.GetValues(t)).Cast<object>().Last();
if (t == typeof(string))
return Guid.NewGuid().ToString();
if (t == typeof(Guid))
return Guid.NewGuid();
throw new Exception($"Doesn't know how to fabricate a random value for {t}, path {pathInfo}");
}
foreach (var t in typeof(MeasureViewportMessage).Assembly.GetTypes().Where(t =>
t.GetCustomAttribute(typeof(AvaloniaRemoteMessageGuidAttribute)) != null))
{
var o = Activator.CreateInstance(t);
foreach (var p in t.GetProperties())
p.SetValue(o, GetRandomValue(p.PropertyType, $"{t.FullName}.{p.Name}"));
_client.Send(o).Wait(200);
var received = TakeServer();
Helpers.StructDiff(received, o);
}
}
[Fact]
void RemoteProtocolShouldBeBackwardsCompatible()
{
Init(new DefaultMessageTypeResolver(typeof(ExtendedMeasureViewportMessage).Assembly));
_client.Send(new ExtendedMeasureViewportMessage()
{
Width = 100, Height = 200, SomeNewProperty = 300,
SomeArrayProperty = new[]{1,2,3},
SubObjectProperty = new ExtendedMeasureViewportMessage.SubObject()
{
Foo = 543
}
});
var received = (MeasureViewportMessage)TakeServer();
Assert.Equal(100, received.Width);
Assert.Equal(200, received.Height);
}
public void Dispose()
{
_disposables.ForEach(d => d.Dispose());
SynchronizationContext.SetSynchronizationContext(_originalContext);
}
}
[AvaloniaRemoteMessageGuid("6E3C5310-E2B1-4C3D-8688-01183AA48C5B")]
public class ExtendedMeasureViewportMessage
{
public double Width { get; set; }
public int SomeNewProperty { get; set; }
public int[] SomeArrayProperty { get; set; }
public class SubObject
{
public int Foo { get; set; }
}
public SubObject SubObjectProperty { get; set; }
public double Height { get; set; }
}
}
Loading…
Cancel
Save