1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-16 16:23:39 +08:00
Files
osu-lazer/osu.Game.Tests/Editing/Checks/CheckLowestDiffDrainTimeTest.cs
T
Bartłomiej Dach 19f28813a0 Clean up ctors
There were too many of them, and they were a bit twisty for my liking.
2025-08-13 12:32:17 +02:00

252 lines
9.9 KiB
C#

// 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 NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Checks;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu;
using osu.Game.Tests.Beatmaps;
namespace osu.Game.Tests.Editing.Checks
{
[TestFixture]
public class CheckLowestDiffDrainTimeTest
{
private TestCheckLowestDiffDrainTime check = null!;
[SetUp]
public void Setup()
{
check = new TestCheckLowestDiffDrainTime();
}
[Test]
public void TestSingleDifficultyMeetsRequirement()
{
var beatmap = createBeatmapWithDrainTime(4 * 60 * 1000, 3.5, "Hard"); // 4 minutes
assertOk(beatmap);
}
[Test]
public void TestSingleDifficultyTooShort()
{
var beatmap = createBeatmapWithDrainTime(2 * 60 * 1000, 3.5, "Hard"); // 2 minutes - too short for Hard
assertTooShort(beatmap);
}
[Test]
public void TestHardDifficultyAtThreshold()
{
var beatmap = createBeatmapWithDrainTime((3 * 60 + 30) * 1000, 3.5, "Hard"); // Exactly 3:30
assertOk(beatmap);
}
[Test]
public void TestHardDifficultyJustUnderThreshold()
{
var beatmap = createBeatmapWithDrainTime((3 * 60 + 29) * 1000, 3.5, "Hard"); // 3:29 - just under threshold
assertTooShort(beatmap);
}
[Test]
public void TestInsaneDifficultyAtThreshold()
{
var beatmap = createBeatmapWithDrainTime((4 * 60 + 15) * 1000, 4.5, "Insane"); // Exactly 4:15
assertOk(beatmap);
}
[Test]
public void TestInsaneDifficultyTooShort()
{
var beatmap = createBeatmapWithDrainTime(4 * 60 * 1000, 4.5, "Insane"); // 4:00 - too short for Insane
assertTooShort(beatmap);
}
[Test]
public void TestExpertDifficultyAtThreshold()
{
var beatmap = createBeatmapWithDrainTime(5 * 60 * 1000, 5.5, "Expert"); // Exactly 5:00
assertOk(beatmap);
}
[Test]
public void TestExpertDifficultyTooShort()
{
var beatmap = createBeatmapWithDrainTime((4 * 60 + 30) * 1000, 5.5, "Expert"); // 4:30 - too short for Expert
assertTooShort(beatmap);
}
[Test]
public void TestEasyDifficultyMeetsRequirement()
{
var beatmap = createBeatmapWithDrainTime(2 * 60 * 1000, 1.5, "Easy"); // 2 minutes - should be ok for Easy
assertOk(beatmap);
}
[Test]
public void TestNormalDifficultyMeetsRequirement()
{
var beatmap = createBeatmapWithDrainTime(2 * 60 * 1000, 2.5, "Normal"); // 2 minutes - should be ok for Normal
assertOk(beatmap);
}
[Test]
public void TestMultipleDifficultiesMeetsRequirement()
{
var difficulties = new List<IBeatmap>
{
createBeatmapWithDrainTime((3 * 60 + 30) * 1000, 3.5, "Hard"), // Hard - lowest difficulty, 3:30
createBeatmapWithDrainTime((3 * 60 + 30) * 1000, 4.5, "Insane"),
createBeatmapWithDrainTime((3 * 60 + 30) * 1000, 5.5, "Expert")
};
// All should be ok because lowest difficulty is Hard and drain time meets Hard requirement
assertOkWithMultipleDifficulties(difficulties[0], difficulties);
assertOkWithMultipleDifficulties(difficulties[1], difficulties);
assertOkWithMultipleDifficulties(difficulties[2], difficulties);
}
[Test]
public void TestMultipleDifficultiesTooShort()
{
var difficulties = new List<IBeatmap>
{
createBeatmapWithDrainTime(4 * 60 * 1000, 4.5, "Insane"), // Insane - lowest difficulty, 4:00
createBeatmapWithDrainTime(4 * 60 * 1000, 5.5, "Expert") // Same drain time
};
// Should be too short because lowest difficulty is Insane and requires 4:15
assertTooShortWithMultipleDifficulties(difficulties[0], difficulties);
assertTooShortWithMultipleDifficulties(difficulties[1], difficulties);
}
[Test]
public void TestPlayTimeVsDrainTimeNotHighestDifficulty()
{
var expertBeatmap = createBeatmapWithPlayTime(5 * 60 * 1000, 5.5, "Expert"); // 5:00 play time
expertBeatmap.Breaks.Add(new BreakPeriod(60000, 100000)); // 40-second break
var difficulties = new List<IBeatmap>
{
expertBeatmap, // Expert - 5:00 play, 4:20 drain
createBeatmapWithPlayTime(5 * 60 * 1000, 6.5, "ExpertPlus") // ExpertPlus - highest difficulty
};
// The Expert difficulty (not highest) should use play time (5:00) and pass the Expert requirement
assertOkWithMultipleDifficulties(difficulties[0], difficulties);
}
[Test]
public void TestPlayTimeVsDrainTimeHighestDifficulty()
{
var expertBeatmap = createBeatmapWithPlayTime(5 * 60 * 1000, 5.5, "Expert"); // 5:00 play time
expertBeatmap.Breaks.Add(new BreakPeriod(60000, 100000)); // 40-second break
// As the highest difficulty with breaks > 30s, it should use drain time and fail
assertTooShort(expertBeatmap);
}
private IBeatmap createBeatmapWithDrainTime(double drainTimeMs, double starRating = 3.5, string difficultyName = "Default")
{
var beatmap = new Beatmap<HitObject>
{
BeatmapInfo = new BeatmapInfo
{
StarRating = starRating,
DifficultyName = difficultyName,
Ruleset = new OsuRuleset().RulesetInfo
},
HitObjects = new List<HitObject>
{
new HitObject { StartTime = 0 },
new HitObject { StartTime = drainTimeMs } // Last object at drain time
}
};
return beatmap;
}
private IBeatmap createBeatmapWithPlayTime(double playTimeMs, double starRating = 3.5, string difficultyName = "Default")
{
var beatmap = new Beatmap<HitObject>
{
BeatmapInfo = new BeatmapInfo
{
StarRating = starRating,
DifficultyName = difficultyName,
Ruleset = new OsuRuleset().RulesetInfo
},
HitObjects = new List<HitObject>
{
new HitObject { StartTime = 0 },
new HitObject { StartTime = playTimeMs } // Last object at play time
}
};
return beatmap;
}
private void assertOk(IBeatmap beatmap)
{
var difficultyRating = StarDifficulty.GetDifficultyRating(beatmap.BeatmapInfo.StarRating);
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap), difficultyRating);
Assert.That(check.Run(context), Is.Empty);
}
private void assertTooShort(IBeatmap beatmap)
{
var difficultyRating = StarDifficulty.GetDifficultyRating(beatmap.BeatmapInfo.StarRating);
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap), difficultyRating);
var issues = check.Run(context).ToList();
Assert.That(issues, Has.Count.EqualTo(1));
Assert.That(issues.First().Template is CheckLowestDiffDrainTime.IssueTemplateTooShort);
}
private void assertOkWithMultipleDifficulties(IBeatmap currentBeatmap, IEnumerable<IBeatmap> allDifficulties)
{
var context = createContextWithMultipleDifficulties(currentBeatmap, allDifficulties);
Assert.That(check.Run(context), Is.Empty);
}
private void assertTooShortWithMultipleDifficulties(IBeatmap currentBeatmap, IEnumerable<IBeatmap> allDifficulties)
{
var context = createContextWithMultipleDifficulties(currentBeatmap, allDifficulties);
var issues = check.Run(context).ToList();
Assert.That(issues, Has.Count.EqualTo(1));
Assert.That(issues.First().Template is CheckLowestDiffDrainTime.IssueTemplateTooShort);
}
private BeatmapVerifierContext createContextWithMultipleDifficulties(IBeatmap currentBeatmap, IEnumerable<IBeatmap> allDifficulties)
{
var difficultiesArray = allDifficulties.ToArray();
var currentDifficultyRating = StarDifficulty.GetDifficultyRating(currentBeatmap.BeatmapInfo.StarRating);
var verifiedCurrentBeatmap = new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(currentBeatmap), currentBeatmap);
var verifiedOtherBeatmaps = difficultiesArray.Select(b => new BeatmapVerifierContext.VerifiedBeatmap(new TestWorkingBeatmap(b), b)).ToList();
return new BeatmapVerifierContext(verifiedCurrentBeatmap, verifiedOtherBeatmaps, currentDifficultyRating);
}
private class TestCheckLowestDiffDrainTime : CheckLowestDiffDrainTime
{
protected override IEnumerable<(DifficultyRating rating, double thresholdMs, string name)> GetThresholds()
{
// Same thresholds as `CheckOsuLowestDiffDrainTime` for testing
yield return (DifficultyRating.Hard, new TimeSpan(0, 3, 30).TotalMilliseconds, "Hard");
yield return (DifficultyRating.Insane, new TimeSpan(0, 4, 15).TotalMilliseconds, "Insane");
yield return (DifficultyRating.Expert, new TimeSpan(0, 5, 0).TotalMilliseconds, "Expert");
}
}
}
}