refactor: organize test project structure

This commit is contained in:
yyc12345 committed 2026-10-22 21:24:13 +08:00
1 parent 996c0a9515
commit c6d16fd108
8 files changed
+106 -94

No files matched your search

@@ -0,0 +1,252 @@
using SongTidy.Services;
namespace SongTidy.Tests.Services;
/// <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.");
}
}