diff options
Diffstat (limited to 'src/SMAPI.Tests/Core')
-rw-r--r-- | src/SMAPI.Tests/Core/AssetNameTests.cs | 10 | ||||
-rw-r--r-- | src/SMAPI.Tests/Core/InterfaceProxyTests.cs | 12 | ||||
-rw-r--r-- | src/SMAPI.Tests/Core/ModResolverTests.cs | 31 | ||||
-rw-r--r-- | src/SMAPI.Tests/Core/TranslationTests.cs | 83 |
4 files changed, 94 insertions, 42 deletions
diff --git a/src/SMAPI.Tests/Core/AssetNameTests.cs b/src/SMAPI.Tests/Core/AssetNameTests.cs index ef8a08ef..a1712726 100644 --- a/src/SMAPI.Tests/Core/AssetNameTests.cs +++ b/src/SMAPI.Tests/Core/AssetNameTests.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using FluentAssertions; @@ -28,7 +26,7 @@ namespace SMAPI.Tests.Core [TestCase("Characters/Dialogue/Abigail.fr-FR", "Characters/Dialogue/Abigail", "fr-FR", LocalizedContentManager.LanguageCode.fr)] [TestCase("Characters/Dialogue\\Abigail.fr-FR", "Characters/Dialogue/Abigail.fr-FR", null, null)] [TestCase("Characters/Dialogue/Abigail.fr-FR", "Characters/Dialogue/Abigail", "fr-FR", LocalizedContentManager.LanguageCode.fr)] - public void Constructor_Valid(string name, string expectedBaseName, string expectedLocale, LocalizedContentManager.LanguageCode? expectedLanguageCode) + public void Constructor_Valid(string name, string expectedBaseName, string? expectedLocale, LocalizedContentManager.LanguageCode? expectedLanguageCode) { // arrange name = PathUtilities.NormalizeAssetName(name); @@ -55,13 +53,13 @@ namespace SMAPI.Tests.Core [TestCase(" ")] [TestCase("\t")] [TestCase(" \t ")] - public void Constructor_NullOrWhitespace(string name) + public void Constructor_NullOrWhitespace(string? name) { // act - ArgumentException exception = Assert.Throws<ArgumentException>(() => _ = AssetName.Parse(name, null)); + ArgumentException exception = Assert.Throws<ArgumentException>(() => _ = AssetName.Parse(name!, _ => null))!; // assert - exception!.ParamName.Should().Be("rawName"); + exception.ParamName.Should().Be("rawName"); exception.Message.Should().Be("The asset name can't be null or empty. (Parameter 'rawName')"); } diff --git a/src/SMAPI.Tests/Core/InterfaceProxyTests.cs b/src/SMAPI.Tests/Core/InterfaceProxyTests.cs index 1bf2ed68..0b4919ed 100644 --- a/src/SMAPI.Tests/Core/InterfaceProxyTests.cs +++ b/src/SMAPI.Tests/Core/InterfaceProxyTests.cs @@ -1,5 +1,3 @@ -#nullable disable - using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -41,7 +39,7 @@ namespace SMAPI.Tests.Core public void CanProxy_EventField() { // arrange - var providerMod = new ProviderMod(); + ProviderMod providerMod = new(); object implementation = providerMod.GetModApi(); int expectedValue = this.Random.Next(); @@ -61,7 +59,7 @@ namespace SMAPI.Tests.Core public void CanProxy_EventProperty() { // arrange - var providerMod = new ProviderMod(); + ProviderMod providerMod = new(); object implementation = providerMod.GetModApi(); int expectedValue = this.Random.Next(); @@ -86,7 +84,7 @@ namespace SMAPI.Tests.Core public void CanProxy_Properties(string setVia) { // arrange - var providerMod = new ProviderMod(); + ProviderMod providerMod = new(); object implementation = providerMod.GetModApi(); int expectedNumber = this.Random.Next(); int expectedObject = this.Random.Next(); @@ -317,13 +315,13 @@ namespace SMAPI.Tests.Core /// <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) + 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); + PropertyInfo? property = type.GetProperty(name); if (property is null) throw new InvalidOperationException($"The '{type.FullName}' type has no public property named '{name}'."); diff --git a/src/SMAPI.Tests/Core/ModResolverTests.cs b/src/SMAPI.Tests/Core/ModResolverTests.cs index e1b56559..bd621bbf 100644 --- a/src/SMAPI.Tests/Core/ModResolverTests.cs +++ b/src/SMAPI.Tests/Core/ModResolverTests.cs @@ -145,7 +145,7 @@ namespace SMAPI.Tests.Core { // arrange Mock<IModMetadata> mock = this.GetMetadata("Mod A", Array.Empty<string>(), allowStatusChange: true); - this.SetupMetadataForValidation(mock, new ModDataRecordVersionedFields + this.SetupMetadataForValidation(mock, new ModDataRecordVersionedFields(this.GetModDataRecord()) { Status = ModStatus.AssumeBroken }); @@ -216,9 +216,9 @@ namespace SMAPI.Tests.Core File.WriteAllText(Path.Combine(modFolder, manifest.EntryDll!), ""); // arrange - Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict); + Mock<IModMetadata> mock = new(MockBehavior.Strict); mock.Setup(p => p.Status).Returns(ModMetadataStatus.Found); - mock.Setup(p => p.DataRecord).Returns(() => null); + mock.Setup(p => p.DataRecord).Returns(this.GetModDataRecordVersionedFields()); mock.Setup(p => p.Manifest).Returns(manifest); mock.Setup(p => p.DirectoryPath).Returns(modFolder); @@ -265,7 +265,7 @@ namespace SMAPI.Tests.Core public void ProcessDependencies_Skips_Failed() { // arrange - Mock<IModMetadata> mock = new Mock<IModMetadata>(MockBehavior.Strict); + Mock<IModMetadata> mock = new(MockBehavior.Strict); mock.Setup(p => p.Status).Returns(ModMetadataStatus.Failed); // act @@ -380,7 +380,7 @@ namespace SMAPI.Tests.Core Mock<IModMetadata> modA = this.GetMetadata("Mod A"); Mock<IModMetadata> modB = this.GetMetadata("Mod B", dependencies: new[] { "Mod A" }); Mock<IModMetadata> modC = this.GetMetadata("Mod C", dependencies: new[] { "Mod B" }, allowStatusChange: true); - Mock<IModMetadata> modD = new Mock<IModMetadata>(MockBehavior.Strict); + Mock<IModMetadata> modD = new(MockBehavior.Strict); modD.Setup(p => p.Manifest).Returns<IManifest>(null); modD.Setup(p => p.Status).Returns(ModMetadataStatus.Failed); @@ -507,7 +507,7 @@ namespace SMAPI.Tests.Core /// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param> private Mock<IModMetadata> GetMetadata(string uniqueID, string[] dependencies, bool allowStatusChange = false) { - IManifest manifest = this.GetManifest(id: uniqueID, version: "1.0", dependencies: dependencies?.Select(dependencyID => (IManifestDependency)new ManifestDependency(dependencyID, null as ISemanticVersion)).ToArray()); + IManifest manifest = this.GetManifest(id: uniqueID, version: "1.0", dependencies: dependencies.Select(dependencyID => (IManifestDependency)new ManifestDependency(dependencyID, null as ISemanticVersion)).ToArray()); return this.GetMetadata(manifest, allowStatusChange); } @@ -516,8 +516,8 @@ namespace SMAPI.Tests.Core /// <param name="allowStatusChange">Whether the code being tested is allowed to change the mod status.</param> private Mock<IModMetadata> GetMetadata(IManifest manifest, bool allowStatusChange = false) { - Mock<IModMetadata> mod = new Mock<IModMetadata>(MockBehavior.Strict); - mod.Setup(p => p.DataRecord).Returns(() => null); + Mock<IModMetadata> mod = new(MockBehavior.Strict); + mod.Setup(p => p.DataRecord).Returns(this.GetModDataRecordVersionedFields()); mod.Setup(p => p.Status).Returns(ModMetadataStatus.Found); mod.Setup(p => p.DisplayName).Returns(manifest.UniqueID); mod.Setup(p => p.Manifest).Returns(manifest); @@ -538,11 +538,22 @@ namespace SMAPI.Tests.Core private void SetupMetadataForValidation(Mock<IModMetadata> mod, ModDataRecordVersionedFields? modRecord = null) { mod.Setup(p => p.Status).Returns(ModMetadataStatus.Found); - mod.Setup(p => p.DataRecord).Returns(() => null); mod.Setup(p => p.Manifest).Returns(this.GetManifest()); mod.Setup(p => p.DirectoryPath).Returns(Path.GetTempPath()); - mod.Setup(p => p.DataRecord).Returns(modRecord); + mod.Setup(p => p.DataRecord).Returns(modRecord ?? this.GetModDataRecordVersionedFields()); mod.Setup(p => p.GetUpdateKeys(It.IsAny<bool>())).Returns(Enumerable.Empty<UpdateKey>()); } + + /// <summary>Generate a default mod data record.</summary> + private ModDataRecord GetModDataRecord() + { + return new("Default Display Name", new ModDataModel("Sample ID", null, ModWarning.None)); + } + + /// <summary>Generate a default mod data versioned fields instance.</summary> + private ModDataRecordVersionedFields GetModDataRecordVersionedFields() + { + return new ModDataRecordVersionedFields(this.GetModDataRecord()); + } } } diff --git a/src/SMAPI.Tests/Core/TranslationTests.cs b/src/SMAPI.Tests/Core/TranslationTests.cs index f8f0e315..a52df607 100644 --- a/src/SMAPI.Tests/Core/TranslationTests.cs +++ b/src/SMAPI.Tests/Core/TranslationTests.cs @@ -1,11 +1,14 @@ -#nullable disable - using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Linq; using NUnit.Framework; using StardewModdingAPI; +using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ModHelpers; +using StardewModdingAPI.Framework.ModLoading; +using StardewModdingAPI.Toolkit.Serialization.Models; using StardewValley; namespace SMAPI.Tests.Core @@ -18,7 +21,7 @@ namespace SMAPI.Tests.Core ** Data *********/ /// <summary>Sample translation text for unit tests.</summary> - public static string[] Samples = { null, "", " ", "boop", " boop " }; + public static string?[] Samples = { null, "", " ", "boop", " boop " }; /********* @@ -34,15 +37,15 @@ namespace SMAPI.Tests.Core var data = new Dictionary<string, IDictionary<string, string>>(); // act - ITranslationHelper helper = new TranslationHelper("ModID", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); + ITranslationHelper helper = new TranslationHelper(this.CreateModMetadata(), "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); Translation translation = helper.Get("key"); - Translation[] translationList = helper.GetTranslations()?.ToArray(); + Translation[]? translationList = helper.GetTranslations()?.ToArray(); // assert Assert.AreEqual("en", helper.Locale, "The locale doesn't match the input value."); Assert.AreEqual(LocalizedContentManager.LanguageCode.en, helper.LocaleEnum, "The locale enum doesn't match the input value."); Assert.IsNotNull(translationList, "The full list of translations is unexpectedly null."); - Assert.AreEqual(0, translationList.Length, "The full list of translations is unexpectedly not empty."); + Assert.AreEqual(0, translationList!.Length, "The full list of translations is unexpectedly not empty."); Assert.IsNotNull(translation, "The translation helper unexpectedly returned a null translation."); Assert.AreEqual(this.GetPlaceholderText("key"), translation.ToString(), "The translation returned an unexpected value."); @@ -56,8 +59,8 @@ namespace SMAPI.Tests.Core var expected = this.GetExpectedTranslations(); // act - var actual = new Dictionary<string, Translation[]>(); - TranslationHelper helper = new TranslationHelper("ModID", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); + var actual = new Dictionary<string, Translation[]?>(); + TranslationHelper helper = new TranslationHelper(this.CreateModMetadata(), "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); foreach (string locale in expected.Keys) { this.AssertSetLocale(helper, locale, LocalizedContentManager.LanguageCode.en); @@ -81,7 +84,7 @@ namespace SMAPI.Tests.Core // act var actual = new Dictionary<string, Translation[]>(); - TranslationHelper helper = new TranslationHelper("ModID", "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); + TranslationHelper helper = new TranslationHelper(this.CreateModMetadata(), "en", LocalizedContentManager.LanguageCode.en).SetTranslations(data); foreach (string locale in expected.Keys) { this.AssertSetLocale(helper, locale, LocalizedContentManager.LanguageCode.en); @@ -109,13 +112,13 @@ namespace SMAPI.Tests.Core [TestCase(" ", ExpectedResult = true)] [TestCase("boop", ExpectedResult = true)] [TestCase(" boop ", ExpectedResult = true)] - public bool Translation_HasValue(string text) + public bool Translation_HasValue(string? text) { return new Translation("pt-BR", "key", text).HasValue(); } [Test(Description = "Assert that the translation's ToString method returns the expected text for various inputs.")] - public void Translation_ToString([ValueSource(nameof(TranslationTests.Samples))] string text) + public void Translation_ToString([ValueSource(nameof(TranslationTests.Samples))] string? text) { // act Translation translation = new("pt-BR", "key", text); @@ -128,20 +131,20 @@ namespace SMAPI.Tests.Core } [Test(Description = "Assert that the translation's implicit string conversion returns the expected text for various inputs.")] - public void Translation_ImplicitStringConversion([ValueSource(nameof(TranslationTests.Samples))] string text) + public void Translation_ImplicitStringConversion([ValueSource(nameof(TranslationTests.Samples))] string? text) { // act Translation translation = new("pt-BR", "key", text); // assert if (translation.HasValue()) - Assert.AreEqual(text, (string)translation, "The translation returned an unexpected value given a valid input."); + Assert.AreEqual(text, (string?)translation, "The translation returned an unexpected value given a valid input."); else - Assert.AreEqual(this.GetPlaceholderText("key"), (string)translation, "The translation returned an unexpected value given a null or empty input."); + Assert.AreEqual(this.GetPlaceholderText("key"), (string?)translation, "The translation returned an unexpected value given a null or empty input."); } [Test(Description = "Assert that the translation returns the expected text given a use-placeholder setting.")] - public void Translation_UsePlaceholder([Values(true, false)] bool value, [ValueSource(nameof(TranslationTests.Samples))] string text) + public void Translation_UsePlaceholder([Values(true, false)] bool value, [ValueSource(nameof(TranslationTests.Samples))] string? text) { // act Translation translation = new Translation("pt-BR", "key", text).UsePlaceholder(value); @@ -156,7 +159,7 @@ namespace SMAPI.Tests.Core } [Test(Description = "Assert that the translation returns the expected text after setting the default.")] - public void Translation_Default([ValueSource(nameof(TranslationTests.Samples))] string text, [ValueSource(nameof(TranslationTests.Samples))] string @default) + public void Translation_Default([ValueSource(nameof(TranslationTests.Samples))] string? text, [ValueSource(nameof(TranslationTests.Samples))] string? @default) { // act Translation translation = new Translation("pt-BR", "key", text).Default(@default); @@ -192,7 +195,7 @@ namespace SMAPI.Tests.Core break; case "class": - translation = translation.Tokens(new TokenModel { Start = start, Middle = middle, End = end }); + translation = translation.Tokens(new TokenModel(start, middle, end)); break; case "IDictionary<string, object>": @@ -326,21 +329,63 @@ namespace SMAPI.Tests.Core return string.Format(Translation.PlaceholderText, key); } + /// <summary>Create a fake mod manifest.</summary> + private IModMetadata CreateModMetadata() + { + string id = $"smapi.unit-tests.fake-mod-{Guid.NewGuid():N}"; + + string tempPath = Path.Combine(Path.GetTempPath(), id); + return new ModMetadata( + displayName: "Mod Display Name", + directoryPath: tempPath, + rootPath: tempPath, + manifest: new Manifest( + uniqueID: id, + name: "Mod Name", + author: "Mod Author", + description: "Mod Description", + version: new SemanticVersion(1, 0, 0) + ), + dataRecord: null, + isIgnored: false + ); + } + /********* ** Test models *********/ /// <summary>A model used to test token support.</summary> + [SuppressMessage("ReSharper", "NotAccessedField.Local", Justification = "Used dynamically via translation helper.")] + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local", Justification = "Used dynamically via translation helper.")] private class TokenModel { + /********* + ** Accessors + *********/ /// <summary>A sample token property.</summary> - public string Start { get; set; } + public string Start { get; } /// <summary>A sample token property.</summary> - public string Middle { get; set; } + public string Middle { get; } /// <summary>A sample token field.</summary> public string End; + + + /********* + ** public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="start">A sample token property.</param> + /// <param name="middle">A sample token field.</param> + /// <param name="end">A sample token property.</param> + public TokenModel(string start, string middle, string end) + { + this.Start = start; + this.Middle = middle; + this.End = end; + } } } } |