use FluentAssertions consistently in unit tests

This commit is contained in:
Jesse Plamondon-Willard
2024-05-24 18:53:00 -04:00
parent df1df51c0b
commit acbbe50526
8 changed files with 182 additions and 156 deletions
+4 -5
View File
@@ -56,11 +56,10 @@ namespace SMAPI.Tests.Core
public void Constructor_NullOrWhitespace(string? name)
{
// act
ArgumentException exception = Assert.Throws<ArgumentException>(() => _ = AssetName.Parse(name!, _ => null))!;
// assert
exception.ParamName.Should().Be("rawName");
exception.Message.Should().Be("The asset name can't be null or empty. (Parameter 'rawName')");
FluentActions.Invoking(() => _ = AssetName.Parse(name!, _ => null)).Should()
.Throw<ArgumentException>()
.WithParameterName("rawName")
.WithMessage("The asset name can't be null or empty. (Parameter 'rawName')");
}
+63 -65
View File
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
@@ -38,7 +39,7 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ReadManifests(new ModToolkit(), rootFolder, new ModDatabase(), useCaseInsensitiveFilePaths: true).ToArray();
// assert
Assert.AreEqual(0, mods.Length, 0, $"Expected to find zero manifests, found {mods.Length} instead.");
mods.Should().BeEmpty("it should match number of mods input");
// cleanup
Directory.Delete(rootFolder, recursive: true);
@@ -57,9 +58,9 @@ namespace SMAPI.Tests.Core
IModMetadata? mod = mods.FirstOrDefault();
// assert
Assert.AreEqual(1, mods.Length, 0, $"Expected to find one manifest, found {mods.Length} instead.");
Assert.AreEqual(ModMetadataStatus.Failed, mod!.Status, "The mod metadata was not marked failed.");
Assert.IsNotNull(mod.Error, "The mod metadata did not have an error message set.");
mods.Should().HaveCount(1, "it should match number of mods input");
mod!.Status.Should().Be(ModMetadataStatus.Failed);
mod.Error.Should().NotBeNull();
// cleanup
Directory.Delete(rootFolder, recursive: true);
@@ -100,30 +101,27 @@ namespace SMAPI.Tests.Core
IModMetadata? mod = mods.FirstOrDefault();
// assert
Assert.AreEqual(1, mods.Length, 0, "Expected to find one manifest.");
Assert.IsNotNull(mod, "The loaded manifest shouldn't be null.");
Assert.AreEqual(null, mod!.DataRecord, "The data record should be null since we didn't provide one.");
Assert.AreEqual(modFolder, mod.DirectoryPath, "The directory path doesn't match.");
Assert.AreEqual(null, mod.Error, "The error should be null since parsing should have succeeded.");
Assert.AreEqual(ModMetadataStatus.Found, mod.Status, "The status doesn't match.");
mods.Should().HaveCount(1, "it should match number of mods input");
mod.Should().NotBeNull();
mod!.DataRecord.Should().BeNull("we didn't provide one");
mod.DirectoryPath.Should().Be(modFolder);
mod.Error.Should().BeNull();
mod.Status.Should().Be(ModMetadataStatus.Found);
Assert.AreEqual(original[nameof(IManifest.Name)], mod.DisplayName, "The display name should use the manifest name.");
Assert.AreEqual(original[nameof(IManifest.Name)], mod.Manifest.Name, "The manifest's name doesn't match.");
Assert.AreEqual(original[nameof(IManifest.Author)], mod.Manifest.Author, "The manifest's author doesn't match.");
Assert.AreEqual(original[nameof(IManifest.Description)], mod.Manifest.Description, "The manifest's description doesn't match.");
Assert.AreEqual(original[nameof(IManifest.EntryDll)], mod.Manifest.EntryDll, "The manifest's entry DLL doesn't match.");
Assert.AreEqual(original[nameof(IManifest.MinimumApiVersion)], mod.Manifest.MinimumApiVersion?.ToString(), "The manifest's minimum API version doesn't match.");
Assert.AreEqual(original[nameof(IManifest.MinimumGameVersion)], mod.Manifest.MinimumGameVersion?.ToString(), "The manifest's minimum game version doesn't match.");
Assert.AreEqual(original[nameof(IManifest.Version)].ToString(), mod.Manifest.Version.ToString(), "The manifest's version doesn't match.");
mod.DisplayName.Should().Be((string)original[nameof(IManifest.Name)], mod.DisplayName);
mod.Manifest.Name.Should().Be((string)original[nameof(IManifest.Name)], mod.Manifest.Name);
mod.Manifest.ExtraFields.Should()
.NotBeNull()
.And.HaveCount(2)
.And.ContainKeys("ExtraString", "ExtraInt");
mod.Manifest.ExtraFields["ExtraString"].Should().Be(original["ExtraString"]);
mod.Manifest.ExtraFields["ExtraInt"].Should().Be(original["ExtraInt"]);
Assert.IsNotNull(mod.Manifest.ExtraFields, "The extra fields should not be null.");
Assert.AreEqual(2, mod.Manifest.ExtraFields.Count, "The extra fields should contain two values.");
Assert.AreEqual(original["ExtraString"], mod.Manifest.ExtraFields["ExtraString"], "The manifest's extra fields should contain an 'ExtraString' value.");
Assert.AreEqual(original["ExtraInt"], mod.Manifest.ExtraFields["ExtraInt"], "The manifest's extra fields should contain an 'ExtraInt' value.");
Assert.IsNotNull(mod.Manifest.Dependencies, "The dependencies field should not be null.");
Assert.AreEqual(1, mod.Manifest.Dependencies.Length, "The dependencies field should contain one value.");
Assert.AreEqual(originalDependency[nameof(IManifestDependency.UniqueID)], mod.Manifest.Dependencies[0].UniqueID, "The first dependency's unique ID doesn't match.");
mod.Manifest.Dependencies.Should()
.NotBeNull()
.And.HaveCount(1);
mod.Manifest.Dependencies[0].Should().NotBeNull();
mod.Manifest.Dependencies[0].UniqueID.Should().Be((string)originalDependency[nameof(IManifestDependency.UniqueID)]);
// cleanup
Directory.Delete(rootFolder, recursive: true);
@@ -268,7 +266,7 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(Array.Empty<IModMetadata>(), new ModDatabase()).ToArray();
// assert
Assert.AreEqual(0, mods.Length, 0, "Expected to get an empty list of mods.");
mods.Should().BeEmpty("it should match number of mods input");
}
[Test(Description = "Assert that processing dependencies doesn't change the order if there are no mod dependencies.")]
@@ -284,10 +282,10 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modA.Object, modB.Object, modC.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(3, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order unexpectedly changed with no dependencies.");
Assert.AreSame(modB.Object, mods[1], "The load order unexpectedly changed with no dependencies.");
Assert.AreSame(modC.Object, mods[2], "The load order unexpectedly changed with no dependencies.");
mods.Should().HaveCount(3, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "the load order shouldn't change with no dependencies");
mods[1].Should().BeSameAs(modB.Object, "the load order shouldn't change with no dependencies");
mods[2].Should().BeSameAs(modC.Object, "the load order shouldn't change with no dependencies");
}
[Test(Description = "Assert that processing dependencies skips mods that have already failed without calling any other properties.")]
@@ -320,10 +318,10 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modC.Object, modA.Object, modB.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(3, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order is incorrect: mod A should be first since the other mods depend on it.");
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A, and is needed by mod C.");
Assert.AreSame(modC.Object, mods[2], "The load order is incorrect: mod C should be third since it needs both mod A and mod B.");
mods.Should().HaveCount(3, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "mod A should be first since the other mods depend on it");
mods[1].Should().BeSameAs(modB.Object, "mod B should be second since it needs mod A, and is needed by mod C");
mods[2].Should().BeSameAs(modC.Object, "mod C should be third since it needs both mod A and mod B");
}
[Test(Description = "Assert that simple dependency chains are reordered correctly.")]
@@ -340,11 +338,11 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modC.Object, modA.Object, modB.Object, modD.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(4, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order is incorrect: mod A should be first since it's needed by mod B.");
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A, and is needed by mod C.");
Assert.AreSame(modC.Object, mods[2], "The load order is incorrect: mod C should be third since it needs mod B, and is needed by mod D.");
Assert.AreSame(modD.Object, mods[3], "The load order is incorrect: mod D should be fourth since it needs mod C.");
mods.Should().HaveCount(4, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "mod A should be first since it's needed by mod B");
mods[1].Should().BeSameAs(modB.Object, "mod B should be second since it needs mod A, and is needed by mod C");
mods[2].Should().BeSameAs(modC.Object, "mod C should be third since it needs mod B, and is needed by mod D");
mods[3].Should().BeSameAs(modD.Object, "mod D should be fourth since it needs mod C");
}
[Test(Description = "Assert that overlapping dependency chains are reordered correctly.")]
@@ -366,13 +364,13 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modC.Object, modA.Object, modB.Object, modD.Object, modF.Object, modE.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(6, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order is incorrect: mod A should be first since it's needed by mod B.");
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A, and is needed by mod C.");
Assert.AreSame(modC.Object, mods[2], "The load order is incorrect: mod C should be third since it needs mod B, and is needed by mod D.");
Assert.AreSame(modD.Object, mods[3], "The load order is incorrect: mod D should be fourth since it needs mod C.");
Assert.AreSame(modE.Object, mods[4], "The load order is incorrect: mod E should be fifth since it needs mod B, but is specified after C which also needs mod B.");
Assert.AreSame(modF.Object, mods[5], "The load order is incorrect: mod F should be last since it needs mods E and C.");
mods.Should().HaveCount(6, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "mod A should be first since it's needed by mod B");
mods[1].Should().BeSameAs(modB.Object, "mod B should be second since it needs mod A, and is needed by mod C");
mods[2].Should().BeSameAs(modC.Object, "mod C should be third since it needs mod B, and is needed by mod D");
mods[3].Should().BeSameAs(modD.Object, "mod D should be fourth since it needs mod C");
mods[4].Should().BeSameAs(modE.Object, "mod E should be fifth since it needs mod B, but is specified after C which also needs mod B");
mods[5].Should().BeSameAs(modF.Object, "mod F should be last since it needs mods E and C");
}
[Test(Description = "Assert that mods with circular dependency chains are skipped, but any other mods are loaded in the correct order.")]
@@ -393,9 +391,9 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modC.Object, modA.Object, modB.Object, modD.Object, modE.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(5, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order is incorrect: mod A should be first since it's needed by mod B.");
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A.");
mods.Should().HaveCount(5, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "mod A should be first since it's needed by mod B");
mods[1].Should().BeSameAs(modB.Object, "mod B should be second since it needs mod A");
modC.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<ModFailReason>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once, "Mod C was expected to fail since it's part of a dependency loop.");
modD.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<ModFailReason>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once, "Mod D was expected to fail since it's part of a dependency loop.");
modE.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<ModFailReason>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once, "Mod E was expected to fail since it's part of a dependency loop.");
@@ -410,18 +408,18 @@ namespace SMAPI.Tests.Core
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(MockBehavior.Strict);
modD.Setup(p => p.Manifest).Returns<IManifest>(null);
modD.Setup(p => p.Manifest).Returns<IManifest>(null!); // deliberately testing null handling
modD.Setup(p => p.Status).Returns(ModMetadataStatus.Failed);
// act
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modC.Object, modA.Object, modB.Object, modD.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(4, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modD.Object, mods[0], "The load order is incorrect: mod D should be first since it was already failed.");
Assert.AreSame(modA.Object, mods[1], "The load order is incorrect: mod A should be second since it's needed by mod B.");
Assert.AreSame(modB.Object, mods[2], "The load order is incorrect: mod B should be third since it needs mod A, and is needed by mod C.");
Assert.AreSame(modC.Object, mods[3], "The load order is incorrect: mod C should be fourth since it needs mod B, and is needed by mod D.");
mods.Should().HaveCount(4, "it should match number of mods input");
mods[0].Should().BeSameAs(modD.Object, "mod D should be first since it was already failed");
mods[1].Should().BeSameAs(modA.Object, "mod A should be second since it's needed by mod B");
mods[2].Should().BeSameAs(modB.Object, "mod B should be third since it needs mod A, and is needed by mod C");
mods[3].Should().BeSameAs(modC.Object, "mod C should be fourth since it needs mod B, and is needed by mod D");
}
[Test(Description = "Assert that dependencies are failed if they don't meet the minimum version.")]
@@ -436,7 +434,7 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modA.Object, modB.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(2, mods.Length, 0, "Expected to get the same number of mods input.");
mods.Should().HaveCount(2, "it should match number of mods input");
modB.Verify(p => p.SetStatus(ModMetadataStatus.Failed, It.IsAny<ModFailReason>(), It.IsAny<string>(), It.IsAny<string>()), Times.Once, "Mod B unexpectedly didn't fail even though it needs a newer version of Mod A.");
}
@@ -452,9 +450,9 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modA.Object, modB.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(2, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order is incorrect: mod A should be first since it's needed by mod B.");
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A.");
mods.Should().HaveCount(2, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "mod A should be first since it's needed by mod B");
mods[1].Should().BeSameAs(modB.Object, "mod B should be second since it needs mod A");
}
[Test(Description = "Assert that optional dependencies are sorted correctly if present.")]
@@ -469,9 +467,9 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modB.Object, modA.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(2, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modA.Object, mods[0], "The load order is incorrect: mod A should be first since it's needed by mod B.");
Assert.AreSame(modB.Object, mods[1], "The load order is incorrect: mod B should be second since it needs mod A.");
mods.Should().HaveCount(2, "it should match number of mods input");
mods[0].Should().BeSameAs(modA.Object, "mod A should be first since it's needed by mod B");
mods[1].Should().BeSameAs(modB.Object, "mod B should be second since it needs mod A");
}
[Test(Description = "Assert that optional dependencies are accepted if they're missing.")]
@@ -485,8 +483,8 @@ namespace SMAPI.Tests.Core
IModMetadata[] mods = new ModResolver().ProcessDependencies(new[] { modB.Object }, new ModDatabase()).ToArray();
// assert
Assert.AreEqual(1, mods.Length, 0, "Expected to get the same number of mods input.");
Assert.AreSame(modB.Object, mods[0], "The load order is incorrect: mod B should be first since it's the only mod.");
mods.Should().HaveCount(1, "should match number of mods input");
mods[0].Should().BeSameAs(modB.Object, "mod B should be first since it's the only mod");
}
+27 -33
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Framework;
@@ -42,13 +43,12 @@ namespace SMAPI.Tests.Core
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.");
helper.Locale.Should().Be("en");
helper.LocaleEnum.Should().Be(LocalizedContentManager.LanguageCode.en);
translationList.Should().NotBeNull().And.BeEmpty();
Assert.IsNotNull(translation, "The translation helper unexpectedly returned a null translation.");
Assert.AreEqual(this.GetPlaceholderText("key"), translation.ToString(), "The translation returned an unexpected value.");
translation.Should().NotBeNull();
translation.ToString().Should().Be(this.GetPlaceholderText("key"));
}
[Test(Description = "Assert that the translation helper returns the expected translations correctly.")]
@@ -70,8 +70,9 @@ namespace SMAPI.Tests.Core
// assert
foreach (string locale in expected.Keys)
{
Assert.IsNotNull(actual[locale], $"The translations for {locale} is unexpectedly null.");
Assert.That(actual[locale], Is.EquivalentTo(expected[locale]).Using<Translation, Translation>(this.CompareEquality), $"The translations for {locale} don't match the expected values.");
actual[locale].Should()
.NotBeNull($"the translations for {locale} should be set")
.And.BeEquivalentTo(expected[locale], $"the translations for {locale} should match the input values");
}
}
@@ -98,8 +99,9 @@ namespace SMAPI.Tests.Core
// assert
foreach (string locale in expected.Keys)
{
Assert.IsNotNull(actual[locale], $"The translations for {locale} is unexpectedly null.");
Assert.That(actual[locale], Is.EquivalentTo(expected[locale]).Using<Translation, Translation>(this.CompareEquality), $"The translations for {locale} don't match the expected values.");
actual[locale].Should()
.NotBeNull($"the translations for {locale} should be set")
.And.BeEquivalentTo(expected[locale], $"the translations for {locale} should match the input values");
}
}
@@ -125,9 +127,9 @@ namespace SMAPI.Tests.Core
// assert
if (translation.HasValue())
Assert.AreEqual(text, translation.ToString(), "The translation returned an unexpected value given a valid input.");
translation.ToString().Should().Be(text, "the translation should match the valid input");
else
Assert.AreEqual(this.GetPlaceholderText("key"), translation.ToString(), "The translation returned an unexpected value given a null or empty input.");
translation.ToString().Should().Be(this.GetPlaceholderText("key"), "the translation should match the placeholder given a null or empty input");
}
[Test(Description = "Assert that the translation's implicit string conversion returns the expected text for various inputs.")]
@@ -138,9 +140,9 @@ namespace SMAPI.Tests.Core
// assert
if (translation.HasValue())
Assert.AreEqual(text, (string?)translation, "The translation returned an unexpected value given a valid input.");
((string?)translation).Should().Be(text, "the translation should match the valid input");
else
Assert.AreEqual(this.GetPlaceholderText("key"), (string?)translation, "The translation returned an unexpected value given a null or empty input.");
((string?)translation).Should().Be(this.GetPlaceholderText("key"), "the translation should match the placeholder given a null or empty input");
}
[Test(Description = "Assert that the translation returns the expected text given a use-placeholder setting.")]
@@ -151,11 +153,11 @@ namespace SMAPI.Tests.Core
// assert
if (translation.HasValue())
Assert.AreEqual(text, translation.ToString(), "The translation returned an unexpected value given a valid input.");
translation.ToString().Should().Be(text, "the translation should match the valid input");
else if (!value)
Assert.AreEqual(text, translation.ToString(), "The translation returned an unexpected value given a null or empty input with the placeholder disabled.");
translation.ToString().Should().Be(text, "the translation should return the text as-is given a null or empty input with the placeholder disabled");
else
Assert.AreEqual(this.GetPlaceholderText("key"), translation.ToString(), "The translation returned an unexpected value given a null or empty input with the placeholder enabled.");
translation.ToString().Should().Be(this.GetPlaceholderText("key"), "the translation should match the placeholder given a null or empty input with the placeholder enabled");
}
[Test(Description = "Assert that the translation returns the expected text after setting the default.")]
@@ -166,11 +168,11 @@ namespace SMAPI.Tests.Core
// assert
if (!string.IsNullOrEmpty(text))
Assert.AreEqual(text, translation.ToString(), "The translation returned an unexpected value given a valid base text.");
translation.ToString().Should().Be(text, "the translation should match the valid base text");
else if (!string.IsNullOrEmpty(@default))
Assert.AreEqual(@default, translation.ToString(), "The translation returned an unexpected value given a null or empty base text, but valid default.");
translation.ToString().Should().Be(@default, "the translation should match the default text, given a null or empty base text and valid default.");
else
Assert.AreEqual(this.GetPlaceholderText("key"), translation.ToString(), "The translation returned an unexpected value given a null or empty base and default text.");
translation.ToString().Should().Be(this.GetPlaceholderText("key"), translation.ToString(), "the translation should match the placeholder, given a null or empty base text and no default text");
}
/****
@@ -211,7 +213,7 @@ namespace SMAPI.Tests.Core
}
// assert
Assert.AreEqual(expected, translation.ToString(), "The translation returned an unexpected text.");
translation.ToString().Should().Be(expected);
}
[Test(Description = "Assert that the translation can replace tokens in all valid formats.")]
@@ -231,7 +233,7 @@ namespace SMAPI.Tests.Core
Translation translation = new Translation("pt-BR", "key", text).Tokens(new Dictionary<string, object> { [key] = value });
// assert
Assert.AreEqual(value, translation.ToString(), "The translation returned an unexpected value given a valid base text.");
translation.ToString().Should().Be(value);
}
[Test(Description = "Assert that translation tokens are case-insensitive and surrounding-whitespace-insensitive.")]
@@ -247,7 +249,7 @@ namespace SMAPI.Tests.Core
Translation translation = new Translation("pt-BR", "key", text).Tokens(new Dictionary<string, object> { [key] = value });
// assert
Assert.AreEqual(value, translation.ToString(), "The translation returned an unexpected value given a valid base text.");
translation.ToString().Should().Be(value);
}
@@ -261,8 +263,8 @@ namespace SMAPI.Tests.Core
private void AssertSetLocale(TranslationHelper helper, string locale, LocalizedContentManager.LanguageCode localeEnum)
{
helper.SetLocale(locale, localeEnum);
Assert.AreEqual(locale, helper.Locale, "The locale doesn't match the input value.");
Assert.AreEqual(localeEnum, helper.LocaleEnum, "The locale enum doesn't match the input value.");
helper.Locale.Should().Be(locale);
helper.LocaleEnum.Should().Be(localeEnum);
}
/// <summary>Get sample raw translations to input.</summary>
@@ -314,14 +316,6 @@ namespace SMAPI.Tests.Core
return expected;
}
/// <summary>Get whether two translations have the same public values.</summary>
/// <param name="a">The first translation to compare.</param>
/// <param name="b">The second translation to compare.</param>
private bool CompareEquality(Translation a, Translation b)
{
return a.Key == b.Key && a.ToString() == b.ToString();
}
/// <summary>Get the default placeholder text when a translation is missing.</summary>
/// <param name="key">The translation key.</param>
private string GetPlaceholderText(string key)
+16 -17
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Utilities;
@@ -24,11 +25,10 @@ namespace SMAPI.Tests.Utilities
bool success = KeybindList.TryParse($"{button}", out KeybindList? parsed, out string[] errors);
// assert
Assert.IsTrue(success, "Parsing unexpectedly failed.");
Assert.IsNotNull(parsed, "The parsed result should not be null.");
Assert.AreEqual(parsed!.ToString(), $"{button}");
Assert.IsNotNull(errors, message: "The errors should never be null.");
Assert.IsEmpty(errors, message: "The input bindings incorrectly reported errors.");
success.Should().BeTrue();
parsed.Should().NotBeNull();
parsed!.ToString().Should().Be(button.ToString());
errors.Should().NotBeNull().And.BeEmpty();
}
/// <summary>Assert the parsed fields when constructed from multi-key values.</summary>
@@ -50,10 +50,10 @@ namespace SMAPI.Tests.Utilities
bool success = KeybindList.TryParse(input, out KeybindList? parsed, out string[] errors);
// assert
Assert.IsTrue(success, "Parsing unexpectedly failed.");
Assert.IsNotNull(parsed, "The parsed result should not be null.");
Assert.IsNotNull(errors, message: "The errors should never be null.");
Assert.IsEmpty(errors, message: "The input bindings incorrectly reported errors.");
success.Should().BeTrue();
parsed.Should().NotBeNull();
errors.Should().NotBeNull().And.BeEmpty();
return parsed!.ToString();
}
@@ -70,10 +70,9 @@ namespace SMAPI.Tests.Utilities
bool success = KeybindList.TryParse(input, out KeybindList? parsed, out string[] errors);
// assert
Assert.IsFalse(success, "Parsing unexpectedly succeeded.");
Assert.IsNull(parsed, "The parsed result should be null.");
Assert.IsNotNull(errors, message: "The errors should never be null.");
Assert.AreEqual(expectedError, string.Join("; ", errors), "The errors don't match the expected ones.");
success.Should().BeFalse();
parsed.Should().BeNull();
errors.Should().BeEquivalentTo(errors);
}
@@ -110,10 +109,10 @@ namespace SMAPI.Tests.Utilities
}
// assert
Assert.IsTrue(success, "Parsing unexpected failed");
Assert.IsNotNull(parsed, "The parsed result should not be null.");
Assert.IsNotNull(errors, message: "The errors should never be null.");
Assert.IsEmpty(errors, message: "The input bindings incorrectly reported errors.");
success.Should().BeTrue();
parsed.Should().NotBeNull();
errors.Should().NotBeNull().And.BeEmpty();
return parsed!.GetState();
}
@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using FluentAssertions;
using NUnit.Framework;
using StardewModdingAPI.Toolkit.Utilities;
@@ -152,7 +153,9 @@ namespace SMAPI.Tests.Utilities
string[] segments = PathUtilities.GetSegments(path.OriginalPath);
// assert
Assert.AreEqual(path.Segments, segments);
path.Segments.Should()
.HaveCount(segments.Length)
.And.ContainInOrder(segments);
}
[Test(Description = "Assert that PathUtilities.GetSegments splits paths correctly when given a limit.")]
@@ -163,7 +166,9 @@ namespace SMAPI.Tests.Utilities
string[] segments = PathUtilities.GetSegments(path.OriginalPath, 3);
// assert
Assert.AreEqual(path.SegmentsLimit3, segments);
path.SegmentsLimit3.Should()
.HaveCount(segments.Length)
.And.ContainInOrder(segments);
}
/****
@@ -180,7 +185,7 @@ namespace SMAPI.Tests.Utilities
string normalized = PathUtilities.NormalizeAssetName(path.OriginalPath);
// assert
Assert.AreEqual(path.NormalizedOnUnix, normalized); // MonoGame uses the Linux format
normalized.Should().Be(path.NormalizedOnUnix); // MonoGame uses the Linux format
}
/****
@@ -194,11 +199,13 @@ namespace SMAPI.Tests.Utilities
string normalized = PathUtilities.NormalizePath(path.OriginalPath);
// assert
normalized.Should().Be(
#if SMAPI_FOR_WINDOWS
Assert.AreEqual(path.NormalizedOnWindows, normalized);
path.NormalizedOnWindows
#else
Assert.AreEqual(path.NormalizedOnUnix, normalized);
path.NormalizedOnUnix
#endif
);
}
/****
+15 -8
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.RegularExpressions;
using FluentAssertions;
using NUnit.Framework;
using StardewModdingAPI.Utilities;
using StardewValley;
@@ -67,11 +68,11 @@ namespace SMAPI.Tests.Utilities
SDate date = new(day, season, year);
// assert
Assert.AreEqual(day, date.Day);
Assert.AreEqual(expectedSeason, date.Season);
Assert.AreEqual((int)expectedSeason, date.SeasonIndex);
Assert.AreEqual(Utility.getSeasonKey(expectedSeason), date.SeasonKey);
Assert.AreEqual(year, date.Year);
date.Day.Should().Be(day);
date.Season.Should().Be(expectedSeason);
date.SeasonIndex.Should().Be((int)expectedSeason);
date.SeasonKey.Should().Be(Utility.getSeasonKey(expectedSeason));
date.Year.Should().Be(year);
}
[Test(Description = "Assert that the constructor throws an exception if the values are invalid.")]
@@ -86,7 +87,9 @@ namespace SMAPI.Tests.Utilities
public void Constructor_RejectsInvalidValues(int day, string season, int year)
{
// act & assert
Assert.Throws<ArgumentException>(() => _ = new SDate(day, season, year), "Constructing the invalid date didn't throw the expected exception.");
FluentActions
.Invoking(() => _ = new SDate(day, season, year))
.Should().Throw<ArgumentException>();
}
/****
@@ -111,7 +114,9 @@ namespace SMAPI.Tests.Utilities
public void FromDaysSinceStart_RejectsInvalidValues(int daysSinceStart)
{
// act & assert
Assert.Throws<ArgumentException>(() => _ = SDate.FromDaysSinceStart(daysSinceStart), "Passing the invalid number of days didn't throw the expected exception.");
FluentActions
.Invoking(() => _ = SDate.FromDaysSinceStart(daysSinceStart))
.Should().Throw<ArgumentException>();
}
/****
@@ -241,7 +246,9 @@ namespace SMAPI.Tests.Utilities
public void AddDays_RejectsInvalidValues(string dateStr, int addDays)
{
// act & assert
Assert.Throws<ArithmeticException>(() => _ = this.GetDate(dateStr).AddDays(addDays), "Passing the invalid number of days didn't throw the expected exception.");
FluentActions
.Invoking(() => _ = this.GetDate(dateStr).AddDays(addDays))
.Should().Throw<ArithmeticException>();
}
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using FluentAssertions;
using Newtonsoft.Json;
using NUnit.Framework;
using StardewModdingAPI;
@@ -91,7 +92,9 @@ namespace SMAPI.Tests.Utilities
[TestCase("1.2.3.4-some-tag.4 ")]
public void Constructor_FromString_Standard_DisallowsNonStandardVersion(string input)
{
Assert.Throws<FormatException>(() => _ = new SemanticVersion(input));
FluentActions
.Invoking(() => _ = new SemanticVersion(input))
.Should().Throw<FormatException>();
}
/// <summary>Assert the parsed version when constructed from standard parts.</summary>
@@ -277,7 +280,10 @@ namespace SMAPI.Tests.Utilities
: null;
// assert
Assert.AreEqual(versionA.IsOlderThan(versionB), versionA.IsOlderThan(versionB?.ToString()), "The two signatures returned different results.");
bool olderThanVersion = versionA.IsOlderThan(versionB);
bool olderThanString = versionA.IsOlderThan(versionB?.ToString());
olderThanVersion.Should().Be(olderThanString, "comparing to a version or string should return the same result");
return versionA.IsOlderThan(versionB);
}
@@ -326,7 +332,10 @@ namespace SMAPI.Tests.Utilities
: null;
// assert
Assert.AreEqual(versionA.IsNewerThan(versionB), versionA.IsNewerThan(versionB?.ToString()), "The two signatures returned different results.");
bool newerThanVersion = versionA.IsNewerThan(versionB);
bool newerThanString = versionA.IsNewerThan(versionB?.ToString());
newerThanVersion.Should().Be(newerThanString, "comparing to a version or string should return the same result");
return versionA.IsNewerThan(versionB);
}
@@ -366,7 +375,10 @@ namespace SMAPI.Tests.Utilities
ISemanticVersion version = new SemanticVersion(versionStr);
// assert
Assert.AreEqual(version.IsBetween(lower, upper), version.IsBetween(lower?.ToString(), upper?.ToString()), "The two signatures returned different results.");
bool betweenVersions = version.IsBetween(lower, upper);
bool betweenStrings = version.IsBetween(lower?.ToString(), upper?.ToString());
betweenVersions.Should().Be(betweenStrings, "comparing to a version or string should return the same result");
return version.IsBetween(lower, upper);
}
@@ -385,8 +397,8 @@ namespace SMAPI.Tests.Utilities
SemanticVersion? after = JsonConvert.DeserializeObject<SemanticVersion>(json);
// assert
Assert.IsNotNull(after, "The semantic version after deserialization is unexpectedly null.");
Assert.AreEqual(versionStr, after!.ToString(), "The semantic version after deserialization doesn't match the input version.");
after.Should().NotBeNull();
after!.ToString().Should().Be(versionStr);
}
@@ -419,7 +431,7 @@ namespace SMAPI.Tests.Utilities
GameVersion version = new(versionStr);
// assert
Assert.AreEqual(versionStr, version.ToString(), "The game version did not round-trip to the same value.");
version.ToString().Should().Be(versionStr, "the game version should round-trip to the same value");
}
@@ -436,12 +448,21 @@ namespace SMAPI.Tests.Utilities
/// <param name="nonStandard">Whether the version should be marked as non-standard.</param>
private void AssertParts(ISemanticVersion version, int major, int minor, int patch, string? prerelease, string? build, bool nonStandard)
{
Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match.");
Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match.");
Assert.AreEqual(patch, version.PatchVersion, "The patch version doesn't match.");
Assert.AreEqual(string.IsNullOrWhiteSpace(prerelease) ? null : prerelease.Trim(), version.PrereleaseTag, "The prerelease tag doesn't match.");
Assert.AreEqual(string.IsNullOrWhiteSpace(build) ? null : build.Trim(), version.BuildMetadata, "The build metadata doesn't match.");
Assert.AreEqual(nonStandard, version.IsNonStandard(), $"The version is incorrectly marked {(nonStandard ? "standard" : "non-standard")}.");
version.MajorVersion.Should().Be(major);
version.MinorVersion.Should().Be(minor);
version.PatchVersion.Should().Be(patch);
if (string.IsNullOrWhiteSpace(prerelease))
version.PrereleaseTag.Should().BeNull();
else
version.PrereleaseTag.Should().Be(prerelease.Trim());
if (string.IsNullOrWhiteSpace(build))
version.BuildMetadata.Should().BeNull();
else
version.BuildMetadata.Should().Be(build.Trim());
version.IsNonStandard().Should().Be(nonStandard);
}
/// <summary>Assert that the expected exception type is thrown, and log the action output and thrown exception.</summary>
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
using StardewModdingAPI;
using StardewModdingAPI.Toolkit.Framework.Clients.Wiki;
@@ -36,10 +37,10 @@ namespace SMAPI.Tests.WikiClient
ChangeDescriptor parsed = ChangeDescriptor.Parse(rawDescriptor, out string[] errors);
// assert
Assert.That(parsed.Add, Is.EquivalentTo(expectedAdd), $"{nameof(parsed.Add)} doesn't match the expected value.");
Assert.That(parsed.Remove, Is.EquivalentTo(expectedRemove), $"{nameof(parsed.Replace)} doesn't match the expected value.");
Assert.That(parsed.Replace, Is.EquivalentTo(expectedReplace), $"{nameof(parsed.Replace)} doesn't match the expected value.");
Assert.That(errors, Is.EquivalentTo(expectedErrors), $"{nameof(errors)} doesn't match the expected value.");
parsed.Add.Should().BeEquivalentTo(expectedAdd);
parsed.Remove.Should().BeEquivalentTo(expectedRemove);
parsed.Replace.Should().BeEquivalentTo(expectedReplace);
errors.Should().BeEquivalentTo(expectedErrors);
}
[Test(Description = "Assert that Parse sets the expected values for descriptors when a format callback is specified.")]
@@ -69,10 +70,10 @@ namespace SMAPI.Tests.WikiClient
);
// assert
Assert.That(parsed.Add, Is.EquivalentTo(expectedAdd), $"{nameof(parsed.Add)} doesn't match the expected value.");
Assert.That(parsed.Remove, Is.EquivalentTo(expectedRemove), $"{nameof(parsed.Replace)} doesn't match the expected value.");
Assert.That(parsed.Replace, Is.EquivalentTo(expectedReplace), $"{nameof(parsed.Replace)} doesn't match the expected value.");
Assert.That(errors, Is.EquivalentTo(expectedErrors), $"{nameof(errors)} doesn't match the expected value.");
parsed.Add.Should().BeEquivalentTo(expectedAdd);
parsed.Remove.Should().BeEquivalentTo(expectedRemove);
parsed.Replace.Should().BeEquivalentTo(expectedReplace);
errors.Should().BeEquivalentTo(expectedErrors);
}
[Test(Description = "Assert that Apply returns the expected value for the given descriptor.")]
@@ -111,7 +112,7 @@ namespace SMAPI.Tests.WikiClient
{
ChangeDescriptor parsed = ChangeDescriptor.Parse(descriptor, out string[] errors);
Assert.IsEmpty(errors, "Parsing the descriptor failed.");
errors.Should().BeEmpty();
return parsed.ApplyToCopy(input);
}
@@ -128,7 +129,7 @@ namespace SMAPI.Tests.WikiClient
{
var parsed = ChangeDescriptor.Parse(descriptor, out string[] errors);
Assert.IsEmpty(errors, "Parsing the descriptor failed.");
errors.Should().BeEmpty();
return parsed.ToString();
}