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