PKHeX/Tests/PKHeX.Core.Tests/Util/StringQualityTests.cs
Kurt 9dedd33694 Duplicate locations: across lists, not each array
BD/SP has Pokémon HOME as location 30018 and 40086; need to differentiate.
Revise the unit test to share the unique-check set across all location lists of that context

Ignore "empty" location values (dashes, empty). For deduplicating, ignore empty indexes as well.
2025-02-01 19:23:11 -06:00

133 lines
4.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Xunit;
namespace PKHeX.Core.Tests.Util;
public class StringQualityTests
{
[Theory]
[InlineData("ja")]
[InlineData("en")]
[InlineData("it")]
[InlineData("de")]
[InlineData("fr")]
[InlineData("es")]
[InlineData("ko")]
[InlineData("zh-Hans")]
[InlineData("zh-Hant")]
public void HasNoDuplicates(string language)
{
CheckMetLocations(language);
CheckItemNames(language);
CheckMoveNames(language);
CheckSpeciesNames(language);
}
/// <summary>
/// Checks for duplicate hashes in the species list.
/// </summary>
/// <remarks>
/// Uses hashes instead of strings as other logic uses dictionaries of hashes.
/// </remarks>
private static void CheckSpeciesNames(string language)
{
var strings = GameInfo.GetStrings(language);
var arr = strings.specieslist;
var hashset = new HashSet<int>(arr.Length);
var duplicates = new List<string>(0);
foreach (var line in arr)
{
var hash = line.GetHashCode();
if (!hashset.Add(hash))
duplicates.Add(line);
}
duplicates.Count.Should().Be(0, "expected no duplicate strings.");
}
private static void CheckMoveNames(string language)
{
var strings = GameInfo.GetStrings(language);
var arr = strings.movelist;
var duplicates = GetDuplicates(arr);
duplicates.Count.Should().Be(0, "expected no duplicate strings.");
}
private static void CheckItemNames(string language)
{
var strings = GameInfo.GetStrings(language);
var arr = strings.itemlist;
var duplicates = GetDuplicates(arr);
var questionmarks = arr[129];
duplicates.RemoveAll(z => z == questionmarks);
duplicates.Count.Should().Be(0, "expected no duplicate strings.");
}
private static List<string> GetDuplicates(string[] arr)
{
var hs = new HashSet<string>();
var duplicates = new List<string>();
foreach (var line in arr)
{
if (line.Length == 0)
continue;
if (hs.Contains(line))
duplicates.Add(line);
hs.Add(line);
}
return duplicates;
}
private static void CheckMetLocations(string language)
{
var strings = GameInfo.GetStrings(language);
var sets = typeof(GameStrings).GetFields()
.Where(z => typeof(ILocationSet).IsAssignableFrom(z.FieldType));
bool iterated = false;
var duplicates = new List<string>(0);
foreach (var setField in sets)
{
iterated = true;
var name = setField.Name;
var group = setField.GetValue(strings) as ILocationSet;
Assert.NotNull(group);
var dict = new Dictionary<string, (int Bank, int Index)>();
foreach (var (bank, mem) in group.GetAll())
{
var arr = mem.Span;
bool sm0 = bank == 0 && name == nameof(GameStrings.Gen7);
for (int index = 0; index < arr.Length; index++)
{
var line = arr[index];
if (line.Length == 0)
continue;
if (sm0 && index % 2 != 0)
continue;
if (line is "----------" or "" or "——————" or "")
continue; // don't care
if (dict.TryGetValue(line, out var other))
duplicates.Add($"{name}\t{other.Bank}-{other.Index}\t{bank}-{index}\t{line}");
else
dict.Add(line, (bank, index));
}
}
if (duplicates.Count == 0)
continue;
// None of the location names displayed to the user should be exactly the same.
// This prevents a location list selection from being ambiguous/not what the user intended.
var result = string.Join(Environment.NewLine, duplicates);
Assert.Fail($"Disallowed - duplicate locations for {name}:{Environment.NewLine}{result}");
}
iterated.Should().BeTrue();
}
}