mirror of
https://github.com/ppy/osu.git
synced 2026-06-03 18:03:55 +08:00
Merge pull request #34368 from Hiviexd/verify/check-inconsistent-metadata
Add verify check for inconsistent metadata
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Checks;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
|
||||
namespace osu.Game.Tests.Editing.Checks
|
||||
{
|
||||
[TestFixture]
|
||||
public class CheckInconsistentMetadataTest
|
||||
{
|
||||
private CheckInconsistentMetadata check = null!;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
check = new CheckInconsistentMetadata();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestConsistentMetadata()
|
||||
{
|
||||
var metadata = createMetadata("Test Artist", "Test Title", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata, metadata);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
Assert.That(check.Run(context), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInconsistentArtist()
|
||||
{
|
||||
var metadata1 = createMetadata("Artist One", "Test Title", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var metadata2 = createMetadata("Artist Two", "Test Title", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues[0].Template is CheckInconsistentMetadata.IssueTemplateInconsistentOtherFields);
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Inconsistent artist fields"));
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Artist One"));
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Artist Two"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInconsistentTitle()
|
||||
{
|
||||
var metadata1 = createMetadata("Test Artist", "Title One", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var metadata2 = createMetadata("Test Artist", "Title Two", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues[0].Template is CheckInconsistentMetadata.IssueTemplateInconsistentOtherFields);
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Inconsistent title fields"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInconsistentUnicodeArtist()
|
||||
{
|
||||
var metadata1 = createMetadata("Test Artist", "Test Title", "Test Source", "Test Creator", "tag1 tag2", unicodeArtist: "Test Unicode Artist 1");
|
||||
var metadata2 = createMetadata("Test Artist", "Test Title", "Test Source", "Test Creator", "tag1 tag2", unicodeArtist: "Test Unicode Artist 2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues[0].Template is CheckInconsistentMetadata.IssueTemplateInconsistentOtherFields);
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Inconsistent unicode artist fields"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInconsistentSource()
|
||||
{
|
||||
var metadata1 = createMetadata("Test Artist", "Test Title", "Source One", "Test Creator", "tag1 tag2");
|
||||
var metadata2 = createMetadata("Test Artist", "Test Title", "Source Two", "Test Creator", "tag1 tag2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues[0].Template is CheckInconsistentMetadata.IssueTemplateInconsistentOtherFields);
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Inconsistent source fields"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInconsistentCreator()
|
||||
{
|
||||
var metadata1 = createMetadata("Test Artist", "Test Title", "Test Source", "Creator One", "tag1 tag2");
|
||||
var metadata2 = createMetadata("Test Artist", "Test Title", "Test Source", "Creator Two", "tag1 tag2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues[0].Template is CheckInconsistentMetadata.IssueTemplateInconsistentOtherFields);
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Inconsistent creator fields"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInconsistentTags()
|
||||
{
|
||||
var metadata1 = createMetadata("Test Artist", "Test Title", "Test Source", "Test Creator", "tag1 tag2 tag3");
|
||||
var metadata2 = createMetadata("Test Artist", "Test Title", "Test Source", "Test Creator", "tag1 tag4 tag5");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(1));
|
||||
Assert.That(issues[0].Template is CheckInconsistentMetadata.IssueTemplateInconsistentTags);
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("Inconsistent tags"));
|
||||
Assert.That(issues[0].ToString(), Contains.Substring("tag2 tag3 tag4 tag5"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleInconsistencies()
|
||||
{
|
||||
var metadata1 = createMetadata("Artist One", "Title One", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var metadata2 = createMetadata("Artist Two", "Title Two", "Test Source", "Test Creator", "tag3 tag4");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
var issues = check.Run(context).ToList();
|
||||
|
||||
Assert.That(issues, Has.Count.EqualTo(3)); // artist, title, tags
|
||||
Assert.That(issues.Count(i => i.Template is CheckInconsistentMetadata.IssueTemplateInconsistentOtherFields), Is.EqualTo(2));
|
||||
Assert.That(issues.Count(i => i.Template is CheckInconsistentMetadata.IssueTemplateInconsistentTags), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleDifficulty()
|
||||
{
|
||||
var metadata = createMetadata("Test Artist", "Test Title", "Test Source", "Test Creator", "tag1 tag2");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
Assert.That(check.Run(context), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmptyStringFieldsAreConsistent()
|
||||
{
|
||||
var metadata1 = createMetadata("Test Artist", "Test Title", "", "Test Creator", "");
|
||||
var metadata2 = createMetadata("Test Artist", "Test Title", "", "Test Creator", "");
|
||||
var beatmaps = createBeatmapSetWithMetadata(metadata1, metadata2);
|
||||
var context = createContextWithMultipleDifficulties(beatmaps.First(), beatmaps);
|
||||
|
||||
Assert.That(check.Run(context), Is.Empty);
|
||||
}
|
||||
|
||||
private BeatmapMetadata createMetadata(string artist, string title, string source, string creator, string tags, string unicodeArtist = "", string unicodeTitle = "")
|
||||
{
|
||||
return new BeatmapMetadata(new RealmUser { Username = creator })
|
||||
{
|
||||
Artist = artist,
|
||||
Title = title,
|
||||
Source = source,
|
||||
Tags = tags,
|
||||
ArtistUnicode = unicodeArtist,
|
||||
TitleUnicode = unicodeTitle
|
||||
};
|
||||
}
|
||||
|
||||
private IBeatmap[] createBeatmapSetWithMetadata(params BeatmapMetadata[] metadata)
|
||||
{
|
||||
var beatmapSet = new BeatmapSetInfo();
|
||||
var beatmaps = new IBeatmap[metadata.Length];
|
||||
|
||||
for (int i = 0; i < metadata.Length; i++)
|
||||
{
|
||||
beatmaps[i] = createBeatmapWithMetadata(metadata[i], $"Difficulty {i + 1}");
|
||||
beatmaps[i].BeatmapInfo.BeatmapSet = beatmapSet;
|
||||
}
|
||||
|
||||
// Configure the beatmapset to contain all the beatmap infos
|
||||
foreach (var beatmap in beatmaps)
|
||||
beatmapSet.Beatmaps.Add(beatmap.BeatmapInfo);
|
||||
|
||||
return beatmaps;
|
||||
}
|
||||
|
||||
private Beatmap createBeatmapWithMetadata(BeatmapMetadata metadata, string difficultyName)
|
||||
{
|
||||
return new Beatmap
|
||||
{
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
DifficultyName = difficultyName,
|
||||
Metadata = metadata
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private BeatmapVerifierContext createContextWithMultipleDifficulties(IBeatmap currentBeatmap, IBeatmap[] allDifficulties)
|
||||
{
|
||||
return new BeatmapVerifierContext(
|
||||
currentBeatmap,
|
||||
new TestWorkingBeatmap(currentBeatmap),
|
||||
DifficultyRating.ExpertPlus,
|
||||
beatmapInfo => allDifficulties.FirstOrDefault(b => b.BeatmapInfo.Equals(beatmapInfo))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
// Metadata
|
||||
new CheckTitleMarkers(),
|
||||
new CheckInconsistentMetadata(),
|
||||
};
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||
|
||||
namespace osu.Game.Rulesets.Edit.Checks
|
||||
{
|
||||
public class CheckInconsistentMetadata : ICheck
|
||||
{
|
||||
public CheckMetadata Metadata => new CheckMetadata(CheckCategory.Metadata, "Inconsistent metadata");
|
||||
|
||||
public IEnumerable<IssueTemplate> PossibleTemplates => new IssueTemplate[]
|
||||
{
|
||||
new IssueTemplateInconsistentTags(this),
|
||||
new IssueTemplateInconsistentOtherFields(this)
|
||||
};
|
||||
|
||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||
{
|
||||
var difficulties = context.BeatmapsetDifficulties;
|
||||
|
||||
if (difficulties.Count <= 1)
|
||||
yield break;
|
||||
|
||||
var referenceBeatmap = difficulties.OrderByDescending(b => b.BeatmapInfo.StarRating).First();
|
||||
var referenceMetadata = referenceBeatmap.Metadata;
|
||||
|
||||
// Define metadata fields to check
|
||||
var fieldsToCheck = new (string fieldName, Func<BeatmapMetadata, string> fieldSelector)[]
|
||||
{
|
||||
("artist", m => m.Artist),
|
||||
("unicode artist", m => m.ArtistUnicode),
|
||||
("title", m => m.Title),
|
||||
("unicode title", m => m.TitleUnicode),
|
||||
("source", m => m.Source),
|
||||
("creator", m => m.Author.Username)
|
||||
};
|
||||
|
||||
foreach (var beatmap in difficulties)
|
||||
{
|
||||
if (beatmap == referenceBeatmap)
|
||||
continue;
|
||||
|
||||
var currentMetadata = beatmap.Metadata;
|
||||
|
||||
// Check each metadata field for inconsistencies
|
||||
foreach ((string fieldName, var fieldSelector) in fieldsToCheck)
|
||||
{
|
||||
string referenceField = fieldSelector(referenceMetadata);
|
||||
string currentField = fieldSelector(currentMetadata);
|
||||
|
||||
if (referenceField != currentField)
|
||||
{
|
||||
yield return new IssueTemplateInconsistentOtherFields(this).Create(
|
||||
fieldName,
|
||||
referenceBeatmap.BeatmapInfo.DifficultyName,
|
||||
beatmap.BeatmapInfo.DifficultyName,
|
||||
referenceField,
|
||||
currentField
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for tags
|
||||
if (referenceMetadata.Tags != currentMetadata.Tags)
|
||||
{
|
||||
var differenceTags = referenceMetadata.Tags.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToHashSet();
|
||||
differenceTags.SymmetricExceptWith(currentMetadata.Tags.Split(' ', StringSplitOptions.RemoveEmptyEntries));
|
||||
|
||||
string difference = string.Join(" ", differenceTags);
|
||||
|
||||
if (!string.IsNullOrEmpty(difference))
|
||||
{
|
||||
yield return new IssueTemplateInconsistentTags(this).Create(
|
||||
referenceBeatmap.BeatmapInfo.DifficultyName,
|
||||
beatmap.BeatmapInfo.DifficultyName,
|
||||
difference
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class IssueTemplateInconsistentTags : IssueTemplate
|
||||
{
|
||||
public IssueTemplateInconsistentTags(ICheck check)
|
||||
: base(check, IssueType.Problem, "Inconsistent tags between \"{0}\" and \"{1}\", difference being \"{2}\".")
|
||||
{
|
||||
}
|
||||
|
||||
public Issue Create(string referenceDifficulty, string currentDifficulty, string difference)
|
||||
=> new Issue(this, referenceDifficulty, currentDifficulty, difference);
|
||||
}
|
||||
|
||||
public class IssueTemplateInconsistentOtherFields : IssueTemplate
|
||||
{
|
||||
public IssueTemplateInconsistentOtherFields(ICheck check)
|
||||
: base(check, IssueType.Problem, "Inconsistent {0} fields between \"{1}\" and \"{2}\"; \"{3}\" and \"{4}\" respectively.")
|
||||
{
|
||||
}
|
||||
|
||||
public Issue Create(string fieldName, string referenceDifficulty, string currentDifficulty, string referenceValue, string currentValue)
|
||||
=> new Issue(this, fieldName, referenceDifficulty, currentDifficulty, referenceValue, currentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user