Fixed example generation
Additional logging
This commit is contained in:
parent
db443556e8
commit
8ca67c2cc5
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -9,6 +9,16 @@ namespace PettingZoo.Core.Settings
|
|||||||
public static string AppDataRoot { get; }
|
public static string AppDataRoot { get; }
|
||||||
public static string InstallationRoot { get; }
|
public static string InstallationRoot { get; }
|
||||||
|
|
||||||
|
public static string LogPath => Path.Combine(AppDataRoot, @"Logs");
|
||||||
|
|
||||||
|
public static string DatabasePath => AppDataRoot;
|
||||||
|
|
||||||
|
|
||||||
|
public const string AssembliesPath = @"Assemblies";
|
||||||
|
|
||||||
|
public static string AppDataAssemblies => Path.Combine(AppDataRoot, AssembliesPath);
|
||||||
|
public static string InstallationAssemblies => Path.Combine(InstallationRoot, AssembliesPath);
|
||||||
|
|
||||||
|
|
||||||
static PettingZooPaths()
|
static PettingZooPaths()
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="RabbitMQ.Client" Version="6.2.2" />
|
<PackageReference Include="RabbitMQ.Client" Version="6.2.2" />
|
||||||
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -16,7 +16,7 @@ namespace PettingZoo.Settings.LiteDB
|
|||||||
|
|
||||||
public BaseLiteDBRepository(string databaseName)
|
public BaseLiteDBRepository(string databaseName)
|
||||||
{
|
{
|
||||||
databaseFilename = Path.Combine(PettingZooPaths.AppDataRoot, $"{databaseName}.litedb");
|
databaseFilename = Path.Combine(PettingZooPaths.DatabasePath, $"{databaseName}.litedb");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LiteDB" Version="5.0.11" />
|
<PackageReference Include="LiteDB" Version="5.0.11" />
|
||||||
<PackageReference Include="LiteDB.Async" Version="0.0.11" />
|
<PackageReference Include="LiteDB.Async" Version="0.0.11" />
|
||||||
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -2,37 +2,37 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Runtime.Loader;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PettingZoo.Core.Generator;
|
using PettingZoo.Core.Generator;
|
||||||
using Tapeti.DataAnnotations.Extensions;
|
|
||||||
|
|
||||||
namespace PettingZoo.Tapeti.AssemblyParser
|
namespace PettingZoo.Tapeti.AssemblyParser
|
||||||
{
|
{
|
||||||
public class AssemblyParser : IDisposable
|
public class AssemblyParser : IDisposable
|
||||||
{
|
{
|
||||||
private readonly MetadataLoadContext loadContext;
|
private readonly AssemblyLoadContext loadContext;
|
||||||
|
|
||||||
public AssemblyParser(params string[] extraAssemblies)
|
public AssemblyParser(params string[] extraAssembliesPaths)
|
||||||
{
|
{
|
||||||
var runtimeAssemblies = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");
|
// Using the MetadataLoadContext introduces extra complexity since types can not be compared
|
||||||
var paths = runtimeAssemblies
|
// (a string from the loaded assembly does not equal our typeof(string) for example).
|
||||||
.Concat(extraAssemblies)
|
// So instead we'll use a regular AssemblyLoadContext. Not ideal, and will probably cause other side-effects
|
||||||
|
// if we're not careful, but I don't feel like writing a full metadata parser right now.
|
||||||
|
// If you have a better idea, it's open-source! :-)
|
||||||
|
loadContext = new AssemblyLoadContext(null, true);
|
||||||
|
|
||||||
// TODO find a cleaner way
|
foreach (var extraAssembly in extraAssembliesPaths.SelectMany(p => Directory.Exists(p)
|
||||||
.Append(typeof(JsonSerializer).Assembly.Location)
|
? Directory.GetFiles(p, "*.dll")
|
||||||
.Append(typeof(RequiredGuidAttribute).Assembly.Location);
|
: Enumerable.Empty<string>()))
|
||||||
|
{
|
||||||
|
loadContext.LoadFromAssemblyPath(extraAssembly);
|
||||||
var resolver = new PathAssemblyResolver(paths);
|
}
|
||||||
loadContext = new MetadataLoadContext(resolver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
loadContext.Dispose();
|
loadContext.Unload();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace PettingZoo.Tapeti.NuGet
|
namespace PettingZoo.Tapeti.NuGet
|
||||||
{
|
{
|
||||||
// TODO support logger
|
|
||||||
public interface INuGetPackageManager
|
public interface INuGetPackageManager
|
||||||
{
|
{
|
||||||
public IReadOnlyList<INuGetPackageSource> Sources { get; }
|
public IReadOnlyList<INuGetPackageSource> Sources { get; }
|
||||||
@ -36,7 +35,6 @@ namespace PettingZoo.Tapeti.NuGet
|
|||||||
{
|
{
|
||||||
public string Version { get; }
|
public string Version { get; }
|
||||||
|
|
||||||
// TODO support fetching dependencies
|
|
||||||
public Task Download(Stream destination, CancellationToken cancellationToken);
|
public Task Download(Stream destination, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,23 +9,28 @@ using NuGet.Common;
|
|||||||
using NuGet.Protocol;
|
using NuGet.Protocol;
|
||||||
using NuGet.Protocol.Core.Types;
|
using NuGet.Protocol.Core.Types;
|
||||||
using NuGet.Versioning;
|
using NuGet.Versioning;
|
||||||
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace PettingZoo.Tapeti.NuGet
|
namespace PettingZoo.Tapeti.NuGet
|
||||||
{
|
{
|
||||||
public class NuGetPackageManager : INuGetPackageManager
|
public class NuGetPackageManager : INuGetPackageManager
|
||||||
{
|
{
|
||||||
|
private const string NuGetDefaultSource = @"https://api.nuget.org/v3/index.json";
|
||||||
|
|
||||||
|
private readonly ILogger logger;
|
||||||
private readonly SourceCacheContext cache;
|
private readonly SourceCacheContext cache;
|
||||||
private readonly List<Source> sources;
|
private readonly List<Source> sources;
|
||||||
|
|
||||||
public IReadOnlyList<INuGetPackageSource> Sources => sources;
|
public IReadOnlyList<INuGetPackageSource> Sources => sources;
|
||||||
|
|
||||||
|
|
||||||
public NuGetPackageManager()
|
public NuGetPackageManager(ILogger logger)
|
||||||
{
|
{
|
||||||
|
this.logger = logger;
|
||||||
cache = new SourceCacheContext();
|
cache = new SourceCacheContext();
|
||||||
sources = new List<Source>
|
sources = new List<Source>
|
||||||
{
|
{
|
||||||
new(cache, "nuget.org", @"https://api.nuget.org/v3/index.json")
|
new(logger.ForContext("source", NuGetDefaultSource), cache, "nuget.org", NuGetDefaultSource)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +58,7 @@ namespace PettingZoo.Tapeti.NuGet
|
|||||||
if (string.IsNullOrEmpty(nameAttribute?.Value) || string.IsNullOrEmpty(urlAttribute?.Value))
|
if (string.IsNullOrEmpty(nameAttribute?.Value) || string.IsNullOrEmpty(urlAttribute?.Value))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sources.Add(new Source(cache, nameAttribute.Value, urlAttribute.Value));
|
sources.Add(new Source(logger.ForContext("source", urlAttribute.Value), cache, nameAttribute.Value, urlAttribute.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@ -63,14 +68,16 @@ namespace PettingZoo.Tapeti.NuGet
|
|||||||
|
|
||||||
private class Source : INuGetPackageSource
|
private class Source : INuGetPackageSource
|
||||||
{
|
{
|
||||||
|
private readonly ILogger logger;
|
||||||
private readonly SourceCacheContext cache;
|
private readonly SourceCacheContext cache;
|
||||||
private readonly SourceRepository repository;
|
private readonly SourceRepository repository;
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
|
||||||
public Source(SourceCacheContext cache, string name, string url)
|
public Source(ILogger logger, SourceCacheContext cache, string name, string url)
|
||||||
{
|
{
|
||||||
|
this.logger = logger;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
Name = name;
|
Name = name;
|
||||||
repository = Repository.Factory.GetCoreV3(url);
|
repository = Repository.Factory.GetCoreV3(url);
|
||||||
@ -82,19 +89,30 @@ namespace PettingZoo.Tapeti.NuGet
|
|||||||
if (string.IsNullOrWhiteSpace(searchTerm))
|
if (string.IsNullOrWhiteSpace(searchTerm))
|
||||||
return Array.Empty<INuGetPackage>();
|
return Array.Empty<INuGetPackage>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var resource = await repository.GetResourceAsync<PackageSearchResource>(cancellationToken);
|
var resource = await repository.GetResourceAsync<PackageSearchResource>(cancellationToken);
|
||||||
var filter = new SearchFilter(includePrerelease);
|
var filter = new SearchFilter(includePrerelease);
|
||||||
|
|
||||||
return (await resource.SearchAsync(searchTerm, filter, 0, 20, new NullLogger(),
|
var result = (await resource.SearchAsync(searchTerm, filter, 0, 20, new NullLogger(),
|
||||||
cancellationToken))
|
cancellationToken))
|
||||||
.Select(p => new Package(cache, repository, p))
|
.Select(p => new Package(logger, cache, repository, p))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e, "NuGet Search failed for term '{searchTerm}' (includePrerelease {includePrerelease})", searchTerm, includePrerelease);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected class Package : INuGetPackage
|
protected class Package : INuGetPackage
|
||||||
{
|
{
|
||||||
|
private readonly ILogger logger;
|
||||||
private readonly SourceCacheContext cache;
|
private readonly SourceCacheContext cache;
|
||||||
private readonly SourceRepository repository;
|
private readonly SourceRepository repository;
|
||||||
private readonly IPackageSearchMetadata packageSearchMetadata;
|
private readonly IPackageSearchMetadata packageSearchMetadata;
|
||||||
@ -108,8 +126,9 @@ namespace PettingZoo.Tapeti.NuGet
|
|||||||
private IReadOnlyList<INuGetPackageVersion>? versions;
|
private IReadOnlyList<INuGetPackageVersion>? versions;
|
||||||
|
|
||||||
|
|
||||||
public Package(SourceCacheContext cache, SourceRepository repository, IPackageSearchMetadata packageSearchMetadata)
|
public Package(ILogger logger, SourceCacheContext cache, SourceRepository repository, IPackageSearchMetadata packageSearchMetadata)
|
||||||
{
|
{
|
||||||
|
this.logger = logger;
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.packageSearchMetadata = packageSearchMetadata;
|
this.packageSearchMetadata = packageSearchMetadata;
|
||||||
@ -117,11 +136,19 @@ namespace PettingZoo.Tapeti.NuGet
|
|||||||
|
|
||||||
|
|
||||||
public async Task<IReadOnlyList<INuGetPackageVersion>> GetVersions(CancellationToken cancellationToken)
|
public async Task<IReadOnlyList<INuGetPackageVersion>> GetVersions(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return versions ??= (await packageSearchMetadata.GetVersionsAsync())
|
return versions ??= (await packageSearchMetadata.GetVersionsAsync())
|
||||||
.Select(v => new PackageVersion(cache, repository, packageSearchMetadata, v.Version))
|
.Select(v => new PackageVersion(cache, repository, packageSearchMetadata, v.Version))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e, "NuGet GetVersions failed for packge Id '{packageId}')", packageSearchMetadata.Identity.Id);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="NuGet.Packaging" Version="6.0.0" />
|
<PackageReference Include="NuGet.Packaging" Version="6.0.0" />
|
||||||
<PackageReference Include="NuGet.Protocol" Version="6.0.0" />
|
<PackageReference Include="NuGet.Protocol" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
<PackageReference Include="SharpVectors" Version="1.7.7" />
|
<PackageReference Include="SharpVectors" Version="1.7.7" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||||
|
@ -13,14 +13,24 @@ using PettingZoo.Tapeti.NuGet;
|
|||||||
using PettingZoo.Tapeti.UI.ClassSelection;
|
using PettingZoo.Tapeti.UI.ClassSelection;
|
||||||
using PettingZoo.Tapeti.UI.PackageProgress;
|
using PettingZoo.Tapeti.UI.PackageProgress;
|
||||||
using PettingZoo.Tapeti.UI.PackageSelection;
|
using PettingZoo.Tapeti.UI.PackageSelection;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace PettingZoo.Tapeti
|
namespace PettingZoo.Tapeti
|
||||||
{
|
{
|
||||||
public class TapetiClassLibraryExampleGenerator : IExampleGenerator
|
public class TapetiClassLibraryExampleGenerator : IExampleGenerator
|
||||||
{
|
{
|
||||||
|
private readonly ILogger logger;
|
||||||
|
|
||||||
|
|
||||||
|
public TapetiClassLibraryExampleGenerator(ILogger logger)
|
||||||
|
{
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Select(object? ownerWindow, Action<IExample> onExampleSelected)
|
public void Select(object? ownerWindow, Action<IExample> onExampleSelected)
|
||||||
{
|
{
|
||||||
var packageManager = new NuGetPackageManager()
|
var packageManager = new NuGetPackageManager(logger)
|
||||||
.WithSourcesFrom(Path.Combine(PettingZooPaths.InstallationRoot, @"nuget.config"))
|
.WithSourcesFrom(Path.Combine(PettingZooPaths.InstallationRoot, @"nuget.config"))
|
||||||
.WithSourcesFrom(Path.Combine(PettingZooPaths.AppDataRoot, @"nuget.config"));
|
.WithSourcesFrom(Path.Combine(PettingZooPaths.AppDataRoot, @"nuget.config"));
|
||||||
|
|
||||||
@ -97,8 +107,11 @@ namespace PettingZoo.Tapeti
|
|||||||
|
|
||||||
private static IEnumerable<IClassTypeExample> LoadExamples(IEnumerable<IPackageAssembly> assemblies)
|
private static IEnumerable<IClassTypeExample> LoadExamples(IEnumerable<IPackageAssembly> assemblies)
|
||||||
{
|
{
|
||||||
// TODO support folder with additional assemblies to load, or implement a proper NuGet install (with dependencies) instead
|
var assemblyParser = new AssemblyParser.AssemblyParser(
|
||||||
var assemblyParser = new AssemblyParser.AssemblyParser();
|
PettingZooPaths.AppDataAssemblies,
|
||||||
|
PettingZooPaths.InstallationAssemblies
|
||||||
|
);
|
||||||
|
|
||||||
return assemblies
|
return assemblies
|
||||||
.SelectMany(a =>
|
.SelectMany(a =>
|
||||||
{
|
{
|
||||||
|
@ -6,26 +6,47 @@ using Newtonsoft.Json.Linq;
|
|||||||
|
|
||||||
namespace PettingZoo.Tapeti
|
namespace PettingZoo.Tapeti
|
||||||
{
|
{
|
||||||
// TODO detect recursion
|
|
||||||
// TODO detect recursion
|
|
||||||
// TODO detect recursion
|
|
||||||
// TODO stop making nerdy jokes in comments.
|
|
||||||
|
|
||||||
// TODO generate at least one item for enumerables
|
|
||||||
// TODO support basic types
|
|
||||||
|
|
||||||
public class TypeToJObjectConverter
|
public class TypeToJObjectConverter
|
||||||
{
|
{
|
||||||
public static JObject Convert(Type type)
|
public static JObject Convert(Type type)
|
||||||
{
|
{
|
||||||
|
if (!type.IsClass)
|
||||||
|
throw new ArgumentException($"TypeToJObjectConverter.Convert expects a class, got {type.Name}");
|
||||||
|
|
||||||
|
return ClassToJToken(type, Array.Empty<Type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly Dictionary<Type, Type> TypeEquivalenceMap = new()
|
||||||
|
{
|
||||||
|
{ typeof(uint), typeof(int) },
|
||||||
|
{ typeof(long), typeof(int) },
|
||||||
|
{ typeof(ulong), typeof(int) },
|
||||||
|
{ typeof(short), typeof(int) },
|
||||||
|
{ typeof(ushort), typeof(int) },
|
||||||
|
{ typeof(float), typeof(decimal) }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly Dictionary<Type, JToken> TypeValueMap = new()
|
||||||
|
{
|
||||||
|
{ typeof(int), 0 },
|
||||||
|
{ typeof(decimal), 0.0 },
|
||||||
|
{ typeof(bool), false }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private static JObject ClassToJToken(Type classType, IEnumerable<Type> typesEncountered)
|
||||||
|
{
|
||||||
|
var newTypesEncountered = typesEncountered.Append(classType).ToArray();
|
||||||
var result = new JObject();
|
var result = new JObject();
|
||||||
|
|
||||||
foreach (var propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
foreach (var propertyInfo in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||||
{
|
{
|
||||||
// Note: unfortunately we can not call GetCustomAttributes here, as that would
|
// Note: unfortunately we can not call GetCustomAttributes here for now, as that would
|
||||||
// trigger assemblies not included in the package to be loaded
|
// trigger assemblies not included in the package to be loaded, which may not exist
|
||||||
|
|
||||||
var value = PropertyToJToken(propertyInfo.PropertyType);
|
var value = TypeToJToken(propertyInfo.PropertyType, newTypesEncountered);
|
||||||
result.Add(propertyInfo.Name, value);
|
result.Add(propertyInfo.Name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,23 +54,12 @@ namespace PettingZoo.Tapeti
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static readonly Dictionary<Type, JToken> TypeMap = new()
|
private static JToken TypeToJToken(Type type, ICollection<Type> typesEncountered)
|
||||||
{
|
{
|
||||||
{ typeof(short), 0 },
|
var actualType = Nullable.GetUnderlyingType(type) ?? type;
|
||||||
{ typeof(ushort), 0 },
|
|
||||||
{ typeof(int), 0 },
|
|
||||||
{ typeof(uint), 0 },
|
|
||||||
{ typeof(long), 0 },
|
|
||||||
{ typeof(ulong), 0 },
|
|
||||||
{ typeof(decimal), 0.0 },
|
|
||||||
{ typeof(float), 0.0 },
|
|
||||||
{ typeof(bool), false }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
if (TypeEquivalenceMap.TryGetValue(actualType, out var equivalentType))
|
||||||
private static JToken PropertyToJToken(Type propertyType)
|
actualType = equivalentType;
|
||||||
{
|
|
||||||
var actualType = Nullable.GetUnderlyingType(propertyType) ?? propertyType;
|
|
||||||
|
|
||||||
|
|
||||||
// String is also a class
|
// String is also a class
|
||||||
@ -64,14 +74,13 @@ namespace PettingZoo.Tapeti
|
|||||||
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
|
||||||
|
|
||||||
if (enumerableInterface != null)
|
if (enumerableInterface != null)
|
||||||
return new JArray(Convert(enumerableInterface.GetGenericArguments()[0]));
|
return new JArray(TypeToJToken(enumerableInterface.GetGenericArguments()[0], typesEncountered));
|
||||||
|
|
||||||
|
return typesEncountered.Contains(actualType) ? new JValue((object?)null) : ClassToJToken(actualType, typesEncountered);
|
||||||
return Convert(actualType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualType.IsArray)
|
if (actualType.IsArray)
|
||||||
return new JArray(Convert(actualType.GetElementType()!));
|
return new JArray(TypeToJToken(actualType.GetElementType()!, typesEncountered));
|
||||||
|
|
||||||
if (actualType.IsEnum)
|
if (actualType.IsEnum)
|
||||||
return Enum.GetNames(actualType).FirstOrDefault();
|
return Enum.GetNames(actualType).FirstOrDefault();
|
||||||
@ -88,11 +97,9 @@ namespace PettingZoo.Tapeti
|
|||||||
if (actualType == typeof(Guid))
|
if (actualType == typeof(Guid))
|
||||||
return Guid.NewGuid().ToString();
|
return Guid.NewGuid().ToString();
|
||||||
|
|
||||||
return TypeMap.TryGetValue(actualType, out var mappedToken)
|
return TypeValueMap.TryGetValue(actualType, out var mappedToken)
|
||||||
? mappedToken
|
? mappedToken
|
||||||
: $"(unknown type: {actualType.Name})";
|
: $"(unknown type: {actualType.Name})";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,7 @@ namespace PettingZoo.Tapeti.UI.PackageSelection
|
|||||||
public ICommand AssemblyBrowse => assemblyBrowse;
|
public ICommand AssemblyBrowse => assemblyBrowse;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO hint for extra assemblies path
|
||||||
public static string HintNuGetSources => string.Format(PackageSelectionStrings.HintNuGetSources, PettingZooPaths.InstallationRoot, PettingZooPaths.AppDataRoot);
|
public static string HintNuGetSources => string.Format(PackageSelectionStrings.HintNuGetSources, PettingZooPaths.InstallationRoot, PettingZooPaths.AppDataRoot);
|
||||||
|
|
||||||
public string NuGetSearchTerm
|
public string NuGetSearchTerm
|
||||||
|
24
PettingZoo.Test/PettingZoo.Test.csproj
Normal file
24
PettingZoo.Test/PettingZoo.Test.csproj
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.2.0" />
|
||||||
|
<PackageReference Include="FluentAssertions.Json" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\PettingZoo.Tapeti\PettingZoo.Tapeti.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
65
PettingZoo.Test/Tapeti/TypeToJObjectTest.cs
Normal file
65
PettingZoo.Test/Tapeti/TypeToJObjectTest.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using FluentAssertions.Execution;
|
||||||
|
using FluentAssertions.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using PettingZoo.Tapeti;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace PettingZoo.Test.Tapeti
|
||||||
|
{
|
||||||
|
public class TypeToJObjectTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void TestAllSupportedTypes()
|
||||||
|
{
|
||||||
|
var converted = TypeToJObjectConverter.Convert(typeof(AllSupportedTypesTest));
|
||||||
|
|
||||||
|
using (new AssertionScope())
|
||||||
|
{
|
||||||
|
// Directly supported
|
||||||
|
converted.Should().HaveElement("StringValue").Which.Should().HaveValue("");
|
||||||
|
converted.Should().HaveElement("IntValue").Which.Should().Match(t => t.Type == JTokenType.Integer);
|
||||||
|
converted.Should().HaveElement("BoolValue").Which.Should().Match(t => t.Type == JTokenType.Boolean);
|
||||||
|
|
||||||
|
var guidValue = converted.Should().HaveElement("GuidValue").Which.Should().Match(t => t.Type == JTokenType.String)
|
||||||
|
.And.Subject.Value<string>();
|
||||||
|
Guid.TryParse(guidValue, out _).Should().BeTrue();
|
||||||
|
|
||||||
|
|
||||||
|
var objectValue = converted.Should().HaveElement("ObjectValue").Subject;
|
||||||
|
objectValue.Should().HaveElement("SubStringValue").Which.Should().HaveValue("");
|
||||||
|
objectValue.Should().HaveElement("SubIntValue").Which.Should().Match(t => t.Type == JTokenType.Integer);
|
||||||
|
objectValue.Should().HaveElement("RecursiveValue").Which.Type.Should().Be(JTokenType.Null);
|
||||||
|
|
||||||
|
// Via type mapping
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Local
|
||||||
|
private class AllSupportedTypesTest
|
||||||
|
{
|
||||||
|
public string StringValue { get; set; }
|
||||||
|
public int IntValue { get; set; }
|
||||||
|
public bool BoolValue { get; set; }
|
||||||
|
|
||||||
|
public Guid GuidValue { get; set; }
|
||||||
|
|
||||||
|
public ClassProperty ObjectValue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ReSharper disable once ClassNeverInstantiated.Local
|
||||||
|
private class ClassProperty
|
||||||
|
{
|
||||||
|
public string SubStringValue { get; set; }
|
||||||
|
public int SubIntValue { get; set; }
|
||||||
|
|
||||||
|
public AllSupportedTypesTest RecursiveValue { get; set; }
|
||||||
|
}
|
||||||
|
// ReSharper restore UnusedMember.Local
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo.Tapeti", "Pettin
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo.Settings.LiteDB", "PettingZoo.Settings.LiteDB\PettingZoo.Settings.LiteDB.csproj", "{7157B09C-FDD9-4928-B14D-C25B784CA865}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo.Settings.LiteDB", "PettingZoo.Settings.LiteDB\PettingZoo.Settings.LiteDB.csproj", "{7157B09C-FDD9-4928-B14D-C25B784CA865}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PettingZoo.WPF", "PettingZoo.WPF\PettingZoo.WPF.csproj", "{E6617B69-2AC4-4056-B801-DD32E2374B71}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PettingZoo.WPF", "PettingZoo.WPF\PettingZoo.WPF.csproj", "{E6617B69-2AC4-4056-B801-DD32E2374B71}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PettingZoo.Test", "PettingZoo.Test\PettingZoo.Test.csproj", "{3DD7F8D5-2CEE-414D-AC9C-9F395568B79F}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -50,6 +52,10 @@ Global
|
|||||||
{E6617B69-2AC4-4056-B801-DD32E2374B71}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{E6617B69-2AC4-4056-B801-DD32E2374B71}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E6617B69-2AC4-4056-B801-DD32E2374B71}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{E6617B69-2AC4-4056-B801-DD32E2374B71}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E6617B69-2AC4-4056-B801-DD32E2374B71}.Release|Any CPU.Build.0 = Release|Any CPU
|
{E6617B69-2AC4-4056-B801-DD32E2374B71}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3DD7F8D5-2CEE-414D-AC9C-9F395568B79F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3DD7F8D5-2CEE-414D-AC9C-9F395568B79F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3DD7F8D5-2CEE-414D-AC9C-9F395568B79F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3DD7F8D5-2CEE-414D-AC9C-9F395568B79F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -56,7 +56,7 @@ namespace PettingZoo
|
|||||||
|
|
||||||
private static ILogger CreateLogger()
|
private static ILogger CreateLogger()
|
||||||
{
|
{
|
||||||
var logPath = Path.Combine(PettingZooPaths.AppDataRoot, @"logs", "PettingZoo.log");
|
var logPath = Path.Combine(PettingZooPaths.LogPath, @"PettingZoo.log");
|
||||||
|
|
||||||
return new LoggerConfiguration()
|
return new LoggerConfiguration()
|
||||||
.MinimumLevel.Verbose()
|
.MinimumLevel.Verbose()
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
Must-have
|
Must-have
|
||||||
---------
|
---------
|
||||||
|
- Check required fields before enabling Publish button
|
||||||
|
|
||||||
|
|
||||||
Should-have
|
Should-have
|
||||||
-----------
|
-----------
|
||||||
- Save / load publisher messages (either as templates or to disk)
|
- Save / load publisher messages (either as templates or to disk)
|
||||||
- Export received messages to Tapeti JSON file / Tapeti.Cmd command-line
|
- Tapeti: export received messages to Tapeti.Cmd JSON file / Tapeti.Cmd command-line
|
||||||
|
- Tapeti: fetch NuGet dependencies to improve the chances of succesfully loading the assembly, instead of the current "extraAssembliesPaths" workaround
|
||||||
|
|
||||||
|
|
||||||
Nice-to-have
|
Nice-to-have
|
||||||
------------
|
------------
|
||||||
- JSON syntax highlighting
|
- Validation against message classes (for Tapeti messages)
|
@ -127,8 +127,6 @@ namespace PettingZoo.UI.Tab.Publisher
|
|||||||
}
|
}
|
||||||
|
|
||||||
Payload = example.Generate();
|
Payload = example.Generate();
|
||||||
|
|
||||||
// TODO if validating example, keep reference for validation... and implement validation of course
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user