/* * Copyright © 2025 The Files contributors * * SPDX-License-Identifier: GPL-3.0-or-later * * Authors: Khalid Abu Shawarib */ #include "test-utilities.h" #include #include #include #include #include #include static const gchar * mime_type_for_format (AutoarFormat format, AutoarFilter filter) { if (format == AUTOAR_FORMAT_ZIP && filter == AUTOAR_FILTER_NONE) { return "application/zip"; } if (format == AUTOAR_FORMAT_TAR && filter == AUTOAR_FILTER_XZ) { return "application/x-xz-compressed-tar"; } g_return_val_if_reached (""); } typedef struct { GList *files; gboolean success; GMainLoop *loop; } ArchiveCallbackData; static ArchiveCallbackData * archive_callback_data_new (GList *files) { ArchiveCallbackData *data = g_new0 (ArchiveCallbackData, 1); data->files = files; data->loop = g_main_loop_new (NULL, FALSE); return data; } static void archive_callback_data_free (ArchiveCallbackData *data) { g_clear_pointer (&data->loop, g_main_loop_unref); g_free (data); } G_DEFINE_AUTOPTR_CLEANUP_FUNC (ArchiveCallbackData, archive_callback_data_free) static void compression_callback (GFile *new_file, gboolean success, gpointer callback_data) { ArchiveCallbackData *data = callback_data; GFile *data_file = data->files->data; g_assert_cmpuint (g_list_length (data->files), ==, 1); g_assert (new_file == data_file || g_file_equal (new_file, data_file)); data->success = success; if (data->loop != NULL) { g_main_loop_quit (data->loop); } } static gint file_compare (GFile *a, GFile *b) { return !g_file_equal (a, b); } static void extraction_callback (GList *outputs, gpointer callback_data) { ArchiveCallbackData *data = callback_data; g_assert_cmpuint (g_list_length (data->files), ==, g_list_length (outputs)); for (GList *expected = data->files; expected != NULL; expected = expected->next) { g_assert_true (g_list_find_custom (outputs, expected->data, (GCompareFunc) file_compare)); } data->success = outputs != NULL; if (data->loop != NULL) { g_main_loop_quit (data->loop); } } static void file_hierarchy_create_compress (const GStrv hier, const gchar *substitution, GFile *output_file, AutoarFormat format, AutoarFilter filter, const gchar *passphrase) { g_autolist (GFile) compressed_files = file_hierarchy_get_files_list (hier, "", TRUE); g_autoptr (ArchiveCallbackData) data = archive_callback_data_new (&(GList) { .data = output_file }); g_autoptr (GError) error = NULL; const gchar *mimetype = mime_type_for_format (format, filter); file_hierarchy_create (hier, ""); nautilus_file_operations_compress (compressed_files, output_file, format, filter, passphrase, NULL, NULL, compression_callback, data); g_main_loop_run (data->loop); g_assert_true (data->success); g_assert_true (g_file_query_exists (output_file, NULL)); g_autoptr (GFileInfo) info = g_file_query_info (output_file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error); g_assert_no_error (error); g_assert_cmpstr (g_file_info_get_content_type (info), ==, mimetype); } static void test_archive_file (void) { const GStrv compressed_files_hier = (char *[]) { "my_file", NULL }; const GStrv extracted_files_hier = (char *[]) { "archive/", "archive/my_file", NULL }; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) archive_file = g_file_new_build_filename (test_get_tmp_dir (), "archive.zip", NULL); AutoarFormat format = AUTOAR_FORMAT_ZIP; AutoarFilter filter = AUTOAR_FILTER_NONE; /* * Compression */ file_hierarchy_create_compress (compressed_files_hier, "", archive_file, format, filter, NULL); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); g_assert_true (g_file_query_exists (archive_file, NULL)); test_operation_undo (); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); g_assert_false (g_file_query_exists (archive_file, NULL)); test_operation_redo (); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); g_assert_true (g_file_query_exists (archive_file, NULL)); /* * Extraction */ g_autolist (GFile) extracted_files = file_hierarchy_get_files_list (extracted_files_hier, "", TRUE); g_autoptr (ArchiveCallbackData) extract_data = archive_callback_data_new (extracted_files); /* Delete original files so that they can be replace with extracted ones. */ file_hierarchy_delete (compressed_files_hier, ""); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); nautilus_file_operations_extract_files (&(GList){ .data = archive_file }, tmp_dir, NULL, NULL, extraction_callback, extract_data); g_main_loop_run (extract_data->loop); g_assert_true (extract_data->success); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_operation_undo (); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (extracted_files_hier, "", FALSE); test_operation_redo (); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_clear_tmp_dir (); } static void test_archive_file_long (void) { /* Create a and compress a 16 MiB file using XZ to take longer. */ gsize file_size = 16 * 1024 * 1024; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) big_file = g_file_get_child (tmp_dir, "my_big_file"); g_autoptr (GFile) archive_file = g_file_get_child (tmp_dir, "my_big_file.tar.xz"); AutoarFormat format = AUTOAR_FORMAT_TAR; AutoarFilter filter = AUTOAR_FILTER_XZ; g_autoptr (ArchiveCallbackData) compress_data = archive_callback_data_new (&(GList) { .data = archive_file }); g_autoptr (GError) error = NULL; create_random_file (big_file, file_size); /* * Compression */ nautilus_file_operations_compress (&(GList){ .data = big_file }, archive_file, format, filter, NULL, NULL, NULL, compression_callback, compress_data); g_main_loop_run (compress_data->loop); g_assert_true (compress_data->success); g_assert_true (g_file_query_exists (archive_file, NULL)); g_autoptr (GFileInfo) info = g_file_query_info (archive_file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error); g_assert_no_error (error); g_assert_cmpstr (g_file_info_get_content_type (info), ==, mime_type_for_format (format, filter)); g_assert_true (g_file_query_exists (archive_file, NULL)); g_assert_true (g_file_query_exists (big_file, NULL)); test_operation_undo (); g_assert_false (g_file_query_exists (archive_file, NULL)); g_assert_true (g_file_query_exists (big_file, NULL)); test_operation_redo (); g_assert_true (g_file_query_exists (archive_file, NULL)); g_assert_true (g_file_query_exists (big_file, NULL)); /* * Extraction */ g_autoptr (ArchiveCallbackData) extract_data = archive_callback_data_new (&(GList) { .data = big_file }); g_file_delete (big_file, NULL, &error); g_assert_no_error (error); g_assert_false (g_file_query_exists (big_file, NULL)); nautilus_file_operations_extract_files (&(GList){ .data = archive_file }, tmp_dir, NULL, NULL, extraction_callback, extract_data); g_main_loop_run (extract_data->loop); g_assert_true (extract_data->success); g_assert_true (g_file_query_exists (big_file, NULL)); g_assert_true (g_file_query_exists (archive_file, NULL)); test_operation_undo (); g_assert_false (g_file_query_exists (big_file, NULL)); g_assert_true (g_file_query_exists (archive_file, NULL)); test_operation_redo (); g_assert_true (g_file_query_exists (big_file, NULL)); g_assert_true (g_file_query_exists (archive_file, NULL)); test_clear_tmp_dir (); } static void test_compress_file_password (void) { gsize file_size = 4 * 1024; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) compressed_file = g_file_get_child (tmp_dir, "my_file"); g_autoptr (GFile) archive_file = g_file_get_child (tmp_dir, "my_file.zip"); const gchar *password = "The Quick Brown Fox Jumps Over The Lazy Dog."; AutoarFormat format = AUTOAR_FORMAT_ZIP; AutoarFilter filter = AUTOAR_FILTER_NONE; g_autoptr (ArchiveCallbackData) data = archive_callback_data_new (&(GList) { .data = archive_file }); g_autoptr (GError) error = NULL; create_random_file (compressed_file, file_size); /* * Compression */ nautilus_file_operations_compress (&(GList){ .data = compressed_file }, archive_file, format, filter, password, NULL, NULL, compression_callback, data); g_main_loop_run (data->loop); g_assert_true (data->success); g_assert_true (g_file_query_exists (archive_file, NULL)); g_autoptr (GFileInfo) info = g_file_query_info (archive_file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error); g_assert_no_error (error); g_assert_cmpstr (g_file_info_get_content_type (info), ==, mime_type_for_format (format, filter)); g_assert_true (g_file_query_exists (archive_file, NULL)); g_assert_true (g_file_query_exists (compressed_file, NULL)); test_operation_undo (); g_assert_false (g_file_query_exists (archive_file, NULL)); g_assert_true (g_file_query_exists (compressed_file, NULL)); test_operation_redo (); g_assert_true (g_file_query_exists (archive_file, NULL)); g_assert_true (g_file_query_exists (compressed_file, NULL)); /* TODO: Implement extraction */ test_clear_tmp_dir (); } static void test_archive_full_dir (void) { const GStrv compressed_files_hier = (char *[]) { "my_file", "my_directory/", "my_directory/my_inner_file", NULL }; const GStrv extracted_files_hier = (char *[]) { "archive/", "archive/my_file", "archive/my_directory/", "archive/my_directory/my_inner_file", NULL }; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) archive_file = g_file_new_build_filename (test_get_tmp_dir (), "archive.zip", NULL); AutoarFormat format = AUTOAR_FORMAT_ZIP; AutoarFilter filter = AUTOAR_FILTER_NONE; /* * Compression */ file_hierarchy_create_compress (compressed_files_hier, "", archive_file, format, filter, NULL); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); test_operation_undo (); g_assert_false (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); test_operation_redo (); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); /* * Extraction */ g_autolist (GFile) extracted_files = file_hierarchy_get_files_list (extracted_files_hier, "", TRUE); g_autoptr (ArchiveCallbackData) data = archive_callback_data_new (extracted_files); /* Delete original files so that they can be replace with extracted ones. */ file_hierarchy_delete (compressed_files_hier, ""); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); nautilus_file_operations_extract_files (&(GList){ .data = archive_file }, tmp_dir, NULL, NULL, extraction_callback, data); g_main_loop_run (data->loop); g_assert_true (data->success); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_operation_undo (); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (extracted_files_hier, "", FALSE); test_operation_redo (); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_clear_tmp_dir (); } static void test_archive_full_dir_cancel (void) { const GStrv compressed_files_hier = (char *[]) { "my_file", "my_directory/", "my_directory/my_inner_file", NULL }; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) archive_file = g_file_new_build_filename (test_get_tmp_dir (), "archive.zip", NULL); g_autolist (GFile) compressed_files = file_hierarchy_get_files_list (compressed_files_hier, "", TRUE); AutoarFormat format = AUTOAR_FORMAT_ZIP; AutoarFilter filter = AUTOAR_FILTER_NONE; g_autoptr (NautilusProgressInfoManager) progress_manager = NULL; GList *progress_infos; NautilusProgressInfo *info; g_autoptr (ArchiveCallbackData) compress_data = archive_callback_data_new (&(GList) { .data = NULL }); /* * Compression */ progress_manager = nautilus_progress_info_manager_dup_singleton (); file_hierarchy_create (compressed_files_hier, ""); nautilus_file_operations_compress (compressed_files, archive_file, format, filter, NULL, NULL, NULL, compression_callback, compress_data); /* TODO: Move progress manager management to test-utilities */ progress_infos = nautilus_progress_info_manager_get_all_infos (progress_manager); g_assert_nonnull (progress_infos); info = progress_infos->data; nautilus_progress_info_cancel (info); g_main_loop_run (compress_data->loop); g_assert_false (compress_data->success); /* File might be there even when cancelled */ g_file_delete (archive_file, NULL, NULL); compress_data->files = (&(GList){ .data = archive_file, }); nautilus_file_operations_compress (compressed_files, archive_file, format, filter, NULL, NULL, NULL, compression_callback, compress_data); g_main_loop_run (compress_data->loop); g_assert_true (compress_data->success); g_assert_true (g_file_query_exists (archive_file, NULL)); /* * Extraction */ g_autoptr (ArchiveCallbackData) cancel_extract_data = archive_callback_data_new (NULL); /* Delete original files so that they can be replace with extracted ones. */ file_hierarchy_delete (compressed_files_hier, ""); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); nautilus_file_operations_extract_files (&(GList){ .data = archive_file }, tmp_dir, NULL, NULL, extraction_callback, cancel_extract_data); progress_infos = nautilus_progress_info_manager_get_all_infos (progress_manager); g_assert_nonnull (progress_infos); info = progress_infos->data; nautilus_progress_info_cancel (info); g_main_loop_run (cancel_extract_data->loop); g_assert_false (cancel_extract_data->success); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); g_assert_true (g_file_query_exists (archive_file, NULL)); test_clear_tmp_dir (); } static void test_archive_files (void) { const GStrv compressed_files_hier = (char *[]) { "my_file_1", "my_file_2", NULL }; const GStrv extracted_files_hier = (char *[]) { "archive/", "archive/my_file_1", "archive/my_file_2", NULL }; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) archive_file = g_file_new_build_filename (test_get_tmp_dir (), "archive.zip", NULL); AutoarFormat format = AUTOAR_FORMAT_ZIP; AutoarFilter filter = AUTOAR_FILTER_NONE; /* * Compression */ file_hierarchy_create_compress (compressed_files_hier, "", archive_file, format, filter, NULL); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); g_assert_true (g_file_query_exists (archive_file, NULL)); test_operation_undo (); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); g_assert_false (g_file_query_exists (archive_file, NULL)); test_operation_redo (); file_hierarchy_assert_exists (compressed_files_hier, "", TRUE); g_assert_true (g_file_query_exists (archive_file, NULL)); /* * Extraction */ g_autolist (GFile) extracted_files = file_hierarchy_get_files_list (extracted_files_hier, "", TRUE); g_autoptr (ArchiveCallbackData) data = archive_callback_data_new (extracted_files); /* Delete original files so that they can be replace with extracted ones. */ file_hierarchy_delete (compressed_files_hier, ""); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); nautilus_file_operations_extract_files (&(GList){ .data = archive_file }, tmp_dir, NULL, NULL, extraction_callback, data); g_main_loop_run (data->loop); g_assert_true (data->success); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_operation_undo (); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); file_hierarchy_assert_exists (extracted_files_hier, "", FALSE); test_operation_redo (); file_hierarchy_assert_exists (compressed_files_hier, "", FALSE); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_clear_tmp_dir (); } static void test_archives_files (void) { const GStrv first_compressed_hier = (char *[]) { "my_first_file_1", "my_first_file_2", NULL }; const GStrv second_compressed_hier = (char *[]) { "my_second_file_1", "my_second_file_2", NULL }; const GStrv extracted_files_hier = (char *[]) { "first_archive/", "first_archive/my_first_file_1", "first_archive/my_first_file_2", "second_archive/", "second_archive/my_second_file_1", "second_archive/my_second_file_2", NULL }; g_autoptr (GFile) tmp_dir = g_file_new_for_path (test_get_tmp_dir ()); g_autoptr (GFile) first_archive = g_file_new_build_filename (test_get_tmp_dir (), "first_archive.zip", NULL); g_autoptr (GFile) second_archive = g_file_new_build_filename (test_get_tmp_dir (), "second_archive.zip", NULL); AutoarFormat format = AUTOAR_FORMAT_ZIP; AutoarFilter filter = AUTOAR_FILTER_NONE; g_autoptr (GList) archives_to_extract = NULL; archives_to_extract = g_list_prepend (archives_to_extract, first_archive); archives_to_extract = g_list_prepend (archives_to_extract, second_archive); /* * Compression */ file_hierarchy_create_compress (first_compressed_hier, "", first_archive, format, filter, NULL); file_hierarchy_assert_exists (first_compressed_hier, "", TRUE); g_assert_true (g_file_query_exists (first_archive, NULL)); file_hierarchy_create_compress (second_compressed_hier, "", second_archive, format, filter, NULL); file_hierarchy_assert_exists (second_compressed_hier, "", TRUE); g_assert_true (g_file_query_exists (second_archive, NULL)); /* * Extraction */ g_autolist (GFile) extracted_files = file_hierarchy_get_files_list (extracted_files_hier, "", TRUE); g_autoptr (ArchiveCallbackData) data = archive_callback_data_new (extracted_files); /* Delete original files so that they can be replace with extracted ones. */ file_hierarchy_delete (first_compressed_hier, ""); file_hierarchy_assert_exists (first_compressed_hier, "", FALSE); file_hierarchy_delete (second_compressed_hier, ""); file_hierarchy_assert_exists (second_compressed_hier, "", FALSE); nautilus_file_operations_extract_files (archives_to_extract, tmp_dir, NULL, NULL, extraction_callback, data); g_main_loop_run (data->loop); g_assert_true (data->success); file_hierarchy_assert_exists (first_compressed_hier, "", FALSE); file_hierarchy_assert_exists (second_compressed_hier, "", FALSE); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_operation_undo (); file_hierarchy_assert_exists (first_compressed_hier, "", FALSE); file_hierarchy_assert_exists (second_compressed_hier, "", FALSE); file_hierarchy_assert_exists (extracted_files_hier, "", FALSE); test_operation_redo (); file_hierarchy_assert_exists (first_compressed_hier, "", FALSE); file_hierarchy_assert_exists (second_compressed_hier, "", FALSE); file_hierarchy_assert_exists (extracted_files_hier, "", TRUE); test_clear_tmp_dir (); } int main (int argc, char *argv[]) { g_autoptr (NautilusFileUndoManager) undo_manager = NULL; g_test_init (&argc, &argv, NULL); g_test_set_nonfatal_assertions (); nautilus_ensure_extension_points (); undo_manager = nautilus_file_undo_manager_new (); g_test_add_func ("/single_file/short", test_archive_file); g_test_add_func ("/single_file/long", test_archive_file_long); g_test_add_func ("/single_file/password", test_compress_file_password); g_test_add_func ("/single_folder/short", test_archive_full_dir); g_test_add_func ("/single_folder/short/cancel", test_archive_full_dir_cancel); g_test_add_func ("/multi_in/single_out/short", test_archive_files); g_test_add_func ("/multi_in/multi_out/short", test_archives_files); return g_test_run (); }