-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #276 from andy840119/andy840119/text-tag-utils
Implement ruby/romaji tag checking utility.
- Loading branch information
Showing
6 changed files
with
227 additions
and
5 deletions.
There are no files selected for viewing
142 changes: 142 additions & 0 deletions
142
osu.Game.Rulesets.Karaoke.Tests/Utils/TextTagsUtilsTest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using Microsoft.EntityFrameworkCore.Internal; | ||
using NUnit.Framework; | ||
using osu.Game.Rulesets.Karaoke.Objects; | ||
using osu.Game.Rulesets.Karaoke.Utils; | ||
using System; | ||
using System.Linq; | ||
|
||
namespace osu.Game.Rulesets.Karaoke.Tests.Utils | ||
{ | ||
[TestFixture] | ||
public class TextTagsUtilsTest | ||
{ | ||
private const string lyric = "Test lyric"; | ||
|
||
[TestCase(nameof(ValidTextTagWithSorted), TextTagsUtils.Sorting.Asc, new int[] { 0, 1, 1, 2, 2, 3 })] | ||
[TestCase(nameof(ValidTextTagWithSorted), TextTagsUtils.Sorting.Desc, new int[] { 2, 3, 1, 2, 0, 1 })] | ||
[TestCase(nameof(ValidTextTagWithUnsorted), TextTagsUtils.Sorting.Asc, new int[] { 0, 1, 1, 2, 2, 3 })] | ||
[TestCase(nameof(ValidTextTagWithUnsorted), TextTagsUtils.Sorting.Desc, new int[] { 2, 3, 1, 2, 0, 1 })] | ||
public void TestSort(string testCase, TextTagsUtils.Sorting sorting, int[] results) | ||
{ | ||
var textTags = getValueByMethodName(testCase); | ||
|
||
var sortedTextTags = TextTagsUtils.Sort(textTags, sorting); | ||
for (int i = 0; i < sortedTextTags.Length; i++) | ||
{ | ||
// result would be start, end, start, end... | ||
Assert.AreEqual(sortedTextTags[i].StartIndex, results[i * 2]); | ||
Assert.AreEqual(sortedTextTags[i].EndIndex, results[i * 2 + 1]); | ||
} | ||
} | ||
|
||
[TestCase(nameof(ValidTextTagWithSorted), TextTagsUtils.Sorting.Asc, new int[] { })] | ||
[TestCase(nameof(ValidTextTagWithUnsorted), TextTagsUtils.Sorting.Asc, new int[] { })] | ||
[TestCase(nameof(InvalidTextTagWithSameStartAndEndIndex), TextTagsUtils.Sorting.Asc, new int[] {0 })] | ||
[TestCase(nameof(InvalidTextTagWithWrongIndex), TextTagsUtils.Sorting.Asc, new int[] { 0 })] | ||
[TestCase(nameof(InvalidTextTagWithNegativeIndex), TextTagsUtils.Sorting.Asc, new int[] { 0 })] | ||
[TestCase(nameof(InvalidTextTagWithEndLargerThenNextStart), TextTagsUtils.Sorting.Asc, new int[] { 1 })] | ||
[TestCase(nameof(InvalidTextTagWithEndLargerThenNextStart), TextTagsUtils.Sorting.Desc, new int[] { 0 })] | ||
[TestCase(nameof(InvalidTextTagWithWrapNextTextTag), TextTagsUtils.Sorting.Asc, new int[] { 1 })] | ||
[TestCase(nameof(InvalidTextTagWithWrapNextTextTag), TextTagsUtils.Sorting.Desc, new int[] { 1 })] | ||
[TestCase(nameof(InvalidTextTagWithSandwichTextTag), TextTagsUtils.Sorting.Asc, new int[] { 1 })] | ||
[TestCase(nameof(InvalidTextTagWithSandwichTextTag), TextTagsUtils.Sorting.Desc, new int[] { 1 })] | ||
public void TestFindInvalid(string testCase, TextTagsUtils.Sorting sorting, int[] errorIndex) | ||
{ | ||
var textTags = getValueByMethodName(testCase); | ||
|
||
// run all and find invalid indexes. | ||
var invalidTextTag = TextTagsUtils.FindInvalid(textTags, lyric, sorting); | ||
var invalidIndexes = invalidTextTag.Select(v => textTags.IndexOf(v)).ToArray(); | ||
Assert.AreEqual(invalidIndexes, errorIndex); | ||
} | ||
|
||
private RubyTag[] getValueByMethodName(string methodName) | ||
{ | ||
Type thisType = GetType(); | ||
var theMethod = thisType.GetMethod(methodName); | ||
if (theMethod == null) | ||
throw new MissingMethodException("Test method is not exist."); | ||
|
||
return theMethod.Invoke(this, null) as RubyTag[]; | ||
} | ||
|
||
#region valid source | ||
|
||
public static RubyTag[] ValidTextTagWithSorted() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = 1 }, | ||
new RubyTag { StartIndex = 1, EndIndex = 2 }, | ||
new RubyTag { StartIndex = 2, EndIndex = 3 } | ||
}; | ||
|
||
public static RubyTag[] ValidTextTagWithUnsorted() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = 1 }, | ||
new RubyTag { StartIndex = 2, EndIndex = 3 }, | ||
new RubyTag { StartIndex = 1, EndIndex = 2 } | ||
}; | ||
|
||
#endregion | ||
|
||
#region invalid source | ||
|
||
public static RubyTag[] InvalidTextTagWithWrongIndex() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 1, EndIndex = 0 }, | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithNegativeIndex() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = -1, EndIndex = 0 }, | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithSameStartAndEndIndex() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = 0 }, // Same number. | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithStartTimeExceedLyricSize() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = lyric.Length + 1 }, // Same number. | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithEndTimeExceedLyricSize() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = lyric.Length + 1, EndIndex = lyric.Length + 2 }, // Same number. | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithEndLargerThenNextStart() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = 2 }, // End is larger than second start. | ||
new RubyTag { StartIndex = 1, EndIndex = 3 } | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithWrapNextTextTag() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = 3 }, // Wrap second text tag. | ||
new RubyTag { StartIndex = 1, EndIndex = 2 } | ||
}; | ||
|
||
public static RubyTag[] InvalidTextTagWithSandwichTextTag() | ||
=> new[] | ||
{ | ||
new RubyTag { StartIndex = 0, EndIndex = 2 }, | ||
new RubyTag { StartIndex = 1, EndIndex = 3 }, | ||
new RubyTag { StartIndex = 2, EndIndex = 4 } | ||
}; | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright (c) andy840119 <[email protected]>. Licensed under the GPL Licence. | ||
// See the LICENCE file in the repository root for full licence text. | ||
|
||
using osu.Game.Rulesets.Karaoke.Objects.Types; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System; | ||
|
||
namespace osu.Game.Rulesets.Karaoke.Utils | ||
{ | ||
public static class TextTagsUtils | ||
{ | ||
public static T[] Sort<T>(T[] textTags, Sorting sorting = Sorting.Asc) where T : ITextTag | ||
{ | ||
switch (sorting) | ||
{ | ||
case Sorting.Asc: | ||
return textTags?.OrderBy(x => x.StartIndex).ThenBy(x => x.EndIndex).ToArray(); | ||
case Sorting.Desc: | ||
return textTags?.OrderByDescending(x => x.EndIndex).ThenByDescending(x => x.StartIndex).ToArray(); | ||
default: | ||
throw new ArgumentOutOfRangeException(nameof(sorting)); | ||
} | ||
} | ||
|
||
public static T[] FindInvalid<T>(T[] textTags, string lyric, Sorting sorting = Sorting.Asc) where T : ITextTag | ||
{ | ||
// check is null or empty | ||
if (textTags == null || textTags.Length == 0) | ||
return new T[] { }; | ||
|
||
// todo : need to make suure is need to sort in here? | ||
var sortedTextTags = Sort(textTags, sorting); | ||
|
||
var invalidList = new List<T>(); | ||
|
||
// check invalid range | ||
invalidList.AddRange(sortedTextTags.Where(x => x.StartIndex < 0 || x.EndIndex > lyric.Length)); | ||
|
||
// check end is less or equal to start index | ||
invalidList.AddRange(sortedTextTags.Where(x => x.EndIndex <= x.StartIndex)); | ||
|
||
// find other is smaller or bigger | ||
foreach (var textTag in sortedTextTags) | ||
{ | ||
if (invalidList.Contains(textTag)) | ||
continue; | ||
|
||
var checkTags = sortedTextTags.Except(new[] { textTag }); | ||
switch (sorting) | ||
{ | ||
case Sorting.Asc: | ||
// start index within tne target | ||
invalidList.AddRange(checkTags.Where(x => x.StartIndex >= textTag.StartIndex && x.StartIndex < textTag.EndIndex)); | ||
break; | ||
|
||
case Sorting.Desc: | ||
// end index within tne target | ||
invalidList.AddRange(checkTags.Where(x => x.EndIndex > textTag.StartIndex && x.EndIndex <= textTag.EndIndex)); | ||
break; | ||
} | ||
} | ||
|
||
return Sort(invalidList.Distinct().ToArray()); | ||
} | ||
|
||
public enum Sorting | ||
{ | ||
/// <summary> | ||
/// Mark next time tag is error if conflict. | ||
/// </summary> | ||
Asc, | ||
|
||
/// <summary> | ||
/// Mark previous tag is error if conflict. | ||
/// </summary> | ||
Desc | ||
} | ||
} | ||
} |