mirror of
https://github.com/zoriya/octokit.net.git
synced 2026-06-02 02:45:32 +00:00
check for DebuggerDisplay on models
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Octokit.Tests.Helpers;
|
||||
using Xunit;
|
||||
using Xunit.Extensions;
|
||||
|
||||
namespace Octokit.Tests.Conventions
|
||||
{
|
||||
public class DebuggerDisplayOnModels
|
||||
{
|
||||
[Fact]
|
||||
public void CheckModelsForDebuggerDisplayAttributeExample()
|
||||
{
|
||||
CheckModelsForDebuggerDisplayAttribute(typeof(IAuthorizationsClient));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(ClientInterfaces))]
|
||||
public void CheckModelsForDebuggerDisplayAttribute(Type clientInterface)
|
||||
{
|
||||
var methods = clientInterface.GetMethods();
|
||||
var modelTypes =
|
||||
from modelType in
|
||||
(from type in (
|
||||
from method in methods from parameter in method.GetParameters() select parameter.ParameterType
|
||||
).Union(
|
||||
from method in methods select method.ReturnType)
|
||||
select type.GetTypeInfo().Type)
|
||||
where TypeExtensions.IsModel(modelType)
|
||||
select modelType;
|
||||
foreach(var modelType in modelTypes.Distinct())
|
||||
{
|
||||
AssertEx.HasAttribute<DebuggerDisplayAttribute>(modelType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,8 +49,10 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DebuggerDisplayOnModels.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SyncObservableClients.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
@@ -60,6 +62,10 @@
|
||||
<Project>{674b69b8-0780-4d54-ae2b-c15821fa51cb}</Project>
|
||||
<Name>Octokit.Reactive</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Octokit.Tests\Octokit.Tests.csproj">
|
||||
<Project>{149448d4-c2f2-4df9-86bd-03e3272f093b}</Project>
|
||||
<Name>Octokit.Tests</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Octokit\Octokit.csproj">
|
||||
<Project>{08dd4305-7787-4823-a53f-4d0f725a07f3}</Project>
|
||||
<Name>Octokit</Name>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Octokit.Reactive;
|
||||
using Xunit;
|
||||
using Xunit.Extensions;
|
||||
|
||||
@@ -12,23 +11,15 @@ namespace Octokit.Tests.Conventions
|
||||
{
|
||||
public class SyncObservableClients
|
||||
{
|
||||
public static IEnumerable<object[]> ClientInterfaces
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(IEventsClient).Assembly.ExportedTypes.Where(TypeExtensions.IsClientInterface).Select(type => new[]{type});
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
private void CheckClientExample()
|
||||
private void CheckObservableClientExample()
|
||||
{
|
||||
CheckClientInterfaces(typeof(IAssigneesClient));
|
||||
CheckObservableClients(typeof(IAssigneesClient));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[PropertyData("ClientInterfaces")]
|
||||
private void CheckClientInterfaces(Type clientInterface)
|
||||
[ClassData(typeof(ClientInterfaces))]
|
||||
private void CheckObservableClients(Type clientInterface)
|
||||
{
|
||||
var observableClient = clientInterface.GetObservableClientInterface();
|
||||
var mainMethods = clientInterface.GetMethodsOrdered();
|
||||
@@ -55,37 +46,33 @@ namespace Octokit.Tests.Conventions
|
||||
{
|
||||
var mainReturnType = mainMethod.ReturnType;
|
||||
var observableReturnType = observableMethod.ReturnType;
|
||||
if(mainReturnType.IsTask())
|
||||
{
|
||||
CheckTaskReturnType(mainReturnType, observableReturnType);
|
||||
return;
|
||||
}
|
||||
CheckClientInterface(mainReturnType, observableReturnType);
|
||||
}
|
||||
|
||||
private static void CheckClientInterface(Type mainType, Type observableType)
|
||||
{
|
||||
// client interface - IClient => IObservableClient
|
||||
var expectedType = mainType.IsClientInterface() ? mainType.GetObservableClientInterface() : mainType;
|
||||
Assert.Equal(expectedType, observableType);
|
||||
}
|
||||
|
||||
private static void CheckTaskReturnType(Type mainReturnType, Type observableReturnType)
|
||||
{
|
||||
// void - Task => IObservable<Unit>
|
||||
if(!mainReturnType.IsGenericType)
|
||||
{
|
||||
Assert.Equal(typeof(IObservable<Unit>), observableReturnType);
|
||||
return;
|
||||
}
|
||||
var taskResultType = mainReturnType.GetGenericArgument();
|
||||
// single item - Task<TResult> => IObservable<TResult>
|
||||
// list - Task<IReadOnlyList<TResult>> => IObservable<TResult>
|
||||
var expectedInnerType = taskResultType.IsList() ? taskResultType.GetGenericArgument() : taskResultType;
|
||||
var expectedType = typeof(IObservable<>).MakeGenericType(expectedInnerType);
|
||||
var expectedType = GetObservableExpectedType(mainReturnType);
|
||||
Assert.Equal(expectedType, observableReturnType);
|
||||
}
|
||||
|
||||
private static Type GetObservableExpectedType(Type mainType)
|
||||
{
|
||||
var typeInfo = mainType.GetTypeInfo();
|
||||
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();
|
||||
@@ -96,53 +83,32 @@ namespace Octokit.Tests.Conventions
|
||||
{
|
||||
var observableParameter = observableParameters[index];
|
||||
Assert.Equal(mainParameter.Name, observableParameter.Name);
|
||||
CheckClientInterface(mainParameter.ParameterType, observableParameter.ParameterType);
|
||||
var mainType = mainParameter.ParameterType;
|
||||
var typeInfo = mainType.GetTypeInfo();
|
||||
var expectedType = GetObservableExpectedType(mainType);
|
||||
Assert.Equal(expectedType, observableParameter.ParameterType);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypeExtensions
|
||||
public class ClientInterfaces : IEnumerable<object[]>
|
||||
{
|
||||
const string ClientSufix = "Client";
|
||||
const string ObservablePrefix = "IObservable";
|
||||
const int RealNameIndex = 1;
|
||||
private readonly IEnumerable<object[]> data = GetClientInterfaces();
|
||||
|
||||
public static ParameterInfo[] GetParametersOrdered(this MethodInfo method)
|
||||
public static IEnumerable<object[]> GetClientInterfaces()
|
||||
{
|
||||
return method.GetParameters().OrderBy(p=>p.Name).ToArray();
|
||||
return typeof(IEventsClient).Assembly.ExportedTypes.Where(TypeExtensions.IsClientInterface).Select(type => new[] { type });
|
||||
}
|
||||
|
||||
public static MethodInfo[] GetMethodsOrdered(this Type type)
|
||||
public IEnumerator<object[]> GetEnumerator()
|
||||
{
|
||||
return type.GetMethods().OrderBy(m=>m.Name).ToArray();
|
||||
return data.GetEnumerator();
|
||||
}
|
||||
|
||||
public static bool IsClientInterface(this Type type)
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return type.IsInterface && type.Name.EndsWith(ClientSufix) && type.Namespace == typeof(IEventsClient).Namespace;
|
||||
}
|
||||
|
||||
public static Type GetObservableClientInterface(this Type type)
|
||||
{
|
||||
var observableClient = typeof(IObservableEventsClient);
|
||||
var observableClientName = observableClient.Namespace + "." + ObservablePrefix + type.Name.Substring(RealNameIndex);
|
||||
return observableClient.Assembly.GetType(observableClientName, throwOnError: true);
|
||||
}
|
||||
|
||||
public static bool IsTask(this Type type)
|
||||
{
|
||||
return typeof(Task).IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
public static bool IsList(this Type type)
|
||||
{
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IReadOnlyList<>);
|
||||
}
|
||||
|
||||
public static Type GetGenericArgument(this Type type)
|
||||
{
|
||||
return type.GetGenericArguments()[0];
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Octokit.Reactive;
|
||||
|
||||
namespace Octokit.Tests.Conventions
|
||||
{
|
||||
public static class TypeExtensions
|
||||
{
|
||||
const string ClientSufix = "Client";
|
||||
const string ObservablePrefix = "IObservable";
|
||||
const int RealNameIndex = 1;
|
||||
|
||||
public static ParameterInfo[] GetParametersOrdered(this MethodInfo method)
|
||||
{
|
||||
return method.GetParameters().OrderBy(p => p.Name).ToArray();
|
||||
}
|
||||
|
||||
public static MethodInfo[] GetMethodsOrdered(this Type type)
|
||||
{
|
||||
return type.GetMethods().OrderBy(m => m.Name).ToArray();
|
||||
}
|
||||
|
||||
public static TypeInfo GetTypeInfo(this Type type)
|
||||
{
|
||||
var typeInfo = new TypeInfo { Type = type, TypeCategory = TypeCategory.Other };
|
||||
if(type.IsClientInterface())
|
||||
{
|
||||
typeInfo.TypeCategory = TypeCategory.ClientInterface;
|
||||
}
|
||||
else if(type.IsTask())
|
||||
{
|
||||
if(!type.IsGenericType)
|
||||
{
|
||||
typeInfo.TypeCategory = TypeCategory.Task;
|
||||
}
|
||||
else
|
||||
{
|
||||
var taskResultType = type.GetGenericArgument();
|
||||
if(taskResultType.IsList())
|
||||
{
|
||||
typeInfo.TypeCategory = TypeCategory.ReadOnlyList;
|
||||
typeInfo.Type = taskResultType.GetGenericArgument();
|
||||
}
|
||||
else
|
||||
{
|
||||
typeInfo.TypeCategory = TypeCategory.GenericTask;
|
||||
typeInfo.Type = taskResultType;
|
||||
}
|
||||
}
|
||||
}
|
||||
return typeInfo;
|
||||
}
|
||||
|
||||
public static bool IsModel(this Type type)
|
||||
{
|
||||
return !type.IsInterface && type.Assembly == typeof(AuthorizationUpdate).Assembly;
|
||||
}
|
||||
|
||||
public static bool IsClientInterface(this Type type)
|
||||
{
|
||||
return type.IsInterface && type.Name.EndsWith(ClientSufix) && type.Namespace == typeof(IEventsClient).Namespace;
|
||||
}
|
||||
|
||||
public static Type GetObservableClientInterface(this Type type)
|
||||
{
|
||||
var observableClient = typeof(IObservableEventsClient);
|
||||
var observableClientName = observableClient.Namespace + "." + ObservablePrefix + type.Name.Substring(RealNameIndex);
|
||||
return observableClient.Assembly.GetType(observableClientName, throwOnError: true);
|
||||
}
|
||||
|
||||
public static bool IsTask(this Type type)
|
||||
{
|
||||
return typeof(Task).IsAssignableFrom(type);
|
||||
}
|
||||
|
||||
public static bool IsList(this Type type)
|
||||
{
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IReadOnlyList<>);
|
||||
}
|
||||
|
||||
public static Type GetGenericArgument(this Type type)
|
||||
{
|
||||
return type.GetGenericArguments()[0];
|
||||
}
|
||||
}
|
||||
|
||||
public enum TypeCategory { Other, Task, GenericTask, ReadOnlyList, ClientInterface }
|
||||
|
||||
public struct TypeInfo
|
||||
{
|
||||
public Type Type { get; set; }
|
||||
public TypeCategory TypeCategory { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
@@ -6,6 +7,11 @@ namespace Octokit.Tests.Helpers
|
||||
{
|
||||
public static class AssertEx
|
||||
{
|
||||
public static void HasAttribute<TAttribute>(MemberInfo memberInfo, bool inherit = false) where TAttribute : Attribute
|
||||
{
|
||||
Assert.True(memberInfo.IsDefined(typeof(TAttribute), inherit), memberInfo.ToString() + Environment.NewLine);
|
||||
}
|
||||
|
||||
public async static Task<T> Throws<T>(Func<Task> testCode) where T : Exception
|
||||
{
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user