253 lines
8.2 KiB
C#
253 lines
8.2 KiB
C#
using SongTidy.Services;
|
||
|
||
namespace SongTidy.Tests;
|
||
|
||
/// <summary>
|
||
/// Contains tests for <see cref="FilenameParser"/>.
|
||
/// </summary>
|
||
[TestClass]
|
||
public sealed class FilenameParserTests {
|
||
#region Successful parsing
|
||
|
||
/// <summary>
|
||
/// Verifies the documented example with one English and one Chinese bracket group.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ParsesSpecificationExample() {
|
||
AssertParse("A - B (Live - Tokyo)(修正版)", "A", "B", "Live - Tokyo 修正版");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that multiple comment groups are joined with a single half-width space.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ParsesMultipleCommentGroups() {
|
||
AssertParse("A - B (Live)(Remix)", "A", "B", "Live Remix");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that Chinese bracket groups are extracted like English bracket groups.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ParsesChineseBracketComment() {
|
||
AssertParse("歌手 - 歌名(现场)", "歌手", "歌名", "现场");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that all comment groups are removed from the text used for artist and title.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void RemovesAllCommentGroupsFromSource() {
|
||
AssertParse("A - B (Live) (Tokyo)", "A", "B", "Live Tokyo");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that nested brackets stay as literal text inside the comment.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void KeepsNestedBracketsInsideComment() {
|
||
AssertParse("A - B (Live (Tokyo) Mix)", "A", "B", "Live (Tokyo) Mix");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that nested full-width brackets stay as literal text inside an English comment.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void PreservesFullWidthNestedBrackets() {
|
||
AssertParse("A - B (Live(东京))", "A", "B", "Live(东京)");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that only the outermost pair of a nested group is treated as the comment.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void TreatsOnlyOutermostBracketGroupAsComment() {
|
||
AssertParse("A - B ((Live))", "A", "B", "(Live)");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that a comment can be extracted from a name without a hyphen.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ParsesCommentWithoutArtistSeparator() {
|
||
AssertParse("Song (Live)", string.Empty, "Song", "Live");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Invalid bracket structures
|
||
|
||
/// <summary>
|
||
/// Verifies that an unmatched opening bracket disables comment extraction entirely.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForUnmatchedOpeningBracket() {
|
||
AssertParse("A - B (Live", "A", "B (Live", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that an unmatched closing bracket disables comment extraction entirely.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForUnmatchedClosingBracket() {
|
||
AssertParse("A - B Live)", "A", "B Live)", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that opening and closing brackets of different types cannot pair.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForMismatchedBracketTypes() {
|
||
AssertParse("A - B (Live)", "A", "B (Live)", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that an extra closing bracket after a valid pair disables extraction entirely.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForExtraClosingBracket() {
|
||
AssertParse("A - B (Live))", "A", "B (Live))", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that an extra opening bracket after a valid pair disables extraction entirely.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForExtraOpeningBracket() {
|
||
AssertParse("A - B (Live) (", "A", "B (Live) (", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that an unclosed outer bracket invalidates otherwise complete nested brackets.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForUnclosedOuterBracket() {
|
||
AssertParse("A - B (Live (Tokyo)", "A", "B (Live (Tokyo)", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that crossing bracket groups are treated as an invalid structure.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AbandonsExtractionForCrossingBracketGroups() {
|
||
AssertParse("(a(b))", string.Empty, "(a(b))", string.Empty);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Hyphen handling
|
||
|
||
/// <summary>
|
||
/// Verifies that a single half-width hyphen separates artist from title.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void SplitsSingleHalfWidthHyphen() {
|
||
AssertParse("A - B", "A", "B", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that multiple half-width hyphens make the whole remaining text the title.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void TreatsMultipleHyphensAsTitleOnly() {
|
||
AssertParse("A - B - C", string.Empty, "A - B - C", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that hyphens inside a removed comment do not count when applying the multiple-hyphen rule.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void IgnoresHyphensInsideCommentsWhenSplitting() {
|
||
AssertParse("A - B (Live - Tokyo - Mix)", "A", "B", "Live - Tokyo - Mix");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that a full-width hyphen is not treated as a separator.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void DoesNotSplitOnFullWidthHyphen() {
|
||
AssertParse("A - B", string.Empty, "A - B", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that an em dash is not treated as a separator.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void DoesNotSplitOnEmDash() {
|
||
AssertParse("A — B", string.Empty, "A — B", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that a name without a hyphen produces an empty artist and a full title.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ReturnsEmptyArtistWhenNoHyphenExists() {
|
||
AssertParse("Song Title", string.Empty, "Song Title", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that an empty input produces three empty fields.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void ReturnsEmptyFieldsForEmptyInput() {
|
||
AssertParse(string.Empty, string.Empty, string.Empty, string.Empty);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Whitespace handling
|
||
|
||
/// <summary>
|
||
/// Verifies that standard whitespace around the artist and title is removed.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void TrimsStandardWhitespaceAroundArtistAndTitle() {
|
||
AssertParse(" A - B ", "A", "B", string.Empty);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that standard whitespace around extracted comment text is removed.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void TrimsStandardWhitespaceInsideComments() {
|
||
AssertParse("A - B ( Live )", "A", "B", "Live");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that full-width spaces inside comment text are preserved.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void PreservesFullWidthSpacesInsideComments() {
|
||
AssertParse("A - B (\u3000Live\u3000)", "A", "B", "\u3000Live\u3000");
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifies that full-width spaces around artist and title are preserved.
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void PreservesFullWidthSpacesAroundFields() {
|
||
AssertParse("A\u3000-\u3000B", "A\u3000", "\u3000B", string.Empty);
|
||
}
|
||
|
||
#endregion
|
||
|
||
/// <summary>
|
||
/// Parses the input and asserts all three resulting fields.
|
||
/// </summary>
|
||
/// <param name="input">The file name to parse.</param>
|
||
/// <param name="expectedArtist">The expected artist value.</param>
|
||
/// <param name="expectedTitle">The expected title value.</param>
|
||
/// <param name="expectedComment">The expected comment value.</param>
|
||
private static void AssertParse(
|
||
string input,
|
||
string expectedArtist,
|
||
string expectedTitle,
|
||
string expectedComment) {
|
||
FilenameParseResult result = FilenameParser.Parse(input);
|
||
|
||
Assert.AreEqual(expectedArtist, result.Artist, "Artist mismatch.");
|
||
Assert.AreEqual(expectedTitle, result.Title, "Title mismatch.");
|
||
Assert.AreEqual(expectedComment, result.Comment, "Comment mismatch.");
|
||
}
|
||
}
|