1/*
2 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely.
11*/
12/* Simple test of filesystem functions. */
13
14#include <SDL3/SDL.h>
15#include <SDL3/SDL_main.h>
16#include <SDL3/SDL_test.h>
17
18static SDL_EnumerationResult SDLCALL enum_callback(void *userdata, const char *origdir, const char *fname)
19{
20 SDL_PathInfo info;
21 char *fullpath = NULL;
22
23 /* you can use '/' for a path separator on Windows, but to make the log output look correct, we'll #ifdef this... */
24 #ifdef SDL_PLATFORM_WINDOWS
25 const char *pathsep = "\\";
26 #else
27 const char *pathsep = "/";
28 #endif
29
30 if (SDL_asprintf(&fullpath, "%s%s%s", origdir, *origdir ? pathsep : "", fname) < 0) {
31 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
32 return SDL_ENUM_FAILURE;
33 }
34
35 if (!SDL_GetPathInfo(fullpath, &info)) {
36 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't stat '%s': %s", fullpath, SDL_GetError());
37 } else {
38 const char *type;
39 if (info.type == SDL_PATHTYPE_FILE) {
40 type = "FILE";
41 } else if (info.type == SDL_PATHTYPE_DIRECTORY) {
42 type = "DIRECTORY";
43 } else {
44 type = "OTHER";
45 }
46 SDL_Log("%s (type=%s, size=%" SDL_PRIu64 ", create=%" SDL_PRIu64 ", mod=%" SDL_PRIu64 ", access=%" SDL_PRIu64 ")",
47 fullpath, type, info.size, info.modify_time, info.create_time, info.access_time);
48
49 if (info.type == SDL_PATHTYPE_DIRECTORY) {
50 if (!SDL_EnumerateDirectory(fullpath, enum_callback, userdata)) {
51 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Enumeration failed!");
52 }
53 }
54 }
55
56 SDL_free(fullpath);
57 return SDL_ENUM_CONTINUE; /* keep going */
58}
59
60
61int main(int argc, char *argv[])
62{
63 SDLTest_CommonState *state;
64 char *pref_path;
65 char *curdir;
66 const char *base_path;
67
68 /* Initialize test framework */
69 state = SDLTest_CommonCreateState(argv, 0);
70 if (!state) {
71 return 1;
72 }
73
74 /* Parse commandline */
75 if (!SDLTest_CommonDefaultArgs(state, argc, argv)) {
76 return 1;
77 }
78
79 if (!SDL_Init(0)) {
80 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s\n", SDL_GetError());
81 return 1;
82 }
83
84 base_path = SDL_GetBasePath();
85 if (!base_path) {
86 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find base path: %s\n",
87 SDL_GetError());
88 } else {
89 SDL_Log("base path: '%s'\n", base_path);
90 }
91
92 pref_path = SDL_GetPrefPath("libsdl", "test_filesystem");
93 if (!pref_path) {
94 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path: %s\n",
95 SDL_GetError());
96 } else {
97 SDL_Log("pref path: '%s'\n", pref_path);
98 }
99 SDL_free(pref_path);
100
101 pref_path = SDL_GetPrefPath(NULL, "test_filesystem");
102 if (!pref_path) {
103 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find pref path without organization: %s\n",
104 SDL_GetError());
105 } else {
106 SDL_Log("pref path: '%s'\n", pref_path);
107 }
108 SDL_free(pref_path);
109
110 curdir = SDL_GetCurrentDirectory();
111 if (!curdir) {
112 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find current directory: %s\n",
113 SDL_GetError());
114 } else {
115 SDL_Log("current directory: '%s'\n", curdir);
116 }
117 SDL_free(curdir);
118
119 if (base_path) {
120 char **globlist;
121 SDL_IOStream *stream;
122 const char *text = "foo\n";
123
124 if (!SDL_EnumerateDirectory(base_path, enum_callback, NULL)) {
125 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Base path enumeration failed!");
126 }
127
128 globlist = SDL_GlobDirectory(base_path, "*/test*/T?st*", SDL_GLOB_CASEINSENSITIVE, NULL);
129 if (!globlist) {
130 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Base path globbing failed!");
131 } else {
132 int i;
133 for (i = 0; globlist[i]; i++) {
134 SDL_Log("GLOB[%d]: '%s'", i, globlist[i]);
135 }
136 SDL_free(globlist);
137 }
138
139 /* !!! FIXME: put this in a subroutine and make it test more thoroughly (and put it in testautomation). */
140 if (!SDL_CreateDirectory("testfilesystem-test")) {
141 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateDirectory('testfilesystem-test') failed: %s", SDL_GetError());
142 } else if (!SDL_CreateDirectory("testfilesystem-test/1")) {
143 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateDirectory('testfilesystem-test/1') failed: %s", SDL_GetError());
144 } else if (!SDL_CreateDirectory("testfilesystem-test/1")) { /* THIS SHOULD NOT FAIL! Making a directory that already exists should succeed here. */
145 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateDirectory('testfilesystem-test/1') failed: %s", SDL_GetError());
146 } else if (!SDL_CreateDirectory("testfilesystem-test/3/4/5/6")) { /* THIS SHOULD NOT FAIL! Making a directory with missing parents succeed here. */
147 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateDirectory('testfilesystem-test/3/4/5/6') failed: %s", SDL_GetError());
148 } else if (!SDL_RemovePath("testfilesystem-test/3/4/5/6")) { /* THIS SHOULD NOT FAIL! Making a directory with missing parents succeed here. */
149 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test/3/4/5/6') failed: %s", SDL_GetError());
150 } else if (!SDL_RemovePath("testfilesystem-test/3/4/5")) { /* THIS SHOULD NOT FAIL! Making a directory with missing parents succeed here. */
151 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test/3/4/5') failed: %s", SDL_GetError());
152 } else if (!SDL_RemovePath("testfilesystem-test/3/4")) { /* THIS SHOULD NOT FAIL! Making a directory with missing parents succeed here. */
153 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test/3/4') failed: %s", SDL_GetError());
154 } else if (!SDL_RemovePath("testfilesystem-test/3")) { /* THIS SHOULD NOT FAIL! Making a directory with missing parents succeed here. */
155 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test/3') failed: %s", SDL_GetError());
156 } else if (!SDL_RenamePath("testfilesystem-test/1", "testfilesystem-test/2")) {
157 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RenamePath('testfilesystem-test/1', 'testfilesystem-test/2') failed: %s", SDL_GetError());
158 } else if (!SDL_RemovePath("testfilesystem-test/2")) {
159 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test/2') failed: %s", SDL_GetError());
160 } else if (!SDL_RemovePath("testfilesystem-test")) {
161 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test') failed: %s", SDL_GetError());
162 } else if (!SDL_RemovePath("testfilesystem-test")) { /* THIS SHOULD NOT FAIL! Removing a directory that is already gone should succeed here. */
163 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-test') failed: %s", SDL_GetError());
164 }
165
166 stream = SDL_IOFromFile("testfilesystem-A", "wb");
167 if (stream) {
168 SDL_WriteIO(stream, text, SDL_strlen(text));
169 SDL_CloseIO(stream);
170
171 if (!SDL_RenamePath("testfilesystem-A", "testfilesystem-B")) {
172 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RenamePath('testfilesystem-A', 'testfilesystem-B') failed: %s", SDL_GetError());
173 } else if (!SDL_CopyFile("testfilesystem-B", "testfilesystem-A")) {
174 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CopyFile('testfilesystem-B', 'testfilesystem-A') failed: %s", SDL_GetError());
175 } else {
176 size_t sizeA, sizeB;
177 char *textA, *textB;
178
179 textA = (char *)SDL_LoadFile("testfilesystem-A", &sizeA);
180 if (!textA || sizeA != SDL_strlen(text) || SDL_strcmp(textA, text) != 0) {
181 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Contents of testfilesystem-A didn't match, expected %s, got %s\n", text, textA);
182 }
183 SDL_free(textA);
184
185 textB = (char *)SDL_LoadFile("testfilesystem-B", &sizeB);
186 if (!textB || sizeB != SDL_strlen(text) || SDL_strcmp(textB, text) != 0) {
187 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Contents of testfilesystem-B didn't match, expected %s, got %s\n", text, textB);
188 }
189 SDL_free(textB);
190 }
191
192 if (!SDL_RemovePath("testfilesystem-A")) {
193 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-A') failed: %s", SDL_GetError());
194 }
195 if (!SDL_RemovePath("testfilesystem-B")) {
196 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_RemovePath('testfilesystem-B') failed: %s", SDL_GetError());
197 }
198 } else {
199 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_IOFromFile('testfilesystem-A', 'w') failed: %s", SDL_GetError());
200 }
201 }
202
203 SDL_Quit();
204 SDLTest_CommonDestroyState(state);
205 return 0;
206}