about summary refs log tree commit diff stats
path: root/dirent/tests/t-scandir.c
diff options
context:
space:
mode:
authorRory Bradford <roryrjb@gmail.com>2022-11-19 11:11:26 +0000
committerRory Bradford <roryrjb@gmail.com>2022-11-19 11:18:40 +0000
commit0f92f7352d1964a9859868439e8ded2c4de2111e (patch)
tree14c690402fa28c3b465ec00d2fe767054a1a3331 /dirent/tests/t-scandir.c
parentfbb7c479de91b197c6c501c2023bf564a6a7610f (diff)
downloadrf-0f92f7352d1964a9859868439e8ded2c4de2111e.tar.gz
Full native win32 support
This will now compile with MSVC using the make.bat batch file. It does
however bring in some additional third party dependencies: ports of
dirent and getopt (something I'd ideally like to work on in the future).

Signed-off-by: Rory Bradford <roryrjb@gmail.com>
Diffstat (limited to 'dirent/tests/t-scandir.c')
-rw-r--r--dirent/tests/t-scandir.c276
1 files changed, 276 insertions, 0 deletions
diff --git a/dirent/tests/t-scandir.c b/dirent/tests/t-scandir.c
new file mode 100644
index 0000000..c463f9b
--- /dev/null
+++ b/dirent/tests/t-scandir.c
@@ -0,0 +1,276 @@
+/*
+ * Make sure that scandir function works OK.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+
+/* Silence warning about fopen being insecure (MS Visual Studio) */
+#define _CRT_SECURE_NO_WARNINGS
+
+/* Include prototype for versionsort (Linux) */
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+
+#undef NDEBUG
+#include <assert.h>
+
+/* Filter and sort functions */
+static int only_readme(const struct dirent *entry);
+static int no_directories(const struct dirent *entry);
+static int reverse_alpha(const struct dirent **a, const struct dirent **b);
+
+int
+main(int argc, char *argv[])
+{
+	struct dirent **files;
+	int i;
+	int n;
+
+	(void) argc;
+	(void) argv;
+
+	/* Initialize random number generator */
+	srand((unsigned) time(NULL));
+
+	/* Basic scan with simple filter function */
+	{
+		/* Read directory entries */
+		n = scandir("tests/3", &files, only_readme, alphasort);
+		assert(n == 1);
+
+		/* Make sure that the filter works */
+		assert(strcmp(files[0]->d_name, "README.txt") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Basic scan with default sorting function */
+	{
+		/* Read directory entries in alphabetic order */
+		n = scandir("tests/3", &files, NULL, alphasort);
+		assert(n == 13);
+
+		/* Make sure that we got all the names in the proper order */
+		assert(strcmp(files[0]->d_name, ".") == 0);
+		assert(strcmp(files[1]->d_name, "..") == 0);
+		assert(strcmp(files[2]->d_name, "3zero.dat") == 0);
+		assert(strcmp(files[3]->d_name, "666.dat") == 0);
+		assert(strcmp(files[4]->d_name, "Qwerty-my-aunt.dat") == 0);
+		assert(strcmp(files[5]->d_name, "README.txt") == 0);
+		assert(strcmp(files[6]->d_name, "aaa.dat") == 0);
+		assert(strcmp(files[7]->d_name, "dirent.dat") == 0);
+		assert(strcmp(files[8]->d_name, "empty.dat") == 0);
+		assert(strcmp(files[9]->d_name, "sane-1.12.0.dat") == 0);
+		assert(strcmp(files[10]->d_name, "sane-1.2.30.dat") == 0);
+		assert(strcmp(files[11]->d_name, "sane-1.2.4.dat") == 0);
+		assert(strcmp(files[12]->d_name, "zebra.dat") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Custom filter AND sort function */
+	{
+		/* Read directory entries in alphabetic order */
+		n = scandir("tests/3", &files, no_directories, reverse_alpha);
+		assert(n == 11);
+
+		/* Make sure that we got file names in the reverse order */
+		assert(strcmp(files[0]->d_name, "zebra.dat") == 0);
+		assert(strcmp(files[1]->d_name, "sane-1.2.4.dat") == 0);
+		assert(strcmp(files[2]->d_name, "sane-1.2.30.dat") == 0);
+		assert(strcmp(files[3]->d_name, "sane-1.12.0.dat") == 0);
+		assert(strcmp(files[4]->d_name, "empty.dat") == 0);
+		assert(strcmp(files[5]->d_name, "dirent.dat") == 0);
+		assert(strcmp(files[6]->d_name, "aaa.dat") == 0);
+		assert(strcmp(files[7]->d_name, "README.txt") == 0);
+		assert(strcmp(files[8]->d_name, "Qwerty-my-aunt.dat") == 0);
+		assert(strcmp(files[9]->d_name, "666.dat") == 0);
+		assert(strcmp(files[10]->d_name, "3zero.dat") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Trying to read from non-existent directory leads to an error */
+	{
+		files = NULL;
+		n = scandir("tests/invalid", &files, NULL, alphasort);
+		assert(n == -1);
+		assert(files == NULL);
+		assert(errno == ENOENT);
+	}
+
+	/* Trying to open file as a directory produces ENOTDIR error */
+	{
+		files = NULL;
+		n = scandir("tests/3/666.dat", &files, NULL, alphasort);
+		assert(n == -1);
+		assert(files == NULL);
+		assert(errno == ENOTDIR);
+	}
+
+	/* Sort files using versionsort() */
+	{
+		files = NULL;
+		n = scandir("tests/3", &files, no_directories, versionsort);
+		assert(n == 11);
+
+		/*
+		 * Make sure that we got all the file names in the proper order:
+		 * 1.2.4 < 1.2.30 < 1.12.0
+		 */
+		assert(strcmp(files[0]->d_name, "3zero.dat") == 0);
+		assert(strcmp(files[1]->d_name, "666.dat") == 0);
+		assert(strcmp(files[2]->d_name, "Qwerty-my-aunt.dat") == 0);
+		assert(strcmp(files[3]->d_name, "README.txt") == 0);
+		assert(strcmp(files[4]->d_name, "aaa.dat") == 0);
+		assert(strcmp(files[5]->d_name, "dirent.dat") == 0);
+		assert(strcmp(files[6]->d_name, "empty.dat") == 0);
+		assert(strcmp(files[7]->d_name, "sane-1.2.4.dat") == 0);
+		assert(strcmp(files[8]->d_name, "sane-1.2.30.dat") == 0);
+		assert(strcmp(files[9]->d_name, "sane-1.12.0.dat") == 0);
+		assert(strcmp(files[10]->d_name, "zebra.dat") == 0);
+
+		/* Release file names */
+		for (i = 0; i < n; i++) {
+			free(files[i]);
+		}
+		free(files);
+	}
+
+	/* Scan large directory */
+	{
+		char dirname[PATH_MAX+1];
+		int i;
+		int ok;
+
+		/* Copy name of temporary directory to variable dirname */
+#ifdef WIN32
+		i = GetTempPathA(PATH_MAX, dirname);
+		assert(i > 0);
+#else
+		strcpy(dirname, "/tmp/");
+		i = strlen(dirname);
+#endif
+
+		/* Append random characters to dirname */
+		for (int j = 0; j < 10; j++) {
+			char c;
+
+			/* Generate random character */
+			c = "abcdefghijklmnopqrstuvwxyz"[rand() % 26];
+
+			/* Append character to dirname */
+			assert(i < PATH_MAX);
+			dirname[i++] = c;
+		}
+
+		/* Terminate directory name */
+		assert(i < PATH_MAX);
+		dirname[i] = '\0';
+
+		/* Create directory */
+#ifdef WIN32
+		ok = CreateDirectoryA(dirname, NULL);
+		assert(ok);
+#else
+		ok = mkdir(dirname, 0700);
+		assert(ok == /*success*/0);
+#endif
+
+		/* Create one thousand files */
+		assert(i + 5 < PATH_MAX);
+		for (int j = 0; j < 1000; j++) {
+			FILE *fp;
+
+			/* Construct file name */
+			dirname[i] = '/';
+			dirname[i+1] = 'z';
+			dirname[i+2] = '0' + ((j / 100) % 10);
+			dirname[i+3] = '0' + ((j / 10) % 10);
+			dirname[i+4] = '0' + (j % 10);
+			dirname[i+5] = '\0';
+
+			/* Create file */
+			fp = fopen(dirname, "w");
+			assert(fp != NULL);
+			fclose(fp);
+
+		}
+
+		/* Cut out the file name part */
+		dirname[i] = '\0';
+
+		/* Scan directory */
+		n = scandir(dirname, &files, no_directories, alphasort);
+		assert(n == 1000);
+
+		/* Make sure that all 1000 files are read back */
+		for (int j = 0; j < n; j++) {
+			char match[100];
+
+			/* Construct file name */
+			match[0] = 'z';
+			match[1] = '0' + ((j / 100) % 10);
+			match[2] = '0' + ((j / 10) % 10);
+			match[3] = '0' + (j % 10);
+			match[4] = '\0';
+
+			/* Make sure that file name matches that on the disk */
+			assert(strcmp(files[j]->d_name, match) == 0);
+
+		}
+
+		/* Release file names */
+		for (int j = 0; j < n; j++) {
+			free(files[j]);
+		}
+		free(files);
+	}
+
+	printf("OK\n");
+	return EXIT_SUCCESS;
+}
+
+/* Only pass README.txt file */
+static int
+only_readme(const struct dirent *entry)
+{
+	return strcmp(entry->d_name, "README.txt") == 0;
+}
+
+/* Filter out directories */
+static int
+no_directories(const struct dirent *entry)
+{
+	return entry->d_type != DT_DIR;
+}
+
+/* Sort in reverse direction */
+static int
+reverse_alpha(const struct dirent **a, const struct dirent **b)
+{
+	return strcoll((*b)->d_name, (*a)->d_name);
+}