diff options
Diffstat (limited to 'libs/zip/test')
| -rw-r--r-- | libs/zip/test/CMakeLists.txt | 81 | ||||
| -rw-r--r-- | libs/zip/test/data/data.bin | bin | 0 -> 409600 bytes | |||
| -rw-r--r-- | libs/zip/test/minunit.h | 370 | ||||
| -rw-r--r-- | libs/zip/test/test_append.c | 106 | ||||
| -rw-r--r-- | libs/zip/test/test_data.c | 85 | ||||
| -rw-r--r-- | libs/zip/test/test_entry.c | 442 | ||||
| -rw-r--r-- | libs/zip/test/test_extract.c | 199 | ||||
| -rw-r--r-- | libs/zip/test/test_offset.c | 98 | ||||
| -rw-r--r-- | libs/zip/test/test_open.c | 90 | ||||
| -rw-r--r-- | libs/zip/test/test_permissions.c | 204 | ||||
| -rw-r--r-- | libs/zip/test/test_read.c | 198 | ||||
| -rw-r--r-- | libs/zip/test/test_static.c | 98 | ||||
| -rw-r--r-- | libs/zip/test/test_write.c | 115 |
13 files changed, 2086 insertions, 0 deletions
diff --git a/libs/zip/test/CMakeLists.txt b/libs/zip/test/CMakeLists.txt new file mode 100644 index 0000000..255f87a --- /dev/null +++ b/libs/zip/test/CMakeLists.txt @@ -0,0 +1,81 @@ +cmake_minimum_required(VERSION 3.14) +include(ExternalData) + +find_package(Sanitizers) + +# tests +set(test_static_out test_static.out) +add_executable(${test_static_out} test_static.c) +add_test(NAME ${test_static_out} COMMAND ${test_static_out}) +add_sanitizers(${test_static_out}) + +set(test_write_out test_write.out) +add_executable(${test_write_out} test_write.c) +target_link_libraries(${test_write_out} zip) +add_test(NAME ${test_write_out} COMMAND ${test_write_out}) +add_sanitizers(${test_write_out}) + +set(test_append_out test_append.out) +add_executable(${test_append_out} test_append.c) +target_link_libraries(${test_append_out} zip) +add_test(NAME ${test_append_out} COMMAND ${test_append_out}) +add_sanitizers(${test_append_out}) + +set(test_read_out test_read.out) +add_executable(${test_read_out} test_read.c) +target_link_libraries(${test_read_out} zip) +add_test(NAME ${test_read_out} COMMAND ${test_read_out}) +add_sanitizers(${test_read_out}) + +set(test_extract_out test_extract.out) +add_executable(${test_extract_out} test_extract.c) +target_link_libraries(${test_extract_out} zip) +add_test(NAME ${test_extract_out} COMMAND ${test_extract_out}) +add_sanitizers(${test_extract_out}) + +set(test_entry_out test_entry.out) +add_executable(${test_entry_out} test_entry.c) +target_link_libraries(${test_entry_out} zip) +add_test(NAME ${test_entry_out} COMMAND ${test_entry_out}) +add_sanitizers(${test_entry_out}) + +set(test_permissions_out test_permissions.out) +add_executable(${test_permissions_out} test_permissions.c) +target_link_libraries(${test_permissions_out} zip) +if(LINUX OR UNIX) + find_program(UNZIP_PROGRAM unzip) + if(UNZIP_PROGRAM) + message(STATUS "Found unzip: ${UNZIP_PROGRAM}") + if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + target_compile_definitions(${test_permissions_out} + PRIVATE UNZIP_PROGRAM="${UNZIP_PROGRAM}" + ) + endif() + endif() +endif() +add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out}) +add_sanitizers(${test_permissions_out}) + +set(test_open_out test_open.out) +add_executable(${test_open_out} test_open.c) +target_link_libraries(${test_open_out} zip) +add_test(NAME ${test_open_out} COMMAND ${test_open_out}) +add_sanitizers(${test_open_out}) + +set(test_offset_out test_offset.out) +add_executable(${test_offset_out} test_offset.c) +target_link_libraries(${test_offset_out} zip) +add_test(NAME ${test_offset_out} COMMAND ${test_offset_out}) +add_sanitizers(${test_offset_out}) + +set(test_data test_data.out) +add_executable(${test_data} test_data.c) +target_link_libraries(${test_data} zip) +ExternalData_Add_Test(test_data + NAME test_data + COMMAND ${test_data} DATA{data/data.bin} +) + + diff --git a/libs/zip/test/data/data.bin b/libs/zip/test/data/data.bin Binary files differnew file mode 100644 index 0000000..2a4a9cb --- /dev/null +++ b/libs/zip/test/data/data.bin diff --git a/libs/zip/test/minunit.h b/libs/zip/test/minunit.h new file mode 100644 index 0000000..9ffc433 --- /dev/null +++ b/libs/zip/test/minunit.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2012 David Siñuela Pastor, siu.4coders@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef MINUNIT_MINUNIT_H +#define MINUNIT_MINUNIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) +#include <Windows.h> +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#define __func__ __FUNCTION__ +#endif + +#elif defined(__unix__) || defined(__unix) || defined(unix) || \ + (defined(__APPLE__) && defined(__MACH__)) + +/* Change POSIX C SOURCE version for pure c99 compilers */ +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include <string.h> +#include <sys/resource.h> +#include <sys/time.h> /* gethrtime(), gettimeofday() */ +#include <sys/times.h> +#include <time.h> /* clock_gettime(), time() */ +#include <unistd.h> /* POSIX flags */ + +#if defined(__MACH__) && defined(__APPLE__) +#include <mach/mach.h> +#include <mach/mach_time.h> +#endif + +#if __GNUC__ >= 5 && !defined(__STDC_VERSION__) +#define __func__ __extension__ __FUNCTION__ +#endif + +#else +#error "Unable to define timers for an unknown OS." +#endif + +#include <math.h> +#include <stdio.h> + +/* Maximum length of last message */ +#define MINUNIT_MESSAGE_LEN 1024 +/* Accuracy with which floats are compared */ +#define MINUNIT_EPSILON 1E-12 + +/* Misc. counters */ +static int minunit_run = 0; +static int minunit_assert = 0; +static int minunit_fail = 0; +static int minunit_status = 0; + +/* Timers */ +static double minunit_real_timer = 0; +static double minunit_proc_timer = 0; + +/* Last message */ +static char minunit_last_message[MINUNIT_MESSAGE_LEN]; + +/* Test setup and teardown function pointers */ +static void (*minunit_setup)(void) = NULL; +static void (*minunit_teardown)(void) = NULL; + +/* Definitions */ +#define MU_TEST(method_name) static void method_name(void) +#define MU_TEST_SUITE(suite_name) static void suite_name(void) + +#define MU__SAFE_BLOCK(block) \ + do { \ + block \ + } while (0) + +/* Run test suite and unset setup and teardown functions */ +#define MU_RUN_SUITE(suite_name) \ + MU__SAFE_BLOCK(suite_name(); minunit_setup = NULL; minunit_teardown = NULL;) + +/* Configure setup and teardown functions */ +#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) \ + MU__SAFE_BLOCK(minunit_setup = setup_fun; minunit_teardown = teardown_fun;) + +/* Test runner */ +#define MU_RUN_TEST(test) \ + MU__SAFE_BLOCK( \ + if (minunit_real_timer == 0 && minunit_proc_timer == 0) { \ + minunit_real_timer = mu_timer_real(); \ + minunit_proc_timer = mu_timer_cpu(); \ + } if (minunit_setup) (*minunit_setup)(); \ + minunit_status = 0; test(); minunit_run++; if (minunit_status) { \ + minunit_fail++; \ + printf("F"); \ + printf("\n%s\n", minunit_last_message); \ + } fflush(stdout); \ + if (minunit_teardown)(*minunit_teardown)();) + +/* Report */ +#define MU_REPORT() \ + MU__SAFE_BLOCK( \ + double minunit_end_real_timer; double minunit_end_proc_timer; \ + printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, \ + minunit_assert, minunit_fail); \ + minunit_end_real_timer = mu_timer_real(); \ + minunit_end_proc_timer = mu_timer_cpu(); \ + printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n", \ + minunit_end_real_timer - minunit_real_timer, \ + minunit_end_proc_timer - minunit_proc_timer);) +#define MU_EXIT_CODE minunit_fail + +/* Assertions */ +#define mu_check(test) \ + MU__SAFE_BLOCK( \ + minunit_assert++; if (!(test)) { \ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \ + "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, \ + #test); \ + minunit_status = 1; \ + return; \ + } else { printf("."); }) + +#define mu_fail(message) \ + MU__SAFE_BLOCK(minunit_assert++; \ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \ + "%s failed:\n\t%s:%d: %s", __func__, __FILE__, \ + __LINE__, message); \ + minunit_status = 1; return;) + +#define mu_assert(test, message) \ + MU__SAFE_BLOCK( \ + minunit_assert++; if (!(test)) { \ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \ + "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, \ + message); \ + minunit_status = 1; \ + return; \ + } else { printf("."); }) + +#define mu_assert_int_eq(expected, result) \ + MU__SAFE_BLOCK( \ + int minunit_tmp_e; int minunit_tmp_r; minunit_assert++; \ + minunit_tmp_e = (expected); minunit_tmp_r = (result); \ + if (minunit_tmp_e != minunit_tmp_r) { \ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \ + "%s failed:\n\t%s:%d: %d expected but was %d", __func__, \ + __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \ + minunit_status = 1; \ + return; \ + } else { printf("."); }) + +#define mu_assert_double_eq(expected, result) \ + MU__SAFE_BLOCK( \ + double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; \ + minunit_tmp_e = (expected); minunit_tmp_r = (result); \ + if (fabs(minunit_tmp_e - minunit_tmp_r) > MINUNIT_EPSILON) { \ + int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \ + "%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, \ + __FILE__, __LINE__, minunit_significant_figures, \ + minunit_tmp_e, minunit_significant_figures, minunit_tmp_r); \ + minunit_status = 1; \ + return; \ + } else { printf("."); }) + +#define mu_assert_string_eq(expected, result) \ + MU__SAFE_BLOCK( \ + const char *minunit_tmp_e = expected; \ + const char *minunit_tmp_r = result; minunit_assert++; \ + if (!minunit_tmp_e) { \ + minunit_tmp_e = "<null pointer>"; \ + } if (!minunit_tmp_r) { \ + minunit_tmp_r = "<null pointer>"; \ + } if (strcmp(minunit_tmp_e, minunit_tmp_r)) { \ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, \ + "%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, \ + __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \ + minunit_status = 1; \ + return; \ + } else { printf("."); }) + +/* + * The following two functions were written by David Robert Nadeau + * from http://NadeauSoftware.com/ and distributed under the + * Creative Commons Attribution 3.0 Unported License + */ + +/** + * Returns the real time, in seconds, or -1.0 if an error occurred. + * + * Time is measured since an arbitrary and OS-dependent start time. + * The returned real time is only useful for computing an elapsed time + * between two calls to this function. + */ +static double mu_timer_real(void) { +#if defined(_WIN32) + /* Windows 2000 and later. ---------------------------------- */ + LARGE_INTEGER Time; + LARGE_INTEGER Frequency; + + QueryPerformanceFrequency(&Frequency); + QueryPerformanceCounter(&Time); + + Time.QuadPart *= 1000000; + Time.QuadPart /= Frequency.QuadPart; + + return (double)Time.QuadPart / 1000000.0; + +#elif (defined(__hpux) || defined(hpux)) || \ + ((defined(__sun__) || defined(__sun) || defined(sun)) && \ + (defined(__SVR4) || defined(__svr4__))) + /* HP-UX, Solaris. ------------------------------------------ */ + return (double)gethrtime() / 1000000000.0; + +#elif defined(__MACH__) && defined(__APPLE__) + /* OSX. ----------------------------------------------------- */ + static double timeConvert = 0.0; + if (timeConvert == 0.0) { + mach_timebase_info_data_t timeBase; + (void)mach_timebase_info(&timeBase); + timeConvert = + (double)timeBase.numer / (double)timeBase.denom / 1000000000.0; + } + return (double)mach_absolute_time() * timeConvert; + +#elif defined(_POSIX_VERSION) + /* POSIX. --------------------------------------------------- */ + struct timeval tm; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + { + struct timespec ts; +#if defined(CLOCK_MONOTONIC_PRECISE) + /* BSD. --------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_PRECISE; +#elif defined(CLOCK_MONOTONIC_RAW) + /* Linux. ------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_RAW; +#elif defined(CLOCK_HIGHRES) + /* Solaris. ----------------------------------------- */ + const clockid_t id = CLOCK_HIGHRES; +#elif defined(CLOCK_MONOTONIC) + /* AIX, BSD, Linux, POSIX, Solaris. ----------------- */ + const clockid_t id = CLOCK_MONOTONIC; +#elif defined(CLOCK_REALTIME) + /* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */ + const clockid_t id = CLOCK_REALTIME; +#else + const clockid_t id = (clockid_t)-1; /* Unknown. */ +#endif /* CLOCK_* */ + if (id != (clockid_t)-1 && clock_gettime(id, &ts) != -1) + return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; + /* Fall thru. */ + } +#endif /* _POSIX_TIMERS */ + + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */ + gettimeofday(&tm, NULL); + return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0; +#else + return -1.0; /* Failed. */ +#endif +} + +/** + * Returns the amount of CPU time used by the current process, + * in seconds, or -1.0 if an error occurred. + */ +static double mu_timer_cpu(void) { +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + + /* This approach has a resolution of 1/64 second. Unfortunately, Windows' + * API does not offer better */ + if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, + &userTime) != 0) { + ULARGE_INTEGER userSystemTime; + memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER)); + return (double)userSystemTime.QuadPart / 10000000.0; + } + +#elif defined(__unix__) || defined(__unix) || defined(unix) || \ + (defined(__APPLE__) && defined(__MACH__)) + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */ + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + /* Prefer high-res POSIX timers, when available. */ + { + clockid_t id; + struct timespec ts; +#if _POSIX_CPUTIME > 0 + /* Clock ids vary by OS. Query the id, if possible. */ + if (clock_getcpuclockid(0, &id) == -1) +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + /* Use known clock id for AIX, Linux, or Solaris. */ + id = CLOCK_PROCESS_CPUTIME_ID; +#elif defined(CLOCK_VIRTUAL) + /* Use known clock id for BSD or HP-UX. */ + id = CLOCK_VIRTUAL; +#else + id = (clockid_t)-1; +#endif + if (id != (clockid_t)-1 && clock_gettime(id, &ts) != -1) + return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; + } +#endif + +#if defined(RUSAGE_SELF) + { + struct rusage rusage; + if (getrusage(RUSAGE_SELF, &rusage) != -1) + return (double)rusage.ru_utime.tv_sec + + (double)rusage.ru_utime.tv_usec / 1000000.0; + } +#endif + +#if defined(_SC_CLK_TCK) + { + const double ticks = (double)sysconf(_SC_CLK_TCK); + struct tms tms; + if (times(&tms) != (clock_t)-1) + return (double)tms.tms_utime / ticks; + } +#endif + +#if defined(CLOCKS_PER_SEC) + { + clock_t cl = clock(); + if (cl != (clock_t)-1) + return (double)cl / (double)CLOCKS_PER_SEC; + } +#endif + +#endif + + return -1; /* Failed. */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* MINUNIT_MINUNIT_H */ diff --git a/libs/zip/test/test_append.c b/libs/zip/test/test_append.c new file mode 100644 index 0000000..09b08ba --- /dev/null +++ b/libs/zip/test/test_append.c @@ -0,0 +1,106 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; +static int total_entries = 0; + +#define TESTDATA1 "Some test data 1...\0" + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); + + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + + zip_entry_open(zip, "test/test-1.txt"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + ++total_entries; + + zip_close(zip); +} + +void test_teardown(void) { UNLINK(ZIPNAME); } + +#define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA2 2532008468 + +MU_TEST(test_append) { + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test\\test-2.txt")); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt")); + mu_assert_int_eq(total_entries, zip_entry_index(zip)); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); + mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip)); + mu_check(CRC32DATA2 == zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + ++total_entries; + zip_close(zip); + + zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); + mu_assert_int_eq(0, zip_entry_open(zip, "test\\empty/")); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/")); + mu_assert_int_eq(0, zip_entry_size(zip)); + mu_assert_int_eq(0, zip_entry_crc32(zip)); + mu_assert_int_eq(total_entries, zip_entry_index(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + ++total_entries; + zip_close(zip); + + zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); + mu_assert_int_eq(0, zip_entry_open(zip, "empty/")); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "empty/")); + mu_assert_int_eq(0, zip_entry_size(zip)); + mu_assert_int_eq(0, zip_entry_crc32(zip)); + mu_assert_int_eq(total_entries, zip_entry_index(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + ++total_entries; + + mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test")); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "dotfiles/.test")); + mu_assert_int_eq(0, zip_entry_size(zip)); + mu_assert_int_eq(0, zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); + mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip)); + mu_check(CRC32DATA2 == zip_entry_crc32(zip)); + mu_assert_int_eq(total_entries, zip_entry_index(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + ++total_entries; + + mu_assert_int_eq(total_entries, zip_entries_total(zip)); + + zip_close(zip); +} + +MU_TEST_SUITE(test_append_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_append); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_append_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_data.c b/libs/zip/test/test_data.c new file mode 100644 index 0000000..e1cb207 --- /dev/null +++ b/libs/zip/test/test_data.c @@ -0,0 +1,85 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#else +#define MKTEMP mkstemp +#endif + +#define L_TMPNAM 1024 + +static char DATANAME[L_TMPNAM + 1] = {0}; +static char ZIPNAME[L_TMPNAM + 1] = {0}; + +#define CRC32DATABIN 291367082 +#define SIZEDATABIN 409600 + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_TMPNAM); + MKTEMP(ZIPNAME); +} + +void test_teardown(void) { remove(ZIPNAME); } + +MU_TEST(test_entry) { + { + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + { + mu_assert_int_eq(0, zip_entry_open(zip, DATANAME)); + { + mu_assert_int_eq(0, zip_entry_fwrite(zip, DATANAME)); + } + mu_assert_int_eq(0, zip_entry_close(zip)); + } + zip_close(zip); + } + + { + void *buf = NULL; + size_t bufsize = 0; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + { + mu_assert_int_eq(0, zip_entry_open(zip, DATANAME)); + { + mu_assert_int_eq(SIZEDATABIN, zip_entry_size(zip)); + + mu_assert_int_eq(CRC32DATABIN, zip_entry_crc32(zip)); + + mu_assert_int_eq(SIZEDATABIN, zip_entry_read(zip, &buf, &bufsize)); + mu_assert_int_eq(SIZEDATABIN, bufsize); + } + mu_assert_int_eq(0, zip_entry_close(zip)); + } + zip_close(zip); + + free(buf); + } +} + +MU_TEST_SUITE(test_data) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_entry); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + if (argc > 1) { + strncpy(DATANAME, argv[1], L_TMPNAM); + MU_RUN_SUITE(test_data); + } + + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_entry.c b/libs/zip/test/test_entry.c new file mode 100644 index 0000000..7d0227d --- /dev/null +++ b/libs/zip/test/test_entry.c @@ -0,0 +1,442 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE \ + (sizeof(unsigned short) * 2 + sizeof(unsigned long long) * 3) +#define MZ_ZIP_LOCAL_DIR_HEADER_SIZE 30 + +static char ZIPNAME[L_tmpnam + 1] = {0}; + +#define CRC32DATA1 2220805626 +#define TESTDATA1 "Some test data 1...\0" + +#define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA2 2532008468 + +static int total_entries = 0; + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); + + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + + zip_entry_open(zip, "test/test-1.txt"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "test\\test-2.txt"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "test\\empty/"); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "empty/"); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "dotfiles/.test"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "delete.me"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "_"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "delete/file.1"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "delete/file.2"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "deleteme/file.3"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + ++total_entries; + + zip_entry_open(zip, "delete/file.4"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + ++total_entries; + + zip_close(zip); +} + +void test_teardown(void) { + total_entries = 0; + + UNLINK(ZIPNAME); +} + +MU_TEST(test_entry_name) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + const char *name = zip_entry_name(zip); + mu_check(NULL != name); + + const char *name2 = "test/test-1.txt"; + mu_assert_int_eq(0, strcmp(name, name2)); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_index(zip)); + + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + mu_check(NULL != zip_entry_name(zip)); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt")); + mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip)); + mu_check(CRC32DATA2 == zip_entry_crc32(zip)); + mu_assert_int_eq(1, zip_entry_index(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); +} + +MU_TEST(test_entry_opencasesensitive) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_check(zip_entry_name(zip) == NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/TEST-1.TXT")); + mu_check(NULL != zip_entry_name(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(ZIP_ENOENT, + zip_entry_opencasesensitive(zip, "test/TEST-1.TXT")); + + zip_close(zip); +} + +MU_TEST(test_entry_index) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_index(zip)); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt")); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + mu_assert_int_eq(1, zip_entry_index(zip)); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt")); + mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip)); + mu_check(CRC32DATA2 == zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); +} + +MU_TEST(test_entry_openbyindex) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_openbyindex(zip, 1)); + mu_assert_int_eq(1, zip_entry_index(zip)); + + mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip)); + mu_check(CRC32DATA2 == zip_entry_crc32(zip)); + + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-2.txt")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_openbyindex(zip, 0)); + mu_assert_int_eq(0, zip_entry_index(zip)); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); +} + +MU_TEST(test_entry_read) { + char *bufencode1 = NULL; + char *bufencode2 = NULL; + char *buf = NULL; + size_t bufsize; + + struct zip_t *zip = + zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_assert_int_eq(0, zip_entry_close(zip)); + + ssize_t n = zip_stream_copy(zip, (void **)&bufencode1, NULL); + zip_stream_copy(zip, (void **)&bufencode2, &bufsize); + mu_assert_int_eq(0, strncmp(bufencode1, bufencode2, bufsize)); + + zip_stream_close(zip); + + struct zip_t *zipstream = zip_stream_open(bufencode1, n, 0, 'r'); + mu_check(zipstream != NULL); + + mu_assert_int_eq(0, zip_entry_open(zipstream, "test/test-1.txt")); + n = zip_entry_read(zipstream, (void **)&buf, NULL); + mu_assert_int_eq(0, strncmp(buf, TESTDATA1, (size_t)n)); + mu_assert_int_eq(0, zip_entry_close(zipstream)); + + zip_stream_close(zipstream); + + free(buf); + free(bufencode1); + free(bufencode2); +} + +MU_TEST(test_list_entries) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + int i = 0, n = zip_entries_total(zip); + for (; i < n; ++i) { + mu_assert_int_eq(0, zip_entry_openbyindex(zip, i)); + fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip)); + if (zip_entry_isdir(zip)) { + fprintf(stdout, " (DIR)"); + } + fprintf(stdout, "\n"); + mu_assert_int_eq(0, zip_entry_close(zip)); + } + + zip_close(zip); +} + +MU_TEST(test_entries_deletebyindex) { + size_t entries[] = {5, 6, 7, 9, 8}; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'd'); + mu_check(zip != NULL); + + mu_assert_int_eq(5, zip_entries_deletebyindex(zip, entries, 5)); + + zip_close(zip); + + zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(total_entries - 5, zip_entries_total(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4")); + + size_t buftmp = 0; + char *buf = NULL; + ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + + mu_assert_int_eq(bufsize, strlen(TESTDATA2)); + mu_assert_int_eq((size_t)bufsize, buftmp); + mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf); + buf = NULL; + + zip_close(zip); +} + +MU_TEST(test_entries_deleteinvalid) { + size_t entries[] = {111, 222, 333, 444}; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'd'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entries_deletebyindex(zip, entries, 4)); + + zip_close(zip); + + zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "delete.me")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "_")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.1")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "deleteme/file.3")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.2")); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(total_entries, zip_entries_total(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4")); + + size_t buftmp = 0; + char *buf = NULL; + ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + + mu_assert_int_eq(bufsize, strlen(TESTDATA2)); + mu_assert_int_eq((size_t)bufsize, buftmp); + mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf); + buf = NULL; + + zip_close(zip); +} + +MU_TEST(test_entries_delete) { + char *entries[] = {"delete.me", "_", "delete/file.1", "deleteme/file.3", + "delete/file.2"}; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'd'); + mu_check(zip != NULL); + + mu_assert_int_eq(5, zip_entries_delete(zip, entries, 5)); + + zip_close(zip); + + zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete.me")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete.me: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "_")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "_: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.1")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete/file.1: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "deleteme/file.3")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete/file.3: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(ZIP_ENOENT, zip_entry_open(zip, "delete/file.2")); + mu_assert_int_eq(0, zip_entry_close(zip)); + fprintf(stdout, "delete/file.2: %s\n", zip_strerror(ZIP_ENOENT)); + + mu_assert_int_eq(total_entries - 5, zip_entries_total(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "delete/file.4")); + + size_t buftmp = 0; + char *buf = NULL; + ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + + mu_assert_int_eq(bufsize, strlen(TESTDATA2)); + mu_assert_int_eq((size_t)bufsize, buftmp); + mu_assert_int_eq(0, strncmp(buf, TESTDATA2, bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf); + buf = NULL; + + zip_close(zip); +} + +MU_TEST(test_entry_offset) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + unsigned long long off = 0ULL; + int i = 0, n = zip_entries_total(zip); + for (; i < n; i++) { + mu_assert_int_eq(0, zip_entry_openbyindex(zip, i)); + mu_assert_int_eq(i, zip_entry_index(zip)); + + mu_assert_int_eq(off, zip_entry_header_offset(zip)); + + printf("\n'%s'\n", zip_entry_name(zip)); + off = zip_entry_header_offset(zip) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + strlen(zip_entry_name(zip)) + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + + zip_entry_comp_size(zip); + fprintf(stdout, "\n[%d: %s]: header: %llu, dir: %llu, size: %llu (%llu)\n", + i, zip_entry_name(zip), zip_entry_header_offset(zip), + zip_entry_dir_offset(zip), zip_entry_comp_size(zip), off); + + mu_assert_int_eq(0, zip_entry_close(zip)); + } + + zip_close(zip); +} + +MU_TEST_SUITE(test_entry_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_entry_name); + MU_RUN_TEST(test_entry_opencasesensitive); + MU_RUN_TEST(test_entry_index); + MU_RUN_TEST(test_entry_openbyindex); + MU_RUN_TEST(test_entry_read); + MU_RUN_TEST(test_list_entries); + MU_RUN_TEST(test_entries_deletebyindex); + MU_RUN_TEST(test_entries_delete); + MU_RUN_TEST(test_entry_offset); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_entry_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_extract.c b/libs/zip/test/test_extract.c new file mode 100644 index 0000000..177a04d --- /dev/null +++ b/libs/zip/test/test_extract.c @@ -0,0 +1,199 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; + +#define TESTDATA1 "Some test data 1...\0" +#define TESTDATA2 "Some test data 2...\0" + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); + + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + + zip_entry_open(zip, "test/test-1.txt"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + + zip_entry_open(zip, "test\\test-2.txt"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + + zip_entry_open(zip, "test\\empty/"); + zip_entry_close(zip); + + zip_entry_open(zip, "empty/"); + zip_entry_close(zip); + + zip_entry_open(zip, "dotfiles/.test"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + + zip_close(zip); +} + +void test_teardown(void) { + UNLINK("test/test-1.txt"); + UNLINK("test/test-2.txt"); + UNLINK("test/empty"); + UNLINK("test"); + UNLINK("empty"); + UNLINK("dotfiles/.test"); + UNLINK("dotfiles"); + UNLINK(ZIPNAME); +} + +#define UNUSED(x) (void)x + +struct buffer_t { + char *data; + size_t size; +}; + +static size_t on_extract(void *arg, uint64_t offset, const void *data, + size_t size) { + UNUSED(offset); + + struct buffer_t *buf = (struct buffer_t *)arg; + buf->data = realloc(buf->data, buf->size + size + 1); + + memcpy(&(buf->data[buf->size]), data, size); + buf->size += size; + buf->data[buf->size] = 0; + + return size; +} + +MU_TEST(test_extract) { + struct buffer_t buf; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + memset((void *)&buf, 0, sizeof(struct buffer_t)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf)); + mu_assert_int_eq(strlen(TESTDATA1), buf.size); + mu_assert_int_eq(0, strncmp(buf.data, TESTDATA1, buf.size)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf.data); + buf.data = NULL; + buf.size = 0; + + memset((void *)&buf, 0, sizeof(struct buffer_t)); + + mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test")); + mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf)); + mu_assert_int_eq(strlen(TESTDATA2), buf.size); + mu_assert_int_eq(0, strncmp(buf.data, TESTDATA2, buf.size)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf.data); + buf.data = NULL; + buf.size = 0; + + zip_close(zip); +} + +MU_TEST(test_extract_stream) { + mu_assert_int_eq( + ZIP_ENOINIT, + zip_extract("non_existing_directory/non_existing_archive.zip", ".", NULL, + NULL)); + mu_assert_int_eq(ZIP_ENOINIT, zip_stream_extract("", 0, ".", NULL, NULL)); + fprintf(stdout, "zip_stream_extract: %s\n", zip_strerror(ZIP_ENOINIT)); + + FILE *fp = NULL; +#if defined(_MSC_VER) + if (0 != fopen_s(&fp, ZIPNAME, "rb+")) +#else + if (!(fp = fopen(ZIPNAME, "rb+"))) +#endif + { + mu_fail("Cannot open filename\n"); + } + + fseek(fp, 0L, SEEK_END); + size_t filesize = ftell(fp); + fseek(fp, 0L, SEEK_SET); + + char *stream = (char *)malloc(filesize * sizeof(char)); + memset(stream, 0, filesize); + + size_t size = fread(stream, sizeof(char), filesize, fp); + mu_assert_int_eq(filesize, size); + + mu_assert_int_eq(0, zip_stream_extract(stream, size, ".", NULL, NULL)); + + free(stream); + fclose(fp); +} + +MU_TEST(test_extract_cstream) { + struct buffer_t buf; + FILE *ZIPFILE = fopen(ZIPNAME, "r"); + + struct zip_t *zip = zip_cstream_open(ZIPFILE, 0, 'r'); + mu_check(zip != NULL); + + memset((void *)&buf, 0, sizeof(struct buffer_t)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf)); + mu_assert_int_eq(strlen(TESTDATA1), buf.size); + mu_assert_int_eq(0, strncmp(buf.data, TESTDATA1, buf.size)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf.data); + buf.data = NULL; + buf.size = 0; + + memset((void *)&buf, 0, sizeof(struct buffer_t)); + + mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test")); + mu_assert_int_eq(0, zip_entry_extract(zip, on_extract, &buf)); + mu_assert_int_eq(strlen(TESTDATA2), buf.size); + mu_assert_int_eq(0, strncmp(buf.data, TESTDATA2, buf.size)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(buf.data); + buf.data = NULL; + buf.size = 0; + fclose(ZIPFILE); + + zip_cstream_close(zip); +} + +MU_TEST_SUITE(test_extract_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_extract); + MU_RUN_TEST(test_extract_stream); + MU_RUN_TEST(test_extract_cstream); +} + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_extract_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_offset.c b/libs/zip/test/test_offset.c new file mode 100644 index 0000000..d4abdc1 --- /dev/null +++ b/libs/zip/test/test_offset.c @@ -0,0 +1,98 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; + +#define HEADERDATA1 "this precedes the zip header" +#define TESTDATA1 "Some test data 1...\0" +#define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA1 2220805626 +#define CRC32DATA2 2532008468 + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); + + FILE *fp = fopen(ZIPNAME, "wb"); + mu_check(fp != NULL); + fwrite(HEADERDATA1, 1, strlen(HEADERDATA1), fp); + + struct zip_t *zip = zip_cstream_open(fp, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); + fclose(fp); + + zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); +} + +void test_teardown(void) { remove(ZIPNAME); } + +MU_TEST(test_read) { + char *buf = NULL; + ssize_t bufsize; + size_t buftmp; + uint64_t archive_offset; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + zip_offset(zip, &archive_offset); + mu_assert_int_eq(strlen(HEADERDATA1), archive_offset); + + mu_assert_int_eq(2, zip_entries_total(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + mu_assert_int_eq(strlen(TESTDATA1), bufsize); + mu_assert_int_eq((size_t)bufsize, buftmp); + mu_assert_int_eq(0, strncmp(buf, TESTDATA1, bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + zip_close(zip); + free(buf); + buf = NULL; +} + +MU_TEST_SUITE(test_offset_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_read); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_offset_suite); + MU_REPORT(); + return MU_EXIT_CODE; +}
\ No newline at end of file diff --git a/libs/zip/test/test_open.c b/libs/zip/test/test_open.c new file mode 100644 index 0000000..234edfa --- /dev/null +++ b/libs/zip/test/test_open.c @@ -0,0 +1,90 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#else +#define MKTEMP mkstemp +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); +} + +void test_teardown(void) { remove(ZIPNAME); } + +MU_TEST(test_openwitherror) { + int errnum; + struct zip_t *zip = + zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum); + mu_check(zip == NULL); + mu_assert_int_eq(ZIP_ERINIT, errnum); + + zip = zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', &errnum); + mu_check(zip != NULL); + mu_assert_int_eq(0, errnum); + + zip_close(zip); +} + +MU_TEST(test_stream_openwitherror) { + int errnum; + struct zip_t *zip = zip_stream_openwitherror( + NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum); + mu_check(zip == NULL); + mu_assert_int_eq(ZIP_EINVMODE, errnum); + + zip = zip_stream_openwitherror(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', + &errnum); + mu_check(zip != NULL); + mu_assert_int_eq(0, errnum); + + zip_stream_close(zip); +} + +MU_TEST(test_cstream_openwitherror) { + int errnum; + FILE *ZIPFILE = NULL; + + struct zip_t *zip = zip_cstream_openwitherror( + ZIPFILE, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum); + mu_check(zip == NULL); + mu_assert_int_eq(ZIP_ENOFILE, errnum); + + ZIPFILE = fopen(ZIPNAME, "w"); + zip = zip_cstream_openwitherror(ZIPFILE, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', + &errnum); + mu_check(zip != NULL); + mu_assert_int_eq(0, errnum); + + zip_cstream_close(zip); + fclose(ZIPFILE); +} + +MU_TEST_SUITE(test_entry_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_openwitherror); + MU_RUN_TEST(test_stream_openwitherror); + MU_RUN_TEST(test_cstream_openwitherror); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_entry_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_permissions.c b/libs/zip/test/test_permissions.c new file mode 100644 index 0000000..eeb2f8a --- /dev/null +++ b/libs/zip/test/test_permissions.c @@ -0,0 +1,204 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; +static char XFILE[L_tmpnam + 1] = {0}; +static char RFILE[L_tmpnam + 1] = {0}; +static char WFILE[L_tmpnam + 1] = {0}; + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + strncpy(XFILE, "x-XXXXXX\0", L_tmpnam); + strncpy(RFILE, "r-XXXXXX\0", L_tmpnam); + strncpy(WFILE, "w-XXXXXX\0", L_tmpnam); + + MKTEMP(ZIPNAME); + MKTEMP(XFILE); + MKTEMP(RFILE); + MKTEMP(WFILE); +} + +void test_teardown(void) { + UNLINK(WFILE); + UNLINK(RFILE); + UNLINK(XFILE); + UNLINK(ZIPNAME); +} + +#if defined(_MSC_VER) || defined(__MINGW32__) +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#else +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#endif + +#define XMODE 0100777 +#define RMODE 0100444 +#define WMODE 0100666 +#define UNIXMODE 0100600 + +MU_TEST(test_exe_permissions) { + struct MZ_FILE_STAT_STRUCT file_stats; + + const char *filenames[] = {XFILE}; + FILE *f = fopen(XFILE, "w"); + fclose(f); + chmod(XFILE, XMODE); + + mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1)); + remove(XFILE); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + + mu_assert_int_eq(0, MZ_FILE_STAT(XFILE, &file_stats)); + mu_assert_int_eq(XMODE, file_stats.st_mode); + +#ifdef UNZIP_PROGRAM + remove(XFILE); + + char command[128]; + sprintf(command, "%s %s", UNZIP_PROGRAM, ZIPNAME); + mu_assert_int_eq(0, system(command)); + + mu_assert_int_eq(0, MZ_FILE_STAT(XFILE, &file_stats)); + mu_assert_int_eq(XMODE, file_stats.st_mode); +#endif +} + +MU_TEST(test_read_permissions) { + struct MZ_FILE_STAT_STRUCT file_stats; + + const char *filenames[] = {RFILE}; + FILE *f = fopen(RFILE, "w"); + fclose(f); + chmod(RFILE, RMODE); + + mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1)); + remove(RFILE); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + mu_assert_int_eq(0, MZ_FILE_STAT(RFILE, &file_stats)); + mu_assert_int_eq(RMODE, file_stats.st_mode); + + // chmod from 444 to 666 to be able delete the file on windows + chmod(RFILE, WMODE); +} + +MU_TEST(test_write_permissions) { + struct MZ_FILE_STAT_STRUCT file_stats; + + const char *filenames[] = {WFILE}; + FILE *f = fopen(WFILE, "w"); + fclose(f); + chmod(WFILE, WMODE); + + mu_assert_int_eq(0, zip_create(ZIPNAME, filenames, 1)); + remove(WFILE); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + mu_assert_int_eq(0, MZ_FILE_STAT(WFILE, &file_stats)); + mu_assert_int_eq(WMODE, file_stats.st_mode); +} + +#define TESTDATA1 "Some test data 1...\0" + +MU_TEST(test_unix_permissions) { + // UNIX or APPLE + struct MZ_FILE_STAT_STRUCT file_stats; + + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, RFILE)); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + + mu_assert_int_eq(0, MZ_FILE_STAT(RFILE, &file_stats)); + + mu_assert_int_eq(UNIXMODE, file_stats.st_mode); +} + +MU_TEST(test_mtime) { + struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2; + + const char *filename = "test.data"; + FILE *stream = NULL; + struct zip_t *zip = NULL; +#if defined(_MSC_VER) + if (0 != fopen_s(&stream, filename, "w+")) +#else + if (!(stream = fopen(filename, "w+"))) +#endif + { + mu_fail("Cannot open filename\n"); + } + fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream); + mu_assert_int_eq(0, fclose(stream)); + + memset(&file_stat1, 0, sizeof(file_stat1)); + memset(&file_stat2, 0, sizeof(file_stat2)); + + zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, filename)); + mu_assert_int_eq(0, zip_entry_fwrite(zip, filename)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); + + mu_assert_int_eq(0, MZ_FILE_STAT(filename, &file_stat1)); + remove(filename); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + mu_assert_int_eq(0, MZ_FILE_STAT(filename, &file_stat2)); + remove(filename); + + fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime); + fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime); + mu_check(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1); +} + +MU_TEST_SUITE(test_permissions_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + +#if defined(_WIN32) || defined(__WIN32__) +#else + MU_RUN_TEST(test_exe_permissions); + MU_RUN_TEST(test_read_permissions); + MU_RUN_TEST(test_write_permissions); + MU_RUN_TEST(test_unix_permissions); +#endif + MU_RUN_TEST(test_mtime); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_permissions_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_read.c b/libs/zip/test/test_read.c new file mode 100644 index 0000000..4eb8b0e --- /dev/null +++ b/libs/zip/test/test_read.c @@ -0,0 +1,198 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#else +#define MKTEMP mkstemp +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; + +#define CRC32DATA1 2220805626 +#define TESTDATA1 "Some test data 1...\0" + +#define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA2 2532008468 + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); + + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + + zip_entry_open(zip, "test/test-1.txt"); + zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)); + zip_entry_close(zip); + + zip_entry_open(zip, "test\\test-2.txt"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + + zip_entry_open(zip, "test\\empty/"); + zip_entry_close(zip); + + zip_entry_open(zip, "empty/"); + zip_entry_close(zip); + + zip_entry_open(zip, "dotfiles/.test"); + zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2)); + zip_entry_close(zip); + + zip_close(zip); +} + +void test_teardown(void) { remove(ZIPNAME); } + +MU_TEST(test_read) { + char *buf = NULL; + ssize_t bufsize; + size_t buftmp; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + mu_assert_int_eq(1, zip_is64(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + mu_assert_int_eq(strlen(TESTDATA1), bufsize); + mu_assert_int_eq((size_t)bufsize, buftmp); + mu_assert_int_eq(0, strncmp(buf, TESTDATA1, bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + free(buf); + buf = NULL; + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + mu_assert_int_eq(strlen(TESTDATA2), zip_entry_size(zip)); + mu_check(CRC32DATA2 == zip_entry_crc32(zip)); + bufsize = zip_entry_read(zip, (void **)&buf, NULL); + mu_assert_int_eq(strlen(TESTDATA2), (size_t)bufsize); + mu_assert_int_eq(0, strncmp(buf, TESTDATA2, (size_t)bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + free(buf); + buf = NULL; + + mu_assert_int_eq(0, zip_entry_open(zip, "test/empty/")); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/empty/")); + mu_assert_int_eq(0, zip_entry_size(zip)); + mu_assert_int_eq(0, zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); +} + +MU_TEST(test_noallocread) { + ssize_t bufsize; + size_t buftmp = strlen(TESTDATA2); + char *buf = calloc(buftmp, sizeof(char)); + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + mu_assert_int_eq(1, zip_is64(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); + mu_assert_int_eq(buftmp, (size_t)bufsize); + mu_assert_int_eq(0, strncmp(buf, TESTDATA2, buftmp)); + mu_assert_int_eq(0, zip_entry_close(zip)); + free(buf); + buf = NULL; + + buftmp = strlen(TESTDATA1); + buf = calloc(buftmp, sizeof(char)); + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); + mu_assert_int_eq(buftmp, (size_t)bufsize); + mu_assert_int_eq(0, strncmp(buf, TESTDATA1, buftmp)); + mu_assert_int_eq(0, zip_entry_close(zip)); + free(buf); + buf = NULL; + + buftmp = strlen(TESTDATA2); + buf = calloc(buftmp, sizeof(char)); + mu_assert_int_eq(0, zip_entry_open(zip, "dotfiles/.test")); + bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); + mu_assert_int_eq(buftmp, (size_t)bufsize); + mu_assert_int_eq(0, strncmp(buf, TESTDATA2, buftmp)); + mu_assert_int_eq(0, zip_entry_close(zip)); + free(buf); + buf = NULL; + + zip_close(zip); +} + +MU_TEST(test_noallocreadwithoffset) { + size_t expected_size = strlen(TESTDATA2); + char *expected_data = calloc(expected_size, sizeof(char)); + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + mu_assert_int_eq(1, zip_is64(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + { + zip_entry_noallocread(zip, (void *)expected_data, expected_size); + + // Read the file in different chunk sizes + for (size_t i = 1; i <= expected_size; ++i) { + size_t buflen = i; + char *tmpbuf = calloc(buflen, sizeof(char)); + + for (size_t j = 0; j < expected_size; ++j) { + // we test starting from different offsets, to make sure we hit the + // "unaligned" code path + size_t offset = j; + while (offset < expected_size) { + + ssize_t nread = + zip_entry_noallocreadwithoffset(zip, offset, buflen, tmpbuf); + + mu_assert(nread <= buflen, "too many bytes read"); + mu_assert(0u != nread, "no bytes read"); + + // check the data + for (ssize_t j = 0; j < nread; ++j) { + mu_assert_int_eq(expected_data[offset + j], tmpbuf[j]); + } + + offset += nread; + } + } + free(tmpbuf); + tmpbuf = NULL; + } + } + mu_assert_int_eq(0, zip_entry_close(zip)); + + free(expected_data); + expected_data = NULL; + + zip_close(zip); +} + +MU_TEST_SUITE(test_read_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_read); + MU_RUN_TEST(test_noallocread); + MU_RUN_TEST(test_noallocreadwithoffset); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_read_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_static.c b/libs/zip/test/test_static.c new file mode 100644 index 0000000..ebc7083 --- /dev/null +++ b/libs/zip/test/test_static.c @@ -0,0 +1,98 @@ +#include "minunit.h" + +#ifndef ISSLASH +#define ISSLASH(C) ((C) == '/' || (C) == '\\') +#endif + +static inline int zip_strchr_match(const char *const str, size_t len, char c) { + size_t i; + for (i = 0; i < len; ++i) { + if (str[i] != c) { + return 0; + } + } + + return 1; +} + +static char *zip_name_normalize(char *name, char *const nname, size_t len) { + size_t offn = 0, ncpy = 0; + char c; + + if (name == NULL || nname == NULL || len <= 0) { + return NULL; + } + // skip trailing '/' + while (ISSLASH(*name)) { + name++; + } + + while ((c = *name++)) { + if (ISSLASH(c)) { + if (ncpy > 0 && !zip_strchr_match(&nname[offn], ncpy, '.')) { + offn += ncpy; + nname[offn++] = c; // append '/' + } + ncpy = 0; + } else { + nname[offn + ncpy] = c; + if (c) { + ncpy++; + } + } + } + + if (!zip_strchr_match(&nname[offn], ncpy, '.')) { + nname[offn + ncpy] = '\0'; + } else { + nname[offn] = '\0'; + } + + return nname; +} + +void test_setup(void) {} + +void test_teardown(void) {} + +MU_TEST(test_normalize) { + char nname[512] = {0}; + char *name = + "/../../../../../../../../../../../../../../../../../../../../../../../" + "../../../../../../../../../../../../../../../../../tmp/evil.txt"; + size_t len = strlen(name); + mu_assert_int_eq( + 0, strcmp(zip_name_normalize(name, nname, len), "tmp/evil.txt\0")); + + name = "../.ala/ala/...c.../../"; + len = strlen(name); + mu_assert_int_eq( + 0, strcmp(zip_name_normalize(name, nname, len), ".ala/ala/...c.../\0")); + + name = "../evil.txt/.al"; + len = strlen(name); + mu_assert_int_eq( + 0, strcmp(zip_name_normalize(name, nname, len), "evil.txt/.al\0")); + + name = "/.././.../a..../..../..a./.aaaa"; + len = strlen(name); + mu_assert_int_eq( + 0, strcmp(zip_name_normalize(name, nname, len), "a..../..a./.aaaa\0")); +} + +MU_TEST_SUITE(test_static_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_normalize); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_static_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} diff --git a/libs/zip/test/test_write.c b/libs/zip/test/test_write.c new file mode 100644 index 0000000..802d5d0 --- /dev/null +++ b/libs/zip/test/test_write.c @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <zip.h> + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#include <io.h> + +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; +static char WFILE[L_tmpnam + 1] = {0}; + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + strncpy(WFILE, "w-XXXXXX\0", L_tmpnam); + + MKTEMP(ZIPNAME); + MKTEMP(WFILE); +} + +void test_teardown(void) { + UNLINK(WFILE); + UNLINK(ZIPNAME); +} + +#define CRC32DATA1 2220805626 +#define TESTDATA1 "Some test data 1...\0" + +MU_TEST(test_write) { + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_index(zip)); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(1, zip_is64(zip)); + + zip_close(zip); +} + +MU_TEST(test_write_utf) { + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "тест/Если-б-не-было-войны.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_assert_int_eq( + 0, strcmp(zip_entry_name(zip), "тест/Если-б-не-было-войны.txt")); + mu_assert_int_eq(0, zip_entry_index(zip)); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + mu_assert_int_eq(0, zip_entry_close(zip)); + + mu_assert_int_eq(1, zip_is64(zip)); + + zip_close(zip); +} + +MU_TEST(test_fwrite) { + const char *filename = WFILE; + FILE *stream = NULL; + struct zip_t *zip = NULL; +#if defined(_MSC_VER) + if (0 != fopen_s(&stream, filename, "w+")) +#else + if (!(stream = fopen(filename, "w+"))) +#endif + { + // Cannot open filename + mu_fail("Cannot open filename\n"); + } + fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream); + mu_assert_int_eq(0, fclose(stream)); + + zip = zip_open(ZIPNAME, 9, 'w'); + mu_check(zip != NULL); + mu_assert_int_eq(0, zip_entry_open(zip, WFILE)); + mu_assert_int_eq(0, zip_entry_fwrite(zip, WFILE)); + mu_assert_int_eq(0, zip_entry_close(zip)); + mu_assert_int_eq(1, zip_is64(zip)); + + zip_close(zip); +} + +MU_TEST_SUITE(test_write_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_write); + MU_RUN_TEST(test_write_utf); + MU_RUN_TEST(test_fwrite); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_write_suite); + MU_REPORT(); + return MU_EXIT_CODE; +}
\ No newline at end of file |
