Add a test case reproducing the conditions encountered "in the wild"
wherein a skin import would be performed incorrectly due to a __MACOSX
resource fork directory present next to a directory with the actual skin
files in the archive.
As a purely cosmetic code improvement, substitute string literals
in constructor calls of HeadlessGameHost in ImportBeatmapTest for nameof
operator usages.
Tests for the line-buffered reader added in 7b1ff38 were subtly
dependent on the execution environment due to differing end-of-line
markers on Windows and Unix-based systems.
Because StreamReader discards all newlines when reading line-by-line,
LineBufferedReader used a StringBuilder to patch the peeked lines
back together with the remaining contents of the file being read.
As StringBuilder.AppendLine uses the environment-specific newline
delimiter, the delimiters after the peeked-but-unconsumed lines can
therefore be substituted by the platform-specific variants, causing
the test failures due to the overly-simplified way they were written.
Reformulate the test to avoid such issues from resurfacing again
by splitting lines by \r or \n and then testing each line individually.
Additionally remove all raw literals in favour of explicitly mixing
various line delimiter character sequences for additional coverage.
LegacyDifficultyCalculatorBeatmapDecoder was registered as a fallback
decoder in commit ffde389 for future use in the server-side difficulty
calculation components. Due to the pre-existing fallback registrations
this causes a runtime crash when the diffcalc components are started.
Add a test reproducing this scenario to prevent the issue from
resurfacing in the future.
After the preparatory introduction of LineBufferedReader, it is now
possible to introduce registration of fallback decoders that won't drop
input supplied in the first line of the file.
A fallback decoder is used when the magic in the first line of the file
does not match any of the other known decoders. In such a case,
the fallback decoder is constructed and provided a LineBufferedReader
instance. The process of matching magic only peeks the first non-empty
line, so it is available for re-reading in Decode() using ReadLine().
There can be only one fallback decoder per type; a second attempt of
registering a fallback will result in an exception to avoid bugs.
To address the issue of parsing failing on badly or non-headered files,
set the legacy decoders for Beatmaps and Storyboards as the fallbacks.
Due to non-trivial logic, several new, passing unit tests with possible
edge cases also included.