mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-06 17:20:22 +00:00
Come out and Clay
This commit is contained in:
parent
edb644dd98
commit
f1558d9bca
@ -43,9 +43,10 @@ SET(INSTALL_INC include CACHE PATH "Where to install headers to.")
|
|||||||
|
|
||||||
# Build options
|
# Build options
|
||||||
OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
|
OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON)
|
||||||
OPTION (BUILD_TESTS "Build Tests" ON)
|
|
||||||
OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF)
|
OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF)
|
||||||
OPTION (STDCALL "Buildl libgit2 with the __stdcall convention (Windows)" ON)
|
OPTION (STDCALL "Buildl libgit2 with the __stdcall convention (Windows)" ON)
|
||||||
|
OPTION (BUILD_TESTS "Build Tests" OFF)
|
||||||
|
OPTION (BUILD_CLAY "Build Tests using the Clay suite" ON)
|
||||||
|
|
||||||
# Platform specific compilation flags
|
# Platform specific compilation flags
|
||||||
IF (MSVC)
|
IF (MSVC)
|
||||||
@ -113,11 +114,11 @@ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${INSTALL_LIB}/
|
|||||||
INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} )
|
INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} )
|
||||||
INSTALL(FILES include/git2.h DESTINATION ${INSTALL_INC} )
|
INSTALL(FILES include/git2.h DESTINATION ${INSTALL_INC} )
|
||||||
|
|
||||||
|
SET(TEST_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.")
|
||||||
|
ADD_DEFINITIONS(-DTEST_RESOURCES=\"${TEST_RESOURCES}\")
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
IF (BUILD_TESTS)
|
IF (BUILD_TESTS)
|
||||||
SET(TEST_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.")
|
|
||||||
ADD_DEFINITIONS(-DTEST_RESOURCES=\"${TEST_RESOURCES}\")
|
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES(tests)
|
INCLUDE_DIRECTORIES(tests)
|
||||||
FILE(GLOB SRC_TEST tests/t??-*.c)
|
FILE(GLOB SRC_TEST tests/t??-*.c)
|
||||||
|
|
||||||
@ -132,3 +133,19 @@ IF (BUILD_TESTS)
|
|||||||
ENABLE_TESTING()
|
ENABLE_TESTING()
|
||||||
ADD_TEST(libgit2_test libgit2_test)
|
ADD_TEST(libgit2_test libgit2_test)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
|
IF (BUILD_CLAY)
|
||||||
|
INCLUDE_DIRECTORIES(tests-clay)
|
||||||
|
FILE(GLOB_RECURSE SRC_TEST tests-clay/*.c)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(libgit2_test ${SRC} ${SRC_TEST} ${SRC_ZLIB})
|
||||||
|
TARGET_LINK_LIBRARIES(libgit2_test ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
IF (WIN32)
|
||||||
|
TARGET_LINK_LIBRARIES(libgit2_test ws2_32)
|
||||||
|
ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
|
||||||
|
TARGET_LINK_LIBRARIES(libgit2_test socket nsl)
|
||||||
|
ENDIF ()
|
||||||
|
|
||||||
|
ENABLE_TESTING()
|
||||||
|
ADD_TEST(libgit2_test libgit2_test)
|
||||||
|
ENDIF ()
|
||||||
|
226
tests-clay/clay
Executable file
226
tests-clay/clay
Executable file
@ -0,0 +1,226 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from __future__ import with_statement
|
||||||
|
from string import Template
|
||||||
|
import re, fnmatch, os
|
||||||
|
|
||||||
|
VERSION = "0.7.0"
|
||||||
|
|
||||||
|
TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*(void)?\s*\))\s*\{"
|
||||||
|
|
||||||
|
TEMPLATE_MAIN = Template(
|
||||||
|
r"""
|
||||||
|
/*
|
||||||
|
* Clay v${version}
|
||||||
|
*
|
||||||
|
* This is an autogenerated file. Do not modify.
|
||||||
|
* To add new unit tests or suites, regenerate the whole
|
||||||
|
* file with `./clay`
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define clay_print(...) ${clay_print}
|
||||||
|
|
||||||
|
${clay_library}
|
||||||
|
|
||||||
|
${extern_declarations}
|
||||||
|
|
||||||
|
static const struct clay_func _all_callbacks[] = {
|
||||||
|
${test_callbacks}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct clay_suite _all_suites[] = {
|
||||||
|
${test_suites}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _suites_str[] = "${suites_str}";
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return clay_test(
|
||||||
|
argc, argv, _suites_str,
|
||||||
|
_all_callbacks, ${cb_count},
|
||||||
|
_all_suites, ${suite_count}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
TEMPLATE_SUITE = Template(
|
||||||
|
r"""
|
||||||
|
{
|
||||||
|
"${clean_name}",
|
||||||
|
${initialize},
|
||||||
|
${cleanup},
|
||||||
|
${cb_ptr}, ${cb_count}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
parser = OptionParser()
|
||||||
|
|
||||||
|
parser.add_option('-c', '--clay-path', dest='clay_path')
|
||||||
|
parser.add_option('-o', '--output', dest='output')
|
||||||
|
parser.add_option('-v', '--report-to', dest='print_mode', default='stdout')
|
||||||
|
|
||||||
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
|
for folder in args:
|
||||||
|
builder = ClayTestBuilder(folder,
|
||||||
|
clay_path = options.clay_path,
|
||||||
|
output_folder = options.output,
|
||||||
|
print_mode = options.print_mode)
|
||||||
|
|
||||||
|
builder.render()
|
||||||
|
|
||||||
|
|
||||||
|
class ClayTestBuilder:
|
||||||
|
def __init__(self, folder_name, output_folder = None, clay_path = None, print_mode = 'stdout'):
|
||||||
|
self.declarations = []
|
||||||
|
self.callbacks = []
|
||||||
|
self.suites = []
|
||||||
|
self.suite_list = []
|
||||||
|
|
||||||
|
self.clay_path = os.path.abspath(clay_path)
|
||||||
|
self.print_mode = print_mode
|
||||||
|
|
||||||
|
folder_name = os.path.abspath(folder_name)
|
||||||
|
if not output_folder:
|
||||||
|
output_folder = folder_name
|
||||||
|
|
||||||
|
self.output = os.path.join(output_folder, "clay_main.c")
|
||||||
|
self.output_header = os.path.join(output_folder, "clay.h")
|
||||||
|
|
||||||
|
self.modules = ["clay.c", "clay_sandbox.c"]
|
||||||
|
|
||||||
|
print("Loading test suites...")
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(folder_name):
|
||||||
|
module_root = root[len(folder_name):]
|
||||||
|
module_root = [c for c in module_root.split(os.sep) if c]
|
||||||
|
|
||||||
|
tests_in_module = fnmatch.filter(files, "*.c")
|
||||||
|
|
||||||
|
for test_file in tests_in_module:
|
||||||
|
full_path = os.path.join(root, test_file)
|
||||||
|
test_name = "_".join(module_root + [test_file[:-2]])
|
||||||
|
|
||||||
|
with open(full_path) as f:
|
||||||
|
self._process_test_file(test_name, f.read())
|
||||||
|
|
||||||
|
if not self.suites:
|
||||||
|
raise RuntimeError(
|
||||||
|
'No tests found under "%s"' % folder_name)
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
template = TEMPLATE_MAIN.substitute(
|
||||||
|
version = VERSION,
|
||||||
|
clay_print = self._get_print_method(),
|
||||||
|
clay_library = self._get_library(),
|
||||||
|
extern_declarations = "\n".join(self.declarations),
|
||||||
|
|
||||||
|
suites_str = ", ".join(self.suite_list),
|
||||||
|
|
||||||
|
test_callbacks = ",\n\t".join(self.callbacks),
|
||||||
|
cb_count = len(self.callbacks),
|
||||||
|
|
||||||
|
test_suites = ",\n\t".join(self.suites),
|
||||||
|
suite_count = len(self.suites),
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(self.output, "w") as out:
|
||||||
|
out.write(template)
|
||||||
|
|
||||||
|
with open(self.output_header, "w") as out:
|
||||||
|
out.write(self._load_file('clay.h'))
|
||||||
|
|
||||||
|
print ('Written test suite to "%s"' % self.output)
|
||||||
|
print ('Written header to "%s"' % self.output_header)
|
||||||
|
|
||||||
|
#####################################################
|
||||||
|
# Internal methods
|
||||||
|
#####################################################
|
||||||
|
def _get_print_method(self):
|
||||||
|
return {
|
||||||
|
'stdout' : 'printf(__VA_ARGS__)',
|
||||||
|
'stderr' : 'fprintf(stderr, __VA_ARGS__)',
|
||||||
|
'silent' : ''
|
||||||
|
}[self.print_mode]
|
||||||
|
|
||||||
|
def _load_file(self, filename):
|
||||||
|
if self.clay_path:
|
||||||
|
filename = os.path.join(self.clay_path, filename)
|
||||||
|
with open(filename) as cfile:
|
||||||
|
return cfile.read()
|
||||||
|
|
||||||
|
else:
|
||||||
|
import zlib, base64, sys
|
||||||
|
content = CLAY_FILES[filename]
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 0):
|
||||||
|
content = bytearray(content, 'utf_8')
|
||||||
|
content = base64.b64decode(content)
|
||||||
|
content = zlib.decompress(content)
|
||||||
|
return str(content)
|
||||||
|
else:
|
||||||
|
content = base64.b64decode(content)
|
||||||
|
return zlib.decompress(content)
|
||||||
|
|
||||||
|
def _get_library(self):
|
||||||
|
return "\n".join(self._load_file(f) for f in self.modules)
|
||||||
|
|
||||||
|
def _parse_comment(self, comment):
|
||||||
|
comment = comment[2:-2]
|
||||||
|
comment = comment.splitlines()
|
||||||
|
comment = [line.strip() for line in comment]
|
||||||
|
comment = "\n".join(comment)
|
||||||
|
|
||||||
|
return comment
|
||||||
|
|
||||||
|
def _process_test_file(self, test_name, contents):
|
||||||
|
regex_string = TEST_FUNC_REGEX % test_name
|
||||||
|
regex = re.compile(regex_string, re.MULTILINE)
|
||||||
|
|
||||||
|
callbacks = []
|
||||||
|
initialize = cleanup = "{NULL, NULL, 0}"
|
||||||
|
|
||||||
|
for (declaration, symbol, short_name, _) in regex.findall(contents):
|
||||||
|
self.declarations.append("extern %s;" % declaration)
|
||||||
|
func_ptr = '{"%s", &%s, %d}' % (
|
||||||
|
short_name, symbol, len(self.suites)
|
||||||
|
)
|
||||||
|
|
||||||
|
if short_name == 'initialize':
|
||||||
|
initialize = func_ptr
|
||||||
|
elif short_name == 'cleanup':
|
||||||
|
cleanup = func_ptr
|
||||||
|
else:
|
||||||
|
callbacks.append(func_ptr)
|
||||||
|
|
||||||
|
if not callbacks:
|
||||||
|
return
|
||||||
|
|
||||||
|
clean_name = test_name.replace("_", "::")
|
||||||
|
|
||||||
|
suite = TEMPLATE_SUITE.substitute(
|
||||||
|
clean_name = clean_name,
|
||||||
|
initialize = initialize,
|
||||||
|
cleanup = cleanup,
|
||||||
|
cb_ptr = "&_all_callbacks[%d]" % len(self.callbacks),
|
||||||
|
cb_count = len(callbacks)
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
self.callbacks += callbacks
|
||||||
|
self.suites.append(suite)
|
||||||
|
self.suite_list.append(clean_name)
|
||||||
|
|
||||||
|
print(" %s (%d tests)" % (clean_name, len(callbacks)))
|
||||||
|
|
||||||
|
CLAY_FILES = {
|
||||||
|
"clay.c" : r"""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""",
|
||||||
|
"clay_sandbox.c" : r"""eJx9VW1P2zAQ/pz8iiNoNKEZDRvaNGX9MIkyVRSoCohJtIpC4lCLxOlst1o3+O+7S0KalJeqamLf47vnOd9dd3kSswSCm+H550/mroELLhiMRz+uTi4mZ8HlYAyd6bRj7rJUsbcAPbKLmCemqXSoeQTRPJQQRGm4Dhahnt8eed++zPzazIU2uQpWYcrjQGeLAmRHuVC6PLpPG475zzSUlstIAx3EH980JNNLKcBOacsmnAt7SjvQ74MHe3umYdiXwfDyeDixlT5QOsjymDnw+IgWMozOT5sGpzwTRhFTqvJ3E1yclg4d33xq0Ub5TcoF2btlkjDpguJ/WaAhZeK+Zl+mo1BWmVehDKJ8KTT04cjfwpQOmVhhcqS6nSEG3RjW1dkYBVku0FvxGJTP68vBZDy5OBmOBpYJxhMmGYwqEsfFbuuGDZ6A/ZPpK5YtxiTAPr65mBw7JWUXSiWOgyGrPB/69d0aSS7B5kjJ84HD940SH7pd7hRMt2Qg+J5pfLFrTXyGSTUKJju4SbHolOZiyZBwaXlZHQQtQ1BNiGixtp/zjib3OevkusHdMJ5M/JpGbx+GCeg5IzSXucgY3kCcMyU6eDXhGkKx1nMu7l3Qcg06h6Vi0MP4sN8z3yBlkd2qeG3TKo0tZg1iFamrOVeg1kqzrGaT8geG0VtEiHm0lLJgzSWLdI7Gd5gdvEnr4F1O1dLbKnyIUhaKIMnTmMnXW7WxmasgymIq3+0CNCwZQ09B7zdMrQ9qall+NVzIlMFHmTQNVeUVTqM8y0IRPw8TQ4mFRGaJXRnKBszrteNWPFwoOG6GR5nvGteUusp5DMXgWgqFxrv8j017hUJKdWOqeTOaEZ2p19k0DFVwK1Ub/PYsKcO8CNJII50KdMjTYhBYBZ5u+FfxsSgH9cihwEVPtSfUJnydngajZqd75AEdYSQsGXxpU3+hnqAf4XAGO/3W/0FZdW1gt0sCmqiq2jAS1eYGDV0S426k16GzB7yzRZMUZf/8ejTaFlGisUta6r2vnucQWe81fDRv419HbnoFyf8Hmxc92w==""",
|
||||||
|
"clay.h" : r"""eJy9VUFvmzAUPpdf8RYuAaEmu3ZdpapKtEqol2WaerJc+1GsOTazzZr9+9lAkoaA2HbICfPw5+97733PxKJQHAsg5CG/fyab1dcN+UJIFPugUHgWj2KhmKw5wq11XIqX6/Iuin5pwYFJ+psQai0aN4+uhHLAtOLCCa2y6MqvrY+U1EBaCIlZu0V6lt5XNEabXoyjZUZU3VkBaEtdS07oizYu+XTQQCw6wiRSVVfzJjZPu9ekfU+TDNqFrujPGgN4kaYRpHDfiPccsKXMaAtvwpWAu0oKJhw0wmCL1tJX9PsXhzJ53m1tHal8+mTuASaDIDk5rUrzJYG7z7DMfGnXj/mKkLDKH5+a1WxdK9YIYFRKKKgvFL+BGcTHMzP4mJwRh53TxLejvKtdhcwhh+JEgNONhgkFLck0/YfxvD2/8XUNxMKC0g6cqXGId9+rhxLZj//oEwu4CzVqmZwzX7hTQxIu0KhlMjFUSv/lOHWSTiesDWbw9C3Ph4ehB2urPgrr0j9g9o4+BYxbbyqbo+mOHO+NOCrs6Jk+cCKjZlMf089nn9BaGxYc5Y+sDS7eqFFCvfaTaFQMmGbMKhv013c7Gdez4ZujY/qXU7+3EOC1CQ8XSHCHrA4Wu5m9N2CM/vdTRH8A5MtAqA=="""
|
||||||
|
}
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
51
tests-clay/clay.h
Normal file
51
tests-clay/clay.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef __CLAY_TEST_H__
|
||||||
|
#define __CLAY_TEST_H__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void clay__assert(
|
||||||
|
int condition,
|
||||||
|
const char *file,
|
||||||
|
int line,
|
||||||
|
const char *error,
|
||||||
|
const char *description,
|
||||||
|
int should_abort);
|
||||||
|
|
||||||
|
void cl_set_cleanup(void (*cleanup)(void *), void *opaque);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertion macros with explicit error message
|
||||||
|
*/
|
||||||
|
#define cl_must_pass_(expr, desc) clay__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1)
|
||||||
|
#define cl_must_fail_(expr, desc) clay__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
|
||||||
|
#define cl_assert_(expr, desc) clay__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check macros with explicit error message
|
||||||
|
*/
|
||||||
|
#define cl_check_pass_(expr, desc) clay__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0)
|
||||||
|
#define cl_check_fail_(expr, desc) clay__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
|
||||||
|
#define cl_check_(expr, desc) clay__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assertion macros with no error message
|
||||||
|
*/
|
||||||
|
#define cl_must_pass(expr) cl_must_pass_((expr), NULL)
|
||||||
|
#define cl_must_fail(expr) cl_must_fail_((expr), NULL)
|
||||||
|
#define cl_assert(expr) cl_assert_((expr), NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check macros with no error message
|
||||||
|
*/
|
||||||
|
#define cl_check_pass(expr) cl_check_pass_((expr), NULL)
|
||||||
|
#define cl_check_fail(expr) cl_check_fail_((expr), NULL)
|
||||||
|
#define cl_check(expr) cl_check_((expr), NULL)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forced failure/warning
|
||||||
|
*/
|
||||||
|
#define cl_fail(desc) clay__assert(0, __FILE__, __LINE__, "Test failed.", desc, 1)
|
||||||
|
#define cl_warning(desc) clay__assert(0, __FILE__, __LINE__, "Warning during test execution:", desc, 0)
|
||||||
|
|
||||||
|
#endif
|
28
tests-clay/clay_libgit2.h
Normal file
28
tests-clay/clay_libgit2.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef __CLAY_LIBGIT2__
|
||||||
|
#define __CLAY_LIBGIT2__
|
||||||
|
|
||||||
|
#include "clay.h"
|
||||||
|
#include <git2.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special wrapper for `clay_must_pass` that passes
|
||||||
|
* the last library error as the test failure message.
|
||||||
|
*
|
||||||
|
* Use this wrapper around all `git_` library calls that
|
||||||
|
* return error codes!
|
||||||
|
*/
|
||||||
|
#define cl_git_pass(expr) do { \
|
||||||
|
git_clearerror(); \
|
||||||
|
if ((expr) != GIT_SUCCESS) \
|
||||||
|
clay__assert(0, __FILE__, __LINE__, "Function call failed: " #expr, git_lasterror(), 1); \
|
||||||
|
} while(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for `clay_must_fail` -- this one is
|
||||||
|
* just for consistency. Use with `git_` library
|
||||||
|
* calls that are supposed to fail!
|
||||||
|
*/
|
||||||
|
#define cl_git_fail(expr) cl_must_fail((expr))
|
||||||
|
|
||||||
|
#endif
|
531
tests-clay/clay_main.c
Normal file
531
tests-clay/clay_main.c
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
* Clay v0.7.0
|
||||||
|
*
|
||||||
|
* This is an autogenerated file. Do not modify.
|
||||||
|
* To add new unit tests or suites, regenerate the whole
|
||||||
|
* file with `./clay`
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define clay_print(...) printf(__VA_ARGS__)
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/* required for sandboxing */
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "clay.h"
|
||||||
|
|
||||||
|
struct clay_error {
|
||||||
|
const char *test;
|
||||||
|
int test_number;
|
||||||
|
const char *suite;
|
||||||
|
const char *file;
|
||||||
|
int line_number;
|
||||||
|
const char *error_msg;
|
||||||
|
char *description;
|
||||||
|
|
||||||
|
struct clay_error *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
const char *active_test;
|
||||||
|
const char *active_suite;
|
||||||
|
|
||||||
|
int suite_errors;
|
||||||
|
int total_errors;
|
||||||
|
|
||||||
|
int test_count;
|
||||||
|
|
||||||
|
struct clay_error *errors;
|
||||||
|
struct clay_error *last_error;
|
||||||
|
|
||||||
|
void (*local_cleanup)(void *);
|
||||||
|
void *local_cleanup_payload;
|
||||||
|
|
||||||
|
jmp_buf trampoline;
|
||||||
|
int trampoline_enabled;
|
||||||
|
} _clay;
|
||||||
|
|
||||||
|
struct clay_func {
|
||||||
|
const char *name;
|
||||||
|
void (*ptr)(void);
|
||||||
|
size_t suite_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct clay_suite {
|
||||||
|
const char *name;
|
||||||
|
struct clay_func initialize;
|
||||||
|
struct clay_func cleanup;
|
||||||
|
const struct clay_func *tests;
|
||||||
|
size_t test_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* From clay_sandbox.c */
|
||||||
|
static void clay_unsandbox(void);
|
||||||
|
static int clay_sandbox(void);
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_run_test(
|
||||||
|
const struct clay_func *test,
|
||||||
|
const struct clay_func *initialize,
|
||||||
|
const struct clay_func *cleanup)
|
||||||
|
{
|
||||||
|
int error_st = _clay.suite_errors;
|
||||||
|
|
||||||
|
_clay.trampoline_enabled = 1;
|
||||||
|
|
||||||
|
if (setjmp(_clay.trampoline) == 0) {
|
||||||
|
if (initialize->ptr != NULL)
|
||||||
|
initialize->ptr();
|
||||||
|
|
||||||
|
test->ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
_clay.trampoline_enabled = 0;
|
||||||
|
|
||||||
|
if (_clay.local_cleanup != NULL)
|
||||||
|
_clay.local_cleanup(_clay.local_cleanup_payload);
|
||||||
|
|
||||||
|
if (cleanup->ptr != NULL)
|
||||||
|
cleanup->ptr();
|
||||||
|
|
||||||
|
_clay.test_count++;
|
||||||
|
|
||||||
|
/* remove any local-set cleanup methods */
|
||||||
|
_clay.local_cleanup = NULL;
|
||||||
|
_clay.local_cleanup_payload = NULL;
|
||||||
|
|
||||||
|
clay_print("%c", (_clay.suite_errors > error_st) ? 'F' : '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_print_error(int num, const struct clay_error *error)
|
||||||
|
{
|
||||||
|
clay_print(" %d) Failure:\n", num);
|
||||||
|
|
||||||
|
clay_print("%s::%s (%s) [%s:%d] [-t%d]\n",
|
||||||
|
error->suite,
|
||||||
|
error->test,
|
||||||
|
"no description",
|
||||||
|
error->file,
|
||||||
|
error->line_number,
|
||||||
|
error->test_number);
|
||||||
|
|
||||||
|
clay_print(" %s\n", error->error_msg);
|
||||||
|
|
||||||
|
if (error->description != NULL)
|
||||||
|
clay_print(" %s\n", error->description);
|
||||||
|
|
||||||
|
clay_print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_report_errors(void)
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
struct clay_error *error, *next;
|
||||||
|
|
||||||
|
error = _clay.errors;
|
||||||
|
while (error != NULL) {
|
||||||
|
next = error->next;
|
||||||
|
clay_print_error(i++, error);
|
||||||
|
free(error->description);
|
||||||
|
free(error);
|
||||||
|
error = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_run_suite(const struct clay_suite *suite)
|
||||||
|
{
|
||||||
|
const struct clay_func *test = suite->tests;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
_clay.active_suite = suite->name;
|
||||||
|
_clay.suite_errors = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < suite->test_count; ++i) {
|
||||||
|
_clay.active_test = test[i].name;
|
||||||
|
clay_run_test(&test[i], &suite->initialize, &suite->cleanup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_run_single(const struct clay_func *test,
|
||||||
|
const struct clay_suite *suite)
|
||||||
|
{
|
||||||
|
_clay.suite_errors = 0;
|
||||||
|
_clay.active_suite = suite->name;
|
||||||
|
_clay.active_test = test->name;
|
||||||
|
|
||||||
|
clay_run_test(test, &suite->initialize, &suite->cleanup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_usage(const char *arg)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [options]\n\n", arg);
|
||||||
|
printf("Options:\n");
|
||||||
|
printf(" -tXX\t\tRun only the test number XX\n");
|
||||||
|
printf(" -sXX\t\tRun only the suite number XX\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clay_parse_args(
|
||||||
|
int argc, char **argv,
|
||||||
|
const struct clay_func *callbacks,
|
||||||
|
size_t cb_count,
|
||||||
|
const struct clay_suite *suites,
|
||||||
|
size_t suite_count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; ++i) {
|
||||||
|
char *argument = argv[i];
|
||||||
|
char action;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
if (argument[0] != '-')
|
||||||
|
clay_usage(argv[0]);
|
||||||
|
|
||||||
|
action = argument[1];
|
||||||
|
num = strtol(argument + 2, &argument, 10);
|
||||||
|
|
||||||
|
if (*argument != '\0' || num < 0)
|
||||||
|
clay_usage(argv[0]);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 't':
|
||||||
|
if ((size_t)num >= cb_count) {
|
||||||
|
fprintf(stderr, "Test number %d does not exist.\n", num);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
clay_print("Started (%s::%s)\n",
|
||||||
|
suites[callbacks[num].suite_n].name,
|
||||||
|
callbacks[num].name);
|
||||||
|
|
||||||
|
clay_run_single(&callbacks[num], &suites[callbacks[num].suite_n]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
if ((size_t)num >= suite_count) {
|
||||||
|
fprintf(stderr, "Suite number %d does not exist.\n", num);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
clay_print("Started (%s::*)\n", suites[num].name);
|
||||||
|
clay_run_suite(&suites[num]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
clay_usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
clay_test(
|
||||||
|
int argc, char **argv,
|
||||||
|
const char *suites_str,
|
||||||
|
const struct clay_func *callbacks,
|
||||||
|
size_t cb_count,
|
||||||
|
const struct clay_suite *suites,
|
||||||
|
size_t suite_count)
|
||||||
|
{
|
||||||
|
clay_print("Loaded %d suites: %s\n", (int)suite_count, suites_str);
|
||||||
|
|
||||||
|
if (!clay_sandbox()) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Failed to sandbox the test runner.\n"
|
||||||
|
"Testing will proceed without sandboxing.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
clay_parse_args(argc, argv,
|
||||||
|
callbacks, cb_count, suites, suite_count);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
size_t i;
|
||||||
|
clay_print("Started\n");
|
||||||
|
|
||||||
|
for (i = 0; i < suite_count; ++i) {
|
||||||
|
const struct clay_suite *s = &suites[i];
|
||||||
|
clay_run_suite(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clay_print("\n\n");
|
||||||
|
clay_report_errors();
|
||||||
|
|
||||||
|
clay_unsandbox();
|
||||||
|
return _clay.total_errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
clay__assert(
|
||||||
|
int condition,
|
||||||
|
const char *file,
|
||||||
|
int line,
|
||||||
|
const char *error_msg,
|
||||||
|
const char *description,
|
||||||
|
int should_abort)
|
||||||
|
{
|
||||||
|
struct clay_error *error;
|
||||||
|
|
||||||
|
if (condition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error = calloc(1, sizeof(struct clay_error));
|
||||||
|
|
||||||
|
if (_clay.errors == NULL)
|
||||||
|
_clay.errors = error;
|
||||||
|
|
||||||
|
if (_clay.last_error != NULL)
|
||||||
|
_clay.last_error->next = error;
|
||||||
|
|
||||||
|
_clay.last_error = error;
|
||||||
|
|
||||||
|
error->test = _clay.active_test;
|
||||||
|
error->test_number = _clay.test_count;
|
||||||
|
error->suite = _clay.active_suite;
|
||||||
|
error->file = file;
|
||||||
|
error->line_number = line;
|
||||||
|
error->error_msg = error_msg;
|
||||||
|
|
||||||
|
if (description != NULL)
|
||||||
|
error->description = strdup(description);
|
||||||
|
|
||||||
|
_clay.suite_errors++;
|
||||||
|
_clay.total_errors++;
|
||||||
|
|
||||||
|
if (should_abort) {
|
||||||
|
if (!_clay.trampoline_enabled) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Unhandled exception: a cleanup method raised an exception.");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
longjmp(_clay.trampoline, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
|
||||||
|
{
|
||||||
|
_clay.local_cleanup = cleanup;
|
||||||
|
_clay.local_cleanup_payload = opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# define PLATFORM_SEP '\\'
|
||||||
|
#else
|
||||||
|
# define PLATFORM_SEP '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char _clay_path[4096];
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_valid_tmp_path(const char *path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
return (lstat(path, &st) == 0 &&
|
||||||
|
(S_ISDIR(st.st_mode) ||
|
||||||
|
S_ISLNK(st.st_mode)) &&
|
||||||
|
access(path, W_OK) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
find_tmp_path(char *buffer, size_t length)
|
||||||
|
{
|
||||||
|
static const size_t var_count = 4;
|
||||||
|
static const char *env_vars[] = {
|
||||||
|
"TMPDIR", "TMP", "TEMP", "USERPROFILE"
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (GetTempPath((DWORD)length, buffer))
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < var_count; ++i) {
|
||||||
|
const char *env = getenv(env_vars[i]);
|
||||||
|
if (!env)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (is_valid_tmp_path(env)) {
|
||||||
|
strncpy(buffer, env, length);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the environment doesn't say anything, try to use /tmp */
|
||||||
|
if (is_valid_tmp_path("/tmp")) {
|
||||||
|
strncpy(buffer, "/tmp", length);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This system doesn't like us, try to use the current directory */
|
||||||
|
if (is_valid_tmp_path(".")) {
|
||||||
|
strncpy(buffer, ".", length);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clean_folder(const char *path)
|
||||||
|
{
|
||||||
|
const char os_cmd[] =
|
||||||
|
#ifdef _WIN32
|
||||||
|
"rd /s /q \"%s\"";
|
||||||
|
#else
|
||||||
|
"rm -rf \"%s\"";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char command[4096];
|
||||||
|
snprintf(command, sizeof(command), os_cmd, path);
|
||||||
|
return system(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clay_unsandbox(void)
|
||||||
|
{
|
||||||
|
if (_clay_path[0] == '\0')
|
||||||
|
return;
|
||||||
|
|
||||||
|
clean_folder(_clay_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clay_sandbox(void)
|
||||||
|
{
|
||||||
|
const char path_tail[] = "clay_tmp_XXXXXX";
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!find_tmp_path(_clay_path, sizeof(_clay_path)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = strlen(_clay_path);
|
||||||
|
|
||||||
|
if (_clay_path[len - 1] != PLATFORM_SEP) {
|
||||||
|
_clay_path[len++] = PLATFORM_SEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(_clay_path + len, path_tail);
|
||||||
|
|
||||||
|
if (mktemp(_clay_path) == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mkdir(_clay_path, 0700) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (chdir(_clay_path) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern void test_core_dirent__dont_traverse_dot(void);
|
||||||
|
extern void test_core_dirent__traverse_subfolder(void);
|
||||||
|
extern void test_core_dirent__traverse_slash_terminated_folder(void);
|
||||||
|
extern void test_core_dirent__dont_traverse_empty_folders(void);
|
||||||
|
extern void test_core_dirent__traverse_weird_filenames(void);
|
||||||
|
extern void test_core_filebuf__0(void);
|
||||||
|
extern void test_core_filebuf__1(void);
|
||||||
|
extern void test_core_filebuf__2(void);
|
||||||
|
extern void test_core_path__0(void);
|
||||||
|
extern void test_core_path__1(void);
|
||||||
|
extern void test_core_path__2(void);
|
||||||
|
extern void test_core_path__5(void);
|
||||||
|
extern void test_core_path__6(void);
|
||||||
|
extern void test_core_rmdir__initialize();
|
||||||
|
extern void test_core_rmdir__delete_recursive(void);
|
||||||
|
extern void test_core_rmdir__fail_to_delete_non_empty_dir(void);
|
||||||
|
extern void test_core_string__0(void);
|
||||||
|
extern void test_core_string__1(void);
|
||||||
|
extern void test_core_vector__0(void);
|
||||||
|
extern void test_core_vector__1(void);
|
||||||
|
extern void test_core_vector__2(void);
|
||||||
|
|
||||||
|
static const struct clay_func _all_callbacks[] = {
|
||||||
|
{"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 0},
|
||||||
|
{"traverse_subfolder", &test_core_dirent__traverse_subfolder, 0},
|
||||||
|
{"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 0},
|
||||||
|
{"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 0},
|
||||||
|
{"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 0},
|
||||||
|
{"0", &test_core_filebuf__0, 1},
|
||||||
|
{"1", &test_core_filebuf__1, 1},
|
||||||
|
{"2", &test_core_filebuf__2, 1},
|
||||||
|
{"0", &test_core_path__0, 2},
|
||||||
|
{"1", &test_core_path__1, 2},
|
||||||
|
{"2", &test_core_path__2, 2},
|
||||||
|
{"5", &test_core_path__5, 2},
|
||||||
|
{"6", &test_core_path__6, 2},
|
||||||
|
{"delete_recursive", &test_core_rmdir__delete_recursive, 3},
|
||||||
|
{"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 3},
|
||||||
|
{"0", &test_core_string__0, 4},
|
||||||
|
{"1", &test_core_string__1, 4},
|
||||||
|
{"0", &test_core_vector__0, 5},
|
||||||
|
{"1", &test_core_vector__1, 5},
|
||||||
|
{"2", &test_core_vector__2, 5}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct clay_suite _all_suites[] = {
|
||||||
|
{
|
||||||
|
"core::dirent",
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
&_all_callbacks[0], 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"core::filebuf",
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
&_all_callbacks[5], 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"core::path",
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
&_all_callbacks[8], 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"core::rmdir",
|
||||||
|
{"initialize", &test_core_rmdir__initialize, 3},
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
&_all_callbacks[13], 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"core::string",
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
&_all_callbacks[15], 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"core::vector",
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
{NULL, NULL, 0},
|
||||||
|
&_all_callbacks[17], 3
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char _suites_str[] = "core::dirent, core::filebuf, core::path, core::rmdir, core::string, core::vector";
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return clay_test(
|
||||||
|
argc, argv, _suites_str,
|
||||||
|
_all_callbacks, 20,
|
||||||
|
_all_suites, 6
|
||||||
|
);
|
||||||
|
}
|
222
tests-clay/core/dirent.c
Normal file
222
tests-clay/core/dirent.c
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#include "clay_libgit2.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
typedef struct name_data {
|
||||||
|
int count; /* return count */
|
||||||
|
char *name; /* filename */
|
||||||
|
} name_data;
|
||||||
|
|
||||||
|
typedef struct walk_data {
|
||||||
|
char *sub; /* sub-directory name */
|
||||||
|
name_data *names; /* name state data */
|
||||||
|
} walk_data;
|
||||||
|
|
||||||
|
|
||||||
|
static char path_buffer[GIT_PATH_MAX];
|
||||||
|
static char *top_dir = "dir-walk";
|
||||||
|
static walk_data *state_loc;
|
||||||
|
|
||||||
|
static void setup(walk_data *d)
|
||||||
|
{
|
||||||
|
name_data *n;
|
||||||
|
|
||||||
|
cl_must_pass(p_mkdir(top_dir, 0755));
|
||||||
|
|
||||||
|
cl_must_pass(p_chdir(top_dir));
|
||||||
|
|
||||||
|
if (strcmp(d->sub, ".") != 0)
|
||||||
|
cl_must_pass(p_mkdir(d->sub, 0755));
|
||||||
|
|
||||||
|
strcpy(path_buffer, d->sub);
|
||||||
|
state_loc = d;
|
||||||
|
|
||||||
|
for (n = d->names; n->name; n++) {
|
||||||
|
git_file fd = p_creat(n->name, 0600);
|
||||||
|
cl_assert(fd >= 0);
|
||||||
|
p_close(fd);
|
||||||
|
n->count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dirent_cleanup__cb(void *_d)
|
||||||
|
{
|
||||||
|
walk_data *d = _d;
|
||||||
|
name_data *n;
|
||||||
|
|
||||||
|
for (n = d->names; n->name; n++) {
|
||||||
|
cl_must_pass(p_unlink(n->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(d->sub, ".") != 0)
|
||||||
|
cl_must_pass(p_rmdir(d->sub));
|
||||||
|
|
||||||
|
cl_must_pass(p_chdir(".."));
|
||||||
|
|
||||||
|
cl_must_pass(p_rmdir(top_dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_counts(walk_data *d)
|
||||||
|
{
|
||||||
|
name_data *n;
|
||||||
|
|
||||||
|
for (n = d->names; n->name; n++) {
|
||||||
|
cl_assert(n->count == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int one_entry(void *state, char *path)
|
||||||
|
{
|
||||||
|
walk_data *d = (walk_data *) state;
|
||||||
|
name_data *n;
|
||||||
|
|
||||||
|
if (state != state_loc)
|
||||||
|
return GIT_ERROR;
|
||||||
|
|
||||||
|
if (path != path_buffer)
|
||||||
|
return GIT_ERROR;
|
||||||
|
|
||||||
|
for (n = d->names; n->name; n++) {
|
||||||
|
if (!strcmp(n->name, path)) {
|
||||||
|
n->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GIT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dont_call_me(void *GIT_UNUSED(state), char *GIT_UNUSED(path))
|
||||||
|
{
|
||||||
|
GIT_UNUSED_ARG(state)
|
||||||
|
GIT_UNUSED_ARG(path)
|
||||||
|
return GIT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static name_data dot_names[] = {
|
||||||
|
{ 0, "./a" },
|
||||||
|
{ 0, "./asdf" },
|
||||||
|
{ 0, "./pack-foo.pack" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
static walk_data dot = {
|
||||||
|
".",
|
||||||
|
dot_names
|
||||||
|
};
|
||||||
|
|
||||||
|
/* make sure that the '.' folder is not traversed */
|
||||||
|
void test_core_dirent__dont_traverse_dot(void)
|
||||||
|
{
|
||||||
|
cl_set_cleanup(&dirent_cleanup__cb, &dot);
|
||||||
|
setup(&dot);
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_direach(path_buffer,
|
||||||
|
sizeof(path_buffer),
|
||||||
|
one_entry,
|
||||||
|
&dot));
|
||||||
|
|
||||||
|
check_counts(&dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static name_data sub_names[] = {
|
||||||
|
{ 0, "sub/a" },
|
||||||
|
{ 0, "sub/asdf" },
|
||||||
|
{ 0, "sub/pack-foo.pack" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
static walk_data sub = {
|
||||||
|
"sub",
|
||||||
|
sub_names
|
||||||
|
};
|
||||||
|
|
||||||
|
/* traverse a subfolder */
|
||||||
|
void test_core_dirent__traverse_subfolder(void)
|
||||||
|
{
|
||||||
|
cl_set_cleanup(&dirent_cleanup__cb, &sub);
|
||||||
|
setup(&sub);
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_direach(path_buffer,
|
||||||
|
sizeof(path_buffer),
|
||||||
|
one_entry,
|
||||||
|
&sub));
|
||||||
|
|
||||||
|
check_counts(&sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static walk_data sub_slash = {
|
||||||
|
"sub/",
|
||||||
|
sub_names
|
||||||
|
};
|
||||||
|
|
||||||
|
/* traverse a slash-terminated subfolder */
|
||||||
|
void test_core_dirent__traverse_slash_terminated_folder(void)
|
||||||
|
{
|
||||||
|
cl_set_cleanup(&dirent_cleanup__cb, &sub_slash);
|
||||||
|
setup(&sub_slash);
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_direach(path_buffer,
|
||||||
|
sizeof(path_buffer),
|
||||||
|
one_entry,
|
||||||
|
&sub_slash));
|
||||||
|
|
||||||
|
check_counts(&sub_slash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static name_data empty_names[] = {
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
static walk_data empty = {
|
||||||
|
"empty",
|
||||||
|
empty_names
|
||||||
|
};
|
||||||
|
|
||||||
|
/* make sure that empty folders are not traversed */
|
||||||
|
void test_core_dirent__dont_traverse_empty_folders(void)
|
||||||
|
{
|
||||||
|
cl_set_cleanup(&dirent_cleanup__cb, &empty);
|
||||||
|
setup(&empty);
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_direach(path_buffer,
|
||||||
|
sizeof(path_buffer),
|
||||||
|
one_entry,
|
||||||
|
&empty));
|
||||||
|
|
||||||
|
check_counts(&empty);
|
||||||
|
|
||||||
|
/* make sure callback not called */
|
||||||
|
cl_git_pass(git_futils_direach(path_buffer,
|
||||||
|
sizeof(path_buffer),
|
||||||
|
dont_call_me,
|
||||||
|
&empty));
|
||||||
|
}
|
||||||
|
|
||||||
|
static name_data odd_names[] = {
|
||||||
|
{ 0, "odd/.a" },
|
||||||
|
{ 0, "odd/..c" },
|
||||||
|
/* the following don't work on cygwin/win32 */
|
||||||
|
/* { 0, "odd/.b." }, */
|
||||||
|
/* { 0, "odd/..d.." }, */
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
static walk_data odd = {
|
||||||
|
"odd",
|
||||||
|
odd_names
|
||||||
|
};
|
||||||
|
|
||||||
|
/* make sure that strange looking filenames ('..c') are traversed */
|
||||||
|
void test_core_dirent__traverse_weird_filenames(void)
|
||||||
|
{
|
||||||
|
cl_set_cleanup(&dirent_cleanup__cb, &odd);
|
||||||
|
setup(&odd);
|
||||||
|
|
||||||
|
cl_git_pass(git_futils_direach(path_buffer,
|
||||||
|
sizeof(path_buffer),
|
||||||
|
one_entry,
|
||||||
|
&odd));
|
||||||
|
|
||||||
|
check_counts(&odd);
|
||||||
|
}
|
58
tests-clay/core/filebuf.c
Normal file
58
tests-clay/core/filebuf.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "clay_libgit2.h"
|
||||||
|
#include "filebuf.h"
|
||||||
|
|
||||||
|
/* make sure git_filebuf_open doesn't delete an existing lock */
|
||||||
|
void test_core_filebuf__0(void)
|
||||||
|
{
|
||||||
|
git_filebuf file;
|
||||||
|
int fd;
|
||||||
|
char test[] = "test", testlock[] = "test.lock";
|
||||||
|
|
||||||
|
fd = p_creat(testlock, 0744);
|
||||||
|
|
||||||
|
cl_must_pass(fd);
|
||||||
|
cl_must_pass(p_close(fd));
|
||||||
|
|
||||||
|
cl_git_fail(git_filebuf_open(&file, test, 0));
|
||||||
|
cl_git_pass(git_futils_exists(testlock));
|
||||||
|
|
||||||
|
cl_must_pass(p_unlink(testlock));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* make sure GIT_FILEBUF_APPEND works as expected */
|
||||||
|
void test_core_filebuf__1(void)
|
||||||
|
{
|
||||||
|
git_filebuf file;
|
||||||
|
int fd;
|
||||||
|
char test[] = "test";
|
||||||
|
|
||||||
|
fd = p_creat(test, 0644);
|
||||||
|
cl_must_pass(fd);
|
||||||
|
cl_must_pass(p_write(fd, "libgit2 rocks\n", 14));
|
||||||
|
cl_must_pass(p_close(fd));
|
||||||
|
|
||||||
|
cl_git_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND));
|
||||||
|
cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
|
||||||
|
cl_git_pass(git_filebuf_commit(&file));
|
||||||
|
|
||||||
|
cl_must_pass(p_unlink(test));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* make sure git_filebuf_write writes large buffer correctly */
|
||||||
|
void test_core_filebuf__2(void)
|
||||||
|
{
|
||||||
|
git_filebuf file;
|
||||||
|
char test[] = "test";
|
||||||
|
unsigned char buf[4096 * 4]; /* 2 * WRITE_BUFFER_SIZE */
|
||||||
|
|
||||||
|
memset(buf, 0xfe, sizeof(buf));
|
||||||
|
|
||||||
|
cl_git_pass(git_filebuf_open(&file, test, 0));
|
||||||
|
cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf)));
|
||||||
|
cl_git_pass(git_filebuf_commit(&file));
|
||||||
|
|
||||||
|
cl_must_pass(p_unlink(test));
|
||||||
|
}
|
||||||
|
|
139
tests-clay/core/path.c
Normal file
139
tests-clay/core/path.c
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#include "clay_libgit2.h"
|
||||||
|
#include <fileops.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_dirname(const char *A, const char *B)
|
||||||
|
{
|
||||||
|
char dir[64], *dir2;
|
||||||
|
|
||||||
|
cl_assert(git_path_dirname_r(dir, sizeof(dir), A) >= 0);
|
||||||
|
cl_assert(strcmp(dir, B) == 0);
|
||||||
|
cl_assert((dir2 = git_path_dirname(A)) != NULL);
|
||||||
|
cl_assert(strcmp(dir2, B) == 0);
|
||||||
|
|
||||||
|
free(dir2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_basename(const char *A, const char *B)
|
||||||
|
{
|
||||||
|
char base[64], *base2;
|
||||||
|
|
||||||
|
cl_assert(git_path_basename_r(base, sizeof(base), A) >= 0);
|
||||||
|
cl_assert(strcmp(base, B) == 0);
|
||||||
|
cl_assert((base2 = git_path_basename(A)) != NULL);
|
||||||
|
cl_assert(strcmp(base2, B) == 0);
|
||||||
|
|
||||||
|
free(base2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_topdir(const char *A, const char *B)
|
||||||
|
{
|
||||||
|
const char *dir;
|
||||||
|
|
||||||
|
cl_assert((dir = git_path_topdir(A)) != NULL);
|
||||||
|
cl_assert(strcmp(dir, B) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_joinpath(const char *path_a, const char *path_b, const char *expected_path)
|
||||||
|
{
|
||||||
|
char joined_path[GIT_PATH_MAX];
|
||||||
|
|
||||||
|
git_path_join(joined_path, path_a, path_b);
|
||||||
|
cl_assert(strcmp(joined_path, expected_path) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_joinpath_n(
|
||||||
|
const char *path_a,
|
||||||
|
const char *path_b,
|
||||||
|
const char *path_c,
|
||||||
|
const char *path_d,
|
||||||
|
const char *expected_path)
|
||||||
|
{
|
||||||
|
char joined_path[GIT_PATH_MAX];
|
||||||
|
|
||||||
|
git_path_join_n(joined_path, 4, path_a, path_b, path_c, path_d);
|
||||||
|
cl_assert(strcmp(joined_path, expected_path) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get the dirname of a path */
|
||||||
|
void test_core_path__0(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
check_dirname(NULL, ".");
|
||||||
|
check_dirname("", ".");
|
||||||
|
check_dirname("a", ".");
|
||||||
|
check_dirname("/", "/");
|
||||||
|
check_dirname("/usr", "/");
|
||||||
|
check_dirname("/usr/", "/");
|
||||||
|
check_dirname("/usr/lib", "/usr");
|
||||||
|
check_dirname("/usr/lib/", "/usr");
|
||||||
|
check_dirname("/usr/lib//", "/usr");
|
||||||
|
check_dirname("usr/lib", "usr");
|
||||||
|
check_dirname("usr/lib/", "usr");
|
||||||
|
check_dirname("usr/lib//", "usr");
|
||||||
|
check_dirname(".git/", ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the base name of a path */
|
||||||
|
void test_core_path__1(void)
|
||||||
|
{
|
||||||
|
check_basename(NULL, ".");
|
||||||
|
check_basename("", ".");
|
||||||
|
check_basename("a", "a");
|
||||||
|
check_basename("/", "/");
|
||||||
|
check_basename("/usr", "usr");
|
||||||
|
check_basename("/usr/", "usr");
|
||||||
|
check_basename("/usr/lib", "lib");
|
||||||
|
check_basename("/usr/lib//", "lib");
|
||||||
|
check_basename("usr/lib", "lib");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the latest component in a path */
|
||||||
|
void test_core_path__2(void)
|
||||||
|
{
|
||||||
|
check_topdir(".git/", ".git/");
|
||||||
|
check_topdir("/.git/", ".git/");
|
||||||
|
check_topdir("usr/local/.git/", ".git/");
|
||||||
|
check_topdir("./.git/", ".git/");
|
||||||
|
check_topdir("/usr/.git/", ".git/");
|
||||||
|
check_topdir("/", "/");
|
||||||
|
check_topdir("a/", "a/");
|
||||||
|
|
||||||
|
cl_assert(git_path_topdir("/usr/.git") == NULL);
|
||||||
|
cl_assert(git_path_topdir(".") == NULL);
|
||||||
|
cl_assert(git_path_topdir("") == NULL);
|
||||||
|
cl_assert(git_path_topdir("a") == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* properly join path components */
|
||||||
|
void test_core_path__5(void)
|
||||||
|
{
|
||||||
|
check_joinpath("", "", "");
|
||||||
|
check_joinpath("", "a", "a");
|
||||||
|
check_joinpath("", "/a", "/a");
|
||||||
|
check_joinpath("a", "", "a/");
|
||||||
|
check_joinpath("a", "/", "a/");
|
||||||
|
check_joinpath("a", "b", "a/b");
|
||||||
|
check_joinpath("/", "a", "/a");
|
||||||
|
check_joinpath("/", "", "/");
|
||||||
|
check_joinpath("/a", "/b", "/a/b");
|
||||||
|
check_joinpath("/a", "/b/", "/a/b/");
|
||||||
|
check_joinpath("/a/", "b/", "/a/b/");
|
||||||
|
check_joinpath("/a/", "/b/", "/a/b/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* properly join path components for more than one path */
|
||||||
|
void test_core_path__6(void)
|
||||||
|
{
|
||||||
|
check_joinpath_n("", "", "", "", "");
|
||||||
|
check_joinpath_n("", "a", "", "", "a/");
|
||||||
|
check_joinpath_n("a", "", "", "", "a/");
|
||||||
|
check_joinpath_n("", "", "", "a", "a");
|
||||||
|
check_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/");
|
||||||
|
check_joinpath_n("a", "b", "", "/c/d", "a/b/c/d");
|
||||||
|
}
|
50
tests-clay/core/rmdir.c
Normal file
50
tests-clay/core/rmdir.c
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "clay_libgit2.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
static const char *empty_tmp_dir = "test_gitfo_rmdir_recurs_test";
|
||||||
|
|
||||||
|
void test_core_rmdir__initialize()
|
||||||
|
{
|
||||||
|
char path[GIT_PATH_MAX];
|
||||||
|
|
||||||
|
cl_must_pass(p_mkdir(empty_tmp_dir, 0755));
|
||||||
|
|
||||||
|
git_path_join(path, empty_tmp_dir, "/one");
|
||||||
|
cl_must_pass(p_mkdir(path, 0755));
|
||||||
|
|
||||||
|
git_path_join(path, empty_tmp_dir, "/one/two_one");
|
||||||
|
cl_must_pass(p_mkdir(path, 0755));
|
||||||
|
|
||||||
|
git_path_join(path, empty_tmp_dir, "/one/two_two");
|
||||||
|
cl_must_pass(p_mkdir(path, 0755));
|
||||||
|
|
||||||
|
git_path_join(path, empty_tmp_dir, "/one/two_two/three");
|
||||||
|
cl_must_pass(p_mkdir(path, 0755));
|
||||||
|
|
||||||
|
git_path_join(path, empty_tmp_dir, "/two");
|
||||||
|
cl_must_pass(p_mkdir(path, 0755));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure empty dir can be deleted recusively */
|
||||||
|
void test_core_rmdir__delete_recursive(void)
|
||||||
|
{
|
||||||
|
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure non-empty dir cannot be deleted recusively */
|
||||||
|
void test_core_rmdir__fail_to_delete_non_empty_dir(void)
|
||||||
|
{
|
||||||
|
char file[GIT_PATH_MAX];
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
git_path_join(file, empty_tmp_dir, "/two/file.txt");
|
||||||
|
|
||||||
|
fd = p_creat(file, 0755);
|
||||||
|
cl_assert(fd >= 0);
|
||||||
|
|
||||||
|
cl_must_pass(p_close(fd));
|
||||||
|
cl_git_fail(git_futils_rmdir_r(empty_tmp_dir, 0));
|
||||||
|
|
||||||
|
cl_must_pass(p_unlink(file));
|
||||||
|
cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, 0));
|
||||||
|
}
|
28
tests-clay/core/string.c
Normal file
28
tests-clay/core/string.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "clay_libgit2.h"
|
||||||
|
|
||||||
|
/* compare prefixes */
|
||||||
|
void test_core_string__0(void)
|
||||||
|
{
|
||||||
|
cl_assert(git__prefixcmp("", "") == 0);
|
||||||
|
cl_assert(git__prefixcmp("a", "") == 0);
|
||||||
|
cl_assert(git__prefixcmp("", "a") < 0);
|
||||||
|
cl_assert(git__prefixcmp("a", "b") < 0);
|
||||||
|
cl_assert(git__prefixcmp("b", "a") > 0);
|
||||||
|
cl_assert(git__prefixcmp("ab", "a") == 0);
|
||||||
|
cl_assert(git__prefixcmp("ab", "ac") < 0);
|
||||||
|
cl_assert(git__prefixcmp("ab", "aa") > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compare suffixes */
|
||||||
|
void test_core_string__1(void)
|
||||||
|
{
|
||||||
|
cl_assert(git__suffixcmp("", "") == 0);
|
||||||
|
cl_assert(git__suffixcmp("a", "") == 0);
|
||||||
|
cl_assert(git__suffixcmp("", "a") < 0);
|
||||||
|
cl_assert(git__suffixcmp("a", "b") < 0);
|
||||||
|
cl_assert(git__suffixcmp("b", "a") > 0);
|
||||||
|
cl_assert(git__suffixcmp("ba", "a") == 0);
|
||||||
|
cl_assert(git__suffixcmp("zaa", "ac") < 0);
|
||||||
|
cl_assert(git__suffixcmp("zaz", "ac") > 0);
|
||||||
|
}
|
||||||
|
|
66
tests-clay/core/vector.c
Normal file
66
tests-clay/core/vector.c
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#include "clay_libgit2.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
/* initial size of 1 would cause writing past array bounds */
|
||||||
|
void test_core_vector__0(void)
|
||||||
|
{
|
||||||
|
git_vector x;
|
||||||
|
int i;
|
||||||
|
git_vector_init(&x, 1, NULL);
|
||||||
|
for (i = 0; i < 10; ++i) {
|
||||||
|
git_vector_insert(&x, (void*) 0xabc);
|
||||||
|
}
|
||||||
|
git_vector_free(&x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* don't read past array bounds on remove() */
|
||||||
|
void test_core_vector__1(void)
|
||||||
|
{
|
||||||
|
git_vector x;
|
||||||
|
// make initial capacity exact for our insertions.
|
||||||
|
git_vector_init(&x, 3, NULL);
|
||||||
|
git_vector_insert(&x, (void*) 0xabc);
|
||||||
|
git_vector_insert(&x, (void*) 0xdef);
|
||||||
|
git_vector_insert(&x, (void*) 0x123);
|
||||||
|
|
||||||
|
git_vector_remove(&x, 0); // used to read past array bounds.
|
||||||
|
git_vector_free(&x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int test_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return *(const int *)a - *(const int *)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove duplicates */
|
||||||
|
void test_core_vector__2(void)
|
||||||
|
{
|
||||||
|
git_vector x;
|
||||||
|
int *ptrs[2];
|
||||||
|
|
||||||
|
ptrs[0] = git__malloc(sizeof(int));
|
||||||
|
ptrs[1] = git__malloc(sizeof(int));
|
||||||
|
|
||||||
|
*ptrs[0] = 2;
|
||||||
|
*ptrs[1] = 1;
|
||||||
|
|
||||||
|
cl_git_pass(git_vector_init(&x, 5, test_cmp));
|
||||||
|
cl_git_pass(git_vector_insert(&x, ptrs[0]));
|
||||||
|
cl_git_pass(git_vector_insert(&x, ptrs[1]));
|
||||||
|
cl_git_pass(git_vector_insert(&x, ptrs[1]));
|
||||||
|
cl_git_pass(git_vector_insert(&x, ptrs[0]));
|
||||||
|
cl_git_pass(git_vector_insert(&x, ptrs[1]));
|
||||||
|
cl_assert(x.length == 5);
|
||||||
|
|
||||||
|
git_vector_uniq(&x);
|
||||||
|
cl_assert(x.length == 2);
|
||||||
|
|
||||||
|
git_vector_free(&x);
|
||||||
|
|
||||||
|
free(ptrs[0]);
|
||||||
|
free(ptrs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user