OXYGENHUB
◆ main openmsx / src / unittest / FileOperations_test.cc
3.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "catch.hpp"
2
#include "FileOperations.hh"
3
4
using namespace openmsx::FileOperations;
5
6
TEST_CASE("stem")
7
{
8
	auto check = [](std::string_view input) {
9
		// Verify that stem() is equivalent to stripExtension(getFilename(input))
10
		auto expected = stripExtension(getFilename(input));
11
		auto actual = stem(input);
12
		CHECK(actual == expected);
13
	};
14
15
	check("");                       // Input is empty
16
	check("filename");               // No '/' or '.'
17
	check("/path/to/filename");      // Input with '/' but no '.'
18
	check("filename.ext");           // Input with '.' but no '/'
19
	check("/path/to/filename.ext");  // Input with both '/' and '.'
20
	check("/path.to/file.name.ext"); // Input with multiple '.' in filename
21
	check("/path.to/file");          // Input with '.' in directory name
22
	check("/path/to/");              // Input with no filename (ends with '/')
23
	check("/path.to/");              // Input with no filename but has '.' in path
24
	check(".hidden");                //
25
	check("/.hidden");               //
26
	check("/path/to/.hidden");       //
27
	check("/path/to/.hidden.ext");   //
28
29
	// These might be handled differently by std::filesystem::path::stem()
30
	check(".");
31
	check("..");
32
	check("path/.");
33
	check("path/..");
34
}
35
36
TEST_CASE("cleanFilename")
37
{
38
	// Characters that are valid on every platform are left alone.
39
	CHECK(cleanFilename("") == "");
40
	CHECK(cleanFilename("openmsx") == "openmsx");
41
	CHECK(cleanFilename("Philips NMS 8250") == "Philips NMS 8250");
42
	CHECK(cleanFilename("setup-1.oms") == "setup-1.oms");
43
44
	// Path separators are always replaced, this is the actual bug.
45
	CHECK(cleanFilename("Philips VG 8235/39") == "Philips VG 8235_39");
46
	CHECK(cleanFilename("/") == "_");
47
	CHECK(cleanFilename("a/b/c") == "a_b_c");
48
49
	// Control characters and DEL are always replaced.
50
	CHECK(cleanFilename("a\tb") == "a_b");
51
	CHECK(cleanFilename("a\nb") == "a_b");
52
	CHECK(cleanFilename("a\x7f" "b") == "a_b");
53
54
	// Non-ASCII (UTF-8) is left alone: only bytes < 0x80 are considered.
55
	CHECK(cleanFilename("caf\xc3\xa9") == "caf\xc3\xa9");
56
	CHECK(cleanFilename("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e") ==
57
	                    "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"); // 日本語
58
	// A real YEN SIGN is a valid filename character and must be kept. Note
59
	// that on a Japanese Windows the path separator is *displayed* as a yen
60
	// sign, but it is the ordinary backslash (0x5c), which is handled above.
61
	CHECK(cleanFilename("a\xc2\xa5" "b") == "a\xc2\xa5" "b");         // U+00A5 ¥
62
	CHECK(cleanFilename("a\xef\xbf\xa5" "b") == "a\xef\xbf\xa5" "b"); // U+FFE5 ¥
63
	// U+8868 is 0x95 0x5c in Shift-JIS: scanning *those* bytes for a
64
	// backslash would corrupt it. openMSX filenames are UTF-8 (0xe8 0xa1
65
	// 0xa8 here), so no such trailing byte can occur.
66
	CHECK(cleanFilename("\xe8\xa1\xa8") == "\xe8\xa1\xa8");           // U+8868 表
67
68
	// The result always has the same length as the input.
69
	auto checkLen = [](std::string_view input) {
70
		CHECK(cleanFilename(input).size() == input.size());
71
	};
72
	checkLen("Yamaha CX5MII/128");
73
	checkLen("Mitsubishi ML-G30/model 1");
74
	checkLen("caf\xc3\xa9/\xe6\x97\xa5\xe6\x9c\xac");
75
76
#ifdef _WIN32
77
	CHECK(cleanFilename(R"(a\b)") == "a_b");
78
	CHECK(cleanFilename("C:foo") == "C_foo");
79
	CHECK(cleanFilename("a?b*c") == "a_b_c");
80
	CHECK(cleanFilename("a[b]c") == "a_b_c");
81
#else
82
	// These are legal on UNIX and must be preserved.
83
	CHECK(cleanFilename(R"(a\b)") == R"(a\b)");
84
	CHECK(cleanFilename("a:b") == "a:b");
85
	CHECK(cleanFilename("a[b]c") == "a[b]c");
86
#endif
87
}