diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml new file mode 100644 index 0000000..cb0224a --- /dev/null +++ b/.github/workflows/build_wheel.yml @@ -0,0 +1,42 @@ +# Build wheel from source using tox. +name: build_wheel +on: [push, pull_request] +permissions: read-all +jobs: + build_wheel: + runs-on: ubuntu-22.04 + strategy: + matrix: + include: + - python-version: '3.7' + toxenv: 'py37' + - python-version: '3.8' + toxenv: 'py38' + - python-version: '3.9' + toxenv: 'py39' + - python-version: '3.10' + toxenv: 'py310' + - python-version: '3.11' + toxenv: 'py311' + - python-version: '3.12' + toxenv: 'py312' + steps: + - uses: actions/checkout@v3 + - name: Install build dependencies + run: | + sudo add-apt-repository universe && + sudo add-apt-repository -y ppa:deadsnakes/ppa && + sudo apt-get update && + sudo apt-get install -y autoconf automake autopoint build-essential git libtool pkg-config python${{ matrix.python-version }} python${{ matrix.python-version }}-dev python${{ matrix.python-version }}-venv python3-distutils python3-pip python3-setuptools + - name: Install tox + run: | + python3 -m pip install tox + - name: Download test data + run: | + if test -x "synctestdata.sh"; then ./synctestdata.sh; fi + - name: Prepare build + run: | + ./synclibs.sh --use-head && ./autogen.sh && ./configure + - name: Build Python wheel + run: | + tox -e${{ matrix.toxenv }} diff --git a/.gitignore b/.gitignore index 763b39e..fc5e301 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Files to ignore by git # -# Version: 20230405 +# Version: 20230926 # Generic auto-generated build files *~ @@ -25,10 +25,13 @@ *.swp *.Tpo *.trs +*.whl /*.egg-info/ +__pycache__ .deps .dirstamp .libs +.tox INSTALL Makefile Makefile.bcc @@ -125,6 +128,7 @@ stamp-h[1-9] /libevtx/libevtx.rc /libevtx/libevtx_definitions.h /pyevtx-python[23]/*.[ch] +/setup.cfg /evtxtools/*.exe /evtxtools/evtxexport /evtxtools/evtxinfo diff --git a/Makefile.am b/Makefile.am index d32bf33..53e60dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -56,6 +56,9 @@ PKGCONFIG_FILES = \ libevtx.pc.in SETUP_PY_FILES = \ + pyproject.toml \ + setup.cfg \ + setup.cfg.in \ setup.py SPEC_FILES = \ diff --git a/appveyor.yml b/appveyor.yml index 5e18284..83bd4c0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -84,11 +84,16 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: macos-monterey HOMEBREW_NO_INSTALL_CLEANUP: 1 CC: clang + CFLAGS: "-I/usr/local/include" + LDFLAGS: "-L/usr/local/lib" CONFIGURE_OPTIONS: "" - TARGET: macos-x64-gcc BUILD_ENVIRONMENT: xcode APPVEYOR_BUILD_WORKER_IMAGE: macos-monterey HOMEBREW_NO_INSTALL_CLEANUP: 1 + CC: gcc + CFLAGS: "-I/usr/local/include" + LDFLAGS: "-L/usr/local/lib" CONFIGURE_OPTIONS: "" - TARGET: macos-x64-gcc-python BUILD_ENVIRONMENT: xcode @@ -96,6 +101,7 @@ environment: PYTHON: "/usr/local/opt/python@3.11/bin/python3" PYTHON_CONFIG: "/usr/local/opt/python@3.11/bin/python3-config" HOMEBREW_NO_INSTALL_CLEANUP: 1 + CC: gcc CFLAGS: "-I/usr/local/include" LDFLAGS: "-L/usr/local/lib" CONFIGURE_OPTIONS: "--enable-python" @@ -105,6 +111,7 @@ environment: PYTHON: "/usr/local/opt/python@3.11/bin/python3" PYTHON_CONFIG: "/usr/local/opt/python@3.11/bin/python3-config" HOMEBREW_NO_INSTALL_CLEANUP: 1 + CC: gcc CFLAGS: "-I/usr/local/include" LDFLAGS: "-L/usr/local/lib" CONFIGURE_OPTIONS: "--disable-dependency-tracking --prefix=/usr/local --enable-python --with-pyprefix" @@ -140,6 +147,12 @@ environment: HOMEBREW_NO_INSTALL_CLEANUP: 1 PYTHON_VERSION: 3.11 TOXENV: py311 + - TARGET: macos-tox-py312 + BUILD_ENVIRONMENT: python-tox + APPVEYOR_BUILD_WORKER_IMAGE: macos-monterey + HOMEBREW_NO_INSTALL_CLEANUP: 1 + PYTHON_VERSION: 3.12 + TOXENV: py312 - TARGET: cygwin64-gcc BUILD_ENVIRONMENT: cygwin64 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 diff --git a/configure.ac b/configure.ac index e86dc3c..87ba4b6 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ([2.71]) AC_INIT( [libevtx], - [20230826], + [20231009], [joachim.metz@gmail.com]) AC_CONFIG_SRCDIR( @@ -234,6 +234,7 @@ AC_CONFIG_FILES([dpkg/changelog]) AC_CONFIG_FILES([libevtx/libevtx.rc]) AC_CONFIG_FILES([libevtx.pc]) AC_CONFIG_FILES([libevtx.spec]) +AC_CONFIG_FILES([setup.cfg]) dnl Generate a source configuration file AC_CONFIG_HEADERS([common/config.h]) diff --git a/m4/python.m4 b/m4/python.m4 index 307e15c..e10bc9f 100644 --- a/m4/python.m4 +++ b/m4/python.m4 @@ -1,6 +1,6 @@ dnl Functions for Python bindings dnl -dnl Version: 20211114 +dnl Version: 20230923 dnl Function to check if the python binary is available dnl "python${PYTHON_VERSION} python python# python#.#" @@ -8,7 +8,7 @@ AC_DEFUN([AX_PROG_PYTHON], [AS_IF( [test "x${PYTHON_VERSION}" != x], [ax_python_progs="python${PYTHON_VERSION}"], - [ax_python_progs="python python3 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2 python2.7 python2.6 python2.5"]) + [ax_python_progs="python python3 python3.12 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2 python2.7 python2.6 python2.5"]) AC_CHECK_PROGS( [PYTHON], [$ax_python_progs]) @@ -58,7 +58,7 @@ AC_DEFUN([AX_PROG_PYTHON2], dnl Function to check if the python3 binary is available dnl "python3 python3.#" AC_DEFUN([AX_PROG_PYTHON3], - [ax_python3_progs="python3 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0" + [ax_python3_progs="python3 python3.12 python3.11 python3.10 python3.9 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0" AC_CHECK_PROGS( [PYTHON3], [$ax_python3_progs]) @@ -95,7 +95,7 @@ AC_DEFUN([AX_PROG_PYTHON_CONFIG], [test "x${PYTHON_CONFIG}" = x], [AC_CHECK_PROGS( [PYTHON_CONFIG], - [python-config python3-config python3.11-config python3.10-config python3.9-config python3.8-config python3.7-config python3.6-config python3.5-config python3.4-config python3.3-config python3.2-config python3.1-config python3.0-config python2-config python2.7-config python2.6-config python2.5-config]) + [python-config python3-config python3.12-config python3.11-config python3.10-config python3.9-config python3.8-config python3.7-config python3.6-config python3.5-config python3.4-config python3.3-config python3.2-config python3.1-config python3.0-config python2-config python2.7-config python2.6-config python2.5-config]) ]) AS_IF( [test "x${PYTHON_CONFIG}" = x], @@ -131,7 +131,7 @@ AC_DEFUN([AX_PROG_PYTHON3_CONFIG], [test "x${PYTHON3_CONFIG}" = x], [AC_CHECK_PROGS( [PYTHON3_CONFIG], - [python3-config python3.11-config python3.10-config python3.9-config python3.8-config python3.7-config python3.6-config python3.5-config python3.4-config python3.3-config python3.2-config python3.1-config python3.0-config]) + [python3-config python3.12-config python3.11-config python3.10-config python3.9-config python3.8-config python3.7-config python3.6-config python3.5-config python3.4-config python3.3-config python3.2-config python3.1-config python3.0-config]) ]) AS_IF( [test "x${PYTHON3_CONFIG}" = x], diff --git a/pyevtx/pyevtx_file_object_io_handle.c b/pyevtx/pyevtx_file_object_io_handle.c index fb1d203..07ecd9c 100644 --- a/pyevtx/pyevtx_file_object_io_handle.c +++ b/pyevtx/pyevtx_file_object_io_handle.c @@ -232,13 +232,13 @@ int pyevtx_file_object_io_handle_free( Py_DecRef( ( *file_object_io_handle )->file_object ); - PyGILState_Release( - gil_state ); - PyMem_Free( *file_object_io_handle ); *file_object_io_handle = NULL; + + PyGILState_Release( + gil_state ); } return( 1 ); } diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..1870a2e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,4 @@ +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1ded777..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[metadata] -license_files = COPYING COPYING.LESSER diff --git a/setup.cfg.in b/setup.cfg.in new file mode 100644 index 0000000..16b0f64 --- /dev/null +++ b/setup.cfg.in @@ -0,0 +1,15 @@ +[metadata] +name = libevtx-python +version = @VERSION@ +description = Python bindings module for libevtx +long_description = Python bindings module for libevtx +author = Joachim Metz +author_email = joachim.metz@gmail.com +license = GNU Lesser General Public License v3 or later (LGPLv3+) +license_files = COPYING COPYING.LESSER +classifiers = + Development Status :: 3 - Alpha + Programming Language :: Python + +[options] +python_requires = >=3.7 diff --git a/setup.py b/setup.py index afd9215..3a86854 100755 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # Script to build and install Python-bindings. -# Version: 20230411 +# Version: 20230909 from __future__ import print_function @@ -25,44 +25,11 @@ from setuptools.command.build_ext import build_ext from setuptools.command.sdist import sdist -try: - from distutils.command.bdist_msi import bdist_msi -except ImportError: - bdist_msi = None -try: - from setuptools.command.bdist_rpm import bdist_rpm -except ImportError: - from distutils.command.bdist import bdist as bdist_rpm - - -if not bdist_msi: - custom_bdist_msi = None -else: - class custom_bdist_msi(bdist_msi): - """Custom handler for the bdist_msi command.""" - - def run(self): - """Builds an MSI.""" - # Make a deepcopy of distribution so the following version changes - # only apply to bdist_msi. - self.distribution = copy.deepcopy(self.distribution) - - # bdist_msi does not support the library version so we add ".1" - # as a work around. - self.distribution.metadata.version = "{0:s}.1".format( - self.distribution.metadata.version) - - bdist_msi.run(self) - - -class custom_bdist_rpm(bdist_rpm): - """Custom handler for the bdist_rpm command.""" - - def run(self): - """Builds a RPM.""" - print("'setup.py bdist_rpm' command not supported use 'rpmbuild' instead.") - sys.exit(1) +if (sys.version_info[0], sys.version_info[1]) < (3, 7): + print(("Unsupported Python version: {0:s}, version 3.7 or higher " + "required.").format(sys.version)) + sys.exit(1) class custom_build_ext(build_ext): @@ -218,49 +185,25 @@ def module_name(self): """The Python module name.""" return "py{0:s}".format(self.library_name[3:]) - @property - def package_name(self): - """The package name.""" - return "{0:s}-python".format(self.library_name) - - @property - def package_description(self): - """The package description.""" - return "Python bindings module for {0:s}".format(self.library_name) - - @property - def project_url(self): - """The project URL.""" - return "https://github.com/libyal/{0:s}/".format(self.library_name) - def _ReadConfigureAc(self): """Reads configure.ac to initialize the project information.""" - file_object = open("configure.ac", "rb") - if not file_object: - raise IOError("Unable to open: configure.ac") - - found_ac_init = False - found_library_name = False - for line in file_object.readlines(): - line = line.strip() - if found_library_name: - library_version = line[1:-2] - if sys.version_info[0] >= 3: - library_version = library_version.decode("ascii") - self.library_version = library_version - break - - elif found_ac_init: - library_name = line[1:-2] - if sys.version_info[0] >= 3: - library_name = library_name.decode("ascii") - self.library_name = library_name - found_library_name = True - - elif line.startswith(b"AC_INIT"): - found_ac_init = True - - file_object.close() + with open("configure.ac", "r", encoding="utf-8") as file_object: + found_ac_init = False + found_library_name = False + for line in file_object.readlines(): + line = line.strip() + if found_library_name: + library_version = line[1:-2] + self.library_version = library_version + break + + elif found_ac_init: + library_name = line[1:-2] + self.library_name = library_name + found_library_name = True + + elif line.startswith("AC_INIT"): + found_ac_init = True if not self.library_name or not self.library_version: raise RuntimeError( @@ -271,30 +214,23 @@ def _ReadMakefileAm(self): if not self.library_name: raise RuntimeError("Missing library name") - file_object = open("Makefile.am", "rb") - if not file_object: - raise IOError("Unable to open: Makefile.am") - - found_subdirs = False - for line in file_object.readlines(): - line = line.strip() - if found_subdirs: - library_name, _, _ = line.partition(b" ") - if sys.version_info[0] >= 3: - library_name = library_name.decode("ascii") + with open("Makefile.am", "r", encoding="utf-8") as file_object: + found_subdirs = False + for line in file_object.readlines(): + line = line.strip() + if found_subdirs: + library_name, _, _ = line.partition(" ") - self.include_directories.append(library_name) + self.include_directories.append(library_name) - if library_name.startswith("lib"): - self.library_names.append(library_name) + if library_name.startswith("lib"): + self.library_names.append(library_name) - if library_name == self.library_name: - break + if library_name == self.library_name: + break - elif line.startswith(b"SUBDIRS"): - found_subdirs = True - - file_object.close() + elif line.startswith("SUBDIRS"): + found_subdirs = True if not self.include_directories or not self.library_names: raise RuntimeError( @@ -306,12 +242,8 @@ def _ReadMakefileAm(self): CMDCLASS = { "build_ext": custom_build_ext, - "bdist_rpm": custom_bdist_rpm, "sdist": custom_sdist} -if custom_bdist_msi: - CMDCLASS["bdist_msi"] = custom_bdist_msi - SOURCES = [] # TODO: replace by detection of MSC @@ -344,18 +276,7 @@ def _ReadMakefileAm(self): # TODO: find a way to detect missing python.h # e.g. on Ubuntu python-dev is not installed by python-pip -# TODO: what about description and platform in egg file - -setup( - name=project_information.package_name, - url=project_information.project_url, - version=project_information.library_version, - description=project_information.package_description, - long_description=project_information.package_description, - long_description_content_type="text/plain", - author="Joachim Metz", - author_email="joachim.metz@gmail.com", - license="GNU Lesser General Public License v3 or later (LGPLv3+)", +setup_args = dict( cmdclass=CMDCLASS, ext_modules=[ Extension( @@ -364,8 +285,9 @@ def _ReadMakefileAm(self): include_dirs=project_information.include_directories, libraries=[], library_dirs=[], - sources=SOURCES, - ), - ], + sources=SOURCES + ) + ] ) +setup(**setup_args) diff --git a/tests/Makefile.am b/tests/Makefile.am index 00e98aa..8ae6f39 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -37,14 +37,12 @@ TESTS = \ test_tools.sh \ test_evtxinfo.sh \ test_evtxexport.sh \ - test_evtxexport_xml.sh \ $(TESTS_PYEVTX) check_SCRIPTS = \ pyevtx_test_file.py \ pyevtx_test_support.py \ test_evtxexport.sh \ - test_evtxexport_xml.sh \ test_evtxinfo.sh \ test_library.sh \ test_manpage.sh \ diff --git a/tests/runtests.py b/tests/runtests.py new file mode 100755 index 0000000..f91dac7 --- /dev/null +++ b/tests/runtests.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# +# Script to run Python test scripts. +# +# Version: 20231004 + +import glob +import os +import sys +import unittest + + +test_profile = ".pyevtx" +input_glob = "*" +option_sets = [] + + +def ReadIgnoreList(test_profile): + """Reads the test profile ignore file if it exists. + + Args: + test_profile (str): test profile. + + Returns: + set[str]: ignore list. + """ + ignore_file_path = os.path.join("tests", "input", test_profile, "ignore") + if os.path.isfile(ignore_file_path): + with open(ignore_file_path, "r", encoding="utf-8") as file_object: + return set([line.strip() for line in file_object.readlines()]) + + return set() + + +if __name__ == "__main__": + print(f"Using Python version {sys.version!s}") + + test_loader = unittest.TestLoader() + test_runner = unittest.TextTestRunner(verbosity=2) + + test_scripts = test_loader.discover("tests", pattern="*.py") + + ignore_list = ReadIgnoreList(test_profile) + + test_set = None + source_file = None + + for test_set in glob.glob(os.path.join("tests", "input", "*")): + test_set = test_set.rsplit(os.path.sep, maxsplit=1)[-1] + if not test_set or test_set[0] == '.' or test_set in ignore_list: + continue + + source_files = glob.glob(os.path.join( + "tests", "input", test_set, input_glob)) + if source_files: + source_file = source_files[0] + break + + setattr(unittest, "source", source_file) + + for option_set in option_sets: + test_file = os.path.basename(source_file) + test_options_file_path = os.path.join( + "tests", "input", test_profile, test_set, + f"{test_file:s}.{option_set:s}") + if os.path.isfile(test_options_file_path): + with open(test_options_file_path, "r", encoding="utf-8") as file_object: + lines = [line.strip() for line in file_object.readlines()] + if lines[0] == "# libyal test data options": + for line in lines[1:]: + key, value = line.split("=", maxsplit=1) + setattr(unittest, key, value) + + test_results = test_runner.run(test_scripts) + if not test_results.wasSuccessful(): + sys.exit(1) diff --git a/tests/test_evtxexport.sh b/tests/test_evtxexport.sh index 6030be9..517ce24 100755 --- a/tests/test_evtxexport.sh +++ b/tests/test_evtxexport.sh @@ -1,14 +1,15 @@ #!/usr/bin/env bash # Export tool testing script # -# Version: 20230410 +# Version: 20231005 EXIT_SUCCESS=0; EXIT_FAILURE=1; EXIT_IGNORE=77; -OPTION_SETS=""; -OPTIONS=(); +PROFILES=("evtxexport" "evtxexport_xml"); +OPTIONS_PER_PROFILE=("" "-fxml"); +OPTION_SETS=(); INPUT_GLOB="*"; @@ -62,62 +63,88 @@ then exit ${EXIT_IGNORE}; fi -TEST_PROFILE_DIRECTORY=$(get_test_profile_directory "input" "evtxexport"); +for PROFILE_INDEX in ${!PROFILES[*]}; +do + TEST_PROFILE=${PROFILES[${PROFILE_INDEX}]}; -IGNORE_LIST=$(read_ignore_list "${TEST_PROFILE_DIRECTORY}"); + TEST_PROFILE_DIRECTORY=$(get_test_profile_directory "input" "${TEST_PROFILE}"); -RESULT=${EXIT_SUCCESS}; + IGNORE_LIST=$(read_ignore_list "${TEST_PROFILE_DIRECTORY}"); -for TEST_SET_INPUT_DIRECTORY in input/*; -do - if ! test -d "${TEST_SET_INPUT_DIRECTORY}"; - then - continue; - fi - if check_for_directory_in_ignore_list "${TEST_SET_INPUT_DIRECTORY}" "${IGNORE_LIST}"; - then - continue; - fi - - TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); - - OLDIFS=${IFS}; - - # IFS="\n"; is not supported by all platforms. - IFS=" -"; - - if test -f "${TEST_SET_DIRECTORY}/files"; - then - for INPUT_FILE in `cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"`; + IFS=" " read -a PROFILE_OPTIONS <<< ${OPTIONS_PER_PROFILE[${PROFILE_INDEX}]}; + + RESULT=${EXIT_SUCCESS}; + + for TEST_SET_INPUT_DIRECTORY in input/*; + do + if ! test -d "${TEST_SET_INPUT_DIRECTORY}"; + then + continue; + fi + TEST_SET=`basename ${TEST_SET_INPUT_DIRECTORY}`; + + if check_for_test_set_in_ignore_list "${TEST_SET}" "${IGNORE_LIST}"; + then + continue; + fi + TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); + + RESULT=${EXIT_SUCCESS}; + + if test -f "${TEST_SET_DIRECTORY}/files"; + then + IFS="" read -a INPUT_FILES <<< $(cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"); + else + IFS="" read -a INPUT_FILES <<< $(ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}); + fi + for INPUT_FILE in "${INPUT_FILES[@]}"; do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "evtxexport" "with_stdout_reference" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${OPTIONS[@]}"; - RESULT=$?; + TESTED_WITH_OPTIONS=0; - if test ${RESULT} -ne ${EXIT_SUCCESS}; + for OPTION_SET in ${OPTION_SETS[@]}; + do + TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + if test -f ${TEST_DATA_OPTION_FILE}; + then + TESTED_WITH_OPTIONS=1; + + IFS=" " read -a OPTIONS <<< $(read_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + run_test_on_input_file "${TEST_SET_DIRECTORY}" "evtxexport" "with_stdout_reference" "${OPTION_SET}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${PROFILE_OPTIONS[@]}" "${OPTIONS[@]}"; + RESULT=$?; + + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + fi + done + + if test ${TESTED_WITH_OPTIONS} -eq 0; then - break; + run_test_on_input_file "${TEST_SET_DIRECTORY}" "evtxexport" "with_stdout_reference" "" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${PROFILE_OPTIONS[@]}"; + RESULT=$?; fi - done - else - for INPUT_FILE in `ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}`; - do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "evtxexport" "with_stdout_reference" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${OPTIONS[@]}"; - RESULT=$?; if test ${RESULT} -ne ${EXIT_SUCCESS}; then break; fi done - fi - IFS=${OLDIFS}; - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi + # Ignore failures due to corrupted data. + if test "${TEST_SET}" = "corrupted"; + then + RESULT=${EXIT_SUCCESS}; + fi + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + done done exit ${RESULT}; + diff --git a/tests/test_evtxexport_xml.sh b/tests/test_evtxexport_xml.sh deleted file mode 100755 index e08ad00..0000000 --- a/tests/test_evtxexport_xml.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env bash -# Export tool testing script -# -# Version: 20230410 - -EXIT_SUCCESS=0; -EXIT_FAILURE=1; -EXIT_IGNORE=77; - -OPTION_SETS=""; -OPTIONS="-fxml"; - -INPUT_GLOB="*"; - -if ! test -z ${SKIP_TOOLS_TESTS}; -then - exit ${EXIT_IGNORE}; -fi - -TEST_EXECUTABLE="../evtxtools/evtxexport"; - -if ! test -x "${TEST_EXECUTABLE}"; -then - TEST_EXECUTABLE="../evtxtools/evtxexport.exe"; -fi - -if ! test -x "${TEST_EXECUTABLE}"; -then - echo "Missing test executable: ${TEST_EXECUTABLE}"; - - exit ${EXIT_FAILURE}; -fi - -TEST_RUNNER="tests/test_runner.sh"; - -if ! test -f "${TEST_RUNNER}"; -then - TEST_RUNNER="./test_runner.sh"; -fi - -if ! test -f "${TEST_RUNNER}"; -then - echo "Missing test runner: ${TEST_RUNNER}"; - - exit ${EXIT_FAILURE}; -fi - -source ${TEST_RUNNER}; - -if ! test -d "input"; -then - echo "Test input directory: input not found."; - - return ${EXIT_IGNORE}; -fi -RESULT=`ls input/* | tr ' ' '\n' | wc -l`; - -if test ${RESULT} -eq ${EXIT_SUCCESS}; -then - echo "No files or directories found in the test input directory: input"; - - return ${EXIT_IGNORE}; -fi - -TEST_PROFILE_DIRECTORY=$(get_test_profile_directory "input" "evtxexport_xml"); - -IGNORE_LIST=$(read_ignore_list "${TEST_PROFILE_DIRECTORY}"); - -RESULT=${EXIT_SUCCESS}; - -for TEST_SET_INPUT_DIRECTORY in input/*; -do - if ! test -d "${TEST_SET_INPUT_DIRECTORY}"; - then - continue; - fi - if check_for_directory_in_ignore_list "${TEST_SET_INPUT_DIRECTORY}" "${IGNORE_LIST}"; - then - continue; - fi - - TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); - - OLDIFS=${IFS}; - - # IFS="\n"; is not supported by all platforms. - IFS=" -"; - - if test -f "${TEST_SET_DIRECTORY}/files"; - then - for INPUT_FILE in `cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"`; - do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "evtxexport" "with_stdout_reference" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${OPTIONS}"; - RESULT=$?; - - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - else - for INPUT_FILE in `ls -1 ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}`; - do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "evtxexport" "with_stdout_reference" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${OPTIONS}"; - RESULT=$?; - - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - fi - IFS=${OLDIFS}; - - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi -done - -exit ${RESULT}; - diff --git a/tests/test_evtxinfo.sh b/tests/test_evtxinfo.sh index 1c637a4..b08d437 100755 --- a/tests/test_evtxinfo.sh +++ b/tests/test_evtxinfo.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Info tool testing script # -# Version: 20230410 +# Version: 20231005 EXIT_SUCCESS=0; EXIT_FAILURE=1; @@ -9,7 +9,7 @@ EXIT_IGNORE=77; PROFILES=("evtxinfo"); OPTIONS_PER_PROFILE=(""); -OPTION_SETS=""; +OPTION_SETS=(); INPUT_GLOB="*"; @@ -71,7 +71,7 @@ do IGNORE_LIST=$(read_ignore_list "${TEST_PROFILE_DIRECTORY}"); - IFS=" " read -a OPTIONS <<< ${OPTIONS_PER_PROFILE[${PROFILE_INDEX}]}; + IFS=" " read -a PROFILE_OPTIONS <<< ${OPTIONS_PER_PROFILE[${PROFILE_INDEX}]}; RESULT=${EXIT_SUCCESS}; @@ -89,8 +89,49 @@ do fi TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); - run_test_on_test_set_with_options "${TEST_SET_DIRECTORY}" "evtxinfo" "with_stdout_reference" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${OPTIONS[@]}"; - RESULT=$?; + RESULT=${EXIT_SUCCESS}; + + if test -f "${TEST_SET_DIRECTORY}/files"; + then + IFS="" read -a INPUT_FILES <<< $(cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"); + else + IFS="" read -a INPUT_FILES <<< $(ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}); + fi + for INPUT_FILE in "${INPUT_FILES[@]}"; + do + TESTED_WITH_OPTIONS=0; + + for OPTION_SET in ${OPTION_SETS[@]}; + do + TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + if test -f ${TEST_DATA_OPTION_FILE}; + then + TESTED_WITH_OPTIONS=1; + + IFS=" " read -a OPTIONS <<< $(read_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + run_test_on_input_file "${TEST_SET_DIRECTORY}" "evtxinfo" "with_stdout_reference" "${OPTION_SET}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${PROFILE_OPTIONS[@]}" "${OPTIONS[@]}"; + RESULT=$?; + + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + fi + done + + if test ${TESTED_WITH_OPTIONS} -eq 0; + then + run_test_on_input_file "${TEST_SET_DIRECTORY}" "evtxinfo" "with_stdout_reference" "" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${PROFILE_OPTIONS[@]}"; + RESULT=$?; + fi + + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + done # Ignore failures due to corrupted data. if test "${TEST_SET}" = "corrupted"; diff --git a/tests/test_library.sh b/tests/test_library.sh index 7a1f5a8..3794bef 100755 --- a/tests/test_library.sh +++ b/tests/test_library.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Tests library functions and types. # -# Version: 20230410 +# Version: 20231007 EXIT_SUCCESS=0; EXIT_FAILURE=1; @@ -9,7 +9,7 @@ EXIT_IGNORE=77; LIBRARY_TESTS="chunk chunks_table error io_handle notify record record_values template_definition"; LIBRARY_TESTS_WITH_INPUT="file support"; -OPTION_SETS=""; +OPTION_SETS=(); INPUT_GLOB="*"; @@ -78,47 +78,54 @@ run_test_with_input() local TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); - local OLDIFS=${IFS}; - - # IFS="\n" is not supported by all platforms. - IFS=" -"; - if test -f "${TEST_SET_DIRECTORY}/files"; then - for INPUT_FILE in `cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"`; + IFS="" read -a INPUT_FILES <<< $(cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"); + else + IFS="" read -a INPUT_FILES <<< $(ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}); + fi + for INPUT_FILE in "${INPUT_FILES[@]}"; + do + OPTION_INPUT_FILE="${INPUT_FILE}"; + + if test "${OSTYPE}" = "msys"; + then + # A test executable built with MinGW expects a Windows path. + INPUT_FILE=`echo ${INPUT_FILE} | sed 's?/?\\\\?g'`; + fi + local TESTED_WITH_OPTIONS=0; + + for OPTION_SET in ${OPTION_SETS[@]}; do - if test "${OSTYPE}" = "msys"; - then - # A test executable built with MinGW expects a Windows path. - INPUT_FILE=`echo ${INPUT_FILE} | sed 's?/?\\\\?g'`; - fi - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}"; - RESULT=$?; + local TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${OPTION_INPUT_FILE}" "${OPTION_SET}"); - if test ${RESULT} -ne ${EXIT_SUCCESS}; + if test -f ${TEST_DATA_OPTION_FILE}; then - break; + TESTED_WITH_OPTIONS=1; + + IFS=" " read -a OPTIONS <<< $(read_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SET}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${OPTIONS[@]}"; + RESULT=$?; + + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi fi done - else - for INPUT_FILE in `ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}`; - do - if test "${OSTYPE}" = "msys"; - then - # A test executable built with MinGW expects a Windows path. - INPUT_FILE=`echo ${INPUT_FILE} | sed 's?/?\\\\?g'`; - fi - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}"; + + if test ${TESTED_WITH_OPTIONS} -eq 0; + then + run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "" "${TEST_EXECUTABLE}" "${INPUT_FILE}"; RESULT=$?; + fi - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - fi - IFS=${OLDIFS}; + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + done if test ${RESULT} -ne ${EXIT_SUCCESS}; then diff --git a/tests/test_python_module.sh b/tests/test_python_module.sh index a8f0570..3befc38 100755 --- a/tests/test_python_module.sh +++ b/tests/test_python_module.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Tests Python module functions and types. # -# Version: 20230410 +# Version: 20231005 EXIT_SUCCESS=0; EXIT_FAILURE=1; @@ -9,7 +9,7 @@ EXIT_IGNORE=77; TEST_FUNCTIONS="support"; TEST_FUNCTIONS_WITH_INPUT="file"; -OPTION_SETS=""; +OPTION_SETS=(); TEST_TOOL_DIRECTORY="."; INPUT_GLOB="*"; @@ -68,37 +68,47 @@ test_python_function_with_input() local TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); - local OLDIFS=${IFS}; - - # IFS="\n"; is not supported by all platforms. - IFS=" -"; - if test -f "${TEST_SET_DIRECTORY}/files"; then - for INPUT_FILE in `cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"`; + IFS="" read -a INPUT_FILES <<< $(cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"); + else + IFS="" read -a INPUT_FILES <<< $(ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}); + fi + for INPUT_FILE in "${INPUT_FILES[@]}"; + do + local TESTED_WITH_OPTIONS=0; + + for OPTION_SET in ${OPTION_SETS[@]}; do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SETS}" "${TEST_SCRIPT}" "${INPUT_FILE}"; - RESULT=$?; + local TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); - if test ${RESULT} -ne ${EXIT_SUCCESS}; + if test -f ${TEST_DATA_OPTION_FILE}; then - break; + TESTED_WITH_OPTIONS=1; + + IFS=" " read -a OPTIONS <<< $(read_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SET}" "${TEST_SCRIPT}" "${INPUT_FILE}" "${OPTIONS[@]}"; + RESULT=$?; + + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi fi done - else - for INPUT_FILE in `ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}`; - do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SETS}" "${TEST_SCRIPT}" "${INPUT_FILE}"; + + if test ${TESTED_WITH_OPTIONS} -eq 0; + then + run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "" "${TEST_SCRIPT}" "${INPUT_FILE}"; RESULT=$?; + fi - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - fi - IFS=${OLDIFS}; + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + done if test ${RESULT} -ne ${EXIT_SUCCESS}; then diff --git a/tests/test_runner.sh b/tests/test_runner.sh index 6313971..da773fa 100644 --- a/tests/test_runner.sh +++ b/tests/test_runner.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Bash functions to run an executable for testing. # -# Version: 20230410 +# Version: 20231001 # # When CHECK_WITH_ASAN is set to a non-empty value the test executable # is run with asan, otherwise it is run without. @@ -406,9 +406,12 @@ read_test_data_option_file() TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); fi - local OPTIONS=() - local OPTIONS_STRING=`cat "${TEST_DATA_OPTION_FILE}" | head -n 1 | sed 's/[\r\n]*$//'`; + local OPTIONS_STRING=`head -n 1 "${TEST_DATA_OPTION_FILE}" | sed 's/[\r\n]*$//'`; + if test "${OPTIONS_STRING}" = "# libyal test data options"; + then + OPTIONS_STRING=`tail -n +2 "${TEST_DATA_OPTION_FILE}" | sed 's/^offset=/-o/;s/^password=/-p/;s/^recovery_password=/-r/;s/^startup_key=/-s/' | tr '\n' ' '`; + fi echo "${OPTIONS_STRING}"; } @@ -1073,14 +1076,10 @@ run_test_on_input_file() local ARGUMENTS=("$@"); local INPUT_NAME=`basename "${INPUT_FILE}"`; - local OPTIONS=(); local TEST_OUTPUT="${INPUT_NAME}"; if test -n "${OPTION_SET}"; then - OPTIONS_STRING=$(read_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); - IFS=" " read -a OPTIONS <<< "${OPTIONS_STRING}"; - TEST_OUTPUT="${INPUT_NAME}-${OPTION_SET}"; fi @@ -1092,7 +1091,7 @@ run_test_on_input_file() if test "${TEST_MODE}" = "with_callback"; then - test_callback "${TMPDIR}" "${TEST_SET_DIRECTORY}" "${TEST_OUTPUT}" "${TEST_EXECUTABLE}" "${TEST_INPUT}" ${ARGUMENTS[@]} "${OPTIONS[@]}"; + test_callback "${TMPDIR}" "${TEST_SET_DIRECTORY}" "${TEST_OUTPUT}" "${TEST_EXECUTABLE}" "${TEST_INPUT}" ${ARGUMENTS[@]}; RESULT=$?; elif test "${TEST_MODE}" = "with_stdout_reference"; @@ -1109,7 +1108,7 @@ run_test_on_input_file() local INPUT_FILE_FULL_PATH=$( readlink_f "${INPUT_FILE}" ); local TEST_LOG="${TEST_OUTPUT}.log"; - (cd ${TMPDIR} && run_test_with_input_and_arguments "${TEST_EXECUTABLE}" "${INPUT_FILE_FULL_PATH}" ${ARGUMENTS[@]} "${OPTIONS[@]}" > "${TEST_LOG}"); + (cd ${TMPDIR} && run_test_with_input_and_arguments "${TEST_EXECUTABLE}" "${INPUT_FILE_FULL_PATH}" ${ARGUMENTS[@]} > "${TEST_LOG}"); RESULT=$?; # Compare output if test ran successfully. @@ -1135,7 +1134,7 @@ run_test_on_input_file() fi else - run_test_with_input_and_arguments "${TEST_EXECUTABLE}" "${INPUT_FILE}" ${ARGUMENTS[@]} "${OPTIONS[@]}"; + run_test_with_input_and_arguments "${TEST_EXECUTABLE}" "${INPUT_FILE}" ${ARGUMENTS[@]}; RESULT=$?; fi @@ -1144,22 +1143,12 @@ run_test_on_input_file() if test -n "${TEST_DESCRIPTION}"; then ARGUMENTS=`echo "${ARGUMENTS[*]}" | tr '\n' ' ' | sed 's/[ ]\$//'`; - OPTIONS=`echo "${OPTIONS[*]}" | tr '\n' ' ' | sed 's/[ ]\$//'`; - if test -z "${ARGUMENTS}" && test -z "${OPTIONS}"; + if test -z "${ARGUMENTS}"; then echo -n "${TEST_DESCRIPTION} with input: ${INPUT_FILE}"; - - elif test -z "${ARGUMENTS}"; - then - echo -n "${TEST_DESCRIPTION} with options: '${OPTIONS}' and input: ${INPUT_FILE}"; - - elif test -z "${OPTIONS}"; - then - echo -n "${TEST_DESCRIPTION} with options: '${ARGUMENTS}' and input: ${INPUT_FILE}"; - else - echo -n "${TEST_DESCRIPTION} with options: '${ARGUMENTS} ${OPTIONS}' and input: ${INPUT_FILE}"; + echo -n "${TEST_DESCRIPTION} with options: '${ARGUMENTS}' and input: ${INPUT_FILE}"; fi if test ${RESULT} -ne ${EXIT_SUCCESS}; @@ -1172,122 +1161,3 @@ run_test_on_input_file() return ${RESULT}; } -# Runs the test with options on the input file. -# -# Note that this function is not intended to be directly invoked -# from outside the test runner script. -# -# Arguments: -# a string containing the path of the test set directory -# a string containing the description of the test -# a string containing the test mode -# a string containing the name of the test data option sets -# a string containing the path of the test executable -# a string containing the path of the test input file -# an array containing the arguments for the test executable -# -# Returns: -# an integer containg the exit status of the test executable -# -run_test_on_input_file_with_options() -{ - local TEST_SET_DIRECTORY=$1; - local TEST_DESCRIPTION=$2; - local TEST_MODE=$3; - local OPTION_SETS=$4; - local TEST_EXECUTABLE=$5; - local INPUT_FILE=$6; - shift 6; - local ARGUMENTS=("$@"); - - local RESULT=${EXIT_SUCCESS}; - local TESTED_WITH_OPTIONS=0; - - for OPTION_SET in `echo ${OPTION_SETS} | tr ' ' '\n'`; - do - local TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); - - if ! test -f ${TEST_DATA_OPTION_FILE}; - then - continue - fi - - run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "${TEST_MODE}" "${OPTION_SET}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" ${ARGUMENTS[@]}; - RESULT=$?; - - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - TESTED_WITH_OPTIONS=1; - done - - if test ${RESULT} -eq ${EXIT_SUCCESS} && test ${TESTED_WITH_OPTIONS} -eq 0; - then - run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "${TEST_MODE}" "" "${TEST_EXECUTABLE}" "${INPUT_FILE}" ${ARGUMENTS[@]}; - RESULT=$?; - fi - return ${RESULT}; -} - -# Runs the test with options on the file entries in the test set directory. -# -# Note that this function is not intended to be directly invoked -# from outside the test runner script. -# -# Arguments: -# a string containing the path of the test set directory -# a string containing the description of the test -# a string containing the test mode -# a string containing the name of the test data option sets -# a string containing the path of the test executable -# an array containing the arguments for the test executable -# -# Returns: -# an integer containg the exit status of the test executable -# -run_test_on_test_set_with_options() -{ - local TEST_SET_DIRECTORY=$1; - local TEST_DESCRIPTION=$2; - local TEST_MODE=$3; - local OPTION_SETS=$4; - local TEST_EXECUTABLE=$5; - shift 5; - local ARGUMENTS=("$@"); - - local RESULT=${EXIT_SUCCESS}; - - # IFS="\n"; is not supported by all platforms. - IFS=" -"; - - if test -f "${TEST_SET_DIRECTORY}/files"; - then - for INPUT_FILE in `cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"`; - do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "${TEST_MODE}" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" ${ARGUMENTS[@]}; - RESULT=$?; - - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - else - for INPUT_FILE in `ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}`; - do - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "${TEST_MODE}" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" ${ARGUMENTS[@]}; - RESULT=$?; - - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - fi - IFS=${OLDIFS}; - - return ${RESULT}; -} - diff --git a/tests/test_tools.sh b/tests/test_tools.sh index 5500e59..121f1b8 100755 --- a/tests/test_tools.sh +++ b/tests/test_tools.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Tests tools functions and types. # -# Version: 20230410 +# Version: 20231007 EXIT_SUCCESS=0; EXIT_FAILURE=1; @@ -9,7 +9,7 @@ EXIT_IGNORE=77; TOOLS_TESTS="info_handle message_handle message_string output path_handle registry_file resource_file signal"; TOOLS_TESTS_WITH_INPUT=""; -OPTION_SETS=""; +OPTION_SETS=(); INPUT_GLOB="*"; @@ -78,47 +78,54 @@ run_test_with_input() local TEST_SET_DIRECTORY=$(get_test_set_directory "${TEST_PROFILE_DIRECTORY}" "${TEST_SET_INPUT_DIRECTORY}"); - local OLDIFS=${IFS}; - - # IFS="\n" is not supported by all platforms. - IFS=" -"; - if test -f "${TEST_SET_DIRECTORY}/files"; then - for INPUT_FILE in `cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"`; + IFS="" read -a INPUT_FILES <<< $(cat ${TEST_SET_DIRECTORY}/files | sed "s?^?${TEST_SET_INPUT_DIRECTORY}/?"); + else + IFS="" read -a INPUT_FILES <<< $(ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}); + fi + for INPUT_FILE in "${INPUT_FILES[@]}"; + do + OPTION_INPUT_FILE="${INPUT_FILE}"; + + if test "${OSTYPE}" = "msys"; + then + # A test executable built with MinGW expects a Windows path. + INPUT_FILE=`echo ${INPUT_FILE} | sed 's?/?\\\\?g'`; + fi + local TESTED_WITH_OPTIONS=0; + + for OPTION_SET in ${OPTION_SETS[@]}; do - if test "${OSTYPE}" = "msys"; - then - # A test executable built with MinGW expects a Windows path. - INPUT_FILE=`echo ${INPUT_FILE} | sed 's?/?\\\\?g'`; - fi - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}"; - RESULT=$?; + local TEST_DATA_OPTION_FILE=$(get_test_data_option_file "${TEST_SET_DIRECTORY}" "${OPTION_INPUT_FILE}" "${OPTION_SET}"); - if test ${RESULT} -ne ${EXIT_SUCCESS}; + if test -f ${TEST_DATA_OPTION_FILE}; then - break; + TESTED_WITH_OPTIONS=1; + + IFS=" " read -a OPTIONS <<< $(read_test_data_option_file "${TEST_SET_DIRECTORY}" "${INPUT_FILE}" "${OPTION_SET}"); + + run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SET}" "${TEST_EXECUTABLE}" "${INPUT_FILE}" "${OPTIONS[@]}"; + RESULT=$?; + + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi fi done - else - for INPUT_FILE in `ls -1d ${TEST_SET_INPUT_DIRECTORY}/${INPUT_GLOB}`; - do - if test "${OSTYPE}" = "msys"; - then - # A test executable built with MinGW expects a Windows path. - INPUT_FILE=`echo ${INPUT_FILE} | sed 's?/?\\\\?g'`; - fi - run_test_on_input_file_with_options "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "${OPTION_SETS}" "${TEST_EXECUTABLE}" "${INPUT_FILE}"; + + if test ${TESTED_WITH_OPTIONS} -eq 0; + then + run_test_on_input_file "${TEST_SET_DIRECTORY}" "${TEST_DESCRIPTION}" "default" "" "${TEST_EXECUTABLE}" "${INPUT_FILE}"; RESULT=$?; + fi - if test ${RESULT} -ne ${EXIT_SUCCESS}; - then - break; - fi - done - fi - IFS=${OLDIFS}; + if test ${RESULT} -ne ${EXIT_SUCCESS}; + then + break; + fi + done if test ${RESULT} -ne ${EXIT_SUCCESS}; then diff --git a/tox.ini b/tox.ini index df530a0..d24d91f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,20 @@ [tox] -envlist = py3{7,8,9,10,11} +envlist = py3{7,8,9,10,11,12} [testenv] usedevelop = True -allowlist_externals = ./setup.py pip_pre = True passenv = - CFLAGS - CPPFLAGS - INCLUDE - LDFLAGS - LIB + CFLAGS + CPPFLAGS + INCLUDE + LDFLAGS + LIB +deps = + build + setuptools + wheel commands = - ./setup.py bdist_wheel + python -m build --no-isolation --outdir=dist --wheel + python -m pip install --no-index --find-links=dist libevtx-python + python tests/runtests.py