1 /*
2  * test.cpp
3  * --------
4  * Purpose: Unit tests for OpenMPT.
5  * Notes  : We need FAAAAAAAR more unit tests!
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #include "stdafx.h"
12 #include "test.h"
13 
14 
15 #ifdef ENABLE_TESTS
16 
17 #include "mpt/base/numbers.hpp"
18 #include "mpt/crc/crc.hpp"
19 #include "mpt/environment/environment.hpp"
20 #include "mpt/io/base.hpp"
21 #include "mpt/io/io.hpp"
22 #include "mpt/io/io_stdstream.hpp"
23 #include "mpt/io_read/filecursor_stdstream.hpp"
24 #include "mpt/test/test.hpp"
25 #include "mpt/test/test_macros.hpp"
26 #include "mpt/uuid/uuid.hpp"
27 
28 #include "../common/version.h"
29 #include "../common/misc_util.h"
30 #include "../common/mptStringBuffer.h"
31 #include "../common/serialization_utils.h"
32 #include "../soundlib/Sndfile.h"
33 #include "../common/FileReader.h"
34 #include "../soundlib/mod_specifications.h"
35 #include "../soundlib/MIDIEvents.h"
36 #include "../soundlib/MIDIMacros.h"
37 #include "openmpt/soundbase/Copy.hpp"
38 #include "openmpt/soundbase/SampleConvert.hpp"
39 #include "openmpt/soundbase/SampleDecode.hpp"
40 #include "openmpt/soundbase/SampleEncode.hpp"
41 #include "../soundlib/SampleCopy.h"
42 #include "../soundlib/SampleNormalize.h"
43 #include "../soundlib/ModSampleCopy.h"
44 #include "../soundlib/ITCompression.h"
45 #include "../soundlib/tuningcollection.h"
46 #include "../soundlib/tuning.h"
47 #include "openmpt/soundbase/Dither.hpp"
48 #include "../common/Dither.h"
49 #ifdef MODPLUG_TRACKER
50 #include "../mptrack/Mptrack.h"
51 #include "../mptrack/Moddoc.h"
52 #include "../mptrack/ModDocTemplate.h"
53 #include "../mptrack/Mainfrm.h"
54 #include "../mptrack/Settings.h"
55 #include "../mptrack/HTTP.h"
56 #endif // MODPLUG_TRACKER
57 #include "../common/mptFileIO.h"
58 #ifdef MODPLUG_TRACKER
59 #include "mpt/crypto/hash.hpp"
60 #include "mpt/crypto/jwk.hpp"
61 #include "mpt/uuid_namespace/uuid_namespace.hpp"
62 #endif // MODPLUG_TRACKER
63 #ifdef LIBOPENMPT_BUILD
64 #include "../libopenmpt/libopenmpt_version.h"
65 #endif // LIBOPENMPT_BUILD
66 #ifndef NO_PLUGINS
67 #include "../soundlib/plugins/PlugInterface.h"
68 #endif
69 #include <sstream>
70 #include <limits>
71 #ifdef LIBOPENMPT_BUILD
72 #include <iostream>
73 #endif // LIBOPENMPT_BUILD
74 #include <istream>
75 #include <ostream>
76 #include <stdexcept>
77 #if MPT_COMPILER_MSVC
78 #include <tchar.h>
79 #endif
80 #if MPT_OS_WINDOWS
81 #include <windows.h>
82 #endif
83 #if defined(MPT_WITH_ZLIB)
84 #include <zlib.h>
85 #elif defined(MPT_WITH_MINIZ)
86 #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
87 #include <miniz/miniz.h>
88 #endif
89 
90 #define MPT_TEST_HAS_FILESYSTEM 1
91 #if MPT_OS_DJGPP
92 #undef MPT_TEST_HAS_FILESYSTEM
93 #define MPT_TEST_HAS_FILESYSTEM 0
94 #endif
95 
96 #include "TestTools.h"
97 
98 
99 // enable tests which may fail spuriously
100 //#define FLAKY_TESTS
101 
102 
103 
104 OPENMPT_NAMESPACE_BEGIN
105 
106 
107 
108 namespace Test {
109 
110 
111 
112 static MPT_NOINLINE void TestVersion();
113 static MPT_NOINLINE void TestTypes();
114 static MPT_NOINLINE void TestMisc1();
115 static MPT_NOINLINE void TestMisc2();
116 static MPT_NOINLINE void TestRandom();
117 static MPT_NOINLINE void TestCharsets();
118 static MPT_NOINLINE void TestStringFormatting();
119 static MPT_NOINLINE void TestSettings();
120 static MPT_NOINLINE void TestStringIO();
121 static MPT_NOINLINE void TestMIDIEvents();
122 static MPT_NOINLINE void TestSampleConversion();
123 static MPT_NOINLINE void TestITCompression();
124 static MPT_NOINLINE void TestPCnoteSerialization();
125 static MPT_NOINLINE void TestLoadSaveFile();
126 static MPT_NOINLINE void TestEditing();
127 
128 
129 
130 static mpt::PathString *PathPrefix = nullptr;
131 static mpt::default_prng * s_PRNG = nullptr;
132 
133 
134 
GetPathPrefix()135 mpt::PathString GetPathPrefix()
136 {
137 	if((*PathPrefix).empty())
138 	{
139 		return P_("");
140 	}
141 	return *PathPrefix + P_("/");
142 }
143 
144 
DoTests()145 void DoTests()
146 {
147 
148 	#ifdef LIBOPENMPT_BUILD
149 
150 		std::cout << std::flush;
151 		std::clog << std::flush;
152 		std::cerr << std::flush;
153 
154 		std::cout << "libopenmpt test suite" << std::endl;
155 
156 		std::cout << "Version.: " << mpt::ToCharset(mpt::Charset::ASCII, Build::GetVersionString(Build::StringVersion | Build::StringRevision | Build::StringSourceInfo | Build::StringBuildFlags | Build::StringBuildFeatures)) << std::endl;
157 		std::cout << "Compiler: " << mpt::ToCharset(mpt::Charset::ASCII, Build::GetBuildCompilerString()) << std::endl;
158 
159 		std::cout << std::flush;
160 
161 	#endif
162 
163 	#if MPT_OS_WINDOWS
164 
165 		// prefix for test suite
166 		std::wstring pathprefix = std::wstring();
167 
168 		bool libopenmpt = false;
169 		#ifdef LIBOPENMPT_BUILD
170 			libopenmpt = true;
171 		#endif
172 
173 #if !MPT_OS_WINDOWS_WINRT
174 		// set path prefix for test files (if provided)
175 		std::vector<WCHAR> buf(GetEnvironmentVariableW(L"srcdir", NULL, 0) + 1);
176 		if(GetEnvironmentVariableW(L"srcdir", buf.data(), static_cast<DWORD>(buf.size())) > 0)
177 		{
178 			pathprefix = buf.data();
179 		} else
180 #endif
181 		if(libopenmpt && IsDebuggerPresent())
182 		{
183 			pathprefix = L"../../";
184 		}
185 
186 		PathPrefix = new mpt::PathString(mpt::PathString::FromWide(pathprefix));
187 
188 	#else
189 
190 		// prefix for test suite
191 		mpt::ustring pathprefix = mpt::ustring();
192 
193 		// set path prefix for test files (if provided)
194 		mpt::ustring env_srcdir = mpt::getenv( U_("srcdir") ).value_or( U_("") );
195 		if ( !env_srcdir.empty() ) {
196 			pathprefix = env_srcdir;
197 		}
198 
199 		PathPrefix = new mpt::PathString(mpt::PathString::FromUnicode(pathprefix));
200 
201 	#endif
202 
203 	void (*do_mpt_test)(void) = []() {
204 		mpt_test_reporter reporter{};
205 		mpt::test::run_all(reporter);
206 	};
207 	DO_TEST(do_mpt_test);
208 
209 	mpt::random_device rd;
210 	s_PRNG = new mpt::default_prng(mpt::make_prng<mpt::default_prng>(rd));
211 
212 	DO_TEST(TestVersion);
213 	DO_TEST(TestTypes);
214 	DO_TEST(TestMisc1);
215 	DO_TEST(TestMisc2);
216 	DO_TEST(TestRandom);
217 	DO_TEST(TestCharsets);
218 	DO_TEST(TestStringFormatting);
219 	DO_TEST(TestSettings);
220 	DO_TEST(TestStringIO);
221 	DO_TEST(TestMIDIEvents);
222 	DO_TEST(TestSampleConversion);
223 	DO_TEST(TestITCompression);
224 
225 	// slower tests, require opening a CModDoc
226 	DO_TEST(TestPCnoteSerialization);
227 	DO_TEST(TestLoadSaveFile);
228 	DO_TEST(TestEditing);
229 
230 	delete s_PRNG;
231 	s_PRNG = nullptr;
232 
233 	delete PathPrefix;
234 	PathPrefix = nullptr;
235 }
236 
237 
238 static mpt::PathString GetTempFilenameBase();
239 
240 
RemoveFile(const mpt::PathString & filename)241 static void RemoveFile(const mpt::PathString &filename)
242 {
243 	#if MPT_OS_WINDOWS
244 		for(int retry=0; retry<10; retry++)
245 		{
246 			if(DeleteFile(filename.AsNative().c_str()) != FALSE)
247 			{
248 				break;
249 			}
250 			// wait for windows virus scanners
251 			Sleep(10);
252 		}
253 	#else
254 		remove(filename.AsNative().c_str());
255 	#endif
256 }
257 
258 
259 // Test if functions related to program version data work
TestVersion()260 static MPT_NOINLINE void TestVersion()
261 {
262 	//Verify that macros and functions work.
263 	{
264 		VERIFY_EQUAL( Version::Parse(Version::Current().ToUString()), Version::Current() );
265 		VERIFY_EQUAL( Version::Parse(Version::Current().ToUString()).ToUString(), Version::Current().ToUString() );
266 		VERIFY_EQUAL( Version(18285096).ToUString(), U_("1.17.02.28") );
267 		VERIFY_EQUAL( Version::Parse(U_("1.17.02.28")), Version(18285096) );
268 		VERIFY_EQUAL( Version::Parse(U_("1.fe.02.28")), Version(0x01fe0228) );
269 		VERIFY_EQUAL( Version::Parse(U_("01.fe.02.28")), Version(0x01fe0228) );
270 		VERIFY_EQUAL( Version::Parse(U_("1.22")), Version(0x01220000) );
271 		VERIFY_EQUAL( MPT_V("1.17.02.28"), Version(18285096) );
272 		VERIFY_EQUAL( MPT_V("1.fe.02.28"), Version(0x01fe0228) );
273 		VERIFY_EQUAL( MPT_V("01.fe.02.28"), Version(0x01fe0228) );
274 		VERIFY_EQUAL( MPT_V("1.22"), Version(0x01220000) );
275 		VERIFY_EQUAL( MPT_V("1.19.02.00").WithoutTestNumber(), MPT_V("1.19.02.00"));
276 		VERIFY_EQUAL( MPT_V("1.18.03.20").WithoutTestNumber(), MPT_V("1.18.03.00"));
277 		VERIFY_EQUAL( MPT_V("1.18.01.13").IsTestVersion(), true);
278 		VERIFY_EQUAL( MPT_V("1.19.01.00").IsTestVersion(), false);
279 		VERIFY_EQUAL( MPT_V("1.17.02.54").IsTestVersion(), false);
280 		VERIFY_EQUAL( MPT_V("1.18.00.00").IsTestVersion(), false);
281 		VERIFY_EQUAL( MPT_V("1.18.02.00").IsTestVersion(), false);
282 		VERIFY_EQUAL( MPT_V("1.18.02.01").IsTestVersion(), true);
283 
284 		// Ensure that versions ending in .00.00 (which are ambiguous to truncated version numbers in certain file formats (e.g. S3M and IT) do not get qualified as test builds.
285 		VERIFY_EQUAL( MPT_V("1.23.00.00").IsTestVersion(), false);
286 
287 		static_assert( MPT_V("1.17.2.28").GetRawVersion() == 18285096 );
288 		static_assert( MPT_V("1.17.02.48").GetRawVersion() == 18285128 );
289 		static_assert( MPT_V("01.17.02.52").GetRawVersion() == 18285138 );
290 		// Ensure that bit-shifting works (used in some mod loaders for example)
291 		static_assert( MPT_V("01.17.00.00").GetRawVersion() == 0x0117 << 16 );
292 		static_assert( MPT_V("01.17.03.00").GetRawVersion() >> 8 == 0x011703 );
293 
294 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), false);
295 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), false);
296 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), true);
297 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05"))), false);
298 
299 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), true);
300 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), false);
301 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), false);
302 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05"))), false);
303 
304 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), false);
305 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), false);
306 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), false);
307 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsNewerThan(VersionWithRevision::Parse(U_("1.30.00.05"))), false);
308 
309 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), false);
310 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), false);
311 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), false);
312 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsOlderThan(VersionWithRevision::Parse(U_("1.30.00.05"))), false);
313 
314 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), false);
315 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), true);
316 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), false);
317 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05"))), false);
318 
319 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), false);
320 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), true);
321 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), false);
322 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05-r13099")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05"))), true);
323 
324 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), false);
325 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), false);
326 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), false);
327 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEqualTo(VersionWithRevision::Parse(U_("1.30.00.05"))), true);
328 
329 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05-r13100"))), true);
330 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05-r13099"))), true);
331 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05-r13098"))), true);
332 		VERIFY_EQUAL(VersionWithRevision::Parse(U_("1.30.00.05")).IsEquivalentTo(VersionWithRevision::Parse(U_("1.30.00.05"))), true);
333 
334 	}
335 
336 #ifdef MODPLUG_TRACKER
337 	//Verify that the version obtained from the executable file is the same as
338 	//defined in Version.
339 	{
340 		WCHAR szFullPath[MAX_PATH];
341 		DWORD dwVerHnd;
342 		DWORD dwVerInfoSize;
343 
344 		// Get version information from the application
345 		::GetModuleFileNameW(NULL, szFullPath, mpt::saturate_cast<DWORD>(std::size(szFullPath)));
346 		dwVerInfoSize = ::GetFileVersionInfoSizeW(szFullPath, &dwVerHnd);
347 		if (!dwVerInfoSize)
348 			throw std::runtime_error("!dwVerInfoSize is true");
349 
350 		std::vector<TCHAR> pVersionInfo(dwVerInfoSize);
351 
352 		WCHAR *szVer = nullptr;
353 		UINT uVerLength;
354 		if (!(::GetFileVersionInfoW(szFullPath, (DWORD)dwVerHnd,
355 								   (DWORD)dwVerInfoSize, pVersionInfo.data())))
356 		{
357 			throw std::runtime_error("GetFileVersionInfo() returned false");
358 		}
359 		if (!(::VerQueryValueW(pVersionInfo.data(), L"\\StringFileInfo\\040904b0\\FileVersion",
360 							  (LPVOID*)&szVer, &uVerLength))) {
361 			throw std::runtime_error("VerQueryValue() returned false");
362 		}
363 
364 		mpt::ustring version = mpt::ToUnicode(szVer);
365 
366 		VERIFY_EQUAL( version, mpt::ufmt::val(Version::Current()) );
367 		VERIFY_EQUAL( Version::Parse(version), Version::Current() );
368 	}
369 #endif
370 
371 #ifdef LIBOPENMPT_BUILD
372 #if MPT_TEST_HAS_FILESYSTEM
373 #if !MPT_OS_DJGPP
374 	mpt::PathString version_mk = GetPathPrefix() + P_("libopenmpt/libopenmpt_version.mk");
375 	mpt::ifstream f(version_mk, std::ios::in);
376 	VERIFY_EQUAL(f ? true : false, true);
377 	std::map<std::string, std::string> fields;
378 	std::string line;
379 	while(std::getline(f, line))
380 	{
381 		line = mpt::trim(line);
382 		if(line.empty())
383 		{
384 			continue;
385 		}
386 		std::vector<std::string> line_fields = mpt::String::Split<std::string>(line, std::string("="));
387 		VERIFY_EQUAL_NONCONT(line_fields.size(), 2u);
388 		line_fields[0] = mpt::trim(line_fields[0]);
389 		line_fields[1] = mpt::trim(line_fields[1]);
390 		VERIFY_EQUAL_NONCONT(line_fields[0].length() > 0, true);
391 		fields[line_fields[0]] = line_fields[1];
392 	}
393 	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_MAJOR"], mpt::afmt::val(OPENMPT_API_VERSION_MAJOR));
394 	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_MINOR"], mpt::afmt::val(OPENMPT_API_VERSION_MINOR));
395 	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_PATCH"], mpt::afmt::val(OPENMPT_API_VERSION_PATCH));
396 	VERIFY_EQUAL(fields["LIBOPENMPT_VERSION_PREREL"], mpt::afmt::val(OPENMPT_API_VERSION_PREREL));
397 	if(std::string(OPENMPT_API_VERSION_PREREL).length() > 0)
398 	{
399 		VERIFY_EQUAL(std::string(OPENMPT_API_VERSION_PREREL).substr(0, 1), "-");
400 	}
401 	VERIFY_EQUAL(OPENMPT_API_VERSION_IS_PREREL, (std::string(OPENMPT_API_VERSION_PREREL).length() > 0) ? 1 : 0);
402 
403 	VERIFY_EQUAL(fields["LIBOPENMPT_LTVER_CURRENT"].length() > 0, true);
404 	VERIFY_EQUAL(fields["LIBOPENMPT_LTVER_REVISION"].length() > 0, true);
405 	VERIFY_EQUAL(fields["LIBOPENMPT_LTVER_AGE"].length() > 0, true);
406 #endif // !MPT_OS_DJGPP
407 #endif // MPT_TEST_HAS_FILESYSTEM
408 #endif // LIBOPENMPT_BUILD
409 
410 }
411 
412 
413 // Test if data types are interpreted correctly
TestTypes()414 static MPT_NOINLINE void TestTypes()
415 {
416 
417 	static_assert(sizeof(std::uintptr_t) == sizeof(void*));
418 	#if defined(__SIZEOF_POINTER__)
419 		static_assert(__SIZEOF_POINTER__ == mpt::pointer_size);
420 		static_assert(__SIZEOF_POINTER__ == sizeof(void*));
421 	#endif
422 
423 	VERIFY_EQUAL(int8_min, std::numeric_limits<int8>::min());
424 	VERIFY_EQUAL(int8_max, std::numeric_limits<int8>::max());
425 	VERIFY_EQUAL(uint8_max, std::numeric_limits<uint8>::max());
426 
427 	VERIFY_EQUAL(int16_min, std::numeric_limits<int16>::min());
428 	VERIFY_EQUAL(int16_max, std::numeric_limits<int16>::max());
429 	VERIFY_EQUAL(uint16_max, std::numeric_limits<uint16>::max());
430 
431 	VERIFY_EQUAL(int32_min, std::numeric_limits<int32>::min());
432 	VERIFY_EQUAL(int32_max, std::numeric_limits<int32>::max());
433 	VERIFY_EQUAL(uint32_max, std::numeric_limits<uint32>::max());
434 
435 	VERIFY_EQUAL(int64_min, std::numeric_limits<int64>::min());
436 	VERIFY_EQUAL(int64_max, std::numeric_limits<int64>::max());
437 	VERIFY_EQUAL(uint64_max, std::numeric_limits<uint64>::max());
438 
439 
440 	static_assert(int8_max == std::numeric_limits<int8>::max());
441 	static_assert(uint8_max == std::numeric_limits<uint8>::max());
442 
443 	static_assert(int16_max == std::numeric_limits<int16>::max());
444 	static_assert(uint16_max == std::numeric_limits<uint16>::max());
445 
446 	static_assert(int32_max == std::numeric_limits<int32>::max());
447 	static_assert(uint32_max == std::numeric_limits<uint32>::max());
448 
449 	static_assert(int64_max == std::numeric_limits<int64>::max());
450 	static_assert(uint64_max == std::numeric_limits<uint64>::max());
451 
452 }
453 
454 
455 
456 #ifdef MODPLUG_TRACKER
457 
458 // In tracker debug builds, the sprintf-like function is retained in order to be able to validate our own formatting against sprintf.
459 
460 // There are 4 reasons why this is not available for library code:
461 //  1. printf-like functionality is not type-safe.
462 //  2. There are portability problems with char/wchar_t and the semantics of %s/%ls/%S .
463 //  3. There are portability problems with specifying format for 64bit integers.
464 //  4. Formatting of floating point values depends on the currently set C locale.
465 //     A library is not allowed to mock with that and thus cannot influence the behavior in this case.
466 
467 template <typename T>
StringFormat(std::string format,T x)468 static std::string StringFormat(std::string format, T x)
469 {
470 	#if MPT_COMPILER_MSVC
471 		// Count the needed array size.
472 		const size_t nCount = _scprintf(format.c_str(), x); // null character not included.
473 		std::vector<char> buf(nCount + 1); // + 1 is for null terminator.
474 		sprintf_s(&(buf[0]), buf.size(), format.c_str(), x);
475 		return &(buf[0]);
476 	#else
477 		int size = snprintf(NULL, 0, format.c_str(), x); // get required size, requires c99 compliant snprintf which msvc does not have
478 		std::vector<char> temp(size + 1);
479 		snprintf(&(temp[0]), size + 1, format.c_str(), x);
480 		return &(temp[0]);
481 	#endif
482 }
483 
484 #endif
485 
486 template <typename Tfloat>
TestFloatFormat(Tfloat x,std::string format,mpt::FormatFlags f,std::size_t width=0,int precision=-1)487 static void TestFloatFormat(Tfloat x, std::string format, mpt::FormatFlags f, std::size_t width = 0, int precision = -1)
488 {
489 #ifdef MODPLUG_TRACKER
490 	std::string str_sprintf = StringFormat(format, x);
491 #endif
492 	std::string str_iostreams = mpt::afmt::fmt(x, mpt::FormatSpec().SetFlags(f).SetWidth(width).SetPrecision(precision));
493 #ifdef MODPLUG_TRACKER
494 	//MPT_LOG_GLOBAL(LogDebug, "test", mpt::ToUnicode(mpt::Charset::ASCII, str_sprintf));
495 #endif
496 	//MPT_LOG_GLOBAL(LogDebug, "test", mpt::ToUnicode(mpt::Charset::ASCII, str_iostreams));
497 #ifdef MODPLUG_TRACKER
498 #if MPT_MSVC_AT_LEAST(2019,4) || MPT_GCC_AT_LEAST(11,1,0)
499 	// to_chars generates shortest form instead of 0-padded precision
500 	if(precision != -1)
501 #endif
502 	{
503 		VERIFY_EQUAL(str_iostreams, str_sprintf); // this will fail with a set c locale (and there is nothing that can be done about that in libopenmpt)
504 	}
505 #else
506 	MPT_UNREFERENCED_PARAMETER(format);
507 	MPT_UNUSED_VARIABLE(str_iostreams);
508 #endif
509 }
510 
511 
512 template <typename Tfloat>
TestFloatFormats(Tfloat x)513 static void TestFloatFormats(Tfloat x)
514 {
515 
516 	TestFloatFormat(x, "%.8g", mpt::afmt::NotaNrm | mpt::afmt::FillOff, 0, 8);
517 
518 	TestFloatFormat(x, MPT_AFORMAT("%.{}g")(std::numeric_limits<Tfloat>::max_digits10), mpt::afmt::NotaNrm | mpt::afmt::FillOff);
519 	TestFloatFormat(x, MPT_AFORMAT("%.{}f")(std::numeric_limits<Tfloat>::digits10), mpt::afmt::NotaFix | mpt::afmt::FillOff);
520 	TestFloatFormat(x, MPT_AFORMAT("%.{}e")(std::numeric_limits<Tfloat>::max_digits10 - 1), mpt::afmt::NotaSci | mpt::afmt::FillOff);
521 
522 	TestFloatFormat(x, "%.0f", mpt::afmt::NotaFix | mpt::afmt::FillOff, 0, 0);
523 	TestFloatFormat(x, "%.1f", mpt::afmt::NotaFix | mpt::afmt::FillOff, 0, 1);
524 	TestFloatFormat(x, "%.2f", mpt::afmt::NotaFix | mpt::afmt::FillOff, 0, 2);
525 	TestFloatFormat(x, "%.3f", mpt::afmt::NotaFix | mpt::afmt::FillOff, 0, 3);
526 	TestFloatFormat(x, "%0.1f", mpt::afmt::NotaFix | mpt::afmt::FillNul, 0, 1);
527 	TestFloatFormat(x, "%02.0f", mpt::afmt::NotaFix | mpt::afmt::FillNul, 2, 0);
528 }
529 
530 
531 
TestStringFormatting()532 static MPT_NOINLINE void TestStringFormatting()
533 {
534 	VERIFY_EQUAL(mpt::afmt::val(1.5f), "1.5");
535 	VERIFY_EQUAL(mpt::afmt::val(true), "1");
536 	VERIFY_EQUAL(mpt::afmt::val(false), "0");
537 	//VERIFY_EQUAL(mpt::afmt::val('A'), "A"); // deprecated
538 	//VERIFY_EQUAL(mpt::afmt::val(L'A'), "A"); // deprecated
539 
540 	VERIFY_EQUAL(mpt::afmt::val(0), "0");
541 	VERIFY_EQUAL(mpt::afmt::val(-23), "-23");
542 	VERIFY_EQUAL(mpt::afmt::val(42), "42");
543 
544 	VERIFY_EQUAL(mpt::afmt::hex0<3>((int32)-1), "-001");
545 	VERIFY_EQUAL(mpt::afmt::hex((int32)-1), "-1");
546 	VERIFY_EQUAL(mpt::afmt::hex(-0xabcde), "-abcde");
547 	VERIFY_EQUAL(mpt::afmt::hex(int32_min), "-80000000");
548 	VERIFY_EQUAL(mpt::afmt::hex(int32_min + 1), "-7fffffff");
549 	VERIFY_EQUAL(mpt::afmt::hex(0x123e), "123e");
550 	VERIFY_EQUAL(mpt::afmt::hex0<6>(0x123e), "00123e");
551 	VERIFY_EQUAL(mpt::afmt::hex0<2>(0x123e), "123e");
552 
553 	VERIFY_EQUAL(mpt::afmt::dec0<0>(1), "1");
554 	VERIFY_EQUAL(mpt::afmt::dec0<1>(1), "1");
555 	VERIFY_EQUAL(mpt::afmt::dec0<2>(1), "01");
556 	VERIFY_EQUAL(mpt::afmt::dec0<3>(1), "001");
557 	VERIFY_EQUAL(mpt::afmt::dec0<0>(11), "11");
558 	VERIFY_EQUAL(mpt::afmt::dec0<1>(11), "11");
559 	VERIFY_EQUAL(mpt::afmt::dec0<2>(11), "11");
560 	VERIFY_EQUAL(mpt::afmt::dec0<3>(11), "011");
561 	VERIFY_EQUAL(mpt::afmt::dec0<0>(-1), "-1");
562 	VERIFY_EQUAL(mpt::afmt::dec0<1>(-1), "-1");
563 	VERIFY_EQUAL(mpt::afmt::dec0<2>(-1), "-01");
564 	VERIFY_EQUAL(mpt::afmt::dec0<3>(-1), "-001");
565 
566 	VERIFY_EQUAL(mpt::ufmt::HEX0<7>(0xa2345678), U_("A2345678"));
567 	VERIFY_EQUAL(mpt::ufmt::HEX0<8>(0xa2345678), U_("A2345678"));
568 	VERIFY_EQUAL(mpt::ufmt::HEX0<9>(0xa2345678), U_("0A2345678"));
569 	VERIFY_EQUAL(mpt::ufmt::HEX0<10>(0xa2345678), U_("00A2345678"));
570 
571 #if MPT_WSTRING_FORMAT
572 	VERIFY_EQUAL(mpt::wfmt::hex(0x123e), L"123e");
573 	VERIFY_EQUAL(mpt::wfmt::hex0<6>(0x123e), L"00123e");
574 	VERIFY_EQUAL(mpt::wfmt::hex0<2>(0x123e), L"123e");
575 #endif
576 
577 	VERIFY_EQUAL(mpt::afmt::val(-87.0f), "-87");
578 	if(mpt::afmt::val(-0.5e-6) != "-5e-007"
579 		&& mpt::afmt::val(-0.5e-6) != "-5e-07"
580 		&& mpt::afmt::val(-0.5e-6) != "-5e-7"
581 		&& mpt::afmt::val(-0.5e-6) != "-4.9999999999999998e-7"
582 		&& mpt::afmt::val(-0.5e-6) != "-4.9999999999999998e-07"
583 		&& mpt::afmt::val(-0.5e-6) != "-4.9999999999999998e-007"
584 		)
585 	{
586 		VERIFY_EQUAL(true, false);
587 	}
588 	if(mpt::afmt::val(-1.0 / 65536.0) != "-1.52587890625e-005"
589 		&& mpt::afmt::val(-1.0 / 65536.0) != "-1.52587890625e-05"
590 		&& mpt::afmt::val(-1.0 / 65536.0) != "-1.52587890625e-5"
591 		)
592 	{
593 		VERIFY_EQUAL(true, false);
594 	}
595 	if(mpt::afmt::val(-1.0f / 65536.0f) != "-1.52587891e-005"
596 		&& mpt::afmt::val(-1.0f / 65536.0f) != "-1.52587891e-05"
597 		&& mpt::afmt::val(-1.0f / 65536.0f) != "-1.52587891e-5"
598 		&& mpt::afmt::val(-1.0f / 65536.0f) != "-1.5258789e-005"
599 		&& mpt::afmt::val(-1.0f / 65536.0f) != "-1.5258789e-05"
600 		&& mpt::afmt::val(-1.0f / 65536.0f) != "-1.5258789e-5"
601 		)
602 	{
603 		VERIFY_EQUAL(true, false);
604 	}
605 	if(mpt::afmt::val(58.65403492763) != "58.654034927630001"
606 		&& mpt::afmt::val(58.65403492763) != "58.65403492763"
607 		)
608 	{
609 		VERIFY_EQUAL(true, false);
610 	}
611 	VERIFY_EQUAL(mpt::afmt::flt(58.65403492763, 6), "58.654");
612 	VERIFY_EQUAL(mpt::afmt::fix(23.42, 1), "23.4");
613 	VERIFY_EQUAL(mpt::afmt::fix(234.2, 1), "234.2");
614 	VERIFY_EQUAL(mpt::afmt::fix(2342.0, 1), "2342.0");
615 
616 	VERIFY_EQUAL(mpt::afmt::dec(2, ';', 2345678), std::string("2;34;56;78"));
617 	VERIFY_EQUAL(mpt::afmt::dec(2, ';', 12345678), std::string("12;34;56;78"));
618 	VERIFY_EQUAL(mpt::afmt::hex(3, ':', 0xa2345678), std::string("a2:345:678"));
619 
620 	VERIFY_EQUAL(mpt::ufmt::dec(2, ';', 12345678), U_("12;34;56;78"));
621 	VERIFY_EQUAL(mpt::ufmt::hex(3, ':', 0xa2345678), U_("a2:345:678"));
622 
623 	VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', 0xa2345678), U_("A2:345:678"));
624 	VERIFY_EQUAL(mpt::ufmt::HEX0<8>(3, ':', 0xa2345678), U_("A2:345:678"));
625 	VERIFY_EQUAL(mpt::ufmt::HEX0<9>(3, ':', 0xa2345678), U_("0A2:345:678"));
626 	VERIFY_EQUAL(mpt::ufmt::HEX0<10>(3, ':', 0xa2345678), U_("0:0A2:345:678"));
627 	VERIFY_EQUAL(mpt::ufmt::HEX0<11>(3, ':', 0xa2345678), U_("00:0A2:345:678"));
628 	VERIFY_EQUAL(mpt::ufmt::HEX0<12>(3, ':', 0xa2345678), U_("000:0A2:345:678"));
629 	VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', -0x12345678), U_("-12:345:678"));
630 	VERIFY_EQUAL(mpt::ufmt::HEX0<8>(3, ':', -0x12345678), U_("-12:345:678"));
631 	VERIFY_EQUAL(mpt::ufmt::HEX0<9>(3, ':', -0x12345678), U_("-012:345:678"));
632 	VERIFY_EQUAL(mpt::ufmt::HEX0<10>(3, ':', -0x12345678), U_("-0:012:345:678"));
633 	VERIFY_EQUAL(mpt::ufmt::HEX0<11>(3, ':', -0x12345678), U_("-00:012:345:678"));
634 	VERIFY_EQUAL(mpt::ufmt::HEX0<12>(3, ':', -0x12345678), U_("-000:012:345:678"));
635 
636 	VERIFY_EQUAL(mpt::ufmt::HEX0<5>(3, ':', 0x345678), U_("345:678"));
637 	VERIFY_EQUAL(mpt::ufmt::HEX0<6>(3, ':', 0x345678), U_("345:678"));
638 	VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', 0x345678), U_("0:345:678"));
639 	VERIFY_EQUAL(mpt::ufmt::HEX0<5>(3, ':', -0x345678), U_("-345:678"));
640 	VERIFY_EQUAL(mpt::ufmt::HEX0<6>(3, ':', -0x345678), U_("-345:678"));
641 	VERIFY_EQUAL(mpt::ufmt::HEX0<7>(3, ':', -0x345678), U_("-0:345:678"));
642 
643 	VERIFY_EQUAL(mpt::afmt::left(3, "a"), "a  ");
644 	VERIFY_EQUAL(mpt::afmt::right(3, "a"), "  a");
645 	VERIFY_EQUAL(mpt::afmt::center(3, "a"), " a ");
646 	VERIFY_EQUAL(mpt::afmt::center(4, "a"), " a  ");
647 
648 	#if defined(MPT_WITH_MFC)
649 		VERIFY_EQUAL(mpt::cfmt::left(3, CString(_T("a"))), CString(_T("a  ")));
650 		VERIFY_EQUAL(mpt::cfmt::right(3, CString(_T("a"))), CString(_T("  a")));
651 		VERIFY_EQUAL(mpt::cfmt::center(3, CString(_T("a"))), CString(_T(" a ")));
652 		VERIFY_EQUAL(mpt::cfmt::center(4, CString(_T("a"))), CString(_T(" a  ")));
653 	#endif // MPT_WITH_MFC
654 
655 	VERIFY_EQUAL(ConvertStrTo<uint32>("586"), 586u);
656 	VERIFY_EQUAL(ConvertStrTo<uint32>("2147483647"), (uint32)int32_max);
657 	VERIFY_EQUAL(ConvertStrTo<uint32>("4294967295"), uint32_max);
658 
659 	VERIFY_EQUAL(ConvertStrTo<int64>("-9223372036854775808"), int64_min);
660 	VERIFY_EQUAL(ConvertStrTo<int64>("-159"), -159);
661 	VERIFY_EQUAL(ConvertStrTo<int64>("9223372036854775807"), int64_max);
662 
663 	VERIFY_EQUAL(ConvertStrTo<uint64>("85059"), 85059u);
664 	VERIFY_EQUAL(ConvertStrTo<uint64>("9223372036854775807"), (uint64)int64_max);
665 	VERIFY_EQUAL(ConvertStrTo<uint64>("18446744073709551615"), uint64_max);
666 
667 	VERIFY_EQUAL(ConvertStrTo<float>("-87.0"), -87.0f);
668 #if !MPT_OS_DJGPP
669 	VERIFY_EQUAL(ConvertStrTo<double>("-0.5e-6"), -0.5e-6);
670 #endif
671 #if !MPT_OS_DJGPP
672 	VERIFY_EQUAL(ConvertStrTo<double>("58.65403492763"), 58.65403492763);
673 #else
674 	VERIFY_EQUAL_EPS(ConvertStrTo<double>("58.65403492763"), 58.65403492763, 0.0001);
675 #endif
676 
677 	VERIFY_EQUAL(ConvertStrTo<float>(mpt::afmt::val(-87.0)), -87.0f);
678 #if !MPT_OS_DJGPP
679 	VERIFY_EQUAL(ConvertStrTo<double>(mpt::afmt::val(-0.5e-6)), -0.5e-6);
680 #endif
681 
682 	VERIFY_EQUAL(mpt::String::Parse::Hex<unsigned char>("fe"), 254);
683 #if MPT_WSTRING_FORMAT
684 	VERIFY_EQUAL(mpt::String::Parse::Hex<unsigned char>(L"fe"), 254);
685 #endif
686 	VERIFY_EQUAL(mpt::String::Parse::Hex<unsigned int>(U_("ffff")), 65535);
687 
688 	TestFloatFormats(0.0f);
689 	TestFloatFormats(-0.0f);
690 	TestFloatFormats(1.0f);
691 	TestFloatFormats(-1.0f);
692 	TestFloatFormats(0.1f);
693 	TestFloatFormats(-0.1f);
694 	TestFloatFormats(1000000000.0f);
695 	TestFloatFormats(-1000000000.0f);
696 	TestFloatFormats(0.0000000001f);
697 	TestFloatFormats(-0.0000000001f);
698 	TestFloatFormats(6.12345f);
699 
700 	TestFloatFormats(0.0);
701 	TestFloatFormats(-0.0);
702 	TestFloatFormats(1.0);
703 	TestFloatFormats(-1.0);
704 	TestFloatFormats(0.1);
705 	TestFloatFormats(-0.1);
706 	TestFloatFormats(1000000000.0);
707 	TestFloatFormats(-1000000000.0);
708 	TestFloatFormats(0.0000000001);
709 	TestFloatFormats(-0.0000000001);
710 	TestFloatFormats(6.12345);
711 
712 	TestFloatFormats(42.1234567890);
713 	TestFloatFormats(0.1234567890);
714 	TestFloatFormats(1234567890000000.0);
715 	TestFloatFormats(0.0000001234567890);
716 
717 	TestFloatFormats(mpt::numbers::pi);
718 	TestFloatFormats(3.14159265358979323846);
719 	TestFloatFormats(3.14159265358979323846f);
720 
721 	VERIFY_EQUAL(mpt::afmt::flt(6.12345, 3), "6.12");
722 	VERIFY_EQUAL(mpt::afmt::fix(6.12345, 3), "6.123");
723 	VERIFY_EQUAL(mpt::afmt::flt(6.12345, 4), "6.123");
724 	VERIFY_EQUAL(mpt::afmt::fix(6.12345, 4), "6.1235");
725 
726 #if MPT_WSTRING_FORMAT
727 	VERIFY_EQUAL(mpt::wfmt::flt(6.12345, 3), L"6.12");
728 	VERIFY_EQUAL(mpt::wfmt::fix(6.12345, 3), L"6.123");
729 	VERIFY_EQUAL(mpt::wfmt::flt(6.12345, 4), L"6.123");
730 #endif
731 
732 	static_assert(mpt::parse_format_string_argument_count("") == 0);
733 	static_assert(mpt::parse_format_string_argument_count("{{") == 0);
734 	static_assert(mpt::parse_format_string_argument_count("}}") == 0);
735 	static_assert(mpt::parse_format_string_argument_count("{}") == 1);
736 	static_assert(mpt::parse_format_string_argument_count("{}{}") == 2);
737 	static_assert(mpt::parse_format_string_argument_count("{0}{1}") == 2);
738 
739 	// basic
740 	VERIFY_EQUAL(MPT_AFORMAT("{}{}{}")(1,2,3), "123");
741 	VERIFY_EQUAL(MPT_AFORMAT("{2}{1}{0}")(1,2,3), "321");
742 
743 	VERIFY_EQUAL(MPT_AFORMAT("{2}{1}{0}{4}{3}{6}{5}{7}{10}{9}{8}")(0,1,2,3,4,5,6,7,8,9,"a"), "21043657a98");
744 
745 	//VERIFY_EQUAL(MPT_AFORMAT("{2}{1}{0}{2}{1}{0}{10}{9}{8}")(0,1,2,3,4,5,6,7,8,9,"a"), "210210a98");
746 
747 #if MPT_WSTRING_FORMAT
748 	VERIFY_EQUAL(MPT_WFORMAT("{}{}{}")(1,2,3), L"123");
749 #endif
750 
751 	// escaping behviour
752 	VERIFY_EQUAL(MPT_AFORMAT("%")(), "%");
753 	VERIFY_EQUAL(MPT_AFORMAT("%")(), "%");
754 	VERIFY_EQUAL(MPT_AFORMAT("%%")(), "%%");
755 	VERIFY_EQUAL(MPT_AFORMAT("{}")("a"), "a");
756 	VERIFY_EQUAL(MPT_AFORMAT("{}%")("a"), "a%");
757 	VERIFY_EQUAL(MPT_AFORMAT("{}%")("a"), "a%");
758 	VERIFY_EQUAL(MPT_AFORMAT("{}%%")("a"), "a%%");
759 	VERIFY_EQUAL(MPT_AFORMAT("%1")(), "%1");
760 	VERIFY_EQUAL(MPT_AFORMAT("%{}")("a"), "%a");
761 	VERIFY_EQUAL(MPT_AFORMAT("%b")(), "%b");
762 	VERIFY_EQUAL(MPT_AFORMAT("{{}}")(), "{}");
763 	VERIFY_EQUAL(MPT_AFORMAT("{{{}}}")("a"), "{a}");
764 
765 #if defined(MPT_WITH_MFC)
766 	VERIFY_EQUAL(mpt::ufmt::val(CString(_T("foobar"))), U_("foobar"));
767 	VERIFY_EQUAL(mpt::ufmt::val(CString(_T("foobar"))), U_("foobar"));
768 	VERIFY_EQUAL(MPT_CFORMAT("{}{}{}")(1,2,3), _T("123"));
769 	VERIFY_EQUAL(MPT_CFORMAT("{}{}{}")(1,mpt::cfmt::dec0<3>(2),3), _T("10023"));
770 #endif // MPT_WITH_MFC
771 
772 	FlagSet<MODTYPE> foo;
773 	foo.set(MOD_TYPE_MOD, true);
774 	VERIFY_EQUAL(MPT_UFORMAT("{}")(foo), U_("00000000000000000000000000000001"));
775 
776 }
777 
778 
779 namespace {
780 
781 struct Gregorian {
782 	int Y,M,D,h,m,s;
FromTMTest::__anon13919bc00211::Gregorian783 	static Gregorian FromTM(tm t) {
784 		Gregorian g;
785 		g.Y = t.tm_year + 1900;
786 		g.M = t.tm_mon + 1;
787 		g.D = t.tm_mday;
788 		g.h = t.tm_hour;
789 		g.m = t.tm_min;
790 		g.s = t.tm_sec;
791 		return g;
792 	}
ToTMTest::__anon13919bc00211::Gregorian793 	static tm ToTM(Gregorian g) {
794 		tm t;
795 		MemsetZero(t);
796 		t.tm_year = g.Y - 1900;
797 		t.tm_mon = g.M - 1;
798 		t.tm_mday = g.D;
799 		t.tm_hour = g.h;
800 		t.tm_min = g.m;
801 		t.tm_sec = g.s;
802 		return t;
803 	}
804 };
805 
operator ==(Gregorian a,Gregorian b)806 inline bool operator ==(Gregorian a, Gregorian b) {
807 	return a.Y == b.Y && a.M == b.M && a.D == b.D && a.h == b.h && a.m == b.m && a.s == b.s;
808 }
809 
810 }
811 
TestDate1(int s,int m,int h,int D,int M,int Y)812 static int64 TestDate1(int s, int m, int h, int D, int M, int Y) {
813 	return mpt::Date::Unix::FromUTC(Gregorian::ToTM(Gregorian{Y,M,D,h,m,s}));
814 }
815 
TestDate2(int s,int m,int h,int D,int M,int Y)816 static Gregorian TestDate2(int s, int m, int h, int D, int M, int Y) {
817 	return Gregorian{Y,M,D,h,m,s};
818 }
819 
820 
TestMisc1()821 static MPT_NOINLINE void TestMisc1()
822 {
823 
824 	VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_MAX), false);
825 	VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_PC), true);
826 	VERIFY_EQUAL(ModCommand::IsPcNote(NOTE_PCS), true);
827 
828 	VERIFY_EQUAL(CModSpecifications::ExtensionToType(".mod"), MOD_TYPE_MOD);
829 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("mod"), MOD_TYPE_MOD);
830 	VERIFY_EQUAL(CModSpecifications::ExtensionToType(".s3m"), MOD_TYPE_S3M);
831 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("s3m"), MOD_TYPE_S3M);
832 	VERIFY_EQUAL(CModSpecifications::ExtensionToType(".xm"), MOD_TYPE_XM);
833 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("xm"), MOD_TYPE_XM);
834 	VERIFY_EQUAL(CModSpecifications::ExtensionToType(".it"), MOD_TYPE_IT);
835 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("it"), MOD_TYPE_IT);
836 	VERIFY_EQUAL(CModSpecifications::ExtensionToType(".itp"), MOD_TYPE_NONE);
837 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("itp"), MOD_TYPE_NONE);
838 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("mptm"), MOD_TYPE_MPT);
839 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("invalidExtension"), MOD_TYPE_NONE);
840 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("ita"), MOD_TYPE_NONE);
841 	VERIFY_EQUAL(CModSpecifications::ExtensionToType("s2m"), MOD_TYPE_NONE);
842 	VERIFY_EQUAL(CModSpecifications::ExtensionToType(""), MOD_TYPE_NONE);
843 
844 }
845 
846 
TestMisc2()847 static MPT_NOINLINE void TestMisc2()
848 {
849 
850 	// Check for completeness of supported effect list in mod specifications
851 	for(const auto &spec : ModSpecs::Collection)
852 	{
853 		VERIFY_EQUAL(strlen(spec->commands), (size_t)MAX_EFFECTS);
854 		VERIFY_EQUAL(strlen(spec->volcommands), (size_t)MAX_VOLCMDS);
855 	}
856 
857 #ifdef MODPLUG_TRACKER
858 #ifdef MPT_ENABLE_FILEIO
859 
860 	{
861 		std::vector<std::byte> data;
862 		data.push_back(mpt::as_byte(0));
863 		data.push_back(mpt::as_byte(255));
864 		data.push_back(mpt::as_byte(1));
865 		data.push_back(mpt::as_byte(2));
866 		mpt::PathString fn = GetTempFilenameBase() + P_("lazy");
867 		RemoveFile(fn);
868 		mpt::LazyFileRef f(fn);
869 		f = data;
870 		std::vector<std::byte> data2;
871 		data2 = f;
872 		VERIFY_EQUAL(data.size(), data2.size());
873 		for(std::size_t i = 0; i < data.size() && i < data2.size(); ++i)
874 		{
875 			VERIFY_EQUAL(data[i], data2[i]);
876 		}
877 		RemoveFile(fn);
878 	}
879 
880 #endif
881 #endif // MODPLUG_TRACKER
882 
883 #ifdef MPT_WITH_ZLIB
884 	VERIFY_EQUAL(crc32(0, mpt::byte_cast<const unsigned char*>(std::string("123456789").c_str()), 9), 0xCBF43926u);
885 #endif
886 #ifdef MPT_WITH_MINIZ
887 	VERIFY_EQUAL(mz_crc32(0, mpt::byte_cast<const unsigned char*>(std::string("123456789").c_str()), 9), 0xCBF43926u);
888 #endif
889 
890 	// Check floating-point accuracy in TransposeToFrequency
891 	static constexpr int32 transposeToFrequency[] =
892 	{
893 		      5,       5,       5,       5,
894 		     31,      32,      33,      34,
895 		    196,     202,     207,     214,
896 		   1243,    1280,    1317,    1356,
897 		   7894,    8125,    8363,    8608,
898 		  50121,   51590,   53102,   54658,
899 		 318251,  327576,  337175,  347055,
900 		2020767, 2079980, 2140928, 2203663,
901 	};
902 
903 	int freqIndex = 0;
904 	for(int32 transpose = -128; transpose < 128; transpose += 32)
905 	{
906 		for(int32 finetune = -128; finetune < 128; finetune += 64, freqIndex++)
907 		{
908 			const auto freq = ModSample::TransposeToFrequency(transpose, finetune);
909 			VERIFY_EQUAL_EPS(transposeToFrequency[freqIndex], static_cast<int32>(freq), 1);
910 			if(transpose >= -96)
911 			{
912 				// Verify transpose+finetune <-> frequency roundtrip
913 				// (not for transpose = -128 because it would require fractional precision that we don't have here)
914 				ModSample smp;
915 				smp.nC5Speed = freq;
916 				smp.FrequencyToTranspose();
917 				smp.TransposeToFrequency();
918 				VERIFY_EQUAL(freq, smp.nC5Speed);
919 			}
920 		}
921 	}
922 
923 	{
924 		ModSample smp;
925 		smp.nC5Speed = 9999;
926 		smp.Transpose(1.5);
927 		VERIFY_EQUAL_EPS(28281, static_cast<int32>(smp.nC5Speed), 1);
928 		smp.Transpose(-1.3);
929 		VERIFY_EQUAL_EPS(11486, static_cast<int32>(smp.nC5Speed), 1);
930 	}
931 
932 	// Check SamplePosition fixed-point type
933 	VERIFY_EQUAL(SamplePosition(1).GetRaw(), 1);
934 	VERIFY_EQUAL(SamplePosition(2).Set(1), SamplePosition(1, 0));
935 	VERIFY_EQUAL(SamplePosition(2).SetInt(1), SamplePosition(1, 2));
936 	VERIFY_EQUAL(SamplePosition(1).IsPositive(), true);
937 	VERIFY_EQUAL(SamplePosition(0).IsZero(), true);
938 	VERIFY_EQUAL(SamplePosition(1, 0).IsUnity(), true);
939 	VERIFY_EQUAL(SamplePosition(1, 1).IsUnity(), false);
940 	VERIFY_EQUAL(SamplePosition(-1).IsNegative(), true);
941 	VERIFY_EQUAL(SamplePosition(int64_max).GetRaw(), int64_max);
942 	VERIFY_EQUAL(SamplePosition(2, SamplePosition::fractMax).GetInt(), 2);
943 	VERIFY_EQUAL(SamplePosition(2, SamplePosition::fractMax).GetFract(), SamplePosition::fractMax);
944 	VERIFY_EQUAL(SamplePosition(1, SamplePosition::fractMax).GetInvertedFract(), SamplePosition(0, 1));
945 	VERIFY_EQUAL(SamplePosition(1, 0).GetInvertedFract(), SamplePosition(1, 0));
946 	VERIFY_EQUAL(SamplePosition(2, 0).Negate(), SamplePosition(-2, 0));
947 	VERIFY_EQUAL(SamplePosition::Ratio(10, 5), SamplePosition(2, 0));
948 	VERIFY_EQUAL(SamplePosition(1, 1) + SamplePosition(2, 2), SamplePosition(3, 3));
949 	VERIFY_EQUAL(SamplePosition(1, 0) * 3, SamplePosition(3, 0));
950 	VERIFY_EQUAL((SamplePosition(6, 0) / SamplePosition(2, 0)), 3);
951 
952 	VERIFY_EQUAL(srlztn::ID::FromInt(static_cast<uint32>(0x87654321u)).AsString(), srlztn::ID("\x21\x43\x65\x87").AsString());
953 
954 #if defined(MODPLUG_TRACKER)
955 
956 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("1.1.44" )).AsString() , U_("1.1.44"));
957 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("1.6.2"  )).AsString() , U_("1.6.2" ));
958 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("1.8"    )).AsString() , U_("1.8.0" ));
959 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("2.0-rc" )).AsString() , U_("2.0.0" ));
960 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("2.0-rc4")).AsString() , U_("2.0.0" ));
961 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("2.0"    )).AsString() , U_("2.0.0" ));
962 	VERIFY_EQUAL(mpt::OS::Wine::Version(U_("2.4"    )).AsString() , U_("2.4.0" ));
963 
964 #endif // MODPLUG_TRACKER
965 
966 	// date
967 
968 	VERIFY_EQUAL(             0, TestDate1(  0,  0,  0,  1,  1, 1970 ));
969 	VERIFY_EQUAL(          3600, TestDate1(  0,  0,  1,  1,  1, 1970 ));
970 	VERIFY_EQUAL(         86400, TestDate1(  0,  0,  0,  2,  1, 1970 ));
971 	VERIFY_EQUAL(      31536000, TestDate1(  0,  0,  0,  1,  1, 1971 ));
972 	VERIFY_EQUAL(     100000000, TestDate1( 40, 46,  9,  3,  3, 1973 ));
973 	VERIFY_EQUAL(     951782400, TestDate1(  0,  0,  0, 29,  2, 2000 ));
974 	VERIFY_EQUAL(    1000000000, TestDate1( 40, 46,  1,  9,  9, 2001 ));
975 	VERIFY_EQUAL(    1044057600, TestDate1(  0,  0,  0,  1,  2, 2003 ));
976 	VERIFY_EQUAL(    1044144000, TestDate1(  0,  0,  0,  2,  2, 2003 ));
977 	VERIFY_EQUAL(    1046476800, TestDate1(  0,  0,  0,  1,  3, 2003 ));
978 	VERIFY_EQUAL(    1064966400, TestDate1(  0,  0,  0,  1, 10, 2003 ));
979 	VERIFY_EQUAL(    1077926399, TestDate1( 59, 59, 23, 27,  2, 2004 ));
980 	VERIFY_EQUAL(    1077926400, TestDate1(  0,  0,  0, 28,  2, 2004 ));
981 	VERIFY_EQUAL(    1077926410, TestDate1( 10,  0,  0, 28,  2, 2004 ));
982 	VERIFY_EQUAL(    1078012799, TestDate1( 59, 59, 23, 28,  2, 2004 ));
983 	VERIFY_EQUAL(    1078012800, TestDate1(  0,  0,  0, 29,  2, 2004 ));
984 	VERIFY_EQUAL(    1078012820, TestDate1( 20,  0,  0, 29,  2, 2004 ));
985 	VERIFY_EQUAL(    1078099199, TestDate1( 59, 59, 23, 29,  2, 2004 ));
986 	VERIFY_EQUAL(    1078099200, TestDate1(  0,  0,  0,  1,  3, 2004 ));
987 	VERIFY_EQUAL(    1078099230, TestDate1( 30,  0,  0,  1,  3, 2004 ));
988 	VERIFY_EQUAL(    1078185599, TestDate1( 59, 59, 23,  1,  3, 2004 ));
989 	VERIFY_EQUAL(    1096588800, TestDate1(  0,  0,  0,  1, 10, 2004 ));
990 	VERIFY_EQUAL(    1413064016, TestDate1( 56, 46, 21, 11, 10, 2014 ));
991 	VERIFY_EQUAL(    1413064100, TestDate1( 20, 48, 21, 11, 10, 2014 ));
992 
993 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(             0).AsUTC()), TestDate2(  0,  0,  0,  1,  1, 1970 ));
994 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(          3600).AsUTC()), TestDate2(  0,  0,  1,  1,  1, 1970 ));
995 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(         86400).AsUTC()), TestDate2(  0,  0,  0,  2,  1, 1970 ));
996 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(      31536000).AsUTC()), TestDate2(  0,  0,  0,  1,  1, 1971 ));
997 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(     100000000).AsUTC()), TestDate2( 40, 46,  9,  3,  3, 1973 ));
998 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(     951782400).AsUTC()), TestDate2(  0,  0,  0, 29,  2, 2000 ));
999 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1000000000).AsUTC()), TestDate2( 40, 46,  1,  9,  9, 2001 ));
1000 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1044057600).AsUTC()), TestDate2(  0,  0,  0,  1,  2, 2003 ));
1001 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1044144000).AsUTC()), TestDate2(  0,  0,  0,  2,  2, 2003 ));
1002 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1046476800).AsUTC()), TestDate2(  0,  0,  0,  1,  3, 2003 ));
1003 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1064966400).AsUTC()), TestDate2(  0,  0,  0,  1, 10, 2003 ));
1004 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1077926399).AsUTC()), TestDate2( 59, 59, 23, 27,  2, 2004 ));
1005 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1077926400).AsUTC()), TestDate2(  0,  0,  0, 28,  2, 2004 ));
1006 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1077926410).AsUTC()), TestDate2( 10,  0,  0, 28,  2, 2004 ));
1007 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078012799).AsUTC()), TestDate2( 59, 59, 23, 28,  2, 2004 ));
1008 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078012800).AsUTC()), TestDate2(  0,  0,  0, 29,  2, 2004 ));
1009 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078012820).AsUTC()), TestDate2( 20,  0,  0, 29,  2, 2004 ));
1010 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078099199).AsUTC()), TestDate2( 59, 59, 23, 29,  2, 2004 ));
1011 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078099200).AsUTC()), TestDate2(  0,  0,  0,  1,  3, 2004 ));
1012 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078099230).AsUTC()), TestDate2( 30,  0,  0,  1,  3, 2004 ));
1013 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1078185599).AsUTC()), TestDate2( 59, 59, 23,  1,  3, 2004 ));
1014 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1096588800).AsUTC()), TestDate2(  0,  0,  0,  1, 10, 2004 ));
1015 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1413064016).AsUTC()), TestDate2( 56, 46, 21, 11, 10, 2014 ));
1016 	VERIFY_EQUAL(Gregorian::FromTM(mpt::Date::Unix(    1413064100).AsUTC()), TestDate2( 20, 48, 21, 11, 10, 2014 ));
1017 
1018 
1019 #ifdef MODPLUG_TRACKER
1020 
1021 	// URI & HTTP
1022 
1023 	{
1024 		URI uri = ParseURI(U_("scheme://username:password@host:port/path?query#fragment"));
1025 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1026 		VERIFY_EQUAL(uri.username, U_("username"));
1027 		VERIFY_EQUAL(uri.password, U_("password"));
1028 		VERIFY_EQUAL(uri.host, U_("host"));
1029 		VERIFY_EQUAL(uri.port, U_("port"));
1030 		VERIFY_EQUAL(uri.path, U_("/path"));
1031 		VERIFY_EQUAL(uri.query, U_("query"));
1032 		VERIFY_EQUAL(uri.fragment, U_("fragment"));
1033 	}
1034 	{
1035 		URI uri = ParseURI(U_("scheme://host/path"));
1036 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1037 		VERIFY_EQUAL(uri.username, U_(""));
1038 		VERIFY_EQUAL(uri.password, U_(""));
1039 		VERIFY_EQUAL(uri.host, U_("host"));
1040 		VERIFY_EQUAL(uri.port, U_(""));
1041 		VERIFY_EQUAL(uri.path, U_("/path"));
1042 		VERIFY_EQUAL(uri.query, U_(""));
1043 		VERIFY_EQUAL(uri.fragment, U_(""));
1044 	}
1045 	{
1046 		URI uri = ParseURI(U_("scheme://host"));
1047 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1048 		VERIFY_EQUAL(uri.username, U_(""));
1049 		VERIFY_EQUAL(uri.password, U_(""));
1050 		VERIFY_EQUAL(uri.host, U_("host"));
1051 		VERIFY_EQUAL(uri.port, U_(""));
1052 		VERIFY_EQUAL(uri.path, U_(""));
1053 		VERIFY_EQUAL(uri.query, U_(""));
1054 		VERIFY_EQUAL(uri.fragment, U_(""));
1055 	}
1056 	{
1057 		URI uri = ParseURI(U_("scheme://host?query"));
1058 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1059 		VERIFY_EQUAL(uri.username, U_(""));
1060 		VERIFY_EQUAL(uri.password, U_(""));
1061 		VERIFY_EQUAL(uri.host, U_("host"));
1062 		VERIFY_EQUAL(uri.port, U_(""));
1063 		VERIFY_EQUAL(uri.path, U_(""));
1064 		VERIFY_EQUAL(uri.query, U_("query"));
1065 		VERIFY_EQUAL(uri.fragment, U_(""));
1066 	}
1067 	{
1068 		URI uri = ParseURI(U_("scheme://host#fragment"));
1069 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1070 		VERIFY_EQUAL(uri.username, U_(""));
1071 		VERIFY_EQUAL(uri.password, U_(""));
1072 		VERIFY_EQUAL(uri.host, U_("host"));
1073 		VERIFY_EQUAL(uri.port, U_(""));
1074 		VERIFY_EQUAL(uri.path, U_(""));
1075 		VERIFY_EQUAL(uri.query, U_(""));
1076 		VERIFY_EQUAL(uri.fragment, U_("fragment"));
1077 	}
1078 	{
1079 		URI uri = ParseURI(U_("scheme://host?#"));
1080 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1081 		VERIFY_EQUAL(uri.username, U_(""));
1082 		VERIFY_EQUAL(uri.password, U_(""));
1083 		VERIFY_EQUAL(uri.host, U_("host"));
1084 		VERIFY_EQUAL(uri.port, U_(""));
1085 		VERIFY_EQUAL(uri.path, U_(""));
1086 		VERIFY_EQUAL(uri.query, U_(""));
1087 		VERIFY_EQUAL(uri.fragment, U_(""));
1088 	}
1089 	{
1090 		URI uri = ParseURI(U_("scheme://host#?"));
1091 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1092 		VERIFY_EQUAL(uri.username, U_(""));
1093 		VERIFY_EQUAL(uri.password, U_(""));
1094 		VERIFY_EQUAL(uri.host, U_("host"));
1095 		VERIFY_EQUAL(uri.port, U_(""));
1096 		VERIFY_EQUAL(uri.path, U_(""));
1097 		VERIFY_EQUAL(uri.query, U_(""));
1098 		VERIFY_EQUAL(uri.fragment, U_("?"));
1099 	}
1100 	{
1101 		URI uri = ParseURI(U_("scheme://username:password@[2001:db8::1]:port/path?query#fragment"));
1102 		VERIFY_EQUAL(uri.scheme, U_("scheme"));
1103 		VERIFY_EQUAL(uri.username, U_("username"));
1104 		VERIFY_EQUAL(uri.password, U_("password"));
1105 		VERIFY_EQUAL(uri.host, U_("[2001:db8::1]"));
1106 		VERIFY_EQUAL(uri.port, U_("port"));
1107 		VERIFY_EQUAL(uri.path, U_("/path"));
1108 		VERIFY_EQUAL(uri.query, U_("query"));
1109 		VERIFY_EQUAL(uri.fragment, U_("fragment"));
1110 	}
1111 
1112 	{
1113 		URI uri = ParseURI(U_("https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top"));
1114 		VERIFY_EQUAL(uri.scheme, U_("https"));
1115 		VERIFY_EQUAL(uri.username, U_("john.doe"));
1116 		VERIFY_EQUAL(uri.password, U_(""));
1117 		VERIFY_EQUAL(uri.host, U_("www.example.com"));
1118 		VERIFY_EQUAL(uri.port, U_("123"));
1119 		VERIFY_EQUAL(uri.path, U_("/forum/questions/"));
1120 		VERIFY_EQUAL(uri.query, U_("tag=networking&order=newest"));
1121 		VERIFY_EQUAL(uri.fragment, U_("top"));
1122 	}
1123 	{
1124 		URI uri = ParseURI(U_("ldap://[2001:db8::7]/c=GB?objectClass?one"));
1125 		VERIFY_EQUAL(uri.scheme, U_("ldap"));
1126 		VERIFY_EQUAL(uri.username, U_(""));
1127 		VERIFY_EQUAL(uri.password, U_(""));
1128 		VERIFY_EQUAL(uri.host, U_("[2001:db8::7]"));
1129 		VERIFY_EQUAL(uri.port, U_(""));
1130 		VERIFY_EQUAL(uri.path, U_("/c=GB"));
1131 		VERIFY_EQUAL(uri.query, U_("objectClass?one"));
1132 		VERIFY_EQUAL(uri.fragment, U_(""));
1133 	}
1134 	{
1135 		URI uri = ParseURI(U_("mailto:John.Doe@example.com"));
1136 		VERIFY_EQUAL(uri.scheme, U_("mailto"));
1137 		VERIFY_EQUAL(uri.username, U_(""));
1138 		VERIFY_EQUAL(uri.password, U_(""));
1139 		VERIFY_EQUAL(uri.host, U_(""));
1140 		VERIFY_EQUAL(uri.port, U_(""));
1141 		VERIFY_EQUAL(uri.path, U_("John.Doe@example.com"));
1142 		VERIFY_EQUAL(uri.query, U_(""));
1143 		VERIFY_EQUAL(uri.fragment, U_(""));
1144 	}
1145 	{
1146 		URI uri = ParseURI(U_("news:comp.infosystems.www.servers.unix"));
1147 		VERIFY_EQUAL(uri.scheme, U_("news"));
1148 		VERIFY_EQUAL(uri.username, U_(""));
1149 		VERIFY_EQUAL(uri.password, U_(""));
1150 		VERIFY_EQUAL(uri.host, U_(""));
1151 		VERIFY_EQUAL(uri.port, U_(""));
1152 		VERIFY_EQUAL(uri.path, U_("comp.infosystems.www.servers.unix"));
1153 		VERIFY_EQUAL(uri.query, U_(""));
1154 		VERIFY_EQUAL(uri.fragment, U_(""));
1155 	}
1156 	{
1157 		URI uri = ParseURI(U_("tel:+1-816-555-1212"));
1158 		VERIFY_EQUAL(uri.scheme, U_("tel"));
1159 		VERIFY_EQUAL(uri.username, U_(""));
1160 		VERIFY_EQUAL(uri.password, U_(""));
1161 		VERIFY_EQUAL(uri.host, U_(""));
1162 		VERIFY_EQUAL(uri.port, U_(""));
1163 		VERIFY_EQUAL(uri.path, U_("+1-816-555-1212"));
1164 		VERIFY_EQUAL(uri.query, U_(""));
1165 		VERIFY_EQUAL(uri.fragment, U_(""));
1166 	}
1167 	{
1168 		URI uri = ParseURI(U_("telnet://192.0.2.16:80/"));
1169 		VERIFY_EQUAL(uri.scheme, U_("telnet"));
1170 		VERIFY_EQUAL(uri.username, U_(""));
1171 		VERIFY_EQUAL(uri.password, U_(""));
1172 		VERIFY_EQUAL(uri.host, U_("192.0.2.16"));
1173 		VERIFY_EQUAL(uri.port, U_("80"));
1174 		VERIFY_EQUAL(uri.path, U_("/"));
1175 		VERIFY_EQUAL(uri.query, U_(""));
1176 		VERIFY_EQUAL(uri.fragment, U_(""));
1177 	}
1178 	{
1179 		URI uri = ParseURI(U_("urn:oasis:names:specification:docbook:dtd:xml:4.1.2"));
1180 		VERIFY_EQUAL(uri.scheme, U_("urn"));
1181 		VERIFY_EQUAL(uri.username, U_(""));
1182 		VERIFY_EQUAL(uri.password, U_(""));
1183 		VERIFY_EQUAL(uri.host, U_(""));
1184 		VERIFY_EQUAL(uri.port, U_(""));
1185 		VERIFY_EQUAL(uri.path, U_("oasis:names:specification:docbook:dtd:xml:4.1.2"));
1186 		VERIFY_EQUAL(uri.query, U_(""));
1187 		VERIFY_EQUAL(uri.fragment, U_(""));
1188 	}
1189 
1190 	{
1191 		HTTP::Request req;
1192 		req.SetURI(ParseURI(U_("https://host/path?a1=a&a2=b")));
1193 		VERIFY_EQUAL(req.protocol, HTTP::Protocol::HTTPS);
1194 		VERIFY_EQUAL(req.host, U_("host"));
1195 		VERIFY_EQUAL(req.path, U_("/path"));
1196 		VERIFY_EQUAL(req.query.size(), 2u);
1197 		if(req.query.size() == 2)
1198 		{
1199 			VERIFY_EQUAL(req.query[0], std::make_pair(U_("a1"), U_("a")));
1200 			VERIFY_EQUAL(req.query[1], std::make_pair(U_("a2"), U_("b")));
1201 		}
1202 	}
1203 	{
1204 		HTTP::Request req;
1205 		req.SetURI(ParseURI(U_("https://host/")));
1206 		VERIFY_EQUAL(req.protocol, HTTP::Protocol::HTTPS);
1207 		VERIFY_EQUAL(req.host, U_("host"));
1208 		VERIFY_EQUAL(req.path, U_("/"));
1209 	}
1210 
1211 #endif // MODPLUG_TRACKER
1212 
1213 	// https://github.com/kripken/emscripten/issues/4251
1214 	#if MPT_OS_EMSCRIPTEN
1215 		volatile int transpose = 32;
1216 		volatile int finetune = 0;
1217 		float exp = (transpose * 128.0f + finetune) * (1.0f / (12.0f * 128.0f));
1218 		float f  = ::powf(2.0f,         exp);
1219 		double d = ::pow (2.0 , (double)exp);
1220 		VERIFY_EQUAL_EPS(d, 6.349605, 0.00001);
1221 		VERIFY_EQUAL_EPS(f, 6.349605, 0.00001);
1222 	#endif
1223 
1224 }
1225 
1226 
TestRandom()1227 static MPT_NOINLINE void TestRandom()
1228 {
1229 
1230 	#ifdef FLAKY_TESTS
1231 
1232 		mpt::default_prng& prng = *s_PRNG;
1233 
1234 		{
1235 			std::vector<std::size_t> hist(256);
1236 			for(std::size_t i = 0; i < 256*256; ++i)
1237 			{
1238 				uint8 value = mpt::random<uint8>(prng);
1239 				hist[value] += 1;
1240 			}
1241 			for(std::size_t i = 0; i < 256; ++i)
1242 			{
1243 				VERIFY_EQUAL_QUIET_NONCONT(mpt::is_in_range(hist[i], 16u, 65520u), true);
1244 			}
1245 		}
1246 		{
1247 			std::vector<std::size_t> hist(256);
1248 			for(std::size_t i = 0; i < 256*256; ++i)
1249 			{
1250 				int8 value = mpt::random<int8>(prng);
1251 				hist[static_cast<int>(value) + 0x80] += 1;
1252 			}
1253 			for(std::size_t i = 0; i < 256; ++i)
1254 			{
1255 				VERIFY_EQUAL_QUIET_NONCONT(mpt::is_in_range(hist[i], 16u, 65520u), true);
1256 			}
1257 		}
1258 		{
1259 			std::vector<std::size_t> hist(256);
1260 			for(std::size_t i = 0; i < 256*256; ++i)
1261 			{
1262 				uint8 value = mpt::random<uint8>(prng, 1);
1263 				hist[value] += 1;
1264 			}
1265 			for(std::size_t i = 0; i < 256; ++i)
1266 			{
1267 				if(i < 2)
1268 				{
1269 					VERIFY_EQUAL_QUIET_NONCONT(mpt::is_in_range(hist[i], 16u, 65520u), true);
1270 				} else
1271 				{
1272 					VERIFY_EQUAL_QUIET_NONCONT(hist[i], 0u);
1273 				}
1274 			}
1275 		}
1276 	#endif
1277 }
1278 
1279 
TestCharsets()1280 static MPT_NOINLINE void TestCharsets()
1281 {
1282 
1283 	// Path splitting
1284 
1285 #if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
1286 
1287 	VERIFY_EQUAL(P_("").GetDrive(), P_(""));
1288 	VERIFY_EQUAL(P_("").GetDir(), P_(""));
1289 	VERIFY_EQUAL(P_("").GetPath(), P_(""));
1290 	VERIFY_EQUAL(P_("").GetFileName(), P_(""));
1291 	VERIFY_EQUAL(P_("").GetFileExt(), P_(""));
1292 	VERIFY_EQUAL(P_("").GetFullFileName(), P_(""));
1293 
1294 	VERIFY_EQUAL(P_("C:\\").GetDrive(), P_("C:"));
1295 	VERIFY_EQUAL(P_("C:\\").GetDir(), P_("\\"));
1296 	VERIFY_EQUAL(P_("C:\\").GetPath(), P_("C:\\"));
1297 	VERIFY_EQUAL(P_("C:\\").GetFileName(), P_(""));
1298 	VERIFY_EQUAL(P_("C:\\").GetFileExt(), P_(""));
1299 	VERIFY_EQUAL(P_("C:\\").GetFullFileName(), P_(""));
1300 
1301 	VERIFY_EQUAL(P_("\\directory\\").GetDrive(), P_(""));
1302 	VERIFY_EQUAL(P_("\\directory\\").GetDir(), P_("\\directory\\"));
1303 	VERIFY_EQUAL(P_("\\directory\\").GetPath(), P_("\\directory\\"));
1304 	VERIFY_EQUAL(P_("\\directory\\").GetFileName(), P_(""));
1305 	VERIFY_EQUAL(P_("\\directory\\").GetFileExt(), P_(""));
1306 	VERIFY_EQUAL(P_("\\directory\\").GetFullFileName(), P_(""));
1307 
1308 	VERIFY_EQUAL(P_("\\directory\\file.txt").GetDrive(), P_(""));
1309 	VERIFY_EQUAL(P_("\\directory\\file.txt").GetDir(), P_("\\directory\\"));
1310 	VERIFY_EQUAL(P_("\\directory\\file.txt").GetPath(), P_("\\directory\\"));
1311 	VERIFY_EQUAL(P_("\\directory\\file.txt").GetFileName(), P_("file"));
1312 	VERIFY_EQUAL(P_("\\directory\\file.txt").GetFileExt(), P_(".txt"));
1313 	VERIFY_EQUAL(P_("\\directory\\file.txt").GetFullFileName(), P_("file.txt"));
1314 
1315 	VERIFY_EQUAL(P_(".").GetDrive(), P_(""));
1316 	VERIFY_EQUAL(P_(".").GetDir(), P_(""));
1317 	VERIFY_EQUAL(P_(".").GetPath(), P_(""));
1318 	VERIFY_EQUAL(P_(".").GetFileName(), P_("."));
1319 	VERIFY_EQUAL(P_(".").GetFileExt(), P_(""));
1320 	VERIFY_EQUAL(P_(".").GetFullFileName(), P_("."));
1321 
1322 	VERIFY_EQUAL(P_("..").GetDrive(), P_(""));
1323 	VERIFY_EQUAL(P_("..").GetDir(), P_(""));
1324 	VERIFY_EQUAL(P_("..").GetPath(), P_(""));
1325 	VERIFY_EQUAL(P_("..").GetFileName(), P_(".."));
1326 	VERIFY_EQUAL(P_("..").GetFileExt(), P_(""));
1327 	VERIFY_EQUAL(P_("..").GetFullFileName(), P_(".."));
1328 
1329 	VERIFY_EQUAL(P_("dir\\.").GetDrive(), P_(""));
1330 	VERIFY_EQUAL(P_("dir\\.").GetDir(), P_("dir\\"));
1331 	VERIFY_EQUAL(P_("dir\\.").GetPath(), P_("dir\\"));
1332 	VERIFY_EQUAL(P_("dir\\.").GetFileName(), P_("."));
1333 	VERIFY_EQUAL(P_("dir\\.").GetFileExt(), P_(""));
1334 	VERIFY_EQUAL(P_("dir\\.").GetFullFileName(), P_("."));
1335 
1336 	VERIFY_EQUAL(P_("dir\\..").GetDrive(), P_(""));
1337 	VERIFY_EQUAL(P_("dir\\..").GetDir(), P_("dir\\"));
1338 	VERIFY_EQUAL(P_("dir\\..").GetPath(), P_("dir\\"));
1339 	VERIFY_EQUAL(P_("dir\\..").GetFileName(), P_(".."));
1340 	VERIFY_EQUAL(P_("dir\\..").GetFileExt(), P_(""));
1341 	VERIFY_EQUAL(P_("dir\\..").GetFullFileName(), P_(".."));
1342 
1343 	VERIFY_EQUAL(P_(".txt").GetDrive(), P_(""));
1344 	VERIFY_EQUAL(P_(".txt").GetDir(), P_(""));
1345 	VERIFY_EQUAL(P_(".txt").GetPath(), P_(""));
1346 	VERIFY_EQUAL(P_(".txt").GetFileName(), P_(".txt"));
1347 	VERIFY_EQUAL(P_(".txt").GetFileExt(), P_(""));
1348 	VERIFY_EQUAL(P_(".txt").GetFullFileName(), P_(".txt"));
1349 
1350 	VERIFY_EQUAL(P_("C:tmp.txt").GetDrive(), P_("C:"));
1351 	VERIFY_EQUAL(P_("C:tmp.txt").GetDir(), P_(""));
1352 	VERIFY_EQUAL(P_("C:tmp.txt").GetPath(), P_("C:"));
1353 	VERIFY_EQUAL(P_("C:tmp.txt").GetFileName(), P_("tmp"));
1354 	VERIFY_EQUAL(P_("C:tmp.txt").GetFileExt(), P_(".txt"));
1355 	VERIFY_EQUAL(P_("C:tmp.txt").GetFullFileName(), P_("tmp.txt"));
1356 
1357 	VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetDrive(), P_("C:"));
1358 	VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetDir(), P_("tempdir\\"));
1359 	VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetPath(), P_("C:tempdir\\"));
1360 	VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFileName(), P_("tmp"));
1361 	VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFileExt(), P_(".txt"));
1362 	VERIFY_EQUAL(P_("C:tempdir\\tmp.txt").GetFullFileName(), P_("tmp.txt"));
1363 
1364 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetDrive(), P_("C:"));
1365 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetDir(), P_("\\tempdir\\"));
1366 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetPath(), P_("C:\\tempdir\\"));
1367 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFileName(), P_("tmp"));
1368 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFileExt(), P_(".txt"));
1369 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.txt").GetFullFileName(), P_("tmp.txt"));
1370 
1371 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.foo.txt").GetFileName(), P_("tmp.foo"));
1372 	VERIFY_EQUAL(P_("C:\\tempdir\\tmp.foo.txt").GetFileExt(), P_(".txt"));
1373 
1374 	VERIFY_EQUAL(P_("\\\\server").GetDrive(), P_("\\\\server"));
1375 	VERIFY_EQUAL(P_("\\\\server").GetDir(), P_(""));
1376 	VERIFY_EQUAL(P_("\\\\server").GetPath(), P_("\\\\server"));
1377 	VERIFY_EQUAL(P_("\\\\server").GetFileName(), P_(""));
1378 	VERIFY_EQUAL(P_("\\\\server").GetFileExt(), P_(""));
1379 	VERIFY_EQUAL(P_("\\\\server").GetFullFileName(), P_(""));
1380 
1381 	VERIFY_EQUAL(P_("\\\\server\\").GetDrive(), P_("\\\\server\\"));
1382 	VERIFY_EQUAL(P_("\\\\server\\").GetDir(), P_(""));
1383 	VERIFY_EQUAL(P_("\\\\server\\").GetPath(), P_("\\\\server\\"));
1384 	VERIFY_EQUAL(P_("\\\\server\\").GetFileName(), P_(""));
1385 	VERIFY_EQUAL(P_("\\\\server\\").GetFileExt(), P_(""));
1386 	VERIFY_EQUAL(P_("\\\\server\\").GetFullFileName(), P_(""));
1387 
1388 	VERIFY_EQUAL(P_("\\\\server\\share").GetDrive(), P_("\\\\server\\share"));
1389 	VERIFY_EQUAL(P_("\\\\server\\share").GetDir(), P_(""));
1390 	VERIFY_EQUAL(P_("\\\\server\\share").GetPath(), P_("\\\\server\\share"));
1391 	VERIFY_EQUAL(P_("\\\\server\\share").GetFileName(), P_(""));
1392 	VERIFY_EQUAL(P_("\\\\server\\share").GetFileExt(), P_(""));
1393 	VERIFY_EQUAL(P_("\\\\server\\share").GetFullFileName(), P_(""));
1394 
1395 	VERIFY_EQUAL(P_("\\\\server\\share\\").GetDrive(), P_("\\\\server\\share"));
1396 	VERIFY_EQUAL(P_("\\\\server\\share\\").GetDir(), P_("\\"));
1397 	VERIFY_EQUAL(P_("\\\\server\\share\\").GetPath(), P_("\\\\server\\share\\"));
1398 	VERIFY_EQUAL(P_("\\\\server\\share\\").GetFileName(), P_(""));
1399 	VERIFY_EQUAL(P_("\\\\server\\share\\").GetFileExt(), P_(""));
1400 	VERIFY_EQUAL(P_("\\\\server\\share\\").GetFullFileName(), P_(""));
1401 
1402 	VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P_("\\\\server\\share"));
1403 	VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetDir(), P_("\\dir1\\dir2\\"));
1404 	VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetPath(), P_("\\\\server\\share\\dir1\\dir2\\"));
1405 	VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileName(), P_("name.foo"));
1406 	VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileExt(), P_(".ext"));
1407 	VERIFY_EQUAL(P_("\\\\server\\share\\dir1\\dir2\\name.foo.ext").GetFullFileName(), P_("name.foo.ext"));
1408 
1409 	VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDrive(), P_("C:"));
1410 	VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetDir(), P_("\\tempdir\\dir.2\\"));
1411 	VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetPath(), P_("C:\\tempdir\\dir.2\\"));
1412 	VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFileName(), P_("tmp.foo"));
1413 	VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFileExt(), P_(".txt"));
1414 	VERIFY_EQUAL(P_("\\\\?\\C:\\tempdir\\dir.2\\tmp.foo.txt").GetFullFileName(), P_("tmp.foo.txt"));
1415 
1416 	VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDrive(), P_("\\\\server\\share"));
1417 	VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetDir(), P_("\\dir1\\dir2\\"));
1418 	VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetPath(), P_("\\\\server\\share\\dir1\\dir2\\"));
1419 	VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileName(), P_("name.foo"));
1420 	VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFileExt(), P_(".ext"));
1421 	VERIFY_EQUAL(P_("\\\\?\\UNC\\server\\share\\dir1\\dir2\\name.foo.ext").GetFullFileName(), P_("name.foo.ext"));
1422 #endif
1423 
1424 
1425 
1426 	// Path conversions
1427 #ifdef MODPLUG_TRACKER
1428 	const mpt::PathString exePath = P_("C:\\OpenMPT\\");
1429 	VERIFY_EQUAL(P_("C:\\OpenMPT\\").AbsolutePathToRelative(exePath), P_(".\\"));
1430 	VERIFY_EQUAL(P_("c:\\OpenMPT\\foo").AbsolutePathToRelative(exePath), P_(".\\foo"));
1431 	VERIFY_EQUAL(P_("C:\\foo").AbsolutePathToRelative(exePath), P_("\\foo"));
1432 	VERIFY_EQUAL(P_(".\\").RelativePathToAbsolute(exePath), P_("C:\\OpenMPT\\"));
1433 	VERIFY_EQUAL(P_(".\\foo").RelativePathToAbsolute(exePath), P_("C:\\OpenMPT\\foo"));
1434 	VERIFY_EQUAL(P_("\\foo").RelativePathToAbsolute(exePath), P_("C:\\foo"));
1435 	VERIFY_EQUAL(P_("\\\\server\\path\\file").AbsolutePathToRelative(exePath), P_("\\\\server\\path\\file"));
1436 	VERIFY_EQUAL(P_("\\\\server\\path\\file").RelativePathToAbsolute(exePath), P_("\\\\server\\path\\file"));
1437 
1438 	VERIFY_EQUAL(P_("").Simplify(), P_(""));
1439 	VERIFY_EQUAL(P_(" ").Simplify(), P_(" "));
1440 	VERIFY_EQUAL(P_("foo\\bar").Simplify(), P_("foo\\bar"));
1441 	VERIFY_EQUAL(P_(".\\foo\\bar").Simplify(), P_(".\\foo\\bar"));
1442 	VERIFY_EQUAL(P_(".\\\\foo\\bar").Simplify(), P_(".\\foo\\bar"));
1443 	VERIFY_EQUAL(P_("./\\foo\\bar").Simplify(), P_(".\\foo\\bar"));
1444 	VERIFY_EQUAL(P_("\\foo\\bar").Simplify(), P_("\\foo\\bar"));
1445 	VERIFY_EQUAL(P_("A:\\name_1\\.\\name_2\\..\\name_3\\").Simplify(), P_("A:\\name_1\\name_3"));
1446 	VERIFY_EQUAL(P_("A:\\name_1\\..\\name_2\\./name_3").Simplify(), P_("A:\\name_2\\name_3"));
1447 	VERIFY_EQUAL(P_("A:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..").Simplify(), P_("A:\\name_1\\name_2"));
1448 	VERIFY_EQUAL(P_("A:foo\\\\bar").Simplify(), P_("A:\\foo\\bar"));
1449 	VERIFY_EQUAL(P_("C:\\..").Simplify(), P_("C:\\"));
1450 	VERIFY_EQUAL(P_("C:\\.").Simplify(), P_("C:\\"));
1451 	VERIFY_EQUAL(P_("\\\\foo\\..\\.bar").Simplify(), P_("\\\\.bar"));
1452 	VERIFY_EQUAL(P_("\\\\foo\\..\\..\\bar").Simplify(), P_("\\\\bar"));
1453 #endif
1454 
1455 
1456 
1457 #ifdef MODPLUG_TRACKER
1458 #if MPT_COMPILER_MSVC
1459 
1460 	// Tracker code currently relies on BROKEN MSVC behaviour with respect to %s
1461 	// handling in printf functions when the target is a wide string.
1462 	// Ensure that Microsoft KEEPS this BROKEN behavour (it conflicts with C99 and
1463 	// C++11 demanded semantics.
1464 	// Additionally, the tracker code makes use of %hs and %ls which are the only
1465 	// way to unconditionally expect narrow or wide string parameters
1466 	// respectively; %ls is standard conforming, %hs is a Microsoft extension.
1467 	// We check all possible combinations and expect Microsoft-style behaviour
1468 	// here.
1469 
1470 	char src_char[256];
1471 	wchar_t src_wchar_t[256];
1472 	TCHAR src_TCHAR[256];
1473 
1474 	char dst_char[256];
1475 	wchar_t dst_wchar_t[256];
1476 	TCHAR dst_TCHAR[256];
1477 
1478 	MemsetZero(src_char);
1479 	MemsetZero(src_wchar_t);
1480 	MemsetZero(src_TCHAR);
1481 
1482 	strcpy(src_char, "ab");
1483 	wcscpy(src_wchar_t, L"ab");
1484 	_tcscpy(src_TCHAR, _T("ab"));
1485 
1486 #define MPT_TEST_PRINTF(dst_type, function, format, src_type) \
1487 	do { \
1488 		MemsetZero(dst_ ## dst_type); \
1489 		function(dst_ ## dst_type, format, src_ ## src_type); \
1490 		VERIFY_EQUAL(std::char_traits< dst_type >::compare(dst_ ## dst_type, src_ ## dst_type, std::char_traits< dst_type >::length( src_ ## dst_type ) + 1), 0); \
1491 	} while(0) \
1492 /**/
1493 
1494 #define MPT_TEST_PRINTF_N(dst_type, function, format, src_type) \
1495 	do { \
1496 		MemsetZero(dst_ ## dst_type); \
1497 		function(dst_ ## dst_type, 255, format, src_ ## src_type); \
1498 		VERIFY_EQUAL(std::char_traits< dst_type >::compare(dst_ ## dst_type, src_ ## dst_type, std::char_traits< dst_type >::length( src_ ## dst_type ) + 1), 0); \
1499 	} while(0) \
1500 /**/
1501 
1502 	// CRT narrow
1503 	MPT_TEST_PRINTF(char, sprintf, "%s", char);
1504 	MPT_TEST_PRINTF(char, sprintf, "%S", wchar_t);
1505 	MPT_TEST_PRINTF(char, sprintf, "%hs", char);
1506 	MPT_TEST_PRINTF(char, sprintf, "%hS", char);
1507 	MPT_TEST_PRINTF(char, sprintf, "%ls", wchar_t);
1508 	MPT_TEST_PRINTF(char, sprintf, "%lS", wchar_t);
1509 	MPT_TEST_PRINTF(char, sprintf, "%ws", wchar_t);
1510 	MPT_TEST_PRINTF(char, sprintf, "%wS", wchar_t);
1511 
1512 	// CRT wide
1513 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%s", wchar_t);
1514 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%S", char);
1515 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%hs", char);
1516 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%hS", char);
1517 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%ls", wchar_t);
1518 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%lS", wchar_t);
1519 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%ws", wchar_t);
1520 	MPT_TEST_PRINTF_N(wchar_t, swprintf, L"%wS", wchar_t);
1521 
1522 	// WinAPI TCHAR
1523 	MPT_TEST_PRINTF(TCHAR, wsprintf, _T("%s"), TCHAR);
1524 	MPT_TEST_PRINTF(TCHAR, wsprintf, _T("%hs"), char);
1525 	MPT_TEST_PRINTF(TCHAR, wsprintf, _T("%hS"), char);
1526 	MPT_TEST_PRINTF(TCHAR, wsprintf, _T("%ls"), wchar_t);
1527 	MPT_TEST_PRINTF(TCHAR, wsprintf, _T("%lS"), wchar_t);
1528 
1529 	// WinAPI CHAR
1530 	MPT_TEST_PRINTF(char, wsprintfA, "%s", char);
1531 	MPT_TEST_PRINTF(char, wsprintfA, "%S", wchar_t);
1532 	MPT_TEST_PRINTF(char, wsprintfA, "%hs", char);
1533 	MPT_TEST_PRINTF(char, wsprintfA, "%hS", char);
1534 	MPT_TEST_PRINTF(char, wsprintfA, "%ls", wchar_t);
1535 	MPT_TEST_PRINTF(char, wsprintfA, "%lS", wchar_t);
1536 
1537 	// WinAPI WCHAR
1538 	MPT_TEST_PRINTF(wchar_t, wsprintfW, L"%s", wchar_t);
1539 	MPT_TEST_PRINTF(wchar_t, wsprintfW, L"%S", char);
1540 	MPT_TEST_PRINTF(wchar_t, wsprintfW, L"%hs", char);
1541 	MPT_TEST_PRINTF(wchar_t, wsprintfW, L"%hS", char);
1542 	MPT_TEST_PRINTF(wchar_t, wsprintfW, L"%ls", wchar_t);
1543 	MPT_TEST_PRINTF(wchar_t, wsprintfW, L"%lS", wchar_t);
1544 
1545 #undef MPT_TEST_PRINTF
1546 #undef MPT_TEST_PRINTF_n
1547 
1548 #endif
1549 #endif
1550 
1551 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("f", "f", 6) == 0, true);
1552 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("f", "F", 6) == 0, true);
1553 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("F", "f", 6) == 0, true);
1554 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("f", "g", 6) < 0, true);
1555 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("h", "g", 6) > 0, true);
1556 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("fgh", "FgH", 6) == 0, true);
1557 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("012345678", "012345678", 9) == 0, true);
1558 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("", "012345678", 9) < 0, true);
1559 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "", 6) > 0, true);
1560 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "F", 6) > 0, true);
1561 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "Fg", 6) > 0, true);
1562 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "fg", 6) > 0, true);
1563 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("0123456789", "FgH", 0) == 0, true);
1564 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "fgh", 1) == 0, true);
1565 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "fgh", 2) == 0, true);
1566 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "fgh", 3) == 0, true);
1567 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "fghi", 3) == 0, true);
1568 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FgH", "fghi", 4) < 0, true);
1569 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FIH", "fghi", 1) == 0, true);
1570 	VERIFY_EQUAL(mpt::CompareNoCaseAscii("FIH", "fghi", 2) > 0, true);
1571 
1572 }
1573 
1574 
1575 #ifdef MODPLUG_TRACKER
1576 
1577 struct CustomSettingsTestType
1578 {
1579 	float x;
1580 	float y;
CustomSettingsTestTypeTest::CustomSettingsTestType1581 	CustomSettingsTestType(float x_ = 0.0f, float y_ = 0.0f) : x(x_), y(y_) { }
1582 };
1583 
1584 } // namespace Test
1585 
1586 template <>
FromSettingValue(const SettingValue & val)1587 inline Test::CustomSettingsTestType FromSettingValue(const SettingValue &val)
1588 {
1589 	MPT_ASSERT(val.GetTypeTag() == "myType");
1590 	mpt::ustring xy = val.as<mpt::ustring>();
1591 	if(xy.empty())
1592 	{
1593 		return Test::CustomSettingsTestType(0.0f, 0.0f);
1594 	}
1595 	std::size_t pos = xy.find(U_("|"));
1596 	mpt::ustring x = xy.substr(0, pos);
1597 	mpt::ustring y = xy.substr(pos + 1);
1598 	return Test::CustomSettingsTestType(ConvertStrTo<float>(x), ConvertStrTo<float>(y));
1599 }
1600 
1601 template <>
ToSettingValue(const Test::CustomSettingsTestType & val)1602 inline SettingValue ToSettingValue(const Test::CustomSettingsTestType &val)
1603 {
1604 	return SettingValue(mpt::ufmt::val(val.x) + U_("|") + mpt::ufmt::val(val.y), "myType");
1605 }
1606 
1607 namespace Test {
1608 
1609 #endif // MODPLUG_TRACKER
1610 
1611 
TestSettings()1612 static MPT_NOINLINE void TestSettings()
1613 {
1614 
1615 #ifdef MODPLUG_TRACKER
1616 
1617 	VERIFY_EQUAL(SettingPath(U_("a"),U_("b")) < SettingPath(U_("a"),U_("c")), true);
1618 	VERIFY_EQUAL(!(SettingPath(U_("c"),U_("b")) < SettingPath(U_("a"),U_("c"))), true);
1619 
1620 	{
1621 		DefaultSettingsContainer conf;
1622 
1623 		int32 foobar = conf.Read(U_("Test"), U_("bar"), 23);
1624 		conf.Write(U_("Test"), U_("bar"), 64);
1625 		conf.Write(U_("Test"), U_("bar"), 42);
1626 		conf.Read(U_("Test"), U_("baz"), 4711);
1627 		foobar = conf.Read(U_("Test"), U_("bar"), 28);
1628 	}
1629 
1630 	{
1631 		DefaultSettingsContainer conf;
1632 
1633 		int32 foobar = conf.Read(U_("Test"), U_("bar"), 28);
1634 		VERIFY_EQUAL(foobar, 42);
1635 		conf.Write(U_("Test"), U_("bar"), 43);
1636 	}
1637 
1638 	{
1639 		DefaultSettingsContainer conf;
1640 
1641 		int32 foobar = conf.Read(U_("Test"), U_("bar"), 123);
1642 		VERIFY_EQUAL(foobar, 43);
1643 		conf.Write(U_("Test"), U_("bar"), 88);
1644 	}
1645 
1646 	{
1647 		DefaultSettingsContainer conf;
1648 
1649 		Setting<int> foo(conf, U_("Test"), U_("bar"), 99);
1650 
1651 		VERIFY_EQUAL(foo, 88);
1652 
1653 		foo = 7;
1654 
1655 	}
1656 
1657 	{
1658 		DefaultSettingsContainer conf;
1659 		Setting<int> foo(conf, U_("Test"), U_("bar"), 99);
1660 		VERIFY_EQUAL(foo, 7);
1661 	}
1662 
1663 
1664 	{
1665 		DefaultSettingsContainer conf;
1666 		conf.Read(U_("Test"), U_("struct"), std::string(""));
1667 		conf.Write(U_("Test"), U_("struct"), std::string(""));
1668 	}
1669 
1670 	{
1671 		DefaultSettingsContainer conf;
1672 		CustomSettingsTestType dummy = conf.Read(U_("Test"), U_("struct"), CustomSettingsTestType(1.0f, 1.0f));
1673 		dummy = CustomSettingsTestType(0.125f, 32.0f);
1674 		conf.Write(U_("Test"), U_("struct"), dummy);
1675 	}
1676 
1677 	{
1678 		DefaultSettingsContainer conf;
1679 		Setting<CustomSettingsTestType> dummyVar(conf, U_("Test"), U_("struct"), CustomSettingsTestType(1.0f, 1.0f));
1680 		CustomSettingsTestType dummy = dummyVar;
1681 		VERIFY_EQUAL(dummy.x, 0.125f);
1682 		VERIFY_EQUAL(dummy.y, 32.0f);
1683 	}
1684 
1685 #endif // MODPLUG_TRACKER
1686 
1687 }
1688 
1689 
1690 // Test MIDI Event generating / reading
TestMIDIEvents()1691 static MPT_NOINLINE void TestMIDIEvents()
1692 {
1693 	uint32 midiEvent;
1694 
1695 	midiEvent = MIDIEvents::CC(MIDIEvents::MIDICC_Balance_Coarse, 13, 40);
1696 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evControllerChange);
1697 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 13);
1698 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), MIDIEvents::MIDICC_Balance_Coarse);
1699 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 40);
1700 
1701 	midiEvent = MIDIEvents::NoteOn(10, 50, 120);
1702 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evNoteOn);
1703 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 10);
1704 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 50);
1705 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 120);
1706 
1707 	midiEvent = MIDIEvents::NoteOff(15, 127, 42);
1708 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evNoteOff);
1709 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 15);
1710 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 127);
1711 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 42);
1712 
1713 	midiEvent = MIDIEvents::ProgramChange(1, 127);
1714 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evProgramChange);
1715 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 1);
1716 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 127);
1717 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 0);
1718 
1719 	midiEvent = MIDIEvents::PitchBend(2, MIDIEvents::pitchBendCentre);
1720 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evPitchBend);
1721 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), 2);
1722 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 0x00);
1723 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 0x40);
1724 
1725 	midiEvent = MIDIEvents::System(MIDIEvents::sysStart);
1726 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetTypeFromEvent(midiEvent), MIDIEvents::evSystem);
1727 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetChannelFromEvent(midiEvent), MIDIEvents::sysStart);
1728 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte1FromEvent(midiEvent), 0);
1729 	VERIFY_EQUAL_NONCONT(MIDIEvents::GetDataByte2FromEvent(midiEvent), 0);
1730 }
1731 
1732 
1733 // Check if our test file was loaded correctly.
TestLoadXMFile(const CSoundFile & sndFile)1734 static void TestLoadXMFile(const CSoundFile &sndFile)
1735 {
1736 #ifdef MODPLUG_TRACKER
1737 	const CModDoc *pModDoc = sndFile.GetpModDoc();
1738 	VERIFY_EQUAL_NONCONT(pModDoc->IsChannelUnused(0), true);
1739 	VERIFY_EQUAL_NONCONT(pModDoc->IsChannelUnused(1), false);
1740 #endif // MODPLUG_TRACKER
1741 
1742 	// Global Variables
1743 	VERIFY_EQUAL_NONCONT(sndFile.GetTitle(), "Test Module");
1744 	VERIFY_EQUAL_NONCONT(sndFile.m_songMessage.substr(0, 32), "OpenMPT Module Loader Test Suite");
1745 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultTempo, TEMPO(139, 0));
1746 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultSpeed, 5);
1747 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 128);
1748 	VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 42);
1749 	VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 23);
1750 	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_LINEARSLIDES | SONG_EXFILTERRANGE);
1751 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[MSF_COMPATIBLE_PLAY], true);
1752 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMIDICCBugEmulation], false);
1753 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMPTOldSwingBehaviour], false);
1754 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kOldMIDIPitchBends], false);
1755 	VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), MixLevels::Compatible);
1756 	VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, TempoMode::Modern);
1757 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
1758 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
1759 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MPT_V("1.19.02.05"));
1760 	VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 1);
1761 
1762 	// Macros
1763 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetParameteredMacroType(0), kSFxReso);
1764 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetParameteredMacroType(1), kSFxDryWet);
1765 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetFixedMacroType(), kZxxResoFltMode);
1766 
1767 	// Channels
1768 	VERIFY_EQUAL_NONCONT(sndFile.GetNumChannels(), 2);
1769 	VERIFY_EQUAL_NONCONT((sndFile.ChnSettings[0].szName == "First Channel"), true);
1770 #ifndef NO_PLUGINS
1771 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].nMixPlugin, 0);
1772 #endif // NO_PLUGINS
1773 
1774 	VERIFY_EQUAL_NONCONT((sndFile.ChnSettings[1].szName == "Second Channel"), true);
1775 #ifndef NO_PLUGINS
1776 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].nMixPlugin, 1);
1777 #endif // NO_PLUGINS
1778 
1779 	// Samples
1780 	VERIFY_EQUAL_NONCONT(sndFile.GetNumSamples(), 3);
1781 	VERIFY_EQUAL_NONCONT((sndFile.m_szNames[1] == "Pulse Sample"), true);
1782 	VERIFY_EQUAL_NONCONT((sndFile.m_szNames[2] == "Empty Sample"), true);
1783 	VERIFY_EQUAL_NONCONT((sndFile.m_szNames[3] == "Unassigned Sample"), true);
1784 #ifdef MODPLUG_TRACKER
1785 	VERIFY_EQUAL_NONCONT(pModDoc->FindSampleParent(1), 1);
1786 	VERIFY_EQUAL_NONCONT(pModDoc->FindSampleParent(2), 1);
1787 	VERIFY_EQUAL_NONCONT(pModDoc->FindSampleParent(3), INSTRUMENTINDEX_INVALID);
1788 #endif // MODPLUG_TRACKER
1789 	const ModSample &sample = sndFile.GetSample(1);
1790 	VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1);
1791 	VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1);
1792 	VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1);
1793 	VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 16);
1794 	VERIFY_EQUAL_NONCONT(sample.nFineTune, 35);
1795 	VERIFY_EQUAL_NONCONT(sample.RelativeTone, 1);
1796 	VERIFY_EQUAL_NONCONT(sample.nVolume, 32 * 4);
1797 	VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 64);
1798 	VERIFY_EQUAL_NONCONT(sample.nPan, 160);
1799 	VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_PANNING | CHN_LOOP | CHN_PINGPONGLOOP);
1800 
1801 	VERIFY_EQUAL_NONCONT(sample.nLoopStart, 1);
1802 	VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 8);
1803 
1804 	VERIFY_EQUAL_NONCONT(sample.nVibType, VIB_SQUARE);
1805 	VERIFY_EQUAL_NONCONT(sample.nVibSweep, 3);
1806 	VERIFY_EQUAL_NONCONT(sample.nVibRate, 4);
1807 	VERIFY_EQUAL_NONCONT(sample.nVibDepth, 5);
1808 
1809 	// Sample Data
1810 	for(size_t i = 0; i < 6; i++)
1811 	{
1812 		VERIFY_EQUAL_NONCONT(sample.sample8()[i], 18);
1813 	}
1814 	for(size_t i = 6; i < 16; i++)
1815 	{
1816 		VERIFY_EQUAL_NONCONT(sample.sample8()[i], 0);
1817 	}
1818 
1819 	// Instruments
1820 	VERIFY_EQUAL_NONCONT(sndFile.GetNumInstruments(), 1);
1821 	const ModInstrument *pIns = sndFile.Instruments[1];
1822 	VERIFY_EQUAL_NONCONT(pIns->nFadeOut, 1024);
1823 	VERIFY_EQUAL_NONCONT(pIns->nPan, 128);
1824 	VERIFY_EQUAL_NONCONT(pIns->dwFlags, InstrumentFlags(0));
1825 
1826 	VERIFY_EQUAL_NONCONT(pIns->nPPS, 0);
1827 	VERIFY_EQUAL_NONCONT(pIns->nPPC, NOTE_MIDDLEC - 1);
1828 
1829 	VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
1830 	VERIFY_EQUAL_NONCONT(pIns->resampling, SRCMODE_SINC8LP);
1831 
1832 	VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), false);
1833 	VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0);
1834 	VERIFY_EQUAL_NONCONT(pIns->IsResonanceEnabled(), false);
1835 	VERIFY_EQUAL_NONCONT(pIns->GetResonance(), 0);
1836 	VERIFY_EQUAL_NONCONT(pIns->filterMode, FilterMode::Unchanged);
1837 
1838 	VERIFY_EQUAL_NONCONT(pIns->nVolSwing, 0);
1839 	VERIFY_EQUAL_NONCONT(pIns->nPanSwing, 0);
1840 	VERIFY_EQUAL_NONCONT(pIns->nCutSwing, 0);
1841 	VERIFY_EQUAL_NONCONT(pIns->nResSwing, 0);
1842 
1843 	VERIFY_EQUAL_NONCONT(pIns->nNNA, NewNoteAction::NoteCut);
1844 	VERIFY_EQUAL_NONCONT(pIns->nDCT, DuplicateCheckType::None);
1845 
1846 	VERIFY_EQUAL_NONCONT(pIns->nMixPlug, 1);
1847 	VERIFY_EQUAL_NONCONT(pIns->nMidiChannel, 16);
1848 	VERIFY_EQUAL_NONCONT(pIns->nMidiProgram, 64);
1849 	VERIFY_EQUAL_NONCONT(pIns->wMidiBank, 2);
1850 	VERIFY_EQUAL_NONCONT(pIns->midiPWD, 8);
1851 
1852 	VERIFY_EQUAL_NONCONT(pIns->pTuning, sndFile.GetDefaultTuning());
1853 
1854 	VERIFY_EQUAL_NONCONT(pIns->pitchToTempoLock, TEMPO(0, 0));
1855 
1856 	VERIFY_EQUAL_NONCONT(pIns->pluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME);
1857 	VERIFY_EQUAL_NONCONT(pIns->pluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI);
1858 
1859 	for(size_t i = sndFile.GetModSpecifications().noteMin; i < sndFile.GetModSpecifications().noteMax; i++)
1860 	{
1861 		VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? 2 : 1);
1862 	}
1863 
1864 	VERIFY_EQUAL_NONCONT(pIns->VolEnv.dwFlags, ENV_ENABLED | ENV_SUSTAIN);
1865 	VERIFY_EQUAL_NONCONT(pIns->VolEnv.size(), 3);
1866 	VERIFY_EQUAL_NONCONT(pIns->VolEnv.nReleaseNode, ENV_RELEASE_NODE_UNSET);
1867 	VERIFY_EQUAL_NONCONT(pIns->VolEnv[2].tick, 96);
1868 	VERIFY_EQUAL_NONCONT(pIns->VolEnv[2].value, 0);
1869 	VERIFY_EQUAL_NONCONT(pIns->VolEnv.nSustainStart, 1);
1870 	VERIFY_EQUAL_NONCONT(pIns->VolEnv.nSustainEnd, 1);
1871 
1872 	VERIFY_EQUAL_NONCONT(pIns->PanEnv.dwFlags, ENV_LOOP);
1873 	VERIFY_EQUAL_NONCONT(pIns->PanEnv.size(), 12);
1874 	VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopStart, 9);
1875 	VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopEnd, 11);
1876 	VERIFY_EQUAL_NONCONT(pIns->PanEnv.nReleaseNode, ENV_RELEASE_NODE_UNSET);
1877 	VERIFY_EQUAL_NONCONT(pIns->PanEnv[9].tick, 46);
1878 	VERIFY_EQUAL_NONCONT(pIns->PanEnv[9].value, 23);
1879 
1880 	VERIFY_EQUAL_NONCONT(pIns->PitchEnv.dwFlags, EnvelopeFlags(0));
1881 	VERIFY_EQUAL_NONCONT(pIns->PitchEnv.size(), 0);
1882 
1883 	// Sequences
1884 	VERIFY_EQUAL_NONCONT(sndFile.Order.GetNumSequences(), 1);
1885 	VERIFY_EQUAL_NONCONT(sndFile.Order()[0], 0);
1886 	VERIFY_EQUAL_NONCONT(sndFile.Order()[1], 1);
1887 
1888 	// Patterns
1889 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 2);
1890 
1891 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetName(), "First Pattern");
1892 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetNumRows(), 64);
1893 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetNumChannels(), 2);
1894 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetOverrideSignature(), false);
1895 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetRowsPerBeat(), 0);
1896 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetRowsPerMeasure(), 0);
1897 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.IsPatternEmpty(0), true);
1898 
1899 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetName(), "Second Pattern");
1900 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetNumRows(), 32);
1901 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetNumChannels(), 2);
1902 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetOverrideSignature(), false);
1903 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerBeat(), 0);
1904 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerMeasure(), 0);
1905 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.IsPatternEmpty(1), false);
1906 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->IsPcNote(), false);
1907 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->note, NOTE_NONE);
1908 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->instr, 0);
1909 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->volcmd, VOLCMD_VIBRATOSPEED);
1910 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->vol, 15);
1911 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 0)->IsEmpty(), true);
1912 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsEmpty(), false);
1913 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsPcNote(), false);
1914 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->note, NOTE_MIDDLEC + 12);
1915 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->instr, 45);
1916 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->volcmd, VOLCMD_VOLSLIDEDOWN);
1917 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->vol, 5);
1918 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->command, CMD_PANNING8);
1919 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->param, 0xFF);
1920 
1921 	// Test 4-Bit Panning conversion
1922 	for(int i = 0; i < 16; i++)
1923 	{
1924 		VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(10 + i, 0)->vol, i * 4);
1925 	}
1926 
1927 	// Plugins
1928 #ifndef NO_PLUGINS
1929 	const SNDMIXPLUGIN &plug = sndFile.m_MixPlugins[0];
1930 	VERIFY_EQUAL_NONCONT(plug.GetName(), U_("First Plugin"));
1931 	VERIFY_EQUAL_NONCONT(plug.fDryRatio, 0.26f);
1932 	VERIFY_EQUAL_NONCONT(plug.IsMasterEffect(), true);
1933 	VERIFY_EQUAL_NONCONT(plug.GetGain(), 11);
1934 #endif // NO_PLUGINS
1935 }
1936 
1937 
1938 // Check if our test file was loaded correctly.
TestLoadMPTMFile(const CSoundFile & sndFile)1939 static void TestLoadMPTMFile(const CSoundFile &sndFile)
1940 {
1941 
1942 	// Global Variables
1943 	VERIFY_EQUAL_NONCONT(sndFile.GetTitle(), "Test Module_____________X");
1944 	VERIFY_EQUAL_NONCONT(sndFile.m_songMessage.substr(0, 32), "OpenMPT Module Loader Test Suite");
1945 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultTempo, TEMPO(139, 999));
1946 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultSpeed, 5);
1947 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 128);
1948 	VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 42);
1949 	VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 23);
1950 	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_ITCOMPATGXX | SONG_ITOLDEFFECTS);
1951 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[MSF_COMPATIBLE_PLAY], true);
1952 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMIDICCBugEmulation], false);
1953 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMPTOldSwingBehaviour], false);
1954 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kOldMIDIPitchBends], false);
1955 	VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), MixLevels::Compatible);
1956 	VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, TempoMode::Modern);
1957 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerBeat, 6);
1958 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultRowsPerMeasure, 12);
1959 	VERIFY_EQUAL_NONCONT(sndFile.m_dwCreatedWithVersion, MPT_V("1.19.02.05"));
1960 	VERIFY_EQUAL_NONCONT(sndFile.m_nResampling, SRCMODE_SINC8LP);
1961 	VERIFY_EQUAL_NONCONT(sndFile.m_songArtist, U_("Tester"));
1962 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing.size(), 6);
1963 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[0], 29360125);
1964 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[1], 4194305);
1965 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[2], 29360128);
1966 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[3], 4194305);
1967 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[4], 29360128);
1968 	VERIFY_EQUAL_NONCONT(sndFile.m_tempoSwing[5], 4194305);
1969 
1970 	// Edit history
1971 	VERIFY_EQUAL_NONCONT(sndFile.GetFileHistory().size() > 15, true);
1972 	const FileHistory &fh = sndFile.GetFileHistory().front();
1973 	VERIFY_EQUAL_NONCONT(fh.loadDate.tm_year, 111);
1974 	VERIFY_EQUAL_NONCONT(fh.loadDate.tm_mon, 5);
1975 	VERIFY_EQUAL_NONCONT(fh.loadDate.tm_mday, 14);
1976 	VERIFY_EQUAL_NONCONT(fh.loadDate.tm_hour, 21);
1977 	VERIFY_EQUAL_NONCONT(fh.loadDate.tm_min, 8);
1978 	VERIFY_EQUAL_NONCONT(fh.loadDate.tm_sec, 32);
1979 	VERIFY_EQUAL_NONCONT((uint32)((double)fh.openTime / HISTORY_TIMER_PRECISION), 31);
1980 
1981 	// Macros
1982 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetParameteredMacroType(0), kSFxReso);
1983 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetParameteredMacroType(1), kSFxDryWet);
1984 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetParameteredMacroType(2), kSFxPolyAT);
1985 	VERIFY_EQUAL_NONCONT(sndFile.m_MidiCfg.GetFixedMacroType(), kZxxResoFltMode);
1986 
1987 	// Channels
1988 	VERIFY_EQUAL_NONCONT(sndFile.GetNumChannels(), 70);
1989 	VERIFY_EQUAL_NONCONT((sndFile.ChnSettings[0].szName == "First Channel"), true);
1990 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].nPan, 32);
1991 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].nVolume, 32);
1992 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].dwFlags, CHN_MUTE);
1993 #ifndef NO_PLUGINS
1994 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].nMixPlugin, 0);
1995 #endif // NO_PLUGINS
1996 
1997 	VERIFY_EQUAL_NONCONT((sndFile.ChnSettings[1].szName == "Second Channel"), true);
1998 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].nPan, 128);
1999 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].nVolume, 16);
2000 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].dwFlags, CHN_SURROUND);
2001 #ifndef NO_PLUGINS
2002 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].nMixPlugin, 1);
2003 #endif // NO_PLUGINS
2004 
2005 	VERIFY_EQUAL_NONCONT((sndFile.ChnSettings[69].szName == "Last Channel______X"), true);
2006 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[69].nPan, 256);
2007 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[69].nVolume, 7);
2008 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[69].dwFlags, ChannelFlags(0));
2009 #ifndef NO_PLUGINS
2010 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[69].nMixPlugin, 1);
2011 #endif // NO_PLUGINS
2012 	// Samples
2013 	VERIFY_EQUAL_NONCONT(sndFile.GetNumSamples(), 4);
2014 	{
2015 		const ModSample &sample = sndFile.GetSample(1);
2016 		VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1);
2017 		VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1);
2018 		VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1);
2019 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 16);
2020 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_MPT), 9001);
2021 		VERIFY_EQUAL_NONCONT(sample.nVolume, 32 * 4);
2022 		VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 16);
2023 		VERIFY_EQUAL_NONCONT(sample.nPan, 160);
2024 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_PANNING | CHN_LOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN);
2025 
2026 		VERIFY_EQUAL_NONCONT(sample.nLoopStart, 1);
2027 		VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 8);
2028 		VERIFY_EQUAL_NONCONT(sample.nSustainStart, 1);
2029 		VERIFY_EQUAL_NONCONT(sample.nSustainEnd, 7);
2030 
2031 		VERIFY_EQUAL_NONCONT(sample.nVibType, VIB_SQUARE);
2032 		VERIFY_EQUAL_NONCONT(sample.nVibSweep, 3);
2033 		VERIFY_EQUAL_NONCONT(sample.nVibRate, 4);
2034 		VERIFY_EQUAL_NONCONT(sample.nVibDepth, 5);
2035 
2036 		// Sample Data
2037 		for(size_t i = 0; i < 6; i++)
2038 		{
2039 			VERIFY_EQUAL_NONCONT(sample.sample8()[i], 18);
2040 		}
2041 		for(size_t i = 6; i < 16; i++)
2042 		{
2043 			VERIFY_EQUAL_NONCONT(sample.sample8()[i], 0);
2044 		}
2045 
2046 		VERIFY_EQUAL_NONCONT(sample.cues[0], 2);
2047 		VERIFY_EQUAL_NONCONT(sample.cues[8], 9);
2048 	}
2049 
2050 	{
2051 		const ModSample &sample = sndFile.GetSample(2);
2052 		VERIFY_EQUAL_NONCONT((sndFile.m_szNames[2] == "Stereo / 16-Bit"), true);
2053 		VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 4);
2054 		VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 2);
2055 		VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 2);
2056 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 16 * 4);
2057 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_MPT), 16000);
2058 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_16BIT | CHN_STEREO | CHN_LOOP);
2059 
2060 		// Sample Data (Stereo Interleaved)
2061 		for(size_t i = 0; i < 7; i++)
2062 		{
2063 			VERIFY_EQUAL_NONCONT(sample.sample16()[4 + i], int16(-32768));
2064 		}
2065 
2066 		VERIFY_EQUAL_NONCONT(sample.cues[0], 3);
2067 		VERIFY_EQUAL_NONCONT(sample.cues[8], 14);
2068 	}
2069 
2070 	// External sample
2071 	{
2072 		const ModSample &sample = sndFile.GetSample(4);
2073 		VERIFY_EQUAL_NONCONT((sndFile.m_szNames[4] == "Overridden Name"), true);
2074 		VERIFY_EQUAL_NONCONT((sample.filename == "External"), true);
2075 #ifdef MPT_EXTERNAL_SAMPLES
2076 		VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1);
2077 		VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1);
2078 		VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1);
2079 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 64);
2080 
2081 		VERIFY_EQUAL_NONCONT(sample.nLoopStart, 42);
2082 		VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 55);
2083 		VERIFY_EQUAL_NONCONT(sample.nSustainStart, 42);
2084 		VERIFY_EQUAL_NONCONT(sample.nSustainEnd, 55);
2085 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_LOOP | CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN | SMP_KEEPONDISK);
2086 #endif // MPT_EXTERNAL_SAMPLES
2087 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_MPT), 10101);
2088 		VERIFY_EQUAL_NONCONT(sample.nVolume, 26 * 4);
2089 		VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 26);
2090 		VERIFY_EQUAL_NONCONT(sample.nPan, 26 * 4);
2091 
2092 		VERIFY_EQUAL_NONCONT(sample.nVibType, VIB_SINE);
2093 		VERIFY_EQUAL_NONCONT(sample.nVibSweep, 37);
2094 		VERIFY_EQUAL_NONCONT(sample.nVibRate, 42);
2095 		VERIFY_EQUAL_NONCONT(sample.nVibDepth, 23);
2096 
2097 		// Sample Data
2098 #ifdef MPT_EXTERNAL_SAMPLES
2099 		for(size_t i = 0; i < 16; i++)
2100 		{
2101 			VERIFY_EQUAL_NONCONT(sample.sample8()[i], int8(45));
2102 		}
2103 #endif // MPT_EXTERNAL_SAMPLES
2104 
2105 		VERIFY_EQUAL_NONCONT(sample.cues[0], 10);
2106 		VERIFY_EQUAL_NONCONT(sample.cues[8], 50);
2107 	}
2108 
2109 	// Instruments
2110 	VERIFY_EQUAL_NONCONT(sndFile.GetNumInstruments(), 2);
2111 	for(INSTRUMENTINDEX ins = 1; ins <= 2; ins++)
2112 	{
2113 		const ModInstrument *pIns = sndFile.Instruments[ins];
2114 		VERIFY_EQUAL_NONCONT(pIns->nGlobalVol, 32);
2115 		VERIFY_EQUAL_NONCONT(pIns->nFadeOut, 1024);
2116 		VERIFY_EQUAL_NONCONT(pIns->nPan, 64);
2117 		VERIFY_EQUAL_NONCONT(pIns->dwFlags, INS_SETPANNING);
2118 
2119 		VERIFY_EQUAL_NONCONT(pIns->nPPS, 8);
2120 		VERIFY_EQUAL_NONCONT(pIns->nPPC, (NOTE_MIDDLEC - NOTE_MIN) + 6);	// F#5
2121 
2122 		VERIFY_EQUAL_NONCONT(pIns->nVolRampUp, 1200);
2123 		VERIFY_EQUAL_NONCONT(pIns->resampling, SRCMODE_SINC8LP);
2124 
2125 		VERIFY_EQUAL_NONCONT(pIns->IsCutoffEnabled(), true);
2126 		VERIFY_EQUAL_NONCONT(pIns->GetCutoff(), 0x32);
2127 		VERIFY_EQUAL_NONCONT(pIns->IsResonanceEnabled(), true);
2128 		VERIFY_EQUAL_NONCONT(pIns->GetResonance(), 0x64);
2129 		VERIFY_EQUAL_NONCONT(pIns->filterMode, FilterMode::HighPass);
2130 
2131 		VERIFY_EQUAL_NONCONT(pIns->nVolSwing, 0x30);
2132 		VERIFY_EQUAL_NONCONT(pIns->nPanSwing, 0x18);
2133 		VERIFY_EQUAL_NONCONT(pIns->nCutSwing, 0x0C);
2134 		VERIFY_EQUAL_NONCONT(pIns->nResSwing, 0x3C);
2135 
2136 		VERIFY_EQUAL_NONCONT(pIns->nNNA, NewNoteAction::Continue);
2137 		VERIFY_EQUAL_NONCONT(pIns->nDCT, DuplicateCheckType::Note);
2138 		VERIFY_EQUAL_NONCONT(pIns->nDNA, DuplicateNoteAction::NoteFade);
2139 
2140 		VERIFY_EQUAL_NONCONT(pIns->nMixPlug, 1);
2141 		VERIFY_EQUAL_NONCONT(pIns->nMidiChannel, 16);
2142 		VERIFY_EQUAL_NONCONT(pIns->nMidiProgram, 64);
2143 		VERIFY_EQUAL_NONCONT(pIns->wMidiBank, 2);
2144 		VERIFY_EQUAL_NONCONT(pIns->midiPWD, ins);
2145 
2146 		VERIFY_EQUAL_NONCONT(pIns->pTuning, sndFile.GetDefaultTuning());
2147 
2148 		VERIFY_EQUAL_NONCONT(pIns->pitchToTempoLock, TEMPO(130, 2000));
2149 
2150 		VERIFY_EQUAL_NONCONT(pIns->pluginVelocityHandling, PLUGIN_VELOCITYHANDLING_VOLUME);
2151 		VERIFY_EQUAL_NONCONT(pIns->pluginVolumeHandling, PLUGIN_VOLUMEHANDLING_MIDI);
2152 
2153 		for(size_t i = 0; i < NOTE_MAX; i++)
2154 		{
2155 			VERIFY_EQUAL_NONCONT(pIns->Keyboard[i], (i == NOTE_MIDDLEC - 1) ? 99 : 1);
2156 			VERIFY_EQUAL_NONCONT(pIns->NoteMap[i], (i == NOTE_MIDDLEC - 1) ? (i + 13) : (i + 1));
2157 		}
2158 
2159 		VERIFY_EQUAL_NONCONT(pIns->VolEnv.dwFlags, ENV_ENABLED | ENV_CARRY);
2160 		VERIFY_EQUAL_NONCONT(pIns->VolEnv.size(), 3);
2161 		VERIFY_EQUAL_NONCONT(pIns->VolEnv.nReleaseNode, 1);
2162 		VERIFY_EQUAL_NONCONT(pIns->VolEnv[2].tick, 96);
2163 		VERIFY_EQUAL_NONCONT(pIns->VolEnv[2].value, 0);
2164 
2165 		VERIFY_EQUAL_NONCONT(pIns->PanEnv.dwFlags, ENV_LOOP);
2166 		VERIFY_EQUAL_NONCONT(pIns->PanEnv.size(), 76);
2167 		VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopStart, 22);
2168 		VERIFY_EQUAL_NONCONT(pIns->PanEnv.nLoopEnd, 29);
2169 		VERIFY_EQUAL_NONCONT(pIns->PanEnv.nReleaseNode, ENV_RELEASE_NODE_UNSET);
2170 		VERIFY_EQUAL_NONCONT(pIns->PanEnv[75].tick, 427);
2171 		VERIFY_EQUAL_NONCONT(pIns->PanEnv[75].value, 27);
2172 
2173 		VERIFY_EQUAL_NONCONT(pIns->PitchEnv.dwFlags, ENV_ENABLED | ENV_CARRY | ENV_SUSTAIN | ENV_FILTER);
2174 		VERIFY_EQUAL_NONCONT(pIns->PitchEnv.size(), 3);
2175 		VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nSustainStart, 1);
2176 		VERIFY_EQUAL_NONCONT(pIns->PitchEnv.nSustainEnd, 2);
2177 		VERIFY_EQUAL_NONCONT(pIns->PitchEnv[1].tick, 96);
2178 		VERIFY_EQUAL_NONCONT(pIns->PitchEnv[1].value, 64);
2179 	}
2180 	// Sequences
2181 	VERIFY_EQUAL_NONCONT(sndFile.Order.GetNumSequences(), 2);
2182 
2183 	VERIFY_EQUAL_NONCONT(sndFile.Order(0).GetLengthTailTrimmed(), 3);
2184 	VERIFY_EQUAL_NONCONT(sndFile.Order(0).GetName(), U_("First Sequence"));
2185 	VERIFY_EQUAL_NONCONT(sndFile.Order(0)[0], sndFile.Order.GetIgnoreIndex());
2186 	VERIFY_EQUAL_NONCONT(sndFile.Order(0)[1], 0);
2187 	VERIFY_EQUAL_NONCONT(sndFile.Order(0)[2], sndFile.Order.GetIgnoreIndex());
2188 	VERIFY_EQUAL_NONCONT(sndFile.Order(0).GetRestartPos(), 1);
2189 
2190 	VERIFY_EQUAL_NONCONT(sndFile.Order(1).GetLengthTailTrimmed(), 3);
2191 	VERIFY_EQUAL_NONCONT(sndFile.Order(1).GetName(), U_("Second Sequence"));
2192 	VERIFY_EQUAL_NONCONT(sndFile.Order(1)[0], 1);
2193 	VERIFY_EQUAL_NONCONT(sndFile.Order(1)[1], 2);
2194 	VERIFY_EQUAL_NONCONT(sndFile.Order(1)[2], 3);
2195 	VERIFY_EQUAL_NONCONT(sndFile.Order(1).GetRestartPos(), 2);
2196 
2197 	// Patterns
2198 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 2);
2199 
2200 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetName(), "First Pattern");
2201 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetNumRows(), 70);
2202 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetNumChannels(), 70);
2203 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetOverrideSignature(), true);
2204 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetRowsPerBeat(), 5);
2205 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetRowsPerMeasure(), 10);
2206 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].HasTempoSwing(), true);
2207 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.IsPatternEmpty(0), true);
2208 
2209 	{
2210 		TempoSwing swing = sndFile.Patterns[0].GetTempoSwing();
2211 		VERIFY_EQUAL_NONCONT(swing.size(), 5);
2212 		VERIFY_EQUAL_NONCONT(swing[0], 16770149);
2213 		VERIFY_EQUAL_NONCONT(swing[1], 16803696);
2214 		VERIFY_EQUAL_NONCONT(swing[2], 16770157);
2215 		VERIFY_EQUAL_NONCONT(swing[3], 29347774);
2216 		VERIFY_EQUAL_NONCONT(swing[4], 4194304);
2217 	}
2218 
2219 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetName(), "Second Pattern");
2220 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetNumRows(), 32);
2221 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetNumChannels(), 70);
2222 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetOverrideSignature(), false);
2223 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerBeat(), 0);
2224 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerMeasure(), 0);
2225 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].HasTempoSwing(), false);
2226 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.IsPatternEmpty(1), false);
2227 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->IsPcNote(), true);
2228 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->note, NOTE_PC);
2229 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->instr, 99);
2230 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->GetValueVolCol(), 1);
2231 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(0, 0)->GetValueEffectCol(), 200);
2232 
2233 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 0)->IsEmpty(), true);
2234 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsEmpty(), false);
2235 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->IsPcNote(), false);
2236 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->note, NOTE_MIDDLEC + 12);
2237 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->instr, 45);
2238 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->volcmd, VOLCMD_VOLSLIDEDOWN);
2239 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->vol, 5);
2240 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->command, CMD_PANNING8);
2241 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(31, 1)->param, 0xFF);
2242 
2243 	// Plugins
2244 #ifndef NO_PLUGINS
2245 	const SNDMIXPLUGIN &plug = sndFile.m_MixPlugins[0];
2246 	VERIFY_EQUAL_NONCONT(plug.GetName(), U_("First Plugin"));
2247 	VERIFY_EQUAL_NONCONT(plug.fDryRatio, 0.26f);
2248 	VERIFY_EQUAL_NONCONT(plug.IsMasterEffect(), true);
2249 	VERIFY_EQUAL_NONCONT(plug.GetGain(), 11);
2250 	VERIFY_EQUAL_NONCONT(plug.pMixPlugin != nullptr, true);
2251 	if(plug.pMixPlugin)
2252 	{
2253 		VERIFY_EQUAL_NONCONT(plug.pMixPlugin->GetParameter(1), 0.5f);
2254 		VERIFY_EQUAL_NONCONT(plug.pMixPlugin->IsInstrument(), false);
2255 	}
2256 #endif // NO_PLUGINS
2257 
2258 #ifdef MODPLUG_TRACKER
2259 	// MIDI Mapping
2260 	VERIFY_EQUAL_NONCONT(sndFile.GetMIDIMapper().GetCount(), 1);
2261 	const CMIDIMappingDirective &mapping = sndFile.GetMIDIMapper().GetDirective(0);
2262 	VERIFY_EQUAL_NONCONT(mapping.GetAllowPatternEdit(), true);
2263 	VERIFY_EQUAL_NONCONT(mapping.GetCaptureMIDI(), false);
2264 	VERIFY_EQUAL_NONCONT(mapping.IsActive(), true);
2265 	VERIFY_EQUAL_NONCONT(mapping.GetAnyChannel(), false);
2266 	VERIFY_EQUAL_NONCONT(mapping.GetChannel(), 5);
2267 	VERIFY_EQUAL_NONCONT(mapping.GetPlugIndex(), 1);
2268 	VERIFY_EQUAL_NONCONT(mapping.GetParamIndex(), 0);
2269 	VERIFY_EQUAL_NONCONT(mapping.GetEvent(), MIDIEvents::evControllerChange);
2270 	VERIFY_EQUAL_NONCONT(mapping.GetController(), MIDIEvents::MIDICC_ModulationWheel_Coarse);
2271 
2272 	// Channel colors
2273 	const auto &chns = sndFile.ChnSettings;
2274 	VERIFY_EQUAL_NONCONT(chns[0].color, RGB(255, 0, 0));
2275 	VERIFY_EQUAL_NONCONT(chns[1].color, RGB(0, 255, 0));
2276 	VERIFY_EQUAL_NONCONT(chns[2].color, RGB(0, 0, 255));
2277 	VERIFY_EQUAL_NONCONT(chns[3].color, ModChannelSettings::INVALID_COLOR);
2278 	VERIFY_EQUAL_NONCONT(chns[67].color, RGB(255, 0, 255));
2279 	VERIFY_EQUAL_NONCONT(chns[68].color, RGB(255, 255, 0));
2280 	VERIFY_EQUAL_NONCONT(chns[69].color, ModChannelSettings::INVALID_COLOR);
2281 #endif
2282 
2283 	VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(0)), 0);
2284 	VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(80)), 80);
2285 	VERIFY_EQUAL_NONCONT(sndFile.FrequencyToCutOff(sndFile.CutOffToFrequency(127)), 127);
2286 }
2287 
2288 
2289 // Check if our test file was loaded correctly.
TestLoadS3MFile(const CSoundFile & sndFile,bool resaved)2290 static void TestLoadS3MFile(const CSoundFile &sndFile, bool resaved)
2291 {
2292 
2293 	// Global Variables
2294 	VERIFY_EQUAL_NONCONT(sndFile.GetTitle(), "S3M_Test__________________X");
2295 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultTempo, TEMPO(33, 0));
2296 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultSpeed, 254);
2297 	VERIFY_EQUAL_NONCONT(sndFile.m_nDefaultGlobalVolume, 32 * 4);
2298 	VERIFY_EQUAL_NONCONT(sndFile.m_nVSTiVolume, 36);
2299 	VERIFY_EQUAL_NONCONT(sndFile.m_nSamplePreAmp, 16);
2300 	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_FASTVOLSLIDES);
2301 	VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), MixLevels::Compatible);
2302 	VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, TempoMode::Classic);
2303 	VERIFY_EQUAL_NONCONT(sndFile.m_dwLastSavedWithVersion, resaved ? Version::Current() : MPT_V("1.27.00.00"));
2304 
2305 	// Channels
2306 	VERIFY_EQUAL_NONCONT(sndFile.GetNumChannels(), 4);
2307 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].nPan, 0);
2308 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[0].dwFlags, ChannelFlags(0));
2309 
2310 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].nPan, 256);
2311 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[1].dwFlags, CHN_MUTE);
2312 
2313 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[2].nPan, 85);
2314 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[2].dwFlags, ChannelFlags(0));
2315 
2316 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[3].nPan, 171);
2317 	VERIFY_EQUAL_NONCONT(sndFile.ChnSettings[3].dwFlags, CHN_MUTE);
2318 
2319 	// Samples
2320 	VERIFY_EQUAL_NONCONT(sndFile.GetNumSamples(), 4);
2321 	{
2322 		const ModSample &sample = sndFile.GetSample(1);
2323 		VERIFY_EQUAL_NONCONT(sndFile.m_szNames[1], "Sample_1__________________X");
2324 		VERIFY_EQUAL_NONCONT(sample.filename, "Filename_1_X");
2325 		VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1);
2326 		VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1);
2327 		VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1);
2328 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 60);
2329 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 9001);
2330 		VERIFY_EQUAL_NONCONT(sample.nVolume, 32 * 4);
2331 		VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 64);
2332 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_LOOP);
2333 
2334 		VERIFY_EQUAL_NONCONT(sample.nLoopStart, 16);
2335 		VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 60);
2336 
2337 		// Sample Data
2338 		for(size_t i = 0; i < 30; i++)
2339 		{
2340 			VERIFY_EQUAL_NONCONT(sample.sample8()[i], 127);
2341 		}
2342 		for(size_t i = 31; i < 60; i++)
2343 		{
2344 			VERIFY_EQUAL_NONCONT(sample.sample8()[i], -128);
2345 		}
2346 	}
2347 
2348 	{
2349 		const ModSample &sample = sndFile.GetSample(2);
2350 		VERIFY_EQUAL_NONCONT(sndFile.m_szNames[2], "Empty");
2351 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 16384);
2352 		VERIFY_EQUAL_NONCONT(sample.nVolume, 2 * 4);
2353 	}
2354 
2355 	{
2356 		const ModSample &sample = sndFile.GetSample(3);
2357 		VERIFY_EQUAL_NONCONT(sndFile.m_szNames[3], "Stereo / 16-Bit");
2358 		VERIFY_EQUAL_NONCONT(sample.filename, "Filename_3_X");
2359 		VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 4);
2360 		VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 2);
2361 		VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 2);
2362 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 64);
2363 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 16000);
2364 		VERIFY_EQUAL_NONCONT(sample.nVolume, 0);
2365 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_LOOP | CHN_16BIT | CHN_STEREO);
2366 
2367 		VERIFY_EQUAL_NONCONT(sample.nLoopStart, 0);
2368 		VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 16);
2369 
2370 		// Sample Data (Stereo Interleaved)
2371 		for(size_t i = 0; i < 7; i++)
2372 		{
2373 			VERIFY_EQUAL_NONCONT(sample.sample16()[4 + i], int16(-32768));
2374 		}
2375 	}
2376 
2377 	{
2378 		const ModSample &sample = sndFile.GetSample(4);
2379 		VERIFY_EQUAL_NONCONT(sndFile.m_szNames[4], "adlib");
2380 		VERIFY_EQUAL_NONCONT((sample.filename == ""), true);
2381 		VERIFY_EQUAL_NONCONT(sample.GetSampleRate(MOD_TYPE_S3M), 8363);
2382 		VERIFY_EQUAL_NONCONT(sample.nVolume, 58 * 4);
2383 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_ADLIB);
2384 		VERIFY_EQUAL_NONCONT(sample.adlib, (OPLPatch{ { 0x00, 0x00, 0xC0, 0x00, 0xF0, 0xD2, 0x05, 0xB3, 0x01, 0x00, 0x00, 0x00 } }));
2385 	}
2386 
2387 	// Orders
2388 	VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 0);
2389 	VERIFY_EQUAL_NONCONT(sndFile.Order().GetLengthTailTrimmed(), 5);
2390 	VERIFY_EQUAL_NONCONT(sndFile.Order()[0], 0);
2391 	VERIFY_EQUAL_NONCONT(sndFile.Order()[1], sndFile.Order.GetIgnoreIndex());
2392 	VERIFY_EQUAL_NONCONT(sndFile.Order()[2], sndFile.Order.GetInvalidPatIndex());
2393 	VERIFY_EQUAL_NONCONT(sndFile.Order()[3], 1);
2394 	VERIFY_EQUAL_NONCONT(sndFile.Order()[4], 0);
2395 
2396 	// Patterns
2397 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 2);
2398 
2399 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetNumRows(), 64);
2400 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetNumChannels(), 4);
2401 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetOverrideSignature(), false);
2402 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(0, 0)->note, NOTE_MIN + 12);
2403 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(1, 0)->note, NOTE_MIN + 107);
2404 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(0, 1)->volcmd, VOLCMD_VOLUME);
2405 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(0, 1)->vol, 0);
2406 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(1, 1)->volcmd, VOLCMD_VOLUME);
2407 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(1, 1)->vol, 64);
2408 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(2, 1)->volcmd, VOLCMD_PANNING);
2409 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(2, 1)->vol, 0);
2410 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(3, 1)->volcmd, VOLCMD_PANNING);
2411 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(3, 1)->vol, 64);
2412 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(0, 3)->command, CMD_SPEED);
2413 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[0].GetpModCommand(0, 3)->param, 0x11);
2414 
2415 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetNumRows(), 64);
2416 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.IsPatternEmpty(1), false);
2417 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(63, 3)->param, 0x04);
2418 }
2419 
2420 
2421 // Check if our test file was loaded correctly.
TestLoadMODFile(CSoundFile & sndFile)2422 static void TestLoadMODFile(CSoundFile &sndFile)
2423 {
2424 	// Global Variables
2425 	VERIFY_EQUAL_NONCONT(sndFile.GetTitle(), "MOD_Test___________X");
2426 	VERIFY_EQUAL_NONCONT((sndFile.m_SongFlags & SONG_FILE_FLAGS), SONG_PT_MODE | SONG_AMIGALIMITS | SONG_ISAMIGA);
2427 	VERIFY_EQUAL_NONCONT(sndFile.GetMixLevels(), MixLevels::Compatible);
2428 	VERIFY_EQUAL_NONCONT(sndFile.m_nTempoMode, TempoMode::Classic);
2429 	VERIFY_EQUAL_NONCONT(sndFile.GetNumChannels(), 4);
2430 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMODOneShotLoops], true);
2431 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMODSampleSwap], true);
2432 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMODIgnorePanning], true);
2433 	VERIFY_EQUAL_NONCONT(sndFile.m_playBehaviour[kMODVBlankTiming], false);
2434 
2435 	// Test GetLength code, in particular with subsongs
2436 	VERIFY_EQUAL_NONCONT(sndFile.GetLength(eNoAdjust, GetLengthTarget(0, 4)).back().targetReached, false);
2437 
2438 	const auto allSubSongs = sndFile.GetLength(eNoAdjust, GetLengthTarget(true));
2439 	VERIFY_EQUAL_NONCONT(allSubSongs.size(), 2);
2440 	VERIFY_EQUAL_EPS(allSubSongs[0].duration, 2.04, 0.1);
2441 	VERIFY_EQUAL_EPS(allSubSongs[1].duration, 118.84, 0.1);
2442 	VERIFY_EQUAL_NONCONT(allSubSongs[0].lastOrder, 0);
2443 	VERIFY_EQUAL_NONCONT(allSubSongs[0].lastRow, 1);
2444 	VERIFY_EQUAL_NONCONT(allSubSongs[1].lastOrder, 2);
2445 	VERIFY_EQUAL_NONCONT(allSubSongs[1].lastRow, 61);
2446 	VERIFY_EQUAL_NONCONT(allSubSongs[1].startOrder, 2);
2447 	VERIFY_EQUAL_NONCONT(allSubSongs[1].startRow, 0);
2448 
2449 	// Samples
2450 	VERIFY_EQUAL_NONCONT(sndFile.GetNumSamples(), 31);
2451 	{
2452 		const ModSample &sample = sndFile.GetSample(1);
2453 		VERIFY_EQUAL_NONCONT(sndFile.m_szNames[1], "Sample_1_____________X");
2454 		VERIFY_EQUAL_NONCONT(sample.GetBytesPerSample(), 1);
2455 		VERIFY_EQUAL_NONCONT(sample.GetNumChannels(), 1);
2456 		VERIFY_EQUAL_NONCONT(sample.GetElementarySampleSize(), 1);
2457 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 1244);
2458 		VERIFY_EQUAL_NONCONT(sample.nFineTune, 0x70);
2459 		VERIFY_EQUAL_NONCONT(sample.RelativeTone, 0);
2460 		VERIFY_EQUAL_NONCONT(sample.nVolume, 256);
2461 		VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 64);
2462 		VERIFY_EQUAL_NONCONT(sample.uFlags, CHN_LOOP);
2463 
2464 		VERIFY_EQUAL_NONCONT(sample.nLoopStart, 0);
2465 		VERIFY_EQUAL_NONCONT(sample.nLoopEnd, 128);
2466 
2467 		// Sample Data
2468 		VERIFY_EQUAL_NONCONT(sample.sample8()[0], 0);
2469 		VERIFY_EQUAL_NONCONT(sample.sample8()[1], 0);
2470 		VERIFY_EQUAL_NONCONT(sample.sample8()[2], -29);
2471 	}
2472 	{
2473 		const ModSample &sample = sndFile.GetSample(3);
2474 		VERIFY_EQUAL_NONCONT(sndFile.m_szNames[3], "OpenMPT Module Loader");
2475 		VERIFY_EQUAL_NONCONT(sample.GetSampleSizeInBytes(), 0);
2476 		VERIFY_EQUAL_NONCONT(sample.nFineTune, -0x80);
2477 		VERIFY_EQUAL_NONCONT(sample.RelativeTone, 0);
2478 		VERIFY_EQUAL_NONCONT(sample.nVolume, 4);
2479 		VERIFY_EQUAL_NONCONT(sample.nGlobalVol, 64);
2480 	}
2481 
2482 	// Orders
2483 	VERIFY_EQUAL_NONCONT(sndFile.Order().GetRestartPos(), 0);
2484 	VERIFY_EQUAL_NONCONT(sndFile.Order().GetLengthTailTrimmed(), 4);
2485 	VERIFY_EQUAL_NONCONT(sndFile.Order()[0], 0);
2486 	VERIFY_EQUAL_NONCONT(sndFile.Order()[1], 1);
2487 	VERIFY_EQUAL_NONCONT(sndFile.Order()[2], 2);
2488 	VERIFY_EQUAL_NONCONT(sndFile.Order()[3], 0);
2489 
2490 	// Patterns
2491 	VERIFY_EQUAL_NONCONT(sndFile.Patterns.GetNumPatterns(), 3);
2492 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetNumRows(), 64);
2493 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetpModCommand(1, 0)->note, NOTE_MIDDLEC + 12);
2494 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetpModCommand(16, 3)->instr, 1);
2495 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetpModCommand(19, 3)->command, CMD_PANNING8);
2496 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetpModCommand(19, 3)->param, 0x28);
2497 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetpModCommand(20, 0)->command, CMD_TEMPO);
2498 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[2].GetpModCommand(20, 1)->command, CMD_SPEED);
2499 }
2500 
2501 
2502 #ifdef MODPLUG_TRACKER
2503 
ShouldRunTests()2504 static bool ShouldRunTests()
2505 {
2506 	mpt::PathString theFile = theApp.GetInstallPath();
2507 	if(theFile.IsDirectory() && (theFile + P_("test")).IsDirectory())
2508 	{
2509 		if((theFile + P_("test\\test.mptm")).IsFile())
2510 		{
2511 			return true;
2512 		}
2513 	}
2514 	return false;
2515 }
2516 
GetTestFilenameBase()2517 static mpt::PathString GetTestFilenameBase()
2518 {
2519 	mpt::PathString theFile = theApp.GetInstallPath();
2520 	theFile += P_("test/test.");
2521 	return theFile;
2522 }
2523 
GetTempFilenameBase()2524 static mpt::PathString GetTempFilenameBase()
2525 {
2526 	return GetTestFilenameBase();
2527 }
2528 
2529 typedef CModDoc *TSoundFileContainer;
2530 
GetSoundFile(TSoundFileContainer & sndFile)2531 static CSoundFile &GetSoundFile(TSoundFileContainer &sndFile)
2532 {
2533 	return sndFile->GetSoundFile();
2534 }
2535 
2536 
CreateSoundFileContainer(const mpt::PathString & filename)2537 static TSoundFileContainer CreateSoundFileContainer(const mpt::PathString &filename)
2538 {
2539 	CModDoc *pModDoc = static_cast<CModDoc *>(theApp.OpenDocumentFile(filename.ToCString(), FALSE));
2540 	return pModDoc;
2541 }
2542 
DestroySoundFileContainer(TSoundFileContainer & sndFile)2543 static void DestroySoundFileContainer(TSoundFileContainer &sndFile)
2544 {
2545 	sndFile->OnCloseDocument();
2546 }
2547 
SaveTestFile(const TSoundFileContainer & sndFile,const mpt::PathString & filename)2548 static void SaveTestFile(const TSoundFileContainer &sndFile, const mpt::PathString &filename)
2549 {
2550 	sndFile->DoSave(filename);
2551 	// Saving the file puts it in the MRU list...
2552 	theApp.RemoveMruItem(0);
2553 }
2554 
2555 const auto SaveIT = SaveTestFile;
2556 const auto SaveXM = SaveTestFile;
2557 const auto SaveS3M = SaveTestFile;
2558 const auto SaveMOD = SaveTestFile;
2559 
2560 #else // !MODPLUG_TRACKER
2561 
ShouldRunTests()2562 static bool ShouldRunTests()
2563 {
2564 	#if MPT_TEST_HAS_FILESYSTEM
2565 		return true;
2566 	#else
2567 		return false;
2568 	#endif
2569 }
2570 
GetTestFilenameBase()2571 static mpt::PathString GetTestFilenameBase()
2572 {
2573 	return Test::GetPathPrefix() + P_("./test/test.");
2574 }
2575 
GetTempFilenameBase()2576 static mpt::PathString GetTempFilenameBase()
2577 {
2578 	return P_("./test.");
2579 }
2580 
2581 typedef std::shared_ptr<CSoundFile> TSoundFileContainer;
2582 
GetSoundFile(TSoundFileContainer & sndFile)2583 static CSoundFile &GetSoundFile(TSoundFileContainer &sndFile)
2584 {
2585 	return *sndFile.get();
2586 }
2587 
CreateSoundFileContainer(const mpt::PathString & filename)2588 static TSoundFileContainer CreateSoundFileContainer(const mpt::PathString &filename)
2589 {
2590 	mpt::ifstream stream(filename, std::ios::binary);
2591 	FileReader file = mpt::IO::make_FileCursor<mpt::PathString>(stream);
2592 	std::shared_ptr<CSoundFile> pSndFile = std::make_shared<CSoundFile>();
2593 	pSndFile->Create(file, CSoundFile::loadCompleteModule);
2594 	return pSndFile;
2595 }
2596 
DestroySoundFileContainer(TSoundFileContainer &)2597 static void DestroySoundFileContainer(TSoundFileContainer & /* sndFile */ )
2598 {
2599 	return;
2600 }
2601 
2602 #ifndef MODPLUG_NO_FILESAVE
2603 
SaveIT(const TSoundFileContainer & sndFile,const mpt::PathString & filename)2604 static void SaveIT(const TSoundFileContainer &sndFile, const mpt::PathString &filename)
2605 {
2606 	mpt::ofstream f(filename, std::ios::binary);
2607 	sndFile->SaveIT(f, filename, false);
2608 }
2609 
SaveXM(const TSoundFileContainer & sndFile,const mpt::PathString & filename)2610 static void SaveXM(const TSoundFileContainer &sndFile, const mpt::PathString &filename)
2611 {
2612 	mpt::ofstream f(filename, std::ios::binary);
2613 	sndFile->SaveXM(f, false);
2614 }
2615 
SaveS3M(const TSoundFileContainer & sndFile,const mpt::PathString & filename)2616 static void SaveS3M(const TSoundFileContainer &sndFile, const mpt::PathString &filename)
2617 {
2618 	mpt::ofstream f(filename, std::ios::binary);
2619 	sndFile->SaveS3M(f);
2620 }
2621 
SaveMOD(const TSoundFileContainer & sndFile,const mpt::PathString & filename)2622 static void SaveMOD(const TSoundFileContainer &sndFile, const mpt::PathString &filename)
2623 {
2624 	mpt::ofstream f(filename, std::ios::binary);
2625 	sndFile->SaveMod(f);
2626 }
2627 
2628 #endif // !MODPLUG_NO_FILESAVE
2629 
2630 #endif // MODPLUG_TRACKER
2631 
2632 
2633 
2634 // Test file loading and saving
TestLoadSaveFile()2635 static MPT_NOINLINE void TestLoadSaveFile()
2636 {
2637 	if(!ShouldRunTests())
2638 	{
2639 		return;
2640 	}
2641 
2642 #ifdef MODPLUG_TRACKER
2643 	bool saveMutedChannels = TrackerSettings::Instance().MiscSaveChannelMuteStatus;
2644 	TrackerSettings::Instance().MiscSaveChannelMuteStatus = true;
2645 #endif
2646 
2647 	mpt::PathString filenameBaseSrc = GetTestFilenameBase();
2648 	mpt::PathString filenameBase = GetTempFilenameBase();
2649 
2650 	// Test MPTM file loading
2651 	{
2652 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBaseSrc + P_("mptm"));
2653 
2654 		TestLoadMPTMFile(GetSoundFile(sndFileContainer));
2655 
2656 		#ifndef MODPLUG_NO_FILESAVE
2657 			// Test file saving
2658 			GetSoundFile(sndFileContainer).m_dwLastSavedWithVersion = Version::Current();
2659 			SaveIT(sndFileContainer, filenameBase + P_("saved.mptm"));
2660 		#endif
2661 
2662 		DestroySoundFileContainer(sndFileContainer);
2663 	}
2664 
2665 	// Reload the saved file and test if everything is still working correctly.
2666 	#ifndef MODPLUG_NO_FILESAVE
2667 	{
2668 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.mptm"));
2669 
2670 		TestLoadMPTMFile(GetSoundFile(sndFileContainer));
2671 
2672 		DestroySoundFileContainer(sndFileContainer);
2673 
2674 		RemoveFile(filenameBase + P_("saved.mptm"));
2675 	}
2676 	#endif
2677 
2678 	// Test XM file loading
2679 	{
2680 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBaseSrc + P_("xm"));
2681 
2682 		TestLoadXMFile(GetSoundFile(sndFileContainer));
2683 
2684 		// In OpenMPT 1.20 (up to revision 1459), there was a bug in the XM saver
2685 		// that would create broken XMs if the sample map contained samples that
2686 		// were only referenced below C-1 or above B-8 (such samples should not
2687 		// be written). Let's insert a sample there and check if re-loading the
2688 		// file still works.
2689 		GetSoundFile(sndFileContainer).m_nSamples++;
2690 		GetSoundFile(sndFileContainer).Instruments[1]->Keyboard[110] = GetSoundFile(sndFileContainer).GetNumSamples();
2691 
2692 		#ifndef MODPLUG_NO_FILESAVE
2693 			// Test file saving
2694 			GetSoundFile(sndFileContainer).m_dwLastSavedWithVersion = Version::Current();
2695 			SaveXM(sndFileContainer, filenameBase + P_("saved.xm"));
2696 		#endif
2697 
2698 		DestroySoundFileContainer(sndFileContainer);
2699 	}
2700 
2701 	// Reload the saved file and test if everything is still working correctly.
2702 	#ifndef MODPLUG_NO_FILESAVE
2703 	{
2704 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.xm"));
2705 
2706 		TestLoadXMFile(GetSoundFile(sndFileContainer));
2707 
2708 		DestroySoundFileContainer(sndFileContainer);
2709 
2710 		RemoveFile(filenameBase + P_("saved.xm"));
2711 	}
2712 	#endif
2713 
2714 	// Test S3M file loading
2715 	{
2716 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBaseSrc + P_("s3m"));
2717 		auto &sndFile = GetSoundFile(sndFileContainer);
2718 
2719 		TestLoadS3MFile(sndFile, false);
2720 
2721 		// Test GetLength code, in particular with subsongs
2722 		sndFile.ChnSettings[1].dwFlags.reset(CHN_MUTE);
2723 
2724 		VERIFY_EQUAL_EPS(sndFile.GetLength(eAdjustSamplePositions, GetLengthTarget(3, 1)).back().duration, 19.237, 0.01);
2725 		VERIFY_EQUAL_NONCONT(sndFile.GetLength(eAdjustSamplePositions, GetLengthTarget(2, 0).StartPos(0, 1, 0)).back().targetReached, false);
2726 
2727 		auto allSubSongs = sndFile.GetLength(eNoAdjust, GetLengthTarget(true));
2728 		VERIFY_EQUAL_NONCONT(allSubSongs.size(), 3);
2729 		double totalDuration = 0.0;
2730 		for(const auto &subSong : allSubSongs)
2731 		{
2732 			totalDuration += subSong.duration;
2733 		}
2734 		VERIFY_EQUAL_EPS(totalDuration, 3674.38, 1.0);
2735 
2736 		#ifndef MODPLUG_NO_FILESAVE
2737 			// Test file saving
2738 			sndFile.ChnSettings[1].dwFlags.set(CHN_MUTE);
2739 			sndFile.m_dwLastSavedWithVersion = Version::Current();
2740 			SaveS3M(sndFileContainer, filenameBase + P_("saved.s3m"));
2741 		#endif
2742 
2743 		DestroySoundFileContainer(sndFileContainer);
2744 	}
2745 
2746 	// Reload the saved file and test if everything is still working correctly.
2747 	#ifndef MODPLUG_NO_FILESAVE
2748 	{
2749 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.s3m"));
2750 
2751 		TestLoadS3MFile(GetSoundFile(sndFileContainer), true);
2752 
2753 		DestroySoundFileContainer(sndFileContainer);
2754 
2755 		RemoveFile(filenameBase + P_("saved.s3m"));
2756 	}
2757 	#endif
2758 
2759 	// Test MOD file loading
2760 	{
2761 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBaseSrc + P_("mod"));
2762 		auto &sndFile = GetSoundFile(sndFileContainer);
2763 
2764 		TestLoadMODFile(sndFile);
2765 
2766 #ifndef MODPLUG_NO_FILESAVE
2767 		// Test file saving
2768 		SaveMOD(sndFileContainer, filenameBase + P_("saved.mod"));
2769 #endif
2770 
2771 		DestroySoundFileContainer(sndFileContainer);
2772 	}
2773 
2774 	// Reload the saved file and test if everything is still working correctly.
2775 #ifndef MODPLUG_NO_FILESAVE
2776 	{
2777 		TSoundFileContainer sndFileContainer = CreateSoundFileContainer(filenameBase + P_("saved.mod"));
2778 		TestLoadMODFile(GetSoundFile(sndFileContainer));
2779 		DestroySoundFileContainer(sndFileContainer);
2780 		RemoveFile(filenameBase + P_("saved.mod"));
2781 	}
2782 #endif
2783 
2784 	// General file I/O tests
2785 	{
2786 		std::ostringstream f;
2787 		size_t bytesWritten;
2788 		mpt::IO::WriteVarInt(f, uint16(0), &bytesWritten);		VERIFY_EQUAL_NONCONT(bytesWritten, 1);
2789 		mpt::IO::WriteVarInt(f, uint16(127), &bytesWritten);	VERIFY_EQUAL_NONCONT(bytesWritten, 1);
2790 		mpt::IO::WriteVarInt(f, uint16(128), &bytesWritten);	VERIFY_EQUAL_NONCONT(bytesWritten, 2);
2791 		mpt::IO::WriteVarInt(f, uint16(16383), &bytesWritten);	VERIFY_EQUAL_NONCONT(bytesWritten, 2);
2792 		mpt::IO::WriteVarInt(f, uint16(16384), &bytesWritten);	VERIFY_EQUAL_NONCONT(bytesWritten, 3);
2793 		mpt::IO::WriteVarInt(f, uint16(65535), &bytesWritten);	VERIFY_EQUAL_NONCONT(bytesWritten, 3);
2794 		mpt::IO::WriteVarInt(f, uint64(0xFFFFFFFFFFFFFFFFull), &bytesWritten);	VERIFY_EQUAL_NONCONT(bytesWritten, 10);
2795 		std::string data = f.str();
2796 		FileReader file(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(data)));
2797 		uint64 v;
2798 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 0);
2799 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 127);
2800 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 128);
2801 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 16383);
2802 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 16384);
2803 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 65535);
2804 		file.ReadVarInt(v); VERIFY_EQUAL_NONCONT(v, 0xFFFFFFFFFFFFFFFFull);
2805 	}
2806 
2807 #ifdef MODPLUG_TRACKER
2808 	TrackerSettings::Instance().MiscSaveChannelMuteStatus = saveMutedChannels;
2809 #endif
2810 }
2811 
2812 
2813 // Test various editing features
TestEditing()2814 static MPT_NOINLINE void TestEditing()
2815 {
2816 #ifdef MODPLUG_TRACKER
2817 	auto modDoc = static_cast<CModDoc *>(theApp.GetModDocTemplate()->CreateNewDocument());
2818 	auto &sndFile = modDoc->GetSoundFile();
2819 	sndFile.Create(FileReader(), CSoundFile::loadCompleteModule, modDoc);
2820 	sndFile.m_nChannels = 4;
2821 	sndFile.ChangeModTypeTo(MOD_TYPE_MPT);
2822 
2823 	// Rearrange channels
2824 	sndFile.Patterns.ResizeArray(2);
2825 	sndFile.Patterns.Insert(0, 32);
2826 	sndFile.Patterns.Insert(1, 48);
2827 	sndFile.Patterns[1].SetName("Pattern");
2828 	sndFile.Patterns[1].SetSignature(2, 4);
2829 	TempoSwing swing;
2830 	swing.resize(2);
2831 	sndFile.Patterns[1].SetTempoSwing(swing);
2832 	sndFile.Patterns[1].GetpModCommand(37, 0)->instr = 1;
2833 	sndFile.Patterns[1].GetpModCommand(37, 1)->instr = 2;
2834 	sndFile.Patterns[1].GetpModCommand(37, 2)->instr = 3;
2835 	sndFile.Patterns[1].GetpModCommand(37, 3)->instr = 4;
2836 	modDoc->ReArrangeChannels({ 3, 2, CHANNELINDEX_INVALID, 0 });
2837 	modDoc->ReArrangeChannels({ 0, 1, 1, CHANNELINDEX_INVALID, 3 });
2838 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetName(), "Pattern");
2839 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerBeat(), 2);
2840 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetRowsPerMeasure(), 4);
2841 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetTempoSwing(), swing);
2842 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 0)->instr, 4);
2843 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 1)->instr, 3);
2844 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 2)->instr, 3);
2845 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 3)->instr, 0);
2846 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 1);
2847 
2848 	// Rearrange samples
2849 	sndFile.m_nSamples = 2;
2850 	sndFile.GetSample(1).filename = "1";
2851 	sndFile.m_szNames[1] = "1";
2852 	sndFile.GetSample(2).filename = "2";
2853 	sndFile.m_szNames[2] = "2";
2854 	sndFile.GetSample(2).nLength = 16;
2855 	sndFile.GetSample(2).AllocateSample();
2856 	modDoc->ReArrangeSamples({ 2, SAMPLEINDEX_INVALID, 1 });
2857 	VERIFY_EQUAL_NONCONT(sndFile.GetSample(1).HasSampleData(), true);
2858 	VERIFY_EQUAL_NONCONT(sndFile.GetSample(1).filename, "2");
2859 	VERIFY_EQUAL_NONCONT(sndFile.m_szNames[1], "2");
2860 	VERIFY_EQUAL_NONCONT(sndFile.GetSample(2).filename, "");
2861 	VERIFY_EQUAL_NONCONT(sndFile.m_szNames[2], "");
2862 	VERIFY_EQUAL_NONCONT(sndFile.GetSample(3).filename, "1");
2863 	VERIFY_EQUAL_NONCONT(sndFile.m_szNames[3], "1");
2864 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 3);
2865 
2866 	// Convert / rearrange instruments
2867 	modDoc->ConvertSamplesToInstruments();
2868 	modDoc->ReArrangeInstruments({ INSTRUMENTINDEX_INVALID, 2, 1, 3 });
2869 	VERIFY_EQUAL_NONCONT(sndFile.Instruments[1]->name, "");
2870 	VERIFY_EQUAL_NONCONT(sndFile.Instruments[2]->name, "");
2871 	VERIFY_EQUAL_NONCONT(sndFile.Instruments[3]->name, "2");
2872 	VERIFY_EQUAL_NONCONT(sndFile.Instruments[4]->name, "1");
2873 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 4);
2874 	modDoc->ConvertInstrumentsToSamples();
2875 	VERIFY_EQUAL_NONCONT(sndFile.Patterns[1].GetpModCommand(37, 4)->instr, 3);
2876 
2877 	modDoc->SetModified();
2878 	VERIFY_EQUAL_NONCONT(modDoc->IsModified(), true);
2879 	VERIFY_EQUAL_NONCONT(modDoc->ModifiedSinceLastAutosave(), true);
2880 	VERIFY_EQUAL_NONCONT(modDoc->ModifiedSinceLastAutosave(), false);
2881 
2882 	sndFile.Destroy();
2883 	modDoc->OnCloseDocument();
2884 #endif
2885 }
2886 
2887 
RunITCompressionTest(const std::vector<int8> & sampleData,FlagSet<ChannelFlags> smpFormat,bool it215)2888 static void RunITCompressionTest(const std::vector<int8> &sampleData, FlagSet<ChannelFlags> smpFormat, bool it215)
2889 {
2890 
2891 	ModSample smp;
2892 	smp.uFlags = smpFormat;
2893 	smp.pData.pSample = const_cast<int8 *>(sampleData.data());
2894 	smp.nLength = mpt::saturate_cast<SmpLength>(sampleData.size() / smp.GetBytesPerSample());
2895 
2896 	std::string data;
2897 
2898 	{
2899 		std::ostringstream f;
2900 		ITCompression compression(smp, it215, &f);
2901 		data = f.str();
2902 	}
2903 
2904 	{
2905 		FileReader file(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(data)));
2906 
2907 		std::vector<int8> sampleDataNew(sampleData.size(), 0);
2908 		smp.pData.pSample = sampleDataNew.data();
2909 
2910 		ITDecompression decompression(file, smp, it215);
2911 		VERIFY_EQUAL_NONCONT(memcmp(sampleData.data(), sampleDataNew.data(), sampleData.size()), 0);
2912 	}
2913 }
2914 
2915 
TestITCompression()2916 static MPT_NOINLINE void TestITCompression()
2917 {
2918 	// Test loading / saving of IT-compressed samples
2919 	const int sampleDataSize = 65536;
2920 	std::vector<int8> sampleData(sampleDataSize, 0);
2921 	std::srand(0);
2922 	for(int i = 0; i < sampleDataSize; i++)
2923 	{
2924 		sampleData[i] = mpt::random<int8>(*s_PRNG);
2925 	}
2926 
2927 	// Run each compression test with IT215 compression and without.
2928 	for(int i = 0; i < 2; i++)
2929 	{
2930 		RunITCompressionTest(sampleData, ChannelFlags(0), i == 0);
2931 		RunITCompressionTest(sampleData, CHN_16BIT, i == 0);
2932 		RunITCompressionTest(sampleData, CHN_STEREO, i == 0);
2933 		RunITCompressionTest(sampleData, CHN_16BIT | CHN_STEREO, i == 0);
2934 	}
2935 }
2936 
2937 
2938 
2939 #if 0
2940 
2941 static bool RatioEqual(CTuningBase::RATIOTYPE a, CTuningBase::RATIOTYPE b)
2942 {
2943 	if(a == CTuningBase::RATIOTYPE(0) && b == CTuningBase::RATIOTYPE(0))
2944 	{
2945 		return true;
2946 	}
2947 	if(a == CTuningBase::RATIOTYPE(0) || b == CTuningBase::RATIOTYPE(0))
2948 	{
2949 		return false;
2950 	}
2951 	return (std::fabs(CTuningBase::RATIOTYPE(1) - (a/b)) < CTuningBase::RATIOTYPE(0.0001));
2952 }
2953 
2954 
2955 static void CheckEqualTuningCollections(const CTuningCollection &a, const CTuningCollection &b)
2956 {
2957 	VERIFY_EQUAL(a.GetName(), b.GetName());
2958 	VERIFY_EQUAL(a.GetNumTunings(), b.GetNumTunings());
2959 	for(std::size_t tuning = 0; tuning < std::min(a.GetNumTunings(), b.GetNumTunings()); ++tuning)
2960 	{
2961 		VERIFY_EQUAL(a.GetTuning(tuning).GetName(), b.GetTuning(tuning).GetName());
2962 		VERIFY_EQUAL(a.GetTuning(tuning).GetType(), b.GetTuning(tuning).GetType());
2963 		VERIFY_EQUAL(a.GetTuning(tuning).GetGroupSize(), b.GetTuning(tuning).GetGroupSize());
2964 		VERIFY_EQUAL(a.GetTuning(tuning).GetFineStepCount(), b.GetTuning(tuning).GetFineStepCount());
2965 		VERIFY_EQUAL(RatioEqual(a.GetTuning(tuning).GetGroupRatio(), b.GetTuning(tuning).GetGroupRatio()), true);
2966 		VERIFY_EQUAL(a.GetTuning(tuning).GetValidityRange(), b.GetTuning(tuning).GetValidityRange());
2967 		for(ModCommand::NOTE note = NOTE_MIN; note <= NOTE_MAX; ++note)
2968 		{
2969 			VERIFY_EQUAL(a.GetTuning(tuning).GetNoteName(note - NOTE_MIDDLEC), b.GetTuning(tuning).GetNoteName(note - NOTE_MIDDLEC));
2970 			VERIFY_EQUAL(RatioEqual(a.GetTuning(tuning).GetRatio(note - NOTE_MIDDLEC), b.GetTuning(tuning).GetRatio(note - NOTE_MIDDLEC)), true);
2971 		}
2972 	}
2973 }
2974 
2975 #endif
2976 
2977 
2978 
Rand01()2979 static double Rand01()
2980 {
2981 	return mpt::random(*s_PRNG, 0.0, 1.0);
2982 }
2983 
2984 template <class T>
Rand(const T min,const T max)2985 T Rand(const T min, const T max)
2986 {
2987 	return mpt::saturate_round<T>(min + Rand01() * (max - min));
2988 }
2989 
GenerateCommands(CPattern & pat,const double dProbPcs,const double dProbPc)2990 static void GenerateCommands(CPattern& pat, const double dProbPcs, const double dProbPc)
2991 {
2992 	const double dPcxProb = dProbPcs + dProbPc;
2993 	for(auto &m : pat)
2994 	{
2995 		const double rand = Rand01();
2996 		if(rand < dPcxProb)
2997 		{
2998 			if(rand < dProbPcs)
2999 				m.note = NOTE_PCS;
3000 			else
3001 				m.note = NOTE_PC;
3002 
3003 			m.instr = Rand<ModCommand::INSTR>(0, MAX_MIXPLUGINS);
3004 			m.SetValueVolCol(Rand<uint16>(0, ModCommand::maxColumnValue));
3005 			m.SetValueEffectCol(Rand<uint16>(0, ModCommand::maxColumnValue));
3006 		}
3007 		else
3008 			m.Clear();
3009 	}
3010 }
3011 
3012 
3013 // Test PC note serialization
TestPCnoteSerialization()3014 static MPT_NOINLINE void TestPCnoteSerialization()
3015 {
3016 	FileReader file;
3017 	std::unique_ptr<CSoundFile> pSndFile = std::make_unique<CSoundFile>();
3018 	CSoundFile &sndFile = *pSndFile.get();
3019 	sndFile.m_nType = MOD_TYPE_MPT;
3020 	sndFile.Patterns.DestroyPatterns();
3021 	sndFile.m_nChannels = ModSpecs::mptm.channelsMax;
3022 
3023 	sndFile.Patterns.Insert(0, ModSpecs::mptm.patternRowsMin);
3024 	sndFile.Patterns.Insert(1, 64);
3025 	GenerateCommands(sndFile.Patterns[1], 0.3, 0.3);
3026 	sndFile.Patterns.Insert(2, ModSpecs::mptm.patternRowsMax);
3027 	GenerateCommands(sndFile.Patterns[2], 0.5, 0.5);
3028 
3029 	// Copy pattern data for comparison.
3030 	CPatternContainer patterns{ sndFile.Patterns };
3031 
3032 	std::stringstream mem;
3033 	WriteModPatterns(mem, sndFile.Patterns);
3034 
3035 	VERIFY_EQUAL_NONCONT( mem.good(), true );
3036 
3037 	// Clear patterns.
3038 	sndFile.Patterns[0].ClearCommands();
3039 	sndFile.Patterns[1].ClearCommands();
3040 	sndFile.Patterns[2].ClearCommands();
3041 
3042 	// Read data back.
3043 	ReadModPatterns(mem, sndFile.Patterns);
3044 
3045 	// Compare.
3046 	VERIFY_EQUAL_NONCONT( sndFile.Patterns[0].GetNumRows(), ModSpecs::mptm.patternRowsMin);
3047 	VERIFY_EQUAL_NONCONT( sndFile.Patterns[1].GetNumRows(), 64);
3048 	VERIFY_EQUAL_NONCONT( sndFile.Patterns[2].GetNumRows(), ModSpecs::mptm.patternRowsMax);
3049 	for(int i = 0; i < 3; i++)
3050 	{
3051 		VERIFY_EQUAL(sndFile.Patterns[i], patterns[i]);
3052 	}
3053 }
3054 
3055 
strnlen(const char * str,std::size_t n)3056 static inline std::size_t strnlen(const char *str, std::size_t n)
3057 {
3058 #if MPT_COMPILER_MSVC
3059 	return ::strnlen(str, n);
3060 #else
3061 	if(n >= std::numeric_limits<std::size_t>::max())
3062 	{
3063 		return std::strlen(str);
3064 	}
3065 	for(std::size_t i = 0; i < n; ++i)
3066 	{
3067 		if(str[i] == '\0')
3068 		{
3069 			return i;
3070 		}
3071 	}
3072 	return n;
3073 #endif
3074 }
3075 
3076 
3077 // Test String I/O functionality
TestStringIO()3078 static MPT_NOINLINE void TestStringIO()
3079 {
3080 	char src0[4] = { '\0', 'X', ' ', 'X' };		// Weird empty buffer
3081 	char src1[4] = { 'X', ' ', '\0', 'X' };		// Weird buffer (hello Impulse Tracker)
3082 	char src2[4] = { 'X', 'Y', 'Z', ' ' };		// Full buffer, last character space
3083 	char src3[4] = { 'X', 'Y', 'Z', '!' };		// Full buffer, last character non-space
3084 	char src4[4] = { 'x', 'y', '\t', '\n' };	// Full buffer containing non-space whitespace
3085 	char dst1[6];	// Destination buffer, larger than source buffer
3086 	char dst2[3];	// Destination buffer, smaller than source buffer
3087 
3088 #define ReadTest(mode, dst, src, expectedResult) \
3089 	std::memset(dst, 0x7f, sizeof(dst)); \
3090 	mpt::String::WriteAutoBuf(dst) = mpt::String::ReadBuf(mpt::String:: mode , src); \
3091 	VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, std::size(dst)), 0); /* Ensure that the strings are identical */ \
3092 	for(size_t i = strlen(dst); i < std::size(dst); i++) \
3093 		VERIFY_EQUAL_NONCONT(dst[i], '\0'); /* Ensure that rest of the buffer is completely nulled */ \
3094 	/**/
3095 
3096 #define WriteTest(mode, dst, src, expectedResult) \
3097 	std::memset(dst, 0x7f, sizeof(dst)); \
3098 	mpt::String::WriteBuf(mpt::String:: mode , dst) = mpt::String::ReadAutoBuf(src); \
3099 	VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, std::size(dst)), 0);  /* Ensure that the strings are identical */ \
3100 	for(size_t i = Test::strnlen(dst, std::size(dst)); i < std::size(dst); i++) \
3101 		VERIFY_EQUAL_NONCONT(dst[i], '\0'); /* Ensure that rest of the buffer is completely nulled */ \
3102 	/**/
3103 
3104 	// Check reading of null-terminated string into larger buffer
3105 	ReadTest(nullTerminated, dst1, src0, "");
3106 	ReadTest(nullTerminated, dst1, src1, "X ");
3107 	ReadTest(nullTerminated, dst1, src2, "XYZ");
3108 	ReadTest(nullTerminated, dst1, src3, "XYZ");
3109 	ReadTest(nullTerminated, dst1, src4, "xy\t");
3110 
3111 	// Check reading of string that should be null-terminated, but is maybe too long to still hold the null character.
3112 	ReadTest(maybeNullTerminated, dst1, src0, "");
3113 	ReadTest(maybeNullTerminated, dst1, src1, "X ");
3114 	ReadTest(maybeNullTerminated, dst1, src2, "XYZ ");
3115 	ReadTest(maybeNullTerminated, dst1, src3, "XYZ!");
3116 	ReadTest(maybeNullTerminated, dst1, src4, "xy\t\n");
3117 
3118 	// Check reading of space-padded strings with ignored last character
3119 	ReadTest(spacePaddedNull, dst1, src0, " X");
3120 	ReadTest(spacePaddedNull, dst1, src1, "X");
3121 	ReadTest(spacePaddedNull, dst1, src2, "XYZ");
3122 	ReadTest(spacePaddedNull, dst1, src3, "XYZ");
3123 	ReadTest(spacePaddedNull, dst1, src4, "xy\t");
3124 
3125 	// Check reading of space-padded strings
3126 	ReadTest(spacePadded, dst1, src0, " X X");
3127 	ReadTest(spacePadded, dst1, src1, "X  X");
3128 	ReadTest(spacePadded, dst1, src2, "XYZ");
3129 	ReadTest(spacePadded, dst1, src3, "XYZ!");
3130 	ReadTest(spacePadded, dst1, src4, "xy\t\n");
3131 
3132 	///////////////////////////////
3133 
3134 	// Check reading of null-terminated string into smaller buffer
3135 	ReadTest(nullTerminated, dst2, src0, "");
3136 	ReadTest(nullTerminated, dst2, src1, "X ");
3137 	ReadTest(nullTerminated, dst2, src2, "XY");
3138 	ReadTest(nullTerminated, dst2, src3, "XY");
3139 	ReadTest(nullTerminated, dst2, src4, "xy");
3140 
3141 	// Check reading of string that should be null-terminated, but is maybe too long to still hold the null character.
3142 	ReadTest(maybeNullTerminated, dst2, src0, "");
3143 	ReadTest(maybeNullTerminated, dst2, src1, "X ");
3144 	ReadTest(maybeNullTerminated, dst2, src2, "XY");
3145 	ReadTest(maybeNullTerminated, dst2, src3, "XY");
3146 	ReadTest(maybeNullTerminated, dst2, src4, "xy");
3147 
3148 	// Check reading of space-padded strings with ignored last character
3149 	ReadTest(spacePaddedNull, dst2, src0, " X");
3150 	ReadTest(spacePaddedNull, dst2, src1, "X");
3151 	ReadTest(spacePaddedNull, dst2, src2, "XY");
3152 	ReadTest(spacePaddedNull, dst2, src3, "XY");
3153 	ReadTest(spacePaddedNull, dst2, src4, "xy");
3154 
3155 	// Check reading of space-padded strings
3156 	ReadTest(spacePadded, dst2, src0, " X");
3157 	ReadTest(spacePadded, dst2, src1, "X ");
3158 	ReadTest(spacePadded, dst2, src2, "XY");
3159 	ReadTest(spacePadded, dst2, src3, "XY");
3160 	ReadTest(spacePadded, dst2, src4, "xy");
3161 
3162 	///////////////////////////////
3163 
3164 	// Check writing of null-terminated string into larger buffer
3165 	WriteTest(nullTerminated, dst1, src0, "");
3166 	WriteTest(nullTerminated, dst1, src1, "X ");
3167 	WriteTest(nullTerminated, dst1, src2, "XYZ ");
3168 	WriteTest(nullTerminated, dst1, src3, "XYZ!");
3169 
3170 	// Check writing of string that should be null-terminated, but is maybe too long to still hold the null character.
3171 	WriteTest(maybeNullTerminated, dst1, src0, "");
3172 	WriteTest(maybeNullTerminated, dst1, src1, "X ");
3173 	WriteTest(maybeNullTerminated, dst1, src2, "XYZ ");
3174 	WriteTest(maybeNullTerminated, dst1, src3, "XYZ!");
3175 
3176 	// Check writing of space-padded strings with last character set to null
3177 	WriteTest(spacePaddedNull, dst1, src0, "     ");
3178 	WriteTest(spacePaddedNull, dst1, src1, "X    ");
3179 	WriteTest(spacePaddedNull, dst1, src2, "XYZ  ");
3180 	WriteTest(spacePaddedNull, dst1, src3, "XYZ! ");
3181 
3182 	// Check writing of space-padded strings
3183 	WriteTest(spacePadded, dst1, src0, "      ");
3184 	WriteTest(spacePadded, dst1, src1, "X     ");
3185 	WriteTest(spacePadded, dst1, src2, "XYZ   ");
3186 	WriteTest(spacePadded, dst1, src3, "XYZ!  ");
3187 
3188 	///////////////////////////////
3189 
3190 	// Check writing of null-terminated string into smaller buffer
3191 	WriteTest(nullTerminated, dst2, src0, "");
3192 	WriteTest(nullTerminated, dst2, src1, "X ");
3193 	WriteTest(nullTerminated, dst2, src2, "XY");
3194 	WriteTest(nullTerminated, dst2, src3, "XY");
3195 
3196 	// Check writing of string that should be null-terminated, but is maybe too long to still hold the null character.
3197 	WriteTest(maybeNullTerminated, dst2, src0, "");
3198 	WriteTest(maybeNullTerminated, dst2, src1, "X ");
3199 	WriteTest(maybeNullTerminated, dst2, src2, "XYZ");
3200 	WriteTest(maybeNullTerminated, dst2, src3, "XYZ");
3201 
3202 	// Check writing of space-padded strings with last character set to null
3203 	WriteTest(spacePaddedNull, dst2, src0, "  ");
3204 	WriteTest(spacePaddedNull, dst2, src1, "X ");
3205 	WriteTest(spacePaddedNull, dst2, src2, "XY");
3206 	WriteTest(spacePaddedNull, dst2, src3, "XY");
3207 
3208 	// Check writing of space-padded strings
3209 	WriteTest(spacePadded, dst2, src0, "   ");
3210 	WriteTest(spacePadded, dst2, src1, "X  ");
3211 	WriteTest(spacePadded, dst2, src2, "XYZ");
3212 	WriteTest(spacePadded, dst2, src3, "XYZ");
3213 
3214 #undef ReadTest
3215 #undef WriteTest
3216 
3217 	{
3218 
3219 		std::string dststring;
3220 		std::string src0string = std::string(src0, std::size(src0));
3221 		std::string src1string = std::string(src1, std::size(src1));
3222 		std::string src2string = std::string(src2, std::size(src2));
3223 		std::string src3string = std::string(src3, std::size(src3));
3224 
3225 #define ReadTest(mode, dst, src, expectedResult) \
3226 	dst = mpt::String::ReadBuf(mpt::String:: mode , src); \
3227 	VERIFY_EQUAL_NONCONT(dst, expectedResult); /* Ensure that the strings are identical */ \
3228 	/**/
3229 
3230 #define WriteTest(mode, dst, src, expectedResult) \
3231 	std::memset(dst, 0x7f, sizeof(dst)); \
3232 	mpt::String::WriteBuf(mpt::String:: mode , dst) = src; \
3233 	VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, std::size(dst)), 0);  /* Ensure that the strings are identical */ \
3234 	for(size_t i = Test::strnlen(dst, std::size(dst)); i < std::size(dst); i++) \
3235 		VERIFY_EQUAL_NONCONT(dst[i], '\0'); /* Ensure that rest of the buffer is completely nulled */ \
3236 	/**/
3237 
3238 		// Check reading of null-terminated string into std::string
3239 		ReadTest(nullTerminated, dststring, src0, "");
3240 		ReadTest(nullTerminated, dststring, src1, "X ");
3241 		ReadTest(nullTerminated, dststring, src2, "XYZ");
3242 		ReadTest(nullTerminated, dststring, src3, "XYZ");
3243 		ReadTest(nullTerminated, dststring, src4, "xy\t");
3244 
3245 		// Check reading of string that should be null-terminated, but is maybe too long to still hold the null character.
3246 		ReadTest(maybeNullTerminated, dststring, src0, "");
3247 		ReadTest(maybeNullTerminated, dststring, src1, "X ");
3248 		ReadTest(maybeNullTerminated, dststring, src2, "XYZ ");
3249 		ReadTest(maybeNullTerminated, dststring, src3, "XYZ!");
3250 		ReadTest(maybeNullTerminated, dststring, src4, "xy\t\n");
3251 
3252 		// Check reading of space-padded strings with ignored last character
3253 		ReadTest(spacePaddedNull, dststring, src0, " X");
3254 		ReadTest(spacePaddedNull, dststring, src1, "X");
3255 		ReadTest(spacePaddedNull, dststring, src2, "XYZ");
3256 		ReadTest(spacePaddedNull, dststring, src3, "XYZ");
3257 		ReadTest(spacePaddedNull, dststring, src4, "xy\t");
3258 
3259 		// Check reading of space-padded strings
3260 		ReadTest(spacePadded, dststring, src0, " X X");
3261 		ReadTest(spacePadded, dststring, src1, "X  X");
3262 		ReadTest(spacePadded, dststring, src2, "XYZ");
3263 		ReadTest(spacePadded, dststring, src3, "XYZ!");
3264 		ReadTest(spacePadded, dststring, src4, "xy\t\n");
3265 
3266 		///////////////////////////////
3267 
3268 		// Check writing of null-terminated string into larger buffer
3269 		WriteTest(nullTerminated, dst1, src0string, "");
3270 		WriteTest(nullTerminated, dst1, src1string, "X ");
3271 		WriteTest(nullTerminated, dst1, src2string, "XYZ ");
3272 		WriteTest(nullTerminated, dst1, src3string, "XYZ!");
3273 
3274 		// Check writing of string that should be null-terminated, but is maybe too long to still hold the null character.
3275 		WriteTest(maybeNullTerminated, dst1, src0string, "");
3276 		WriteTest(maybeNullTerminated, dst1, src1string, "X ");
3277 		WriteTest(maybeNullTerminated, dst1, src2string, "XYZ ");
3278 		WriteTest(maybeNullTerminated, dst1, src3string, "XYZ!");
3279 
3280 		// Check writing of space-padded strings with last character set to null
3281 		WriteTest(spacePaddedNull, dst1, src0string, "     ");
3282 		WriteTest(spacePaddedNull, dst1, src1string, "X    ");
3283 		WriteTest(spacePaddedNull, dst1, src2string, "XYZ  ");
3284 		WriteTest(spacePaddedNull, dst1, src3string, "XYZ! ");
3285 
3286 		// Check writing of space-padded strings
3287 		WriteTest(spacePadded, dst1, src0string, "      ");
3288 		WriteTest(spacePadded, dst1, src1string, "X     ");
3289 		WriteTest(spacePadded, dst1, src2string, "XYZ   ");
3290 		WriteTest(spacePadded, dst1, src3string, "XYZ!  ");
3291 
3292 		///////////////////////////////
3293 
3294 		// Check writing of null-terminated string into smaller buffer
3295 		WriteTest(nullTerminated, dst2, src0string, "");
3296 		WriteTest(nullTerminated, dst2, src1string, "X ");
3297 		WriteTest(nullTerminated, dst2, src2string, "XY");
3298 		WriteTest(nullTerminated, dst2, src3string, "XY");
3299 
3300 		// Check writing of string that should be null-terminated, but is maybe too long to still hold the null character.
3301 		WriteTest(maybeNullTerminated, dst2, src0string, "");
3302 		WriteTest(maybeNullTerminated, dst2, src1string, "X ");
3303 		WriteTest(maybeNullTerminated, dst2, src2string, "XYZ");
3304 		WriteTest(maybeNullTerminated, dst2, src3string, "XYZ");
3305 
3306 		// Check writing of space-padded strings with last character set to null
3307 		WriteTest(spacePaddedNull, dst2, src0string, "  ");
3308 		WriteTest(spacePaddedNull, dst2, src1string, "X ");
3309 		WriteTest(spacePaddedNull, dst2, src2string, "XY");
3310 		WriteTest(spacePaddedNull, dst2, src3string, "XY");
3311 
3312 		// Check writing of space-padded strings
3313 		WriteTest(spacePadded, dst2, src0string, "   ");
3314 		WriteTest(spacePadded, dst2, src1string, "X  ");
3315 		WriteTest(spacePadded, dst2, src2string, "XYZ");
3316 		WriteTest(spacePadded, dst2, src3string, "XYZ");
3317 
3318 		///////////////////////////////
3319 
3320 #undef ReadTest
3321 #undef WriteTest
3322 
3323 	}
3324 
3325 	{
3326 
3327 		char s0[4] = {'\0', 'X', ' ', 'X' };
3328 		char s2[4] = { 'X', ' ','\0', 'X' };
3329 		char s4[4] = { 'X', 'Y', 'Z', ' ' };
3330 
3331 		char d2[2] = {'\0','\0'};
3332 		char d3[3] = {'\0','\0','\0'};
3333 		char d4[4] = {'\0','\0','\0','\0'};
3334 		char d5[5] = {'\0','\0','\0','\0','\0'};
3335 
3336 		#define CopyTest(dst, src, expectedResult) \
3337 			std::memset(dst, 0x7f, sizeof(dst)); \
3338 			mpt::String::WriteAutoBuf(dst) = mpt::String::ReadAutoBuf(src); \
3339 			VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, std::size(dst)), 0); /* Ensure that the strings are identical */ \
3340 			for(size_t i = strlen(dst); i < std::size(dst); i++) \
3341 				VERIFY_EQUAL_NONCONT(dst[i], '\0'); /* Ensure that rest of the buffer is completely nulled */ \
3342 			/**/
3343 
3344 		CopyTest(d2, s0, "");
3345 		CopyTest(d2, s2, "X");
3346 		CopyTest(d2, s4, "X");
3347 		CopyTest(d3, s0, "");
3348 		CopyTest(d3, s2, "X ");
3349 		CopyTest(d3, s4, "XY");
3350 		CopyTest(d4, s0, "");
3351 		CopyTest(d4, s2, "X ");
3352 		CopyTest(d4, s4, "XYZ");
3353 		CopyTest(d5, s0, "");
3354 		CopyTest(d5, s2, "X ");
3355 		CopyTest(d5, s4, "XYZ ");
3356 
3357 		#undef CopyTest
3358 
3359 		#define CopyTestN(dst, src, len, expectedResult) \
3360 			std::memset(dst, 0x7f, sizeof(dst)); \
3361 			mpt::String::WriteAutoBuf(dst) = mpt::String::ReadAutoBuf(src, std::min(std::size(src), static_cast<std::size_t>(len))); \
3362 			VERIFY_EQUAL_NONCONT(strncmp(dst, expectedResult, std::size(dst)), 0); /* Ensure that the strings are identical */ \
3363 			for(size_t i = strlen(dst); i < std::size(dst); i++) \
3364 				VERIFY_EQUAL_NONCONT(dst[i], '\0'); /* Ensure that rest of the buffer is completely nulled */ \
3365 			/**/
3366 
3367 		CopyTestN(d2, s0, 1, "");
3368 		CopyTestN(d2, s2, 1, "X");
3369 		CopyTestN(d2, s4, 1, "X");
3370 		CopyTestN(d3, s0, 1, "");
3371 		CopyTestN(d3, s2, 1, "X");
3372 		CopyTestN(d3, s4, 1, "X");
3373 		CopyTestN(d4, s0, 1, "");
3374 		CopyTestN(d4, s2, 1, "X");
3375 		CopyTestN(d4, s4, 1, "X");
3376 		CopyTestN(d5, s0, 1, "");
3377 		CopyTestN(d5, s2, 1, "X");
3378 		CopyTestN(d5, s4, 1, "X");
3379 
3380 		CopyTestN(d2, s0, 2, "");
3381 		CopyTestN(d2, s2, 2, "X");
3382 		CopyTestN(d2, s4, 2, "X");
3383 		CopyTestN(d3, s0, 2, "");
3384 		CopyTestN(d3, s2, 2, "X ");
3385 		CopyTestN(d3, s4, 2, "XY");
3386 		CopyTestN(d4, s0, 2, "");
3387 		CopyTestN(d4, s2, 2, "X ");
3388 		CopyTestN(d4, s4, 2, "XY");
3389 		CopyTestN(d5, s0, 2, "");
3390 		CopyTestN(d5, s2, 2, "X ");
3391 		CopyTestN(d5, s4, 2, "XY");
3392 
3393 		CopyTestN(d2, s0, 3, "");
3394 		CopyTestN(d2, s2, 3, "X");
3395 		CopyTestN(d2, s4, 3, "X");
3396 		CopyTestN(d3, s0, 3, "");
3397 		CopyTestN(d3, s2, 3, "X ");
3398 		CopyTestN(d3, s4, 3, "XY");
3399 		CopyTestN(d4, s0, 3, "");
3400 		CopyTestN(d4, s2, 3, "X ");
3401 		CopyTestN(d4, s4, 3, "XYZ");
3402 		CopyTestN(d5, s0, 3, "");
3403 		CopyTestN(d5, s2, 3, "X ");
3404 		CopyTestN(d5, s4, 3, "XYZ");
3405 
3406 		CopyTestN(d2, s0, 4, "");
3407 		CopyTestN(d2, s2, 4, "X");
3408 		CopyTestN(d2, s4, 4, "X");
3409 		CopyTestN(d3, s0, 4, "");
3410 		CopyTestN(d3, s2, 4, "X ");
3411 		CopyTestN(d3, s4, 4, "XY");
3412 		CopyTestN(d4, s0, 4, "");
3413 		CopyTestN(d4, s2, 4, "X ");
3414 		CopyTestN(d4, s4, 4, "XYZ");
3415 		CopyTestN(d5, s0, 4, "");
3416 		CopyTestN(d5, s2, 4, "X ");
3417 		CopyTestN(d5, s4, 4, "XYZ ");
3418 
3419 		CopyTestN(d2, s0, 5, "");
3420 		CopyTestN(d2, s2, 5, "X");
3421 		CopyTestN(d2, s4, 5, "X");
3422 		CopyTestN(d3, s0, 5, "");
3423 		CopyTestN(d3, s2, 5, "X ");
3424 		CopyTestN(d3, s4, 5, "XY");
3425 		CopyTestN(d4, s0, 5, "");
3426 		CopyTestN(d4, s2, 5, "X ");
3427 		CopyTestN(d4, s4, 5, "XYZ");
3428 		CopyTestN(d5, s0, 5, "");
3429 		CopyTestN(d5, s2, 5, "X ");
3430 		CopyTestN(d5, s4, 5, "XYZ ");
3431 
3432 		#undef CopyTest
3433 
3434 	}
3435 
3436 }
3437 
3438 
TestSampleConversion()3439 static MPT_NOINLINE void TestSampleConversion()
3440 {
3441 	std::vector<uint8> sourceBufContainer(65536 * 4);
3442 	std::vector<uint8> targetBufContainer(65536 * 6);
3443 
3444 	uint8 *sourceBuf = &(sourceBufContainer[0]);
3445 	void *targetBuf = &(targetBufContainer[0]);
3446 
3447 	// Signed 8-Bit Integer PCM
3448 	// Unsigned 8-Bit Integer PCM
3449 	// Delta 8-Bit Integer PCM
3450 	{
3451 		uint8 *source8 = sourceBuf;
3452 		for(size_t i = 0; i < 256; i++)
3453 		{
3454 			source8[i] = static_cast<uint8>(i);
3455 		}
3456 
3457 		int8 *signed8 = static_cast<int8 *>(targetBuf);
3458 		uint8 *unsigned8 = static_cast<uint8 *>(targetBuf) + 256;
3459 		int8 *delta8 = static_cast<int8 *>(targetBuf) + 512;
3460 		int8 delta = 0;
3461 		CopySample<SC::DecodeInt8>(signed8, 256, 1, mpt::byte_cast<const std::byte *>(source8), 256, 1);
3462 		CopySample<SC::DecodeUint8>(reinterpret_cast<int8 *>(unsigned8), 256, 1, mpt::byte_cast<const std::byte *>(source8), 256, 1);
3463 		CopySample<SC::DecodeInt8Delta>(delta8, 256, 1, mpt::byte_cast<const std::byte *>(source8), 256, 1);
3464 
3465 		for(size_t i = 0; i < 256; i++)
3466 		{
3467 			delta += static_cast<int8>(i);
3468 			VERIFY_EQUAL_QUIET_NONCONT(signed8[i], static_cast<int8>(i));
3469 			VERIFY_EQUAL_QUIET_NONCONT(unsigned8[i], static_cast<uint8>(i + 0x80u));
3470 			VERIFY_EQUAL_QUIET_NONCONT(delta8[i], static_cast<int8>(delta));
3471 		}
3472 	}
3473 
3474 	// Signed 16-Bit Integer PCM
3475 	// Unsigned 16-Bit Integer PCM
3476 	// Delta 16-Bit Integer PCM
3477 	{
3478 		// Little Endian
3479 
3480 		uint8 *source16 = sourceBuf;
3481 		for(size_t i = 0; i < 65536; i++)
3482 		{
3483 			source16[i * 2 + 0] = static_cast<uint8>(i & 0xFF);
3484 			source16[i * 2 + 1] = static_cast<uint8>(i >> 8);
3485 		}
3486 
3487 		int16 *signed16 = static_cast<int16 *>(targetBuf);
3488 		uint16 *unsigned16 = static_cast<uint16 *>(targetBuf) + 65536;
3489 		int16 *delta16 = static_cast<int16 *>(targetBuf) + 65536 * 2;
3490 		int16 delta = 0;
3491 		CopySample<SC::DecodeInt16<0, littleEndian16> >(signed16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
3492 		CopySample<SC::DecodeInt16<0x8000u, littleEndian16> >(reinterpret_cast<int16*>(unsigned16), 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
3493 		CopySample<SC::DecodeInt16Delta<littleEndian16> >(delta16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
3494 
3495 		for(size_t i = 0; i < 65536; i++)
3496 		{
3497 			delta += static_cast<int16>(i);
3498 			VERIFY_EQUAL_QUIET_NONCONT(signed16[i], static_cast<int16>(i));
3499 			VERIFY_EQUAL_QUIET_NONCONT(unsigned16[i], static_cast<uint16>(i + 0x8000u));
3500 			VERIFY_EQUAL_QUIET_NONCONT(delta16[i], static_cast<int16>(delta));
3501 		}
3502 
3503 		// Big Endian
3504 
3505 		for(size_t i = 0; i < 65536; i++)
3506 		{
3507 			source16[i * 2 + 0] = static_cast<uint8>(i >> 8);
3508 			source16[i * 2 + 1] = static_cast<uint8>(i & 0xFF);
3509 		}
3510 
3511 		CopySample<SC::DecodeInt16<0, bigEndian16> >(signed16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
3512 		CopySample<SC::DecodeInt16<0x8000u, bigEndian16> >(reinterpret_cast<int16*>(unsigned16), 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
3513 		CopySample<SC::DecodeInt16Delta<bigEndian16> >(delta16, 65536, 1, mpt::byte_cast<const std::byte *>(source16), 65536 * 2, 1);
3514 
3515 		delta = 0;
3516 		for(size_t i = 0; i < 65536; i++)
3517 		{
3518 			delta += static_cast<int16>(i);
3519 			VERIFY_EQUAL_QUIET_NONCONT(signed16[i], static_cast<int16>(i));
3520 			VERIFY_EQUAL_QUIET_NONCONT(unsigned16[i], static_cast<uint16>(i + 0x8000u));
3521 			VERIFY_EQUAL_QUIET_NONCONT(delta16[i], static_cast<int16>(delta));
3522 		}
3523 
3524 	}
3525 
3526 	// Signed 24-Bit Integer PCM
3527 	{
3528 		uint8 *source24 = sourceBuf;
3529 		for(size_t i = 0; i < 65536; i++)
3530 		{
3531 			source24[i * 3 + 0] = 0;
3532 			source24[i * 3 + 1] = static_cast<uint8>(i & 0xFF);
3533 			source24[i * 3 + 2] = static_cast<uint8>(i >> 8);
3534 		}
3535 
3536 		int16 *truncated16 = static_cast<int16 *>(targetBuf);
3537 		ModSample sample;
3538 		sample.Initialize();
3539 		sample.nLength = 65536;
3540 		sample.uFlags.set(CHN_16BIT);
3541 		sample.pData.pSample = (static_cast<int16 *>(targetBuf) + 65536);
3542 		CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, mpt::byte_cast<const std::byte *>(source24), 3*65536);
3543 		CopySample<SC::ConversionChain<SC::ConvertShift<int16, int32, 16>, SC::DecodeInt24<0, littleEndian24> > >(truncated16, 65536, 1, mpt::byte_cast<const std::byte *>(source24), 65536 * 3, 1);
3544 
3545 		for(size_t i = 0; i < 65536; i++)
3546 		{
3547 			VERIFY_EQUAL_QUIET_NONCONT(sample.sample16()[i], static_cast<int16>(i));
3548 			VERIFY_EQUAL_QUIET_NONCONT(truncated16[i], static_cast<int16>(i));
3549 		}
3550 	}
3551 
3552 	// Float 32-Bit
3553 	{
3554 		uint8 *source32 = sourceBuf;
3555 		for(size_t i = 0; i < 65536; i++)
3556 		{
3557 			IEEE754binary32BE floatbits = IEEE754binary32BE((static_cast<float>(i) / 65536.0f) - 0.5f);
3558 			source32[i * 4 + 0] = mpt::byte_cast<uint8>(floatbits.GetByte(0));
3559 			source32[i * 4 + 1] = mpt::byte_cast<uint8>(floatbits.GetByte(1));
3560 			source32[i * 4 + 2] = mpt::byte_cast<uint8>(floatbits.GetByte(2));
3561 			source32[i * 4 + 3] = mpt::byte_cast<uint8>(floatbits.GetByte(3));
3562 		}
3563 
3564 		int16 *truncated16 = static_cast<int16 *>(targetBuf);
3565 		ModSample sample;
3566 		sample.Initialize();
3567 		sample.nLength = 65536;
3568 		sample.uFlags.set(CHN_16BIT);
3569 		sample.pData.pSample = static_cast<int16 *>(targetBuf) + 65536;
3570 		CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, mpt::byte_cast<const std::byte *>(source32), 4*65536);
3571 		CopySample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(truncated16, 65536, 1, mpt::byte_cast<const std::byte *>(source32), 65536 * 4, 1);
3572 
3573 		for(size_t i = 0; i < 65536; i++)
3574 		{
3575 			VERIFY_EQUAL_QUIET_NONCONT(sample.sample16()[i], static_cast<int16>(i - 0x8000u));
3576 			VERIFY_EQUAL_QUIET_NONCONT(std::abs(truncated16[i] - static_cast<int16>((i - 0x8000u) / 2)) <= 1, true);
3577 		}
3578 	}
3579 
3580 	// ALaw
3581 	{
3582 		for(unsigned int i = 0; i < 256; ++i)
3583 		{
3584 			std::byte in = mpt::byte_cast<std::byte>(static_cast<uint8>(i));
3585 			std::byte out = SC::EncodeALaw{}(SC::DecodeInt16ALaw{}(&in));
3586 			VERIFY_EQUAL_NONCONT(in, out);
3587 		}
3588 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(-32768), SC::EncodeALaw{}(-32256));
3589 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(-32767), SC::EncodeALaw{}(-32256));
3590 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(-1), SC::EncodeALaw{}(-8));
3591 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(0), SC::EncodeALaw{}(8));
3592 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(1), SC::EncodeALaw{}(8));
3593 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(32766), SC::EncodeALaw{}(32256));
3594 		VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(32767), SC::EncodeALaw{}(32256));
3595 #if 0
3596 		// compare with reference impl
3597 		for (int i = -32768; i <= 32767; ++i)
3598 		{
3599 			VERIFY_EQUAL_NONCONT(SC::EncodeALaw{}(i), mpt::byte_cast<std::byte>(alaw_encode(i)));
3600 		}
3601 #endif
3602 	}
3603 
3604 	// uLaw
3605 	{
3606 		for(unsigned int i = 0; i < 256; ++i)
3607 		{
3608 			std::byte in = mpt::byte_cast<std::byte>(static_cast<uint8>(i));
3609 			std::byte out = SC::EncodeuLaw{}(SC::DecodeInt16uLaw{}(&in));
3610 			VERIFY_EQUAL_NONCONT(in, out);
3611 		}
3612 #if 0
3613 		// compare with reference impl
3614 		/*
3615 		bool lastMatch = true;
3616 		*/
3617 		for(int i = -32768; i <= 32767; ++i)
3618 		{
3619 			/*
3620 			uint8 mine = mpt::byte_cast<uint8>(SC::EncodeuLaw{}(i));
3621 			uint8 ref = ulaw_encode(i);
3622 			if(lastMatch)
3623 			{
3624 				if(mine == ref)
3625 				{
3626 					VERIFY_EQUAL_NONCONT(mine, ref);
3627 					lastMatch = true;
3628 				} else
3629 				{
3630 					VERIFY_EQUAL_NONCONT(std::abs(static_cast<int>(mine) - static_cast<int>(ref)) <= 1, true);
3631 					lastMatch = false;
3632 				}
3633 			} else
3634 			{
3635 				VERIFY_EQUAL_NONCONT(mine, ref);
3636 				lastMatch = true;
3637 			}
3638 			*/
3639 			//MPT_LOG_GLOBAL(LogNotification, "test", MPT_UFORMAT("{} {} {}")(i, ulaw_encode(i), mpt::byte_cast<uint8>(SC::EncodeuLaw{}(i))));
3640 			VERIFY_EQUAL_NONCONT(SC::EncodeuLaw{}(i), mpt::byte_cast<std::byte>(ulaw_encode(i)));
3641 		}
3642 #endif
3643 	}
3644 
3645 	// Range checks
3646 	{
3647 		int8 oneSample = 1;
3648 		char *signed8 = reinterpret_cast<char *>(targetBuf);
3649 		memset(signed8, 0, 4);
3650 		CopySample<SC::DecodeInt8>(reinterpret_cast<int8*>(targetBuf), 4, 1, reinterpret_cast<const std::byte*>(&oneSample), sizeof(oneSample), 1);
3651 		VERIFY_EQUAL_NONCONT(signed8[0], 1);
3652 		VERIFY_EQUAL_NONCONT(signed8[1], 0);
3653 		VERIFY_EQUAL_NONCONT(signed8[2], 0);
3654 		VERIFY_EQUAL_NONCONT(signed8[3], 0);
3655 	}
3656 
3657 	// Dither
3658 	{
3659 		std::vector<MixSampleInt> buffer(64);
3660 		DithersOpenMPT dithers(mpt::global_random_device(), 2 /* DitherModPlug */ , 2);
3661 		for(std::size_t i = 0; i < 64; ++i)
3662 		{
3663 			std::visit(
3664 				[&](auto &dither)
3665 				{
3666 					buffer[i] = dither.template process<16>(0, buffer[i]);
3667 				},
3668 				dithers.Variant()
3669 			);
3670 		}
3671 		std::vector<MixSampleInt> expected = {
3672 		    727,
3673 		    -557,
3674 		    -552,
3675 		    -727,
3676 		    439,
3677 		    405,
3678 		    703,
3679 		    -337,
3680 		    235,
3681 		    -776,
3682 		    -458,
3683 		    905,
3684 		    -110,
3685 		    158,
3686 		    374,
3687 		    -362,
3688 		    283,
3689 		    306,
3690 		    710,
3691 		    304,
3692 		    -608,
3693 		    536,
3694 		    -501,
3695 		    -593,
3696 		    -349,
3697 		    812,
3698 		    916,
3699 		    53,
3700 		    -953,
3701 		    881,
3702 		    -236,
3703 		    -20,
3704 		    -623,
3705 		    -895,
3706 		    -302,
3707 		    -415,
3708 		    899,
3709 		    -948,
3710 		    -766,
3711 		    -186,
3712 		    -390,
3713 		    -169,
3714 		    253,
3715 		    -622,
3716 		    -769,
3717 		    -1001,
3718 		    1019,
3719 		    787,
3720 		    -239,
3721 		    718,
3722 		    -423,
3723 		    988,
3724 		    -91,
3725 		    763,
3726 		    -933,
3727 		    -510,
3728 		    484,
3729 		    794,
3730 		    -340,
3731 		    552,
3732 		    866,
3733 		    -608,
3734 		    35,
3735 		    395};
3736 		for(std::size_t i = 0; i < 64; ++i)
3737 		{
3738 			VERIFY_EQUAL_QUIET_NONCONT(buffer[i], expected[i]);
3739 		}
3740 	}
3741 }
3742 
3743 
3744 } // namespace Test
3745 
3746 OPENMPT_NAMESPACE_END
3747 
3748 #else //Case: ENABLE_TESTS is not defined.
3749 
3750 OPENMPT_NAMESPACE_BEGIN
3751 
3752 namespace Test {
3753 
3754 void DoTests()
3755 {
3756 	return;
3757 }
3758 
3759 } // namespace Test
3760 
3761 OPENMPT_NAMESPACE_END
3762 
3763 #endif
3764