From d87c1c0af459673ae515db95dfd283f2fa32b142 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Wed, 6 Feb 2008 13:52:07 +0000 Subject: [PATCH] New GIO testing module working over real data 2008-02-06 Tomas Bzatek * tests/Makefile.am: * tests/live-g-file.c: * tests/live-g-file.txt: New GIO testing module working over real data svn path=/trunk/; revision=6465 --- gio/ChangeLog | 7 + gio/tests/Makefile.am | 5 +- gio/tests/live-g-file.c | 1160 +++++++++++++++++++++++++++++++++++++++++++++ gio/tests/live-g-file.txt | 27 ++ 4 files changed, 1197 insertions(+), 2 deletions(-) create mode 100644 gio/tests/live-g-file.c create mode 100644 gio/tests/live-g-file.txt diff --git a/gio/ChangeLog b/gio/ChangeLog index 6f05953..304f9e2 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,5 +1,12 @@ 2008-02-06 Tomas Bzatek + * tests/Makefile.am: + * tests/live-g-file.c: + * tests/live-g-file.txt: + New GIO testing module working over real data + +2008-02-06 Tomas Bzatek + * glocalfileoutputstream.c (g_local_file_output_stream_close): Fallback to rename() if link() is not available (when no support on target filesystem) diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 59ff2fa..c4feeae 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -16,7 +16,7 @@ progs_ldadd = \ $(top_builddir)/gio/libgio-2.0.la -TEST_PROGS += memory-input-stream g-file g-file-info data-input-stream data-output-stream +TEST_PROGS += memory-input-stream g-file g-file-info data-input-stream data-output-stream live-g-file memory_input_stream_SOURCES = memory-input-stream.c memory_input_stream_LDADD = $(progs_ldadd) @@ -33,4 +33,5 @@ data_input_stream_LDADD = $(progs_ldadd) data_output_stream_SOURCES = data-output-stream.c data_output_stream_LDADD = $(progs_ldadd) - +live_g_file_SOURCES = live-g-file.c +live_g_file_LDADD = $(progs_ldadd) diff --git a/gio/tests/live-g-file.c b/gio/tests/live-g-file.c new file mode 100644 index 0000000..7604827 --- /dev/null +++ b/gio/tests/live-g-file.c @@ -0,0 +1,1160 @@ +/* GLib testing framework examples and tests + * Copyright (C) 2008 Red Hat, Inc. + * Authors: Tomas Bzatek + * + * This work is provided "as is"; redistribution and modification + * in whole or in part, in any medium, physical or electronic is + * permitted without restriction. + * + * This work is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In no event shall the authors or contributors be liable for any + * direct, indirect, incidental, special, exemplary, or consequential + * damages (including, but not limited to, procurement of substitute + * goods or services; loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, whether + * in contract, strict liability, or tort (including negligence or + * otherwise) arising in any way out of the use of this software, even + * if advised of the possibility of such damage. + */ + +#include +#include +#include +#include +#include + + +#define PATTERN_FILE_SIZE 0x10000 + +#define TEST_HANDLE_SPECIAL TRUE + +enum StructureExtraFlags +{ + TEST_DELETE_NORMAL = 1 << 0, + TEST_DELETE_TRASH = 1 << 1, + TEST_DELETE_NON_EMPTY = 1 << 2, + TEST_DELETE_FAILURE = 1 << 3, + TEST_NOT_EXISTS = 1 << 4, + TEST_ENUMERATE_FILE = 1 << 5, + TEST_NO_ACCESS = 1 << 6, + TEST_COPY = 1 << 7, + TEST_MOVE = 1 << 8, + TEST_COPY_ERROR_RECURSE = 1 << 9, + TEST_ALREADY_EXISTS = 1 << 10, + TEST_TARGET_IS_FILE = 1 << 11, + TEST_CREATE = 1 << 12, + TEST_REPLACE = 1 << 13, + TEST_APPEND = 1 << 14, + TEST_OPEN = 1 << 15, + TEST_OVERWRITE = 1 << 16, + TEST_INVALID_SYMLINK = 1 << 17, +}; + +struct StructureItem +{ + const char *filename; + const char *link_to; + GFileType file_type; + GFileCreateFlags create_flags; + guint32 mode; + gboolean handle_special; + enum StructureExtraFlags extra_flags; +}; + +#define TEST_DIR_NO_ACCESS "dir_no-access" +#define TEST_DIR_NO_WRITE "dir_no-write" +#define TEST_DIR_TARGET "dir-target" +#define TEST_NAME_NOT_EXISTS "not_exists" +#define TEST_TARGET_FILE "target-file" + + +const struct StructureItem sample_struct[] = { +/* filename link file_type create_flags mode | handle_special | extra_flags */ + {"dir1", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_DELETE_NON_EMPTY | TEST_REPLACE | TEST_OPEN}, + {"dir1/subdir", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE | TEST_APPEND}, + {"dir2", NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_MOVE | TEST_CREATE}, + {TEST_DIR_TARGET, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_COPY_ERROR_RECURSE}, + {TEST_DIR_NO_ACCESS, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_PRIVATE, S_IRUSR + S_IWUSR + S_IRGRP + S_IWGRP + S_IROTH + S_IWOTH, 0, TEST_NO_ACCESS | TEST_OPEN}, + {TEST_DIR_NO_WRITE, NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_PRIVATE, S_IRUSR + S_IXUSR + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH, 0, 0}, + {TEST_TARGET_FILE, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OPEN}, + {"normal_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_CREATE | TEST_OVERWRITE}, + {"normal_file-symlink", "normal_file", G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_ENUMERATE_FILE | TEST_COPY | TEST_OPEN}, + {"executable_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, S_IRWXU + S_IRWXG + S_IRWXO, 0, TEST_DELETE_TRASH | TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_REPLACE}, + {"private_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_PRIVATE, 0, 0, TEST_COPY | TEST_OPEN | TEST_OVERWRITE | TEST_APPEND}, + {"normal_file2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_OVERWRITE | TEST_REPLACE}, + {"readonly_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, S_IRUSR + S_IRGRP + S_IROTH, 0, TEST_DELETE_NORMAL | TEST_OPEN}, + {"UTF_p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", + NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_CREATE | TEST_OPEN | TEST_OVERWRITE}, + {"dir_p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88", + NULL, G_FILE_TYPE_DIRECTORY, G_FILE_CREATE_NONE, 0, 0, TEST_DELETE_NORMAL | TEST_CREATE}, + {"pattern_file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_COPY | TEST_OPEN | TEST_APPEND}, + {TEST_NAME_NOT_EXISTS, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_NOT_EXISTS | TEST_COPY | TEST_OPEN}, + {TEST_NAME_NOT_EXISTS, NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_TRASH | TEST_NOT_EXISTS | TEST_MOVE}, + {"not_exists2", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_CREATE}, + {"not_exists3", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_REPLACE}, + {"not_exists4", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_NOT_EXISTS | TEST_APPEND}, + {"dir_no-execute/file", NULL, G_FILE_TYPE_REGULAR, G_FILE_CREATE_NONE, 0, TEST_HANDLE_SPECIAL, TEST_DELETE_NORMAL | TEST_DELETE_FAILURE | TEST_NOT_EXISTS | TEST_OPEN}, + {"lost_symlink", "nowhere", G_FILE_TYPE_SYMBOLIC_LINK, G_FILE_CREATE_NONE, 0, 0, TEST_COPY | TEST_DELETE_NORMAL | TEST_OPEN | TEST_INVALID_SYMLINK}, + }; + + + + +static gboolean write_test; +static gboolean verbose; +static gboolean posix_compat; + +#define log(msg...) if (verbose) g_print (msg) + + + + + + + +GFile * +create_empty_file (GFile * parent, const char *filename, + GFileCreateFlags create_flags) +{ + GFile *child; + gboolean res; + GError *error; + GFileOutputStream *outs; + + + child = g_file_get_child (parent, filename); + g_assert (child != NULL); + + error = NULL; + outs = g_file_replace (child, NULL, FALSE, create_flags, NULL, &error); + g_assert (error == NULL); + g_assert (outs != NULL); + error = NULL; + res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error); + g_object_unref (outs); + return child; +} + +GFile * +create_empty_dir (GFile * parent, const char *filename) +{ + GFile *child; + gboolean res; + GError *error; + + child = g_file_get_child (parent, filename); + g_assert (child != NULL); + error = NULL; + res = g_file_make_directory (child, NULL, &error); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + return child; +} + +GFile * +create_symlink (GFile * parent, const char *filename, const char *points_to) +{ + GFile *child; + gboolean res; + GError *error; + + child = g_file_get_child (parent, filename); + g_assert (child != NULL); + error = NULL; + res = g_file_make_symbolic_link (child, points_to, NULL, &error); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + return child; +} + +static void +test_create_structure (gconstpointer test_data) +{ + GFile *root; + GFile *child; + gboolean res; + GError *error; + GFileOutputStream *outs; + GDataOutputStream *outds; + int i; + struct StructureItem item; + + + g_assert (test_data != NULL); + log ("\n Going to create testing structure in '%s'...\n", + (char *) test_data); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + + /* create root directory */ + res = g_file_make_directory (root, NULL, NULL); + /* don't care about errors here */ + + + /* create any other items */ + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + if ((item.handle_special) + || ((!posix_compat) + && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK))) + continue; + + child = NULL; + switch (item.file_type) + { + case G_FILE_TYPE_REGULAR: + log (" Creating file '%s'...\n", item.filename); + child = create_empty_file (root, item.filename, item.create_flags); + break; + case G_FILE_TYPE_DIRECTORY: + log (" Creating directory '%s'...\n", item.filename); + child = create_empty_dir (root, item.filename); + break; + case G_FILE_TYPE_SYMBOLIC_LINK: + log (" Creating symlink '%s' --> '%s'...\n", item.filename, + item.link_to); + child = create_symlink (root, item.filename, item.link_to); + break; + default: + break; + } + g_assert (child != NULL); + + if ((item.mode > 0) && (posix_compat)) + { + error = NULL; + res = + g_file_set_attribute_uint32 (child, G_FILE_ATTRIBUTE_UNIX_MODE, + item.mode, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, &error); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + } + + g_object_unref (child); + } + + /* create a pattern file */ + log (" Creating pattern file..."); + child = g_file_get_child (root, "pattern_file"); + g_assert (child != NULL); + + error = NULL; + outs = + g_file_replace (child, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error); + g_assert (error == NULL); + + g_assert (outs != NULL); + outds = g_data_output_stream_new (G_OUTPUT_STREAM (outs)); + g_assert (outds != NULL); + for (i = 0; i < PATTERN_FILE_SIZE; i++) + { + error = NULL; + res = g_data_output_stream_put_byte (outds, i % 256, NULL, &error); + g_assert (error == NULL); + } + error = NULL; + res = g_output_stream_close (G_OUTPUT_STREAM (outs), NULL, &error); + g_assert (error == NULL); + g_object_unref (outds); + g_object_unref (outs); + g_object_unref (child); + log (" done.\n"); + + g_object_unref (root); +} + + + + + +GFile * +file_exists (GFile * parent, const char *filename, gboolean * result) +{ + GFile *child; + gboolean res; + + if (result) + *result = FALSE; + + child = g_file_get_child (parent, filename); + g_assert (child != NULL); + res = g_file_query_exists (child, NULL); + if (result) + *result = res; + + return child; +} + +void +test_attributes (struct StructureItem item, GFileInfo * info) +{ + GFileType ftype; + guint32 mode; + const char *name, *display_name, *edit_name, *copy_name, *symlink_target; + gboolean utf8_valid; + gboolean has_attr; + gboolean is_symlink; + gboolean can_read, can_write; + + /* standard::type */ + has_attr = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE); + g_assert_cmpint (has_attr, ==, TRUE); + ftype = g_file_info_get_file_type (info); + g_assert_cmpint (ftype, !=, G_FILE_TYPE_UNKNOWN); + g_assert_cmpint (ftype, ==, item.file_type); + + /* unix::mode */ + if ((item.mode > 0) && (posix_compat)) + { + mode = + g_file_info_get_attribute_uint32 (info, + G_FILE_ATTRIBUTE_UNIX_MODE) & 0xFFF; + g_assert_cmpint (mode, ==, item.mode); + } + + /* access::can-read */ + if (item.file_type != G_FILE_TYPE_SYMBOLIC_LINK) + { + can_read = + g_file_info_get_attribute_boolean (info, + G_FILE_ATTRIBUTE_ACCESS_CAN_READ); + g_assert_cmpint (can_read, ==, TRUE); + } + + /* access::can-write */ + if ((write_test) && ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE)) + { + can_write = + g_file_info_get_attribute_boolean (info, + G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE); + g_assert_cmpint (can_write, ==, TRUE); + } + + /* standard::name */ + name = g_file_info_get_name (info); + g_assert (name != NULL); + + /* standard::display-name */ + display_name = g_file_info_get_display_name (info); + g_assert (display_name != NULL); + utf8_valid = g_utf8_validate (display_name, -1, NULL); + g_assert_cmpint (utf8_valid, ==, TRUE); + + /* standard::edit-name */ + edit_name = g_file_info_get_edit_name (info); + if (edit_name) + { + utf8_valid = g_utf8_validate (edit_name, -1, NULL); + g_assert_cmpint (utf8_valid, ==, TRUE); + } + + /* standard::copy-name */ + copy_name = + g_file_info_get_attribute_string (info, + G_FILE_ATTRIBUTE_STANDARD_COPY_NAME); + if (copy_name) + { + utf8_valid = g_utf8_validate (copy_name, -1, NULL); + g_assert_cmpint (utf8_valid, ==, TRUE); + } + + /* standard::is-symlink */ + if (posix_compat) + { + is_symlink = g_file_info_get_is_symlink (info); + g_assert_cmpint (is_symlink, ==, + item.file_type == G_FILE_TYPE_SYMBOLIC_LINK); + } + + /* standard::symlink-target */ + if ((item.file_type == G_FILE_TYPE_SYMBOLIC_LINK) && (posix_compat)) + { + symlink_target = g_file_info_get_symlink_target (info); + g_assert_cmpstr (symlink_target, ==, item.link_to); + } +} + + +static void +test_initial_structure (gconstpointer test_data) +{ + GFile *root; + GFile *child; + gboolean res; + GError *error; + GFileInputStream *ins; + int i; + GFileInfo *info; + guint32 size; + guchar *buffer; + gssize read, total_read; + struct StructureItem item; + + + g_assert (test_data != NULL); + log ("\n Testing sample structure in '%s'...\n", (char *) test_data); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + + /* test the structure */ + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + if (((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)) + || (item.handle_special)) + continue; + + log (" Testing file '%s'...\n", item.filename); + + child = file_exists (root, item.filename, &res); + g_assert (child != NULL); + g_assert_cmpint (res, ==, TRUE); + + error = NULL; + info = + g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, &error); + g_assert (error == NULL); + g_assert (info != NULL); + + test_attributes (item, info); + + g_object_unref (child); + } + + + /* read and test the pattern file */ + log (" Testing pattern file...\n"); + child = file_exists (root, "pattern_file", &res); + g_assert (child != NULL); + g_assert_cmpint (res, ==, TRUE); + + error = NULL; + info = + g_file_query_info (child, "*", G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, + &error); + g_assert (error == NULL); + g_assert (info != NULL); + size = g_file_info_get_size (info); + g_assert_cmpint (size, ==, PATTERN_FILE_SIZE); + + error = NULL; + ins = g_file_read (child, NULL, &error); + g_assert (ins != NULL); + g_assert (error == NULL); + + buffer = g_malloc (PATTERN_FILE_SIZE); + total_read = 0; + + while (total_read < PATTERN_FILE_SIZE) + { + error = NULL; + read = + g_input_stream_read (G_INPUT_STREAM (ins), buffer + total_read, + PATTERN_FILE_SIZE, NULL, &error); + g_assert (error == NULL); + total_read += read; + log (" read %d bytes, total = %d of %d.\n", read, total_read, + PATTERN_FILE_SIZE); + } + g_assert_cmpint (total_read, ==, PATTERN_FILE_SIZE); + + error = NULL; + res = g_input_stream_close (G_INPUT_STREAM (ins), NULL, &error); + g_assert (error == NULL); + g_assert_cmpint (res, ==, TRUE); + + for (i = 0; i < PATTERN_FILE_SIZE; i++) + g_assert_cmpint (*(buffer + i), ==, i % 256); + + g_object_unref (ins); + g_object_unref (child); + g_free (buffer); + g_object_unref (root); +} + + + + + + +void +traverse_recurse_dirs (GFile * parent, GFile * root) +{ + gboolean res; + GError *error; + GFileEnumerator *enumerator; + GFileInfo *info; + GFile *descend; + char *relative_path; + int i; + gboolean found; + + + g_assert (root != NULL); + + error = NULL; + enumerator = + g_file_enumerate_children (parent, "*", + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, + &error); + g_assert (enumerator != NULL); + g_assert (error == NULL); + + error = NULL; + info = g_file_enumerator_next_file (enumerator, NULL, &error); + while ((info) && (!error)) + { + descend = g_file_get_child (parent, g_file_info_get_name (info)); + g_assert (descend != NULL); + relative_path = g_file_get_relative_path (root, descend); + g_assert (relative_path != NULL); + + found = FALSE; + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + if (strcmp (sample_struct[i].filename, relative_path) == 0) + { + /* test the attributes again */ + test_attributes (sample_struct[i], info); + + found = TRUE; + break; + } + } + g_assert_cmpint (found, ==, TRUE); + + log (" Found file %s, relative to root: %s\n", + g_file_info_get_display_name (info), relative_path); + + if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) + traverse_recurse_dirs (descend, root); + + g_object_unref (descend); + error = NULL; + info = g_file_enumerator_next_file (enumerator, NULL, &error); + } + g_assert (error == NULL); + + + error = NULL; + res = g_file_enumerator_close (enumerator, NULL, &error); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); +} + +static void +test_traverse_structure (gconstpointer test_data) +{ + GFile *root; + gboolean res; + + g_assert (test_data != NULL); + log ("\n Traversing through the sample structure in '%s'...\n", + (char *) test_data); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + traverse_recurse_dirs (root, root); + + g_object_unref (root); +} + + + + +static void +test_enumerate (gconstpointer test_data) +{ + GFile *root, *child; + gboolean res; + GError *error; + GFileEnumerator *enumerator; + GFileInfo *info; + int i; + struct StructureItem item; + + + g_assert (test_data != NULL); + log ("\n Test enumerate '%s'...\n", (char *) test_data); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)) + continue; + + if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) || + (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) + && posix_compat) + || ((item.extra_flags & TEST_ENUMERATE_FILE) == + TEST_ENUMERATE_FILE)) + { + log (" Testing file '%s'\n", item.filename); + child = g_file_get_child (root, item.filename); + g_assert (child != NULL); + error = NULL; + enumerator = + g_file_enumerate_children (child, "*", + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, &error); + + if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) + { + g_assert (enumerator == NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND); + } + if ((item.extra_flags & TEST_ENUMERATE_FILE) == TEST_ENUMERATE_FILE) + { + g_assert (enumerator == NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_DIRECTORY); + } + if ((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) + { + g_assert (enumerator != NULL); + + error = NULL; + info = g_file_enumerator_next_file (enumerator, NULL, &error); + g_assert (info == NULL); + g_assert (error == NULL); + /* no items should be found, no error should be logged */ + } + + if (error) + g_error_free (error); + + if (enumerator) + { + error = NULL; + res = g_file_enumerator_close (enumerator, NULL, &error); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + } + g_object_unref (child); + } + } + g_object_unref (root); +} + + + + + + +void +do_copy_move (GFile * root, struct StructureItem item, const char *target_dir, + enum StructureExtraFlags extra_flags) +{ + GFile *dst_dir, *src_file, *dst_file; + gboolean res; + GError *error; + + log (" do_copy_move: '%s' --> '%s'\n", item.filename, target_dir); + + dst_dir = g_file_get_child (root, target_dir); + g_assert (dst_dir != NULL); + src_file = g_file_get_child (root, item.filename); + g_assert (src_file != NULL); + dst_file = g_file_get_child (dst_dir, item.filename); + g_assert (dst_file != NULL); + + error = NULL; + if ((item.extra_flags & TEST_COPY) == TEST_COPY) + res = + g_file_copy (src_file, dst_file, + G_FILE_COPY_NOFOLLOW_SYMLINKS | + ((extra_flags == + TEST_OVERWRITE) ? G_FILE_COPY_OVERWRITE : + G_FILE_COPY_NONE), NULL, NULL, NULL, &error); + else + res = + g_file_move (src_file, dst_file, G_FILE_COPY_NOFOLLOW_SYMLINKS, NULL, + NULL, NULL, &error); + + if (error) + log (" res = %d, error code %d = %s\n", res, error->code, + error->message); + + + /* copying file/directory to itself (".") */ + if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) && + (extra_flags == TEST_ALREADY_EXISTS)) + { + g_assert_cmpint (res, ==, FALSE); + g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS); + } + /* target file is a file, overwrite is not set */ + else if (((item.extra_flags & TEST_NOT_EXISTS) != TEST_NOT_EXISTS) && + (extra_flags == TEST_TARGET_IS_FILE)) + { + g_assert_cmpint (res, ==, FALSE); + if (item.file_type == G_FILE_TYPE_DIRECTORY) + g_assert_cmpint (error->code, ==, G_IO_ERROR_WOULD_RECURSE); + else + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_DIRECTORY); + } + /* source file is directory */ + else if ((item.extra_flags & TEST_COPY_ERROR_RECURSE) == + TEST_COPY_ERROR_RECURSE) + { + g_assert_cmpint (res, ==, FALSE); + g_assert_cmpint (error->code, ==, G_IO_ERROR_WOULD_RECURSE); + } + /* source or target path doesn't exist */ + else if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) || + (extra_flags == TEST_NOT_EXISTS)) + { + g_assert_cmpint (res, ==, FALSE); + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND); + } + /* source or target path permission denied */ + else if (((item.extra_flags & TEST_NO_ACCESS) == TEST_NO_ACCESS) || + (extra_flags == TEST_NO_ACCESS)) + { + g_assert_cmpint (res, ==, FALSE); + g_assert_cmpint (error->code, ==, G_IO_ERROR_PERMISSION_DENIED); + } + /* no error should be found, all exceptions defined above */ + else + { + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + } + + if (error) + g_error_free (error); + + + g_object_unref (dst_dir); + g_object_unref (src_file); + g_object_unref (dst_file); +} + +static void +test_copy_move (gconstpointer test_data) +{ + GFile *root; + gboolean res; + int i; + struct StructureItem item; + + + log ("\n"); + + g_assert (test_data != NULL); + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + + if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)) + continue; + + if (((item.extra_flags & TEST_COPY) == TEST_COPY) || + ((item.extra_flags & TEST_MOVE) == TEST_MOVE)) + { + /* test copy/move to a directory, expecting no errors if source files exist */ + do_copy_move (root, item, TEST_DIR_TARGET, 0); + + /* some files have been already moved so we can't count with them in the tests */ + if ((item.extra_flags & TEST_COPY) == TEST_COPY) + { + /* test overwrite for flagged files */ + if ((item.extra_flags & TEST_OVERWRITE) == TEST_OVERWRITE) + { + do_copy_move (root, item, TEST_DIR_TARGET, TEST_OVERWRITE); + } + /* source = target, should return G_IO_ERROR_EXISTS */ + do_copy_move (root, item, ".", TEST_ALREADY_EXISTS); + /* target is file */ + do_copy_move (root, item, TEST_TARGET_FILE, + TEST_TARGET_IS_FILE); + /* target path is invalid */ + do_copy_move (root, item, TEST_NAME_NOT_EXISTS, + TEST_NOT_EXISTS); + + /* tests on POSIX-compatible filesystems */ + if (posix_compat) + { + /* target directory is not accessible (no execute flag) */ + do_copy_move (root, item, TEST_DIR_NO_ACCESS, + TEST_NO_ACCESS); + /* target directory is readonly */ + do_copy_move (root, item, TEST_DIR_NO_WRITE, + TEST_NO_ACCESS); + } + } + } + } + g_object_unref (root); +} + + + + + +static void +test_create (gconstpointer test_data) +{ + GFile *root, *child; + gboolean res; + GError *error; + int i; + struct StructureItem item; + GFileOutputStream *os; + + + g_assert (test_data != NULL); + log ("\n"); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + + if (((item.extra_flags & TEST_CREATE) == TEST_CREATE) || + ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE) || + ((item.extra_flags & TEST_APPEND) == TEST_APPEND)) + { + log (" test_create: '%s'\n", item.filename); + + child = g_file_get_child (root, item.filename); + g_assert (child != NULL); + error = NULL; + os = NULL; + + if ((item.extra_flags & TEST_CREATE) == TEST_CREATE) + os = g_file_create (child, item.create_flags, NULL, &error); + else if ((item.extra_flags & TEST_REPLACE) == TEST_REPLACE) + os = + g_file_replace (child, NULL, TRUE, item.create_flags, NULL, + &error); + else if ((item.extra_flags & TEST_APPEND) == TEST_APPEND) + os = g_file_append_to (child, item.create_flags, NULL, &error); + + + if (error) + log (" error code %d = %s\n", error->code, error->message); + + + if (((item.extra_flags & TEST_NOT_EXISTS) == 0) && + ((item.extra_flags & TEST_CREATE) == TEST_CREATE)) + { + g_assert (os == NULL); + g_assert (error != NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS); + } + else if (item.file_type == G_FILE_TYPE_DIRECTORY) + { + g_assert (os == NULL); + g_assert (error != NULL); + if ((item.extra_flags & TEST_CREATE) == TEST_CREATE) + g_assert_cmpint (error->code, ==, G_IO_ERROR_EXISTS); + else + g_assert_cmpint (error->code, ==, G_IO_ERROR_IS_DIRECTORY); + } + else + { + g_assert (os != NULL); + g_assert (error == NULL); + } + + if (error) + g_error_free (error); + + if (os) + { + error = NULL; + res = + g_output_stream_close (G_OUTPUT_STREAM (os), NULL, &error); + if (error) + log (" g_output_stream_close: error %d = %s\n", + error->code, error->message); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + } + g_object_unref (child); + } + } + g_object_unref (root); +} + + + + +static void +test_open (gconstpointer test_data) +{ + GFile *root, *child; + gboolean res; + GError *error; + int i; + struct StructureItem item; + GFileInputStream *input_stream; + + + g_assert (test_data != NULL); + log ("\n"); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + + if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)) + continue; + + if ((item.extra_flags & TEST_OPEN) == TEST_OPEN) + { + log (" test_open: '%s'\n", item.filename); + + child = g_file_get_child (root, item.filename); + g_assert (child != NULL); + error = NULL; + input_stream = g_file_read (child, NULL, &error); + + if (((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) || + ((item.extra_flags & TEST_INVALID_SYMLINK) == + TEST_INVALID_SYMLINK)) + { + g_assert (input_stream == NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND); + } + else if (item.file_type == G_FILE_TYPE_DIRECTORY) + { + g_assert (input_stream == NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_IS_DIRECTORY); + } + else + { + g_assert (input_stream != NULL); + g_assert (error == NULL); + } + + if (error) + g_error_free (error); + + if (input_stream) + { + error = NULL; + res = + g_input_stream_close (G_INPUT_STREAM (input_stream), NULL, + &error); + g_assert_cmpint (res, ==, TRUE); + g_assert (error == NULL); + } + g_object_unref (child); + } + } + g_object_unref (root); +} + + + + + +static void +test_delete (gconstpointer test_data) +{ + GFile *root; + GFile *child; + gboolean res; + GError *error; + int i; + struct StructureItem item; + + + g_assert (test_data != NULL); + log ("\n"); + + root = g_file_new_for_commandline_arg ((char *) test_data); + g_assert (root != NULL); + res = g_file_query_exists (root, NULL); + g_assert_cmpint (res, ==, TRUE); + + for (i = 0; i < G_N_ELEMENTS (sample_struct); i++) + { + item = sample_struct[i]; + + if ((!posix_compat) && (item.file_type == G_FILE_TYPE_SYMBOLIC_LINK)) + continue; + + if (((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL) || + ((item.extra_flags & TEST_DELETE_TRASH) == TEST_DELETE_TRASH)) + { + child = file_exists (root, item.filename, &res); + g_assert (child != NULL); + /* we don't care about result here */ + + log (" Deleting %s, path = %s\n", item.filename, + g_file_get_path (child)); + error = NULL; + if ((item.extra_flags & TEST_DELETE_NORMAL) == TEST_DELETE_NORMAL) + res = g_file_delete (child, NULL, &error); + else + res = g_file_trash (child, NULL, &error); + + if ((item.extra_flags & TEST_DELETE_NON_EMPTY) == + TEST_DELETE_NON_EMPTY) + { + g_assert_cmpint (res, ==, FALSE); + g_assert (error != NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_EMPTY); + } + if ((item.extra_flags & TEST_DELETE_FAILURE) == TEST_DELETE_FAILURE) + { + g_assert_cmpint (res, ==, FALSE); + g_assert (error != NULL); + g_assert_cmpint (error->code, !=, 0); + } + if ((item.extra_flags & TEST_NOT_EXISTS) == TEST_NOT_EXISTS) + { + g_assert_cmpint (res, ==, FALSE); + g_assert (error != NULL); + g_assert_cmpint (error->code, ==, G_IO_ERROR_NOT_FOUND); + } + + if (error) + { + log (" result = %d, error = %s\n", res, error->message); + g_error_free (error); + } + + + g_object_unref (child); + } + } + g_object_unref (root); +} + + + + + + + +int +main (int argc, char *argv[]) +{ + static gboolean create_struct; + static char *target_path; + GError *error; + GOptionContext *context; + + verbose = FALSE; + write_test = FALSE; + create_struct = FALSE; + target_path = NULL; + posix_compat = FALSE; + + static GOptionEntry cmd_entries[] = { + {"read-write", 'w', 0, G_OPTION_ARG_NONE, &write_test, + "Perform write tests (incl. structure creation)", NULL}, + {"create-struct", 'c', 0, G_OPTION_ARG_NONE, &create_struct, + "Only create testing structure (no tests)", NULL}, + {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL}, + {"posix", 'x', 0, G_OPTION_ARG_NONE, &posix_compat, + "Test POSIX-specific features (unix permissions, symlinks)", NULL}, + {NULL} + }; + + /* strip all gtester-specific args */ + g_type_init (); + g_test_init (&argc, &argv, NULL); + + /* add trailing args */ + error = NULL; + context = g_option_context_new ("target_path"); + g_option_context_add_main_entries (context, cmd_entries, NULL); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + return g_test_run (); + } + + /* missing mandatory arg for target dir */ + if (argc < 2) + { + g_print (g_option_context_get_help (context, TRUE, NULL)); + return g_test_run (); + } + target_path = strdup (argv[1]); + + + + /* Write test - create new testing structure */ + if (write_test || create_struct) + g_test_add_data_func ("/live-g-file/create_structure", target_path, + test_create_structure); + + /* Read test - test the sample structure - expect defined attributes to be there */ + if (!create_struct) + g_test_add_data_func ("/live-g-file/test_initial_structure", target_path, + test_initial_structure); + + /* Read test - test traverse the structure - no special file should appear */ + if (!create_struct) + g_test_add_data_func ("/live-g-file/test_traverse_structure", target_path, + test_traverse_structure); + + /* Read test - enumerate */ + if (!create_struct) + g_test_add_data_func ("/live-g-file/test_enumerate", target_path, + test_enumerate); + + /* Read test - open (g_file_read()) */ + if (!create_struct) + g_test_add_data_func ("/live-g-file/test_open", target_path, test_open); + + /* Write test - create */ + if (write_test && (!create_struct)) + g_test_add_data_func ("/live-g-file/test_create", target_path, + test_create); + + /* Write test - copy, move */ + if (write_test && (!create_struct)) + g_test_add_data_func ("/live-g-file/test_copy_move", target_path, + test_copy_move); + + /* Write test - delete, trash */ + if (write_test && (!create_struct)) + g_test_add_data_func ("/live-g-file/test_delete", target_path, + test_delete); + + return g_test_run (); +} diff --git a/gio/tests/live-g-file.txt b/gio/tests/live-g-file.txt new file mode 100644 index 0000000..95da0e0 --- /dev/null +++ b/gio/tests/live-g-file.txt @@ -0,0 +1,27 @@ +Before you start testing it would be good to explain how it works. + +The script works in three modes: + 1. read-only (no special arguments) - suitable for read-only backends. Just + create the sample structure using the second mode, pack it (tar -p is + preffered to preserve unix modes) and put it on a reachable place. + 2. create-structure - only creates reference structure for later testing + in read-only mode + 3. write mode - full test suite, creates testing structure and performs all + read and write tests. Please note the delete/move tests are included + in this mode and target directory structure is unusable after the script + is finished. + + +To see the list of available parameters just run 'live-g-file --help' + + +Notes: + - it's advised to clean target directory first, otherwise some tests might fail + (i.e. the tests creating testing structure) + + +Tested: + - local filesystem (/tmp/...) + - file:// uri (file:///tmp/...) + - locatest:// gvfs backend (localtest:///tmp/...) + - FAT16 filesystem (no POSIX extensions) -- 2.7.4