From 97adac2e0ae235eff15213e6f89dc6dcddd245a6 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 29 Aug 2024 15:31:02 +0900 Subject: [PATCH 1/2] Add test + adjust existing ones with new semantics --- .../Filtering/FilterQueryParserTest.cs | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs index 7897b3d8c0..e6006b7fd2 100644 --- a/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs +++ b/osu.Game.Tests/NonVisual/Filtering/FilterQueryParserTest.cs @@ -537,7 +537,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [TestCaseSource(nameof(correct_date_query_examples))] public void TestValidDateQueries(string dateQuery) { - string query = $"played<{dateQuery} time"; + string query = $"lastplayed<{dateQuery} time"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); @@ -571,7 +571,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestGreaterDateQuery() { - const string query = "played>50"; + const string query = "lastplayed>50"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.That(filterCriteria.LastPlayed.Max, Is.Not.Null); @@ -584,7 +584,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestLowerDateQuery() { - const string query = "played<50"; + const string query = "lastplayed<50"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.That(filterCriteria.LastPlayed.Max, Is.Null); @@ -597,7 +597,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestBothSidesDateQuery() { - const string query = "played>3M played<1y6M"; + const string query = "lastplayed>3M lastplayed<1y6M"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.That(filterCriteria.LastPlayed.Min, Is.Not.Null); @@ -611,7 +611,7 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestEqualDateQuery() { - const string query = "played=50"; + const string query = "lastplayed=50"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual(false, filterCriteria.LastPlayed.HasFilter); @@ -620,11 +620,34 @@ namespace osu.Game.Tests.NonVisual.Filtering [Test] public void TestOutOfRangeDateQuery() { - const string query = "played<10000y"; + const string query = "lastplayed<10000y"; var filterCriteria = new FilterCriteria(); FilterQueryParser.ApplyQueries(filterCriteria, query); Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); Assert.AreEqual(DateTimeOffset.MinValue.AddMilliseconds(1), filterCriteria.LastPlayed.Min); } + + private static readonly object[] played_query_tests = + { + new object[] { "0", DateTimeOffset.MinValue, true }, + new object[] { "0", DateTimeOffset.Now, false }, + new object[] { "false", DateTimeOffset.MinValue, true }, + new object[] { "false", DateTimeOffset.Now, false }, + + new object[] { "1", DateTimeOffset.MinValue, false }, + new object[] { "1", DateTimeOffset.Now, true }, + new object[] { "true", DateTimeOffset.MinValue, false }, + new object[] { "true", DateTimeOffset.Now, true }, + }; + + [Test] + [TestCaseSource(nameof(played_query_tests))] + public void TestPlayedQuery(string query, DateTimeOffset reference, bool matched) + { + var filterCriteria = new FilterCriteria(); + FilterQueryParser.ApplyQueries(filterCriteria, $"played={query}"); + Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter); + Assert.AreEqual(matched, filterCriteria.LastPlayed.IsInRange(reference)); + } } } From fde790c014179ab88a381918dc3b8e5354f8173d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 29 Aug 2024 15:32:35 +0900 Subject: [PATCH 2/2] Rework `played` filter to a boolean value --- osu.Game/Screens/Select/FilterQueryParser.cs | 40 +++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 40fd289be6..3e0dba59f0 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -62,10 +62,31 @@ namespace osu.Game.Screens.Select case "length": return tryUpdateLengthRange(criteria, op, value); - case "played": case "lastplayed": return tryUpdateDateAgoRange(ref criteria.LastPlayed, op, value); + case "played": + if (!tryParseBool(value, out bool played)) + return false; + + // Unplayed beatmaps are filtered on DateTimeOffset.MinValue. + + if (played) + { + criteria.LastPlayed.Min = DateTimeOffset.MinValue; + criteria.LastPlayed.Max = DateTimeOffset.MaxValue; + criteria.LastPlayed.IsLowerInclusive = false; + } + else + { + criteria.LastPlayed.Min = DateTimeOffset.MinValue; + criteria.LastPlayed.Max = DateTimeOffset.MinValue; + criteria.LastPlayed.IsLowerInclusive = true; + criteria.LastPlayed.IsUpperInclusive = true; + } + + return true; + case "divisor": return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); @@ -133,6 +154,23 @@ namespace osu.Game.Screens.Select private static bool tryParseInt(string value, out int result) => int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result); + private static bool tryParseBool(string value, out bool result) + { + switch (value) + { + case "1": + result = true; + return true; + + case "0": + result = false; + return true; + + default: + return bool.TryParse(value, out result); + } + } + private static bool tryParseEnum(string value, out TEnum result) where TEnum : struct { // First try an exact match.