Files
octokit.net/Octokit.Tests.Conventions/SyncObservableClients.cs
Mickaël Derriey 4869fd5423 Fix broken JSON deserialization in .NET 4.5 (#1647)
* Cross target Octokit.Tests against netcoreapp1.0 and net452

* Add net45-specific references

This fixes a build error after adding the net452 target:
error CS0656: Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'

* Add SimpleJson conditional compilation symbols for net45

* Disable AppDomain when running tests

Thanks to Dominick and Patrik: https://twitter.com/leastprivilege/status/893376624233762816

* Use nameof operator instead of magic strings

* Remove conditional compilation symbols as they are not used in the conventions tests project

* Enable cross targetting in the conventions tests project

* Run tests against netcoreapp1.0 only when not on Windows

* Going too fast bites you
2017-08-07 10:21:58 +10:00

132 lines
5.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reflection;
using Octokit.Tests.Helpers;
using Xunit;
namespace Octokit.Tests.Conventions
{
public class SyncObservableClients
{
[Theory]
[MemberData(nameof(GetClientInterfaces))]
public void CheckObservableClients(Type clientInterface)
{
var observableClient = clientInterface.GetObservableClientInterface();
var mainMethods = clientInterface.GetMethodsOrdered();
var observableMethods = observableClient.GetMethodsOrdered();
var mainNames = mainMethods.Select(x => x.Name).ToArray();
var observableNames = observableMethods.Select(x => x.Name).ToArray();
var methodsMissingOnReactiveClient = mainNames.Except(observableNames).ToList();
if (methodsMissingOnReactiveClient.Any())
{
throw new InterfaceMissingMethodsException(observableClient, methodsMissingOnReactiveClient);
}
var additionalMethodsOnReactiveClient = observableNames.Except(mainNames).ToList();
if (additionalMethodsOnReactiveClient.Any())
{
throw new InterfaceHasAdditionalMethodsException(observableClient, additionalMethodsOnReactiveClient);
}
if (mainNames.Count() != observableNames.Count())
{
throw new InterfaceMethodsMismatchException(observableClient, clientInterface);
}
int index = 0;
foreach (var mainMethod in mainMethods)
{
var observableMethod = observableMethods[index];
AssertEx.WithMessage(() => CheckMethod(mainMethod, observableMethod), "Invalid signature for " + observableMethod);
index++;
}
}
private static void CheckMethod(MethodInfo mainMethod, MethodInfo observableMethod)
{
Assert.Equal(mainMethod.MemberType, observableMethod.MemberType);
Assert.Equal(mainMethod.Name, observableMethod.Name);
CheckParameters(mainMethod, observableMethod);
CheckReturnValue(mainMethod, observableMethod);
}
private static void CheckReturnValue(MethodInfo mainMethod, MethodInfo observableMethod)
{
var mainReturnType = mainMethod.ReturnType;
var observableReturnType = observableMethod.ReturnType;
var expectedType = GetObservableExpectedType(mainReturnType);
if (expectedType != observableReturnType)
{
throw new ReturnValueMismatchException(observableMethod, expectedType, observableReturnType);
}
}
private static Type GetObservableExpectedType(Type mainType)
{
var typeInfo = mainType.GetCustomTypeInfo();
switch (typeInfo.TypeCategory)
{
case TypeCategory.ClientInterface:
// client interface - IClient => IObservableClient
return mainType.GetObservableClientInterface();
case TypeCategory.Task:
// void - Task => IObservable<Unit>
return typeof(IObservable<Unit>);
case TypeCategory.GenericTask:
// single item - Task<TResult> => IObservable<TResult>
case TypeCategory.ReadOnlyList:
// list - Task<IReadOnlyList<TResult>> => IObservable<TResult>
return typeof(IObservable<>).MakeGenericType(typeInfo.Type);
case TypeCategory.Other:
return mainType;
default:
throw new Exception("Unknown type category " + typeInfo.TypeCategory);
}
}
private static void CheckParameters(MethodInfo mainMethod, MethodInfo observableMethod)
{
var mainParameters = mainMethod.GetParametersOrdered();
var observableParameters = observableMethod.GetParametersOrdered();
if (mainParameters.Length != observableParameters.Length)
{
throw new ParameterCountMismatchException(observableMethod, mainParameters, observableParameters);
}
int index = 0;
foreach (var mainParameter in mainParameters)
{
var observableParameter = observableParameters[index];
if (mainParameter.Name != observableParameter.Name)
{
throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter);
}
var mainType = mainParameter.ParameterType;
var expectedType = GetObservableExpectedType(mainType);
if (expectedType != observableParameter.ParameterType)
{
throw new ParameterMismatchException(observableMethod, index, mainParameter, observableParameter);
}
index++;
}
}
public static IEnumerable<object[]> GetClientInterfaces()
{
return typeof(IGitHubClient)
.GetTypeInfo()
.Assembly
.ExportedTypes
.Where(TypeExtensions.IsClientInterface)
.Where(t => t != typeof(IStatisticsClient)) // This convention doesn't apply to this one type.
.Select(type => new[] { type });
}
}
}