diff --git a/CMakeLists.txt b/CMakeLists.txt index c118dab..bba4e7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ if (MSVC) elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -pedantic") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wall -Wextra -Werror -pedantic -Wno-deprecated") endif (MSVC) #### diff --git a/src/zip.h b/src/zip.h index fb949a9..202ab7d 100644 --- a/src/zip.h +++ b/src/zip.h @@ -270,36 +270,17 @@ zip_entry_extract(struct zip_t *zip, */ extern int zip_total_entries(struct zip_t *zip); -/** - * Creates a new archive and puts files into a single zip archive. - * - * @param zipname zip archive file. - * @param filenames input files. - * @param len: number of input files. - * - * @return the return code - 0 on success, negative number (< 0) on error. - */ -extern int zip_create(const char *zipname, const char *filenames[], size_t len); /** - * Extracts a zip archive file into directory. + * Deletes zip archive entries. * - * If on_extract_entry is not NULL, the callback will be called after - * successfully extracted each zip entry. - * Returning a negative value from the callback will cause abort and return an - * error. The last argument (void *arg) is optional, which you can use to pass - * data to the on_extract_entry callback. - * - * @param zipname zip archive file. - * @param dir output directory. - * @param on_extract_entry on extract callback. - * @param arg opaque pointer. - * - * @return the return code - 0 on success, negative number (< 0) on error. + * @param zip zip archive handler. + * @param entries array of zip archive entries to be deleted. + * @param len the number of entries to be deleted. + * @return the number of deleted entries, or negative number (< 0) on error. */ -extern int zip_extract(const char *zipname, const char *dir, - int (*on_extract_entry)(const char *filename, void *arg), - void *arg); +extern int zip_entries_delete(struct zip_t *zip, char *const entries[], + size_t len); /** * Extracts a zip archive stream into directory. @@ -355,15 +336,36 @@ extern ssize_t zip_stream_copy(struct zip_t *zip, void **buf, ssize_t *bufsize); extern void zip_stream_close(struct zip_t *zip); /** - * Deletes zip archive entries. + * Creates a new archive and puts files into a single zip archive. * - * @param zip zip archive handler. - * @param entries array of zip archive entries to be deleted. - * @param len the number of entries to be deleted. - * @return the number of deleted entries, or negative number (< 0) on error. + * @param zipname zip archive file. + * @param filenames input files. + * @param len: number of input files. + * + * @return the return code - 0 on success, negative number (< 0) on error. */ -extern int zip_entries_delete(struct zip_t *zip, char *const entries[], - size_t len); +extern int zip_create(const char *zipname, const char *filenames[], size_t len); + +/** + * Extracts a zip archive file into directory. + * + * If on_extract_entry is not NULL, the callback will be called after + * successfully extracted each zip entry. + * Returning a negative value from the callback will cause abort and return an + * error. The last argument (void *arg) is optional, which you can use to pass + * data to the on_extract_entry callback. + * + * @param zipname zip archive file. + * @param dir output directory. + * @param on_extract_entry on extract callback. + * @param arg opaque pointer. + * + * @return the return code - 0 on success, negative number (< 0) on error. + */ +extern int zip_extract(const char *zipname, const char *dir, + int (*on_extract_entry)(const char *filename, void *arg), + void *arg); + /** @} */ #ifdef __cplusplus } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 04c2123..0da1684 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,11 +1,38 @@ cmake_minimum_required(VERSION 3.4) -# test -set(test_out test.out) +# tests +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}) +set(test_write_out ${test_write_out} PARENT_SCOPE) -add_executable(${test_out} test.c) -target_link_libraries(${test_out} zip) +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}) +set(test_append_out ${test_append_out} PARENT_SCOPE) -add_test(NAME ${test_out} COMMAND ${test_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}) +set(test_read_out ${test_read_out} PARENT_SCOPE) -set(test_out ${test_out} PARENT_SCOPE) +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}) +set(test_extract_out ${test_extract_out} PARENT_SCOPE) + +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}) +set(test_entry_out ${test_entry_out} PARENT_SCOPE) + +set(test_permissions_out test_permissions.out) +add_executable(${test_permissions_out} test_permissions.c) +target_link_libraries(${test_permissions_out} zip) +add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out}) +set(test_permissions_out ${test_permissions_out} PARENT_SCOPE) diff --git a/test/minunit.h b/test/minunit.h new file mode 100644 index 0000000..341a6e8 --- /dev/null +++ b/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 +#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 +#include +#include /* gethrtime(), gettimeofday() */ +#include +#include /* clock_gettime(), time() */ +#include /* POSIX flags */ + +#if defined(__MACH__) && defined(__APPLE__) +#include +#include +#endif + +#if __GNUC__ >= 5 && !defined(__STDC_VERSION__) +#define __func__ __extension__ __FUNCTION__ +#endif + +#else +#error "Unable to define timers for an unknown OS." +#endif + +#include +#include + +/* 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 = ""; \ + } if (!minunit_tmp_r) { \ + minunit_tmp_r = ""; \ + } 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/test/test.c b/test/test.c deleted file mode 100644 index cb3779d..0000000 --- a/test/test.c +++ /dev/null @@ -1,698 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) || defined(__MINGW64__) || 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 ZIPNAME "test.zip\0" -#define TESTDATA1 "Some test data 1...\0" -#define CRC32DATA1 2220805626 -#define TESTDATA2 "Some test data 2...\0" -#define CRC32DATA2 2532008468 - -#define RFILE "4.txt\0" -#define RMODE 0100444 - -#define WFILE "6.txt\0" -#define WMODE 0100666 - -#define XFILE "7.txt\0" -#define XMODE 0100777 - -#define UNIXMODE 0100644 - -#define UNUSED(x) (void)x - -static int total_entries = 0; - -static void test_write(void) { - struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, "test/test-1.txt")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); - assert(total_entries == zip_entry_index(zip)); - assert(strlen(TESTDATA1) == zip_entry_size(zip)); - assert(CRC32DATA1 == zip_entry_crc32(zip)); - ++total_entries; - assert(0 == zip_entry_close(zip)); - assert(0 == zip_is64(zip)); - zip_close(zip); -} - -static void test_append(void) { - struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, "test\\test-2.txt")); - assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); - assert(total_entries == zip_entry_index(zip)); - assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); - assert(strlen(TESTDATA2) == zip_entry_size(zip)); - assert(CRC32DATA2 == zip_entry_crc32(zip)); - - ++total_entries; - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "test\\empty/")); - assert(0 == strcmp(zip_entry_name(zip), "test/empty/")); - assert(0 == zip_entry_size(zip)); - assert(0 == zip_entry_crc32(zip)); - - assert(total_entries == zip_entry_index(zip)); - ++total_entries; - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "empty/")); - assert(0 == strcmp(zip_entry_name(zip), "empty/")); - assert(0 == zip_entry_size(zip)); - assert(0 == zip_entry_crc32(zip)); - - assert(total_entries == zip_entry_index(zip)); - ++total_entries; - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "dotfiles/.test")); - assert(0 == strcmp(zip_entry_name(zip), "dotfiles/.test")); - assert(0 == zip_entry_size(zip)); - assert(0 == zip_entry_crc32(zip)); - assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); - assert(strlen(TESTDATA2) == zip_entry_size(zip)); - assert(CRC32DATA2 == zip_entry_crc32(zip)); - - assert(total_entries == zip_entry_index(zip)); - ++total_entries; - assert(0 == zip_entry_close(zip)); - - zip_close(zip); -} - -static void test_read(void) { - char *buf = NULL; - ssize_t bufsize; - size_t buftmp; - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - assert(0 == zip_is64(zip)); - - assert(0 == zip_entry_open(zip, "test\\test-1.txt")); - assert(strlen(TESTDATA1) == zip_entry_size(zip)); - assert(CRC32DATA1 == zip_entry_crc32(zip)); - - bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); - assert(bufsize == strlen(TESTDATA1)); - assert((size_t)bufsize == buftmp); - assert(0 == strncmp(buf, TESTDATA1, bufsize)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - - assert(0 == zip_entry_open(zip, "test/test-2.txt")); - assert(strlen(TESTDATA2) == zip_entry_size(zip)); - assert(CRC32DATA2 == zip_entry_crc32(zip)); - - bufsize = zip_entry_read(zip, (void **)&buf, NULL); - assert((size_t)bufsize == strlen(TESTDATA2)); - assert(0 == strncmp(buf, TESTDATA2, (size_t)bufsize)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - - assert(0 == zip_entry_open(zip, "test\\empty/")); - assert(0 == strcmp(zip_entry_name(zip), "test/empty/")); - assert(0 == zip_entry_size(zip)); - assert(0 == zip_entry_crc32(zip)); - assert(0 == zip_entry_close(zip)); - - buftmp = strlen(TESTDATA2); - buf = calloc(buftmp, sizeof(char)); - assert(0 == zip_entry_open(zip, "test/test-2.txt")); - - bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); - assert(buftmp == (size_t)bufsize); - assert(0 == strncmp(buf, TESTDATA2, buftmp)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - - buftmp = strlen(TESTDATA1); - buf = calloc(buftmp, sizeof(char)); - assert(0 == zip_entry_open(zip, "test/test-1.txt")); - - bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); - assert(buftmp == (size_t)bufsize); - assert(0 == strncmp(buf, TESTDATA1, buftmp)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - - buftmp = strlen(TESTDATA2); - buf = calloc(buftmp, sizeof(char)); - assert(0 == zip_entry_open(zip, "dotfiles/.test")); - - bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); - assert(buftmp == (size_t)bufsize); - assert(0 == strncmp(buf, TESTDATA2, buftmp)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - - zip_close(zip); -} - -struct buffer_t { - char *data; - size_t size; -}; - -static size_t on_extract(void *arg, unsigned long long 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); - assert(NULL != buf->data); - - memcpy(&(buf->data[buf->size]), data, size); - buf->size += size; - buf->data[buf->size] = 0; - - return size; -} - -static void test_extract(void) { - struct buffer_t buf; - - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - - memset((void *)&buf, 0, sizeof(struct buffer_t)); - assert(0 == zip_entry_open(zip, "test/test-1.txt")); - assert(0 == zip_entry_extract(zip, on_extract, &buf)); - assert(buf.size == strlen(TESTDATA1)); - assert(0 == strncmp(buf.data, TESTDATA1, buf.size)); - assert(0 == zip_entry_close(zip)); - free(buf.data); - buf.data = NULL; - buf.size = 0; - - memset((void *)&buf, 0, sizeof(struct buffer_t)); - assert(0 == zip_entry_open(zip, "dotfiles/.test")); - assert(0 == zip_entry_extract(zip, on_extract, &buf)); - assert(buf.size == strlen(TESTDATA2)); - assert(0 == strncmp(buf.data, TESTDATA2, buf.size)); - assert(0 == zip_entry_close(zip)); - free(buf.data); - buf.data = NULL; - buf.size = 0; - - zip_close(zip); -} - -static void test_total_entries(void) { - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - - int n = zip_total_entries(zip); - zip_close(zip); - - assert(n == total_entries); -} - -static void test_entry_name(void) { - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - - assert(zip_entry_name(zip) == NULL); - - assert(0 == zip_entry_open(zip, "test\\test-1.txt")); - assert(NULL != zip_entry_name(zip)); - assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); - assert(strlen(TESTDATA1) == zip_entry_size(zip)); - assert(CRC32DATA1 == zip_entry_crc32(zip)); - assert(0 == zip_entry_index(zip)); - - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "test/test-2.txt")); - assert(NULL != zip_entry_name(zip)); - assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); - assert(strlen(TESTDATA2) == zip_entry_size(zip)); - assert(CRC32DATA2 == zip_entry_crc32(zip)); - assert(1 == zip_entry_index(zip)); - - assert(0 == zip_entry_close(zip)); - - zip_close(zip); -} - -static void test_entry_index(void) { - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, "test\\test-1.txt")); - assert(0 == zip_entry_index(zip)); - assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); - assert(strlen(TESTDATA1) == zip_entry_size(zip)); - assert(CRC32DATA1 == zip_entry_crc32(zip)); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "test/test-2.txt")); - assert(1 == zip_entry_index(zip)); - assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); - assert(strlen(TESTDATA2) == zip_entry_size(zip)); - assert(CRC32DATA2 == zip_entry_crc32(zip)); - assert(0 == zip_entry_close(zip)); - - zip_close(zip); -} - -static void test_entry_openbyindex(void) { - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - - assert(0 == zip_entry_openbyindex(zip, 1)); - assert(1 == zip_entry_index(zip)); - assert(strlen(TESTDATA2) == zip_entry_size(zip)); - assert(CRC32DATA2 == zip_entry_crc32(zip)); - assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_openbyindex(zip, 0)); - assert(0 == zip_entry_index(zip)); - assert(strlen(TESTDATA1) == zip_entry_size(zip)); - assert(CRC32DATA1 == zip_entry_crc32(zip)); - assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); - assert(0 == zip_entry_close(zip)); - - zip_close(zip); -} - -static void test_list_entries(void) { - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); - - int i = 0, n = zip_total_entries(zip); - for (; i < n; ++i) { - assert(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"); - assert(0 == zip_entry_close(zip)); - } - - zip_close(zip); -} - -static void test_fwrite(void) { - 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 - fprintf(stdout, "Cannot open filename\n"); - assert(0 == -1); - } - fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream); - assert(0 == fclose(stream)); - - zip = zip_open(ZIPNAME, 9, 'w'); - assert(zip != NULL); - assert(0 == zip_entry_open(zip, WFILE)); - assert(0 == zip_entry_fwrite(zip, WFILE)); - assert(0 == zip_entry_close(zip)); - assert(0 == zip_is64(zip)); - - zip_close(zip); - remove(WFILE); - remove(ZIPNAME); -} - -static void test_exe_permissions(void) { -#if defined(_WIN32) || defined(__WIN32__) -#else - struct MZ_FILE_STAT_STRUCT file_stats; - const char *filenames[] = {XFILE}; - FILE *f = fopen(XFILE, "w"); - fclose(f); - chmod(XFILE, XMODE); - - remove(ZIPNAME); - - assert(0 == zip_create(ZIPNAME, filenames, 1)); - - remove(XFILE); - - assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); - - assert(0 == MZ_FILE_STAT(XFILE, &file_stats)); - assert(XMODE == file_stats.st_mode); - - remove(XFILE); - remove(ZIPNAME); -#endif -} - -static void test_read_permissions(void) { -#if defined(_MSC_VER) -#else - - struct MZ_FILE_STAT_STRUCT file_stats; - const char *filenames[] = {RFILE}; - FILE *f = fopen(RFILE, "w"); - fclose(f); - chmod(RFILE, RMODE); - - remove(ZIPNAME); - - assert(0 == zip_create(ZIPNAME, filenames, 1)); - - // chmod from 444 to 666 to be able delete the file on windows - chmod(RFILE, WMODE); - remove(RFILE); - - assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); - - assert(0 == MZ_FILE_STAT(RFILE, &file_stats)); - assert(RMODE == file_stats.st_mode); - - chmod(RFILE, WMODE); - remove(RFILE); - remove(ZIPNAME); -#endif -} - -static void test_write_permissions(void) { -#if defined(_MSC_VER) -#else - - struct MZ_FILE_STAT_STRUCT file_stats; - const char *filenames[] = {WFILE}; - FILE *f = fopen(WFILE, "w"); - fclose(f); - chmod(WFILE, WMODE); - - remove(ZIPNAME); - - assert(0 == zip_create(ZIPNAME, filenames, 1)); - - remove(WFILE); - - assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); - - assert(0 == MZ_FILE_STAT(WFILE, &file_stats)); - assert(WMODE == file_stats.st_mode); - - remove(WFILE); - remove(ZIPNAME); -#endif -} - -static void test_mtime(void) { - struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2; - - 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 - fprintf(stdout, "Cannot open filename\n"); - assert(0 == -1); - } - fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream); - assert(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'); - assert(zip != NULL); - assert(0 == zip_entry_open(zip, filename)); - assert(0 == zip_entry_fwrite(zip, filename)); - assert(0 == zip_entry_close(zip)); - zip_close(zip); - - assert(0 == MZ_FILE_STAT(filename, &file_stat1)); - - remove(filename); - assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); - assert(0 == MZ_FILE_STAT(filename, &file_stat2)); - fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime); - fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime); - assert(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1); - - remove(filename); - remove(ZIPNAME); -} - -static void test_unix_permissions(void) { -#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__) -#else - // UNIX or APPLE - struct MZ_FILE_STAT_STRUCT file_stats; - - remove(ZIPNAME); - - struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, RFILE)); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - zip_close(zip); - - remove(RFILE); - - assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); - - assert(0 == MZ_FILE_STAT(RFILE, &file_stats)); - assert(UNIXMODE == file_stats.st_mode); - - remove(RFILE); - remove(ZIPNAME); -#endif -} - -static void test_extract_stream(void) { - assert(0 > zip_extract("non_existing_directory/non_existing_archive.zip", ".", - NULL, NULL)); - assert(0 > zip_stream_extract("", 0, ".", NULL, NULL)); - - remove(ZIPNAME); - - struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, RFILE)); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "dotfiles/.test\0")); - assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); - assert(0 == zip_entry_close(zip)); - - zip_close(zip); - - remove(RFILE); - remove("dotfiles/.test\0"); - - FILE *fp = NULL; - fp = fopen(ZIPNAME, "rb+"); - assert(fp != NULL); - - 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); - assert(filesize == size); - - assert(0 == zip_stream_extract(stream, size, ".", NULL, NULL)); - - free(stream); - fclose(fp); - remove(RFILE); - remove("dotfiles/.test\0"); - remove(ZIPNAME); -} - -static void test_open_stream(void) { - remove(ZIPNAME); - /* COMPRESS MEM TO MEM */ - struct zip_t *zip = - zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, "test/test-1.txt")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - /* write compressed mem to file */ - char *buf_encode1 = NULL; - char *buf_encode2 = NULL; - ssize_t n = zip_stream_copy(zip, (void **)&buf_encode1, NULL); - zip_stream_copy(zip, (void **)&buf_encode2, &n); - assert(0 == strncmp(buf_encode1, buf_encode2, (size_t)n)); - - zip_stream_close(zip); - /* DECOMPRESS MEM TO MEM */ - struct zip_t *zipStream = zip_stream_open(buf_encode1, n, 0, 'r'); - assert(zipStream != NULL); - - assert(0 == zip_entry_open(zipStream, "test/test-1.txt")); - - char *buf = NULL; - ssize_t bufsize; - bufsize = zip_entry_read(zipStream, (void **)&buf, NULL); - assert(0 == strncmp(buf, TESTDATA1, (size_t)bufsize)); - assert(0 == zip_entry_close(zipStream)); - zip_stream_close(zipStream); - - free(buf); - free(buf_encode1); - free(buf_encode2); - remove(ZIPNAME); -} - -static int create_zip_file(const char *filename) { - struct zip_t *zip = zip_open(filename, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); - assert(zip != NULL); - - assert(0 == zip_entry_open(zip, "file.txt")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "a")); - assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "directory/file.1")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "otherdirectory/file.3")); - assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "directory/file.2")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - assert(0 == zip_entry_open(zip, "directory/file.4")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); - - assert(6 == zip_total_entries(zip)); - zip_close(zip); - return 0; -} - -static void test_entries_delete() { - remove(ZIPNAME); - assert(0 == create_zip_file(ZIPNAME)); - - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(0 == zip_entry_open(zip, "file.txt")); - assert(0 == zip_entry_close(zip)); - assert(0 == zip_entry_open(zip, "a")); - assert(0 == zip_entry_close(zip)); - assert(0 == zip_entry_open(zip, "directory/file.1")); - assert(0 == zip_entry_close(zip)); - assert(0 == zip_entry_open(zip, "otherdirectory/file.3")); - assert(0 == zip_entry_close(zip)); - assert(0 == zip_entry_open(zip, "directory/file.2")); - assert(0 == zip_entry_close(zip)); - assert(0 == zip_entry_open(zip, "directory/file.4")); - assert(0 == zip_entry_close(zip)); - zip_close(zip); - - char *entries[] = {"file.txt", "a", "directory/file.1", - "otherdirectory/file.3", "directory/file.2"}; - zip = zip_open(ZIPNAME, 0, 'd'); - assert(5 == zip_entries_delete(zip, entries, 5)); - zip_close(zip); - - zip = zip_open(ZIPNAME, 0, 'r'); - assert(-1 == zip_entry_open(zip, "file.txt")); - assert(0 == zip_entry_close(zip)); - assert(-1 == zip_entry_open(zip, "a")); - assert(0 == zip_entry_close(zip)); - assert(-1 == zip_entry_open(zip, "directory/file.1")); - assert(0 == zip_entry_close(zip)); - assert(-1 == zip_entry_open(zip, "otherdirectory/file.3")); - assert(0 == zip_entry_close(zip)); - assert(-1 == zip_entry_open(zip, "directory/file.2")); - assert(0 == zip_entry_close(zip)); - - assert(1 == zip_total_entries(zip)); - assert(0 == zip_entry_open(zip, "directory/file.4")); - size_t buftmp = 0; - char *buf = NULL; - ssize_t bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); - assert(bufsize == strlen(TESTDATA1)); - assert((size_t)bufsize == buftmp); - assert(0 == strncmp(buf, TESTDATA1, bufsize)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - - zip_close(zip); -} - -int main(int argc, char *argv[]) { - UNUSED(argc); - UNUSED(argv); - - remove(ZIPNAME); - - test_write(); - test_append(); - test_read(); - test_extract(); - test_total_entries(); - test_entry_name(); - test_entry_index(); - test_entry_openbyindex(); - test_list_entries(); - test_fwrite(); - test_read_permissions(); - test_write_permissions(); - test_exe_permissions(); - test_mtime(); - test_unix_permissions(); - test_extract_stream(); - test_open_stream(); - test_entries_delete(); - - remove(ZIPNAME); - - fprintf(stdout, "ALL TEST SUCCESS!\n"); - - return 0; -} diff --git a/test/test_append.c b/test/test_append.c new file mode 100644 index 0000000..207128c --- /dev/null +++ b/test/test_append.c @@ -0,0 +1,94 @@ +#include +#include + +#include + +#include "minunit.h" + +static char *ZIPNAME = NULL; +static int total_entries = 0; + +#define TESTDATA1 "Some test data 1...\0" + +void test_setup(void) { + ZIPNAME = tempnam(NULL, "z-"); + + 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) { + remove(ZIPNAME); + free(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; + + 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_check(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, "empty/")); + mu_assert_int_eq(0, strcmp(zip_entry_name(zip), "empty/")); + mu_assert_int_eq(0, zip_entry_size(zip)); + mu_check(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_check(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_total_entries(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/test/test_entry.c b/test/test_entry.c new file mode 100644 index 0000000..1f42abe --- /dev/null +++ b/test/test_entry.c @@ -0,0 +1,274 @@ +#include +#include + +#include + +#include "minunit.h" + +static char *ZIPNAME = NULL; + +#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) { + ZIPNAME = tempnam(NULL, "z-"); + + 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; + + remove(ZIPNAME); + free(ZIPNAME); +} + +MU_TEST(test_entry_name) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_check(zip_entry_name(zip) == NULL); + + mu_check(0 == zip_entry_open(zip, "test\\test-1.txt")); + mu_check(NULL != zip_entry_name(zip)); + mu_check(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_index(zip)); + + mu_check(0 == zip_entry_close(zip)); + + mu_check(0 == zip_entry_open(zip, "test/test-2.txt")); + mu_check(NULL != zip_entry_name(zip)); + mu_check(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_check(0 == zip_entry_close(zip)); + + zip_close(zip); +} + +MU_TEST(test_entry_index) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + mu_check(0 == zip_entry_open(zip, "test\\test-1.txt")); + mu_assert_int_eq(0, zip_entry_index(zip)); + mu_check(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_check(0 == zip_entry_close(zip)); + + mu_check(0 == zip_entry_open(zip, "test/test-2.txt")); + mu_assert_int_eq(1, zip_entry_index(zip)); + mu_check(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_check(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_check(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_check(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); + mu_check(0 == zip_entry_close(zip)); + + mu_check(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_check(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); + mu_check(0 == zip_entry_close(zip)); + + zip_close(zip); +} + +MU_TEST(test_entry_read) { + char *bufencode1 = NULL; + char *bufencode2 = NULL; + char *buf = NULL; + ssize_t bufsize; + + struct zip_t *zip = + zip_stream_open(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_check(0 == zip_entry_open(zip, "test/test-1.txt")); + mu_check(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_check(0 == zip_entry_close(zip)); + + ssize_t n = zip_stream_copy(zip, (void **)&bufencode1, NULL); + zip_stream_copy(zip, (void **)&bufencode2, &n); + mu_check(0 == strncmp(bufencode1, bufencode2, (size_t)n)); + + zip_stream_close(zip); + + struct zip_t *zipstream = zip_stream_open(bufencode1, n, 0, 'r'); + mu_check(zipstream != NULL); + + mu_check(0 == zip_entry_open(zipstream, "test/test-1.txt")); + bufsize = zip_entry_read(zipstream, (void **)&buf, NULL); + mu_check(0 == strncmp(buf, TESTDATA1, (size_t)bufsize)); + mu_check(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_total_entries(zip); + for (; i < n; ++i) { + mu_check(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_check(0 == zip_entry_close(zip)); + } + + 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_check(0 > zip_entry_open(zip, "delete.me")); + mu_check(0 == zip_entry_close(zip)); + + mu_check(0 > zip_entry_open(zip, "_")); + mu_check(0 == zip_entry_close(zip)); + + mu_check(0 > zip_entry_open(zip, "delete/file.1")); + mu_check(0 == zip_entry_close(zip)); + + mu_check(0 > zip_entry_open(zip, "deleteme/file.3")); + mu_check(0 == zip_entry_close(zip)); + mu_check(0 > zip_entry_open(zip, "delete/file.2")); + mu_check(0 == zip_entry_close(zip)); + + mu_assert_int_eq(total_entries - 5, zip_total_entries(zip)); + + mu_check(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_check(0 == strncmp(buf, TESTDATA2, bufsize)); + mu_check(0 == zip_entry_close(zip)); + + free(buf); + buf = NULL; + + 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_index); + MU_RUN_TEST(test_entry_openbyindex); + MU_RUN_TEST(test_entry_read); + MU_RUN_TEST(test_list_entries); + MU_RUN_TEST(test_entries_delete); +} + +#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/test/test_extract.c b/test/test_extract.c new file mode 100644 index 0000000..d2fef23 --- /dev/null +++ b/test/test_extract.c @@ -0,0 +1,150 @@ +#include +#include + +#include + +#include "minunit.h" + +static char *ZIPNAME = NULL; + +#define TESTDATA1 "Some test data 1...\0" +#define TESTDATA2 "Some test data 2...\0" + +void test_setup(void) { + ZIPNAME = tempnam(".", "z-"); + + 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("test/test-1.txt"); + remove("test/test-2.txt"); + remove("test/empty"); + remove("test"); + remove("empty"); + remove("dotfiles/.test"); + remove("dotfiles"); + remove(ZIPNAME); + free(ZIPNAME); +} + +#define UNUSED(x) (void)x + +struct buffer_t { + char *data; + size_t size; +}; + +static size_t on_extract(void *arg, unsigned long long 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_check(0 == zip_entry_open(zip, "test/test-1.txt")); + mu_check(0 == zip_entry_extract(zip, on_extract, &buf)); + mu_assert_int_eq(strlen(TESTDATA1), buf.size); + mu_check(0 == strncmp(buf.data, TESTDATA1, buf.size)); + mu_check(0 == zip_entry_close(zip)); + + free(buf.data); + buf.data = NULL; + buf.size = 0; + + memset((void *)&buf, 0, sizeof(struct buffer_t)); + + mu_check(0 == zip_entry_open(zip, "dotfiles/.test")); + mu_check(0 == zip_entry_extract(zip, on_extract, &buf)); + mu_assert_int_eq(strlen(TESTDATA2), buf.size); + mu_check(0 == strncmp(buf.data, TESTDATA2, buf.size)); + mu_check(0 == zip_entry_close(zip)); + + free(buf.data); + buf.data = NULL; + buf.size = 0; + + zip_close(zip); +} + +MU_TEST(test_extract_stream) { + mu_check(0 > zip_extract("non_existing_directory/non_existing_archive.zip", + ".", NULL, NULL)); + mu_check(0 > zip_stream_extract("", 0, ".", NULL, NULL)); + + 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_SUITE(test_extract_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_extract); + MU_RUN_TEST(test_extract_stream); +} + +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/test/test_permissions.c b/test/test_permissions.c new file mode 100644 index 0000000..97215ff --- /dev/null +++ b/test/test_permissions.c @@ -0,0 +1,185 @@ +#include +#include +#include + +#include + +#include "minunit.h" + +static char *ZIPNAME = NULL; +static char *XFILE = NULL; +static char *RFILE = NULL; +static char *WFILE = NULL; + +void test_setup(void) { + ZIPNAME = tempnam(".", "z-"); + XFILE = tempnam(".", "x-"); + RFILE = tempnam(".", "r-"); + WFILE = tempnam(".", "w-"); +} + +void test_teardown(void) { + remove(WFILE); + free(WFILE); + + remove(RFILE); + free(RFILE); + + remove(XFILE); + free(XFILE); + + remove(ZIPNAME); + free(ZIPNAME); +} + +#if defined(_MSC_VER) || defined(__MINGW64__) || 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 0100644 + +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_check(0 == zip_create(ZIPNAME, filenames, 1)); + remove(XFILE); + + mu_check(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + + mu_check(0 == MZ_FILE_STAT(XFILE, &file_stats)); + mu_assert_int_eq(XMODE, file_stats.st_mode); +} + +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_check(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + mu_check(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_check(0 == zip_create(ZIPNAME, filenames, 1)); + remove(WFILE); + + mu_check(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + mu_check(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_check(0 == zip_entry_open(zip, RFILE)); + mu_check(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_check(0 == zip_entry_close(zip)); + + zip_close(zip); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + + mu_check(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_check(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_check(0 == zip_entry_open(zip, filename)); + mu_check(0 == zip_entry_fwrite(zip, filename)); + mu_check(0 == zip_entry_close(zip)); + + zip_close(zip); + + mu_check(0 == MZ_FILE_STAT(filename, &file_stat1)); + remove(filename); + + mu_assert_int_eq(0, zip_extract(ZIPNAME, ".", NULL, NULL)); + mu_check(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/test/test_read.c b/test/test_read.c new file mode 100644 index 0000000..50cfb1c --- /dev/null +++ b/test/test_read.c @@ -0,0 +1,142 @@ +#include +#include + +#include + +#include "minunit.h" + +static char *ZIPNAME = NULL; + +#define CRC32DATA1 2220805626 +#define TESTDATA1 "Some test data 1...\0" + +#define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA2 2532008468 + +void test_setup(void) { + ZIPNAME = tempnam(NULL, "z-"); + + 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); + free(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(0, 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_check(0 == strncmp(buf, TESTDATA2, (size_t)bufsize)); + mu_check(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + + mu_check(0 == zip_entry_open(zip, "test\\empty/")); + mu_check(0 == strcmp(zip_entry_name(zip), "test/empty/")); + mu_check(0 == zip_entry_size(zip)); + mu_check(0 == zip_entry_crc32(zip)); + mu_check(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(0, 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_check(0 == strncmp(buf, TESTDATA2, buftmp)); + mu_check(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + + buftmp = strlen(TESTDATA1); + buf = calloc(buftmp, sizeof(char)); + mu_check(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_check(0 == strncmp(buf, TESTDATA1, buftmp)); + mu_check(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + + buftmp = strlen(TESTDATA2); + buf = calloc(buftmp, sizeof(char)); + mu_check(0 == zip_entry_open(zip, "dotfiles/.test")); + bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); + mu_assert_int_eq(buftmp, (size_t)bufsize); + mu_check(0 == strncmp(buf, TESTDATA2, buftmp)); + mu_check(0 == zip_entry_close(zip)); + free(buf); + buf = 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); +} + +#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/test/test_write.c b/test/test_write.c new file mode 100644 index 0000000..a5c7bb9 --- /dev/null +++ b/test/test_write.c @@ -0,0 +1,86 @@ +#include +#include + +#include + +#include "minunit.h" + +static char *ZIPNAME = NULL; +static char *WFILE = NULL; + +void test_setup(void) { + ZIPNAME = tempnam(NULL, "z-"); + WFILE = tempnam(NULL, "w-"); +} + +void test_teardown(void) { + remove(WFILE); + free(WFILE); + + remove(ZIPNAME); + free(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(0, 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_check(0 == fclose(stream)); + + zip = zip_open(ZIPNAME, 9, 'w'); + mu_check(zip != NULL); + mu_check(0 == zip_entry_open(zip, WFILE)); + mu_check(0 == zip_entry_fwrite(zip, WFILE)); + mu_check(0 == zip_entry_close(zip)); + mu_check(0 == 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_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