diff options
-rw-r--r-- | src/SMAPI.Tests.ModApiConsumer/ApiConsumer.cs | 46 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiConsumer/Interfaces/ISimpleApi.cs | 79 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiConsumer/README.md | 3 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiConsumer/SMAPI.Tests.ModApiConsumer.csproj | 11 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiProvider/Framework/BaseApi.cs | 12 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiProvider/Framework/SimpleApi.cs | 108 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiProvider/ProviderMod.cs | 38 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiProvider/README.md | 3 | ||||
-rw-r--r-- | src/SMAPI.Tests.ModApiProvider/SMAPI.Tests.ModApiProvider.csproj | 7 | ||||
-rw-r--r-- | src/SMAPI.Tests/Core/InterfaceProxyTests.cs | 345 | ||||
-rw-r--r-- | src/SMAPI.Tests/SMAPI.Tests.csproj | 7 | ||||
-rw-r--r-- | src/SMAPI.sln | 14 |
12 files changed, 669 insertions, 4 deletions
diff --git a/src/SMAPI.Tests.ModApiConsumer/ApiConsumer.cs b/src/SMAPI.Tests.ModApiConsumer/ApiConsumer.cs new file mode 100644 index 00000000..2c7f9952 --- /dev/null +++ b/src/SMAPI.Tests.ModApiConsumer/ApiConsumer.cs @@ -0,0 +1,46 @@ +using System; +using SMAPI.Tests.ModApiConsumer.Interfaces; + +namespace SMAPI.Tests.ModApiConsumer +{ + /// <summary>A simulated API consumer.</summary> + public class ApiConsumer + { + /********* + ** Public methods + *********/ + /// <summary>Call the event field on the given API.</summary> + /// <param name="api">The API to call.</param> + /// <param name="getValues">Get the number of times the event was called and the last value received.</param> + public void UseEventField(ISimpleApi api, out Func<(int timesCalled, int actualValue)> getValues) + { + // act + int calls = 0; + int lastValue = -1; + api.OnEventRaised += (sender, value) => + { + calls++; + lastValue = value; + }; + + getValues = () => (timesCalled: calls, actualValue: lastValue); + } + + /// <summary>Call the event property on the given API.</summary> + /// <param name="api">The API to call.</param> + /// <param name="getValues">Get the number of times the event was called and the last value received.</param> + public void UseEventProperty(ISimpleApi api, out Func<(int timesCalled, int actualValue)> getValues) + { + // act + int calls = 0; + int lastValue = -1; + api.OnEventRaisedProperty += (sender, value) => + { + calls++; + lastValue = value; + }; + + getValues = () => (timesCalled: calls, actualValue: lastValue); + } + } +} diff --git a/src/SMAPI.Tests.ModApiConsumer/Interfaces/ISimpleApi.cs b/src/SMAPI.Tests.ModApiConsumer/Interfaces/ISimpleApi.cs new file mode 100644 index 00000000..7f94e137 --- /dev/null +++ b/src/SMAPI.Tests.ModApiConsumer/Interfaces/ISimpleApi.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace SMAPI.Tests.ModApiConsumer.Interfaces +{ + /// <summary>A mod-provided API which provides basic events, properties, and methods.</summary> + public interface ISimpleApi + { + /********* + ** Test interface + *********/ + /**** + ** Events + ****/ + /// <summary>A simple event field.</summary> + event EventHandler<int> OnEventRaised; + + /// <summary>A simple event property with custom add/remove logic.</summary> + event EventHandler<int> OnEventRaisedProperty; + + + /**** + ** Properties + ****/ + /// <summary>A simple numeric property.</summary> + int NumberProperty { get; set; } + + /// <summary>A simple object property.</summary> + object ObjectProperty { get; set; } + + /// <summary>A simple list property.</summary> + List<string> ListProperty { get; set; } + + /// <summary>A simple list property with an interface.</summary> + IList<string> ListPropertyWithInterface { get; set; } + + /// <summary>A property with nested generics.</summary> + IDictionary<string, IList<string>> GenericsProperty { get; set; } + + /// <summary>A property using an enum available to both mods.</summary> + BindingFlags EnumProperty { get; set; } + + /// <summary>A read-only property.</summary> + int GetterProperty { get; } + + + /**** + ** Methods + ****/ + /// <summary>A simple method with no return value.</summary> + void GetNothing(); + + /// <summary>A simple method which returns a number.</summary> + int GetInt(int value); + + /// <summary>A simple method which returns an object.</summary> + object GetObject(object value); + + /// <summary>A simple method which returns a list.</summary> + List<string> GetList(string value); + + /// <summary>A simple method which returns a list with an interface.</summary> + IList<string> GetListWithInterface(string value); + + /// <summary>A simple method which returns nested generics.</summary> + IDictionary<string, IList<string>> GetGenerics(string key, string value); + + /// <summary>A simple method which returns a lambda.</summary> + Func<string, string> GetLambda(Func<string, string> value); + + + /**** + ** Inherited members + ****/ + /// <summary>A property inherited from a base class.</summary> + public string InheritedProperty { get; set; } + } +} diff --git a/src/SMAPI.Tests.ModApiConsumer/README.md b/src/SMAPI.Tests.ModApiConsumer/README.md new file mode 100644 index 00000000..ed0c6e3f --- /dev/null +++ b/src/SMAPI.Tests.ModApiConsumer/README.md @@ -0,0 +1,3 @@ +This project contains a simulated [mod-provided API] consumer used in the API proxying unit tests. + +[mod-provided API]: https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Integrations diff --git a/src/SMAPI.Tests.ModApiConsumer/SMAPI.Tests.ModApiConsumer.csproj b/src/SMAPI.Tests.ModApiConsumer/SMAPI.Tests.ModApiConsumer.csproj new file mode 100644 index 00000000..7fef4ebd --- /dev/null +++ b/src/SMAPI.Tests.ModApiConsumer/SMAPI.Tests.ModApiConsumer.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <TargetFramework>net5.0</TargetFramework> + </PropertyGroup> + + <Import Project="..\..\build\common.targets" /> + + <ItemGroup> + <ProjectReference Include="..\SMAPI\SMAPI.csproj" /> + </ItemGroup> +</Project> diff --git a/src/SMAPI.Tests.ModApiProvider/Framework/BaseApi.cs b/src/SMAPI.Tests.ModApiProvider/Framework/BaseApi.cs new file mode 100644 index 00000000..8092e3e7 --- /dev/null +++ b/src/SMAPI.Tests.ModApiProvider/Framework/BaseApi.cs @@ -0,0 +1,12 @@ +namespace SMAPI.Tests.ModApiProvider.Framework +{ + /// <summary>The base class for <see cref="SimpleApi"/>.</summary> + public class BaseApi + { + /********* + ** Test interface + *********/ + /// <summary>A property inherited from a base class.</summary> + public string InheritedProperty { get; set; } + } +} diff --git a/src/SMAPI.Tests.ModApiProvider/Framework/SimpleApi.cs b/src/SMAPI.Tests.ModApiProvider/Framework/SimpleApi.cs new file mode 100644 index 00000000..1100af36 --- /dev/null +++ b/src/SMAPI.Tests.ModApiProvider/Framework/SimpleApi.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace SMAPI.Tests.ModApiProvider.Framework +{ + /// <summary>A mod-provided API which provides basic events, properties, and methods.</summary> + public class SimpleApi : BaseApi + { + /********* + ** Test interface + *********/ + /**** + ** Events + ****/ + /// <summary>A simple event field.</summary> + public event EventHandler<int> OnEventRaised; + + /// <summary>A simple event property with custom add/remove logic.</summary> + public event EventHandler<int> OnEventRaisedProperty + { + add => this.OnEventRaised += value; + remove => this.OnEventRaised -= value; + } + + + /**** + ** Properties + ****/ + /// <summary>A simple numeric property.</summary> + public int NumberProperty { get; set; } + + /// <summary>A simple object property.</summary> + public object ObjectProperty { get; set; } + + /// <summary>A simple list property.</summary> + public List<string> ListProperty { get; set; } + + /// <summary>A simple list property with an interface.</summary> + public IList<string> ListPropertyWithInterface { get; set; } + + /// <summary>A property with nested generics.</summary> + public IDictionary<string, IList<string>> GenericsProperty { get; set; } + + /// <summary>A property using an enum available to both mods.</summary> + public BindingFlags EnumProperty { get; set; } + + /// <summary>A read-only property.</summary> + public int GetterProperty => 42; + + + /**** + ** Methods + ****/ + /// <summary>A simple method with no return value.</summary> + public void GetNothing() { } + + /// <summary>A simple method which returns a number.</summary> + public int GetInt(int value) + { + return value; + } + + /// <summary>A simple method which returns an object.</summary> + public object GetObject(object value) + { + return value; + } + + /// <summary>A simple method which returns a list.</summary> + public List<string> GetList(string value) + { + return new() { value }; + } + + /// <summary>A simple method which returns a list with an interface.</summary> + public IList<string> GetListWithInterface(string value) + { + return new List<string> { value }; + } + + /// <summary>A simple method which returns nested generics.</summary> + public IDictionary<string, IList<string>> GetGenerics(string key, string value) + { + return new Dictionary<string, IList<string>> + { + [key] = new List<string> { value } + }; + } + + /// <summary>A simple method which returns a lambda.</summary> + public Func<string, string> GetLambda(Func<string, string> value) + { + return value; + } + + + /********* + ** Helper methods + *********/ + /// <summary>Raise the <see cref="OnEventRaised"/> event.</summary> + /// <param name="value">The value to pass to the event.</param> + public void RaiseEventField(int value) + { + this.OnEventRaised?.Invoke(null, value); + } + } +} diff --git a/src/SMAPI.Tests.ModApiProvider/ProviderMod.cs b/src/SMAPI.Tests.ModApiProvider/ProviderMod.cs new file mode 100644 index 00000000..c36e1c6d --- /dev/null +++ b/src/SMAPI.Tests.ModApiProvider/ProviderMod.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Reflection; +using SMAPI.Tests.ModApiProvider.Framework; + +namespace SMAPI.Tests.ModApiProvider +{ + /// <summary>A simulated mod instance.</summary> + public class ProviderMod + { + /// <summary>The underlying API instance.</summary> + private readonly SimpleApi Api = new(); + + /// <summary>Get the mod API instance.</summary> + public object GetModApi() + { + return this.Api; + } + + /// <summary>Raise the <see cref="SimpleApi.OnEventRaised"/> event.</summary> + /// <param name="value">The value to send as an event argument.</param> + public void RaiseEvent(int value) + { + this.Api.RaiseEventField(value); + } + + /// <summary>Set the values for the API property.</summary> + public void SetPropertyValues(int number, object obj, string listValue, string listWithInterfaceValue, string dictionaryKey, string dictionaryListValue, BindingFlags enumValue, string inheritedValue) + { + this.Api.NumberProperty = number; + this.Api.ObjectProperty = obj; + this.Api.ListProperty = new List<string> { listValue }; + this.Api.ListPropertyWithInterface = new List<string> { listWithInterfaceValue }; + this.Api.GenericsProperty = new Dictionary<string, IList<string>> { [dictionaryKey] = new List<string> { dictionaryListValue } }; + this.Api.EnumProperty = enumValue; + this.Api.InheritedProperty = inheritedValue; + } + } +} diff --git a/src/SMAPI.Tests.ModApiProvider/README.md b/src/SMAPI.Tests.ModApiProvider/README.md new file mode 100644 index 00000000..c79838e0 --- /dev/null +++ b/src/SMAPI.Tests.ModApiProvider/README.md @@ -0,0 +1,3 @@ +This project contains simulated [mod-provided APIs] used in the API proxying unit tests. + +[mod-provided APIs]: https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Integrations diff --git a/src/SMAPI.Tests.ModApiProvider/SMAPI.Tests.ModApiProvider.csproj b/src/SMAPI.Tests.ModApiProvider/SMAPI.Tests.ModApiProvider.csproj new file mode 100644 index 00000000..70d5a0ce --- /dev/null +++ b/src/SMAPI.Tests.ModApiProvider/SMAPI.Tests.ModApiProvider.csproj @@ -0,0 +1,7 @@ +<Project Sdk="Microsoft.NET.Sdk"> + <PropertyGroup> + <TargetFramework>net5.0</TargetFramework> + </PropertyGroup> + + <Import Project="..\..\build\common.targets" /> +</Project> diff --git a/src/SMAPI.Tests/Core/InterfaceProxyTests.cs b/src/SMAPI.Tests/Core/InterfaceProxyTests.cs new file mode 100644 index 00000000..99c1298f --- /dev/null +++ b/src/SMAPI.Tests/Core/InterfaceProxyTests.cs @@ -0,0 +1,345 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using FluentAssertions; +using NUnit.Framework; +using SMAPI.Tests.ModApiConsumer; +using SMAPI.Tests.ModApiConsumer.Interfaces; +using SMAPI.Tests.ModApiProvider; +using StardewModdingAPI.Framework.Reflection; + +namespace SMAPI.Tests.Core +{ + /// <summary>Unit tests for <see cref="InterfaceProxyFactory"/>.</summary> + [TestFixture] + internal class InterfaceProxyTests + { + /********* + ** Fields + *********/ + /// <summary>The mod ID providing an API.</summary> + private readonly string FromModId = "From.ModId"; + + /// <summary>The mod ID consuming an API.</summary> + private readonly string ToModId = "From.ModId"; + + /// <summary>The random number generator with which to create sample values.</summary> + private readonly Random Random = new(); + + + /********* + ** Unit tests + *********/ + /**** + ** Events + ****/ + /// <summary>Assert that an event field can be proxied correctly.</summary> + [Test] + public void CanProxy_EventField() + { + // arrange + var providerMod = new ProviderMod(); + object implementation = providerMod.GetModApi(); + int expectedValue = this.Random.Next(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + new ApiConsumer().UseEventField(proxy, out Func<(int timesCalled, int lastValue)> getValues); + providerMod.RaiseEvent(expectedValue); + (int timesCalled, int lastValue) = getValues(); + + // assert + timesCalled.Should().Be(1, "Expected the proxied event to be raised once."); + lastValue.Should().Be(expectedValue, "The proxy received a different event argument than the implementation raised."); + } + + /// <summary>Assert that an event property can be proxied correctly.</summary> + [Test] + public void CanProxy_EventProperty() + { + // arrange + var providerMod = new ProviderMod(); + object implementation = providerMod.GetModApi(); + int expectedValue = this.Random.Next(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + new ApiConsumer().UseEventProperty(proxy, out Func<(int timesCalled, int lastValue)> getValues); + providerMod.RaiseEvent(expectedValue); + (int timesCalled, int lastValue) = getValues(); + + // assert + timesCalled.Should().Be(1, "Expected the proxied event to be raised once."); + lastValue.Should().Be(expectedValue, "The proxy received a different event argument than the implementation raised."); + } + + /**** + ** Properties + ****/ + /// <summary>Assert that properties can be proxied correctly.</summary> + /// <param name="setVia">Whether to set the properties through the <c>provider mod</c> or <c>proxy interface</c>.</param> + [TestCase("set via provider mod")] + [TestCase("set via proxy interface")] + public void CanProxy_Properties(string setVia) + { + // arrange + var providerMod = new ProviderMod(); + object implementation = providerMod.GetModApi(); + int expectedNumber = this.Random.Next(); + int expectedObject = this.Random.Next(); + string expectedListValue = this.GetRandomString(); + string expectedListWithInterfaceValue = this.GetRandomString(); + string expectedDictionaryKey = this.GetRandomString(); + string expectedDictionaryListValue = this.GetRandomString(); + string expectedInheritedString = this.GetRandomString(); + BindingFlags expectedEnum = BindingFlags.Instance | BindingFlags.Public; + + // act + ISimpleApi proxy = this.GetProxy(implementation); + switch (setVia) + { + case "set via provider mod": + providerMod.SetPropertyValues( + number: expectedNumber, + obj: expectedObject, + listValue: expectedListValue, + listWithInterfaceValue: expectedListWithInterfaceValue, + dictionaryKey: expectedDictionaryKey, + dictionaryListValue: expectedDictionaryListValue, + enumValue: expectedEnum, + inheritedValue: expectedInheritedString + ); + break; + + case "set via proxy interface": + proxy.NumberProperty = expectedNumber; + proxy.ObjectProperty = expectedObject; + proxy.ListProperty = new() { expectedListValue }; + proxy.ListPropertyWithInterface = new List<string> { expectedListWithInterfaceValue }; + proxy.GenericsProperty = new Dictionary<string, IList<string>> + { + [expectedDictionaryKey] = new List<string> { expectedDictionaryListValue } + }; + proxy.EnumProperty = expectedEnum; + proxy.InheritedProperty = expectedInheritedString; + break; + + default: + throw new InvalidOperationException($"Invalid 'set via' option '{setVia}."); + } + + // assert number + this + .GetPropertyValue(implementation, nameof(proxy.NumberProperty)) + .Should().Be(expectedNumber); + proxy.NumberProperty + .Should().Be(expectedNumber); + + // assert object + this + .GetPropertyValue(implementation, nameof(proxy.ObjectProperty)) + .Should().Be(expectedObject); + proxy.ObjectProperty + .Should().Be(expectedObject); + + // assert list + (this.GetPropertyValue(implementation, nameof(proxy.ListProperty)) as IList<string>) + .Should().NotBeNull() + .And.HaveCount(1) + .And.BeEquivalentTo(expectedListValue); + proxy.ListProperty + .Should().NotBeNull() + .And.HaveCount(1) + .And.BeEquivalentTo(expectedListValue); + + // assert list with interface + (this.GetPropertyValue(implementation, nameof(proxy.ListPropertyWithInterface)) as IList<string>) + .Should().NotBeNull() + .And.HaveCount(1) + .And.BeEquivalentTo(expectedListWithInterfaceValue); + proxy.ListPropertyWithInterface + .Should().NotBeNull() + .And.HaveCount(1) + .And.BeEquivalentTo(expectedListWithInterfaceValue); + + // assert generics + (this.GetPropertyValue(implementation, nameof(proxy.GenericsProperty)) as IDictionary<string, IList<string>>) + .Should().NotBeNull() + .And.HaveCount(1) + .And.ContainKey(expectedDictionaryKey).WhoseValue.Should().BeEquivalentTo(expectedDictionaryListValue); + proxy.GenericsProperty + .Should().NotBeNull() + .And.HaveCount(1) + .And.ContainKey(expectedDictionaryKey).WhoseValue.Should().BeEquivalentTo(expectedDictionaryListValue); + + // assert enum + this + .GetPropertyValue(implementation, nameof(proxy.EnumProperty)) + .Should().Be(expectedEnum); + proxy.EnumProperty + .Should().Be(expectedEnum); + + // assert getter + this + .GetPropertyValue(implementation, nameof(proxy.GetterProperty)) + .Should().Be(42); + proxy.GetterProperty + .Should().Be(42); + + // assert inherited methods + this + .GetPropertyValue(implementation, nameof(proxy.InheritedProperty)) + .Should().Be(expectedInheritedString); + proxy.InheritedProperty + .Should().Be(expectedInheritedString); + } + + /// <summary>Assert that a simple method with no return value can be proxied correctly.</summary> + [Test] + public void CanProxy_SimpleMethod_Void() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + proxy.GetNothing(); + } + + /// <summary>Assert that a simple int method can be proxied correctly.</summary> + [Test] + public void CanProxy_SimpleMethod_Int() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + int expectedValue = this.Random.Next(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + int actualValue = proxy.GetInt(expectedValue); + + // assert + actualValue.Should().Be(expectedValue); + } + + /// <summary>Assert that a simple object method can be proxied correctly.</summary> + [Test] + public void CanProxy_SimpleMethod_Object() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + object expectedValue = new(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + object actualValue = proxy.GetObject(expectedValue); + + // assert + actualValue.Should().BeSameAs(expectedValue); + } + + /// <summary>Assert that a simple list method can be proxied correctly.</summary> + [Test] + public void CanProxy_SimpleMethod_List() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + string expectedValue = this.GetRandomString(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + IList<string> actualValue = proxy.GetList(expectedValue); + + // assert + actualValue.Should().BeEquivalentTo(expectedValue); + } + + /// <summary>Assert that a simple list with interface method can be proxied correctly.</summary> + [Test] + public void CanProxy_SimpleMethod_ListWithInterface() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + string expectedValue = this.GetRandomString(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + IList<string> actualValue = proxy.GetListWithInterface(expectedValue); + + // assert + actualValue.Should().BeEquivalentTo(expectedValue); + } + + /// <summary>Assert that a simple method which returns generic types can be proxied correctly.</summary> + [Test] + public void CanProxy_SimpleMethod_GenericTypes() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + string expectedKey = this.GetRandomString(); + string expectedValue = this.GetRandomString(); + + // act + ISimpleApi proxy = this.GetProxy(implementation); + IDictionary<string, IList<string>> actualValue = proxy.GetGenerics(expectedKey, expectedValue); + + // assert + actualValue + .Should().NotBeNull() + .And.HaveCount(1) + .And.ContainKey(expectedKey).WhoseValue.Should().BeEquivalentTo(expectedValue); + } + + /// <summary>Assert that a simple lambda method can be proxied correctly.</summary> + [Test] + [SuppressMessage("ReSharper", "ConvertToLocalFunction")] + public void CanProxy_SimpleMethod_Lambda() + { + // arrange + object implementation = new ProviderMod().GetModApi(); + Func<string, string> expectedValue = _ => "test"; + + // act + ISimpleApi proxy = this.GetProxy(implementation); + object actualValue = proxy.GetObject(expectedValue); + + // assert + actualValue.Should().BeSameAs(expectedValue); + } + + + /********* + ** Private methods + *********/ + /// <summary>Get a property value from an instance.</summary> + /// <param name="parent">The instance whose property to read.</param> + /// <param name="name">The property name.</param> + private object GetPropertyValue(object parent, string name) + { + if (parent is null) + throw new ArgumentNullException(nameof(parent)); + + Type type = parent.GetType(); + PropertyInfo property = type.GetProperty(name); + if (property is null) + throw new InvalidOperationException($"The '{type.FullName}' type has no public property named '{name}'."); + + return property.GetValue(parent); + } + + /// <summary>Get a random test string.</summary> + private string GetRandomString() + { + return this.Random.Next().ToString(); + } + + /// <summary>Get a proxy API instance.</summary> + /// <param name="implementation">The underlying API instance.</param> + private ISimpleApi GetProxy(object implementation) + { + var proxyFactory = new InterfaceProxyFactory(); + return proxyFactory.CreateProxy<ISimpleApi>(implementation, this.FromModId, this.ToModId); + } + } +} diff --git a/src/SMAPI.Tests/SMAPI.Tests.csproj b/src/SMAPI.Tests/SMAPI.Tests.csproj index 8329b2e1..67997b30 100644 --- a/src/SMAPI.Tests/SMAPI.Tests.csproj +++ b/src/SMAPI.Tests/SMAPI.Tests.csproj @@ -1,21 +1,20 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <AssemblyName>SMAPI.Tests</AssemblyName> - <RootNamespace>SMAPI.Tests</RootNamespace> <TargetFramework>net5.0</TargetFramework> - <GenerateAssemblyInfo>false</GenerateAssemblyInfo> - <LangVersion>latest</LangVersion> </PropertyGroup> <Import Project="..\..\build\common.targets" /> <ItemGroup> + <ProjectReference Include="..\SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj" /> + <ProjectReference Include="..\SMAPI.Tests.ModApiProvider\SMAPI.Tests.ModApiProvider.csproj" /> <ProjectReference Include="..\SMAPI.Toolkit.CoreInterfaces\SMAPI.Toolkit.CoreInterfaces.csproj" /> <ProjectReference Include="..\SMAPI.Toolkit\SMAPI.Toolkit.csproj" /> <ProjectReference Include="..\SMAPI\SMAPI.csproj" /> </ItemGroup> <ItemGroup> + <PackageReference Include="FluentAssertions" Version="6.5.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" /> <PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> diff --git a/src/SMAPI.sln b/src/SMAPI.sln index be5326f7..d9f60a5c 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -101,6 +101,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{3B5BF14D-F61 ..\build\windows\lib\in-place-regex.ps1 = ..\build\windows\lib\in-place-regex.ps1 EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests.ModApiProvider", "SMAPI.Tests.ModApiProvider\SMAPI.Tests.ModApiProvider.csproj", "{239AEEAC-07D1-4A3F-AA99-8C74F5038F50}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI.Tests.ModApiConsumer", "SMAPI.Tests.ModApiConsumer\SMAPI.Tests.ModApiConsumer.csproj", "{2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 @@ -167,6 +171,14 @@ Global {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU + {239AEEAC-07D1-4A3F-AA99-8C74F5038F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {239AEEAC-07D1-4A3F-AA99-8C74F5038F50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {239AEEAC-07D1-4A3F-AA99-8C74F5038F50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {239AEEAC-07D1-4A3F-AA99-8C74F5038F50}.Release|Any CPU.Build.0 = Release|Any CPU + {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -187,6 +199,8 @@ Global {4D661178-38FB-43E4-AA5F-9B0406919344} = {09CF91E5-5BAB-4650-A200-E5EA9A633046} {CAA1488E-842B-433D-994D-1D3D0B5DD125} = {09CF91E5-5BAB-4650-A200-E5EA9A633046} {3B5BF14D-F612-4C83-9EF6-E3EBFCD08766} = {4D661178-38FB-43E4-AA5F-9B0406919344} + {239AEEAC-07D1-4A3F-AA99-8C74F5038F50} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + {2A4DF030-E8B1-4BBD-AA93-D4DE68CB9D85} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} |