diff options
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | debian/control | 4 | ||||
-rw-r--r-- | debian/libnghttp2-14.symbols | 14 | ||||
-rw-r--r-- | debian/patches/0001-Make-fetch-ocsp-response-use-python3.patch | 18 | ||||
-rw-r--r-- | debian/patches/0002-add-munit-explicitly.patch | 4100 | ||||
-rw-r--r-- | debian/patches/series | 2 |
6 files changed, 4123 insertions, 21 deletions
diff --git a/debian/changelog b/debian/changelog index 04038e8..2b2a512 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nghttp2 (1.60.0-1) unstable; urgency=medium + + * New upstream version 1.60.0 + + -- Tomasz Buchert <tomasz@debian.org> Fri, 08 Mar 2024 22:31:26 +0100 + nghttp2 (1.59.0-1) unstable; urgency=medium * New upstream version 1.59.0 diff --git a/debian/control b/debian/control index dae16c5..605d639 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Build-Depends: debhelper (>= 13), libssl-dev, libsystemd-dev, libxml2-dev, - pkg-config, + pkgconf, zlib1g-dev Build-Depends-Indep: python3-sphinx, python3-sphinx-rtd-theme Standards-Version: 4.6.2 @@ -26,7 +26,7 @@ Package: libnghttp2-dev Architecture: any Multi-Arch: same Section: libdevel -Depends: libnghttp2-14 (= ${binary:Version}), pkg-config, ${misc:Depends} +Depends: libnghttp2-14 (= ${binary:Version}), pkgconf, ${misc:Depends} Suggests: libnghttp2-doc Conflicts: libnghttp2-3-dev, libnghttp2-4-dev, libnghttp2-5-dev Replaces: libnghttp2-3-dev, libnghttp2-4-dev, libnghttp2-5-dev diff --git a/debian/libnghttp2-14.symbols b/debian/libnghttp2-14.symbols index ac18b42..9f680af 100644 --- a/debian/libnghttp2-14.symbols +++ b/debian/libnghttp2-14.symbols @@ -13,7 +13,9 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_hd_deflate_get_max_dynamic_table_size@Base 1.4.0 nghttp2_hd_deflate_get_num_table_entries@Base 1.4.0 nghttp2_hd_deflate_get_table_entry@Base 1.4.0 + nghttp2_hd_deflate_hd2@Base 1.60.0 nghttp2_hd_deflate_hd@Base 1.3.0 + nghttp2_hd_deflate_hd_vec2@Base 1.60.0 nghttp2_hd_deflate_hd_vec@Base 1.14.0 nghttp2_hd_deflate_new2@Base 1.3.0 nghttp2_hd_deflate_new@Base 1.3.0 @@ -26,6 +28,7 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_hd_inflate_get_table_entry@Base 1.4.0 nghttp2_hd_inflate_hd@Base 1.3.0 nghttp2_hd_inflate_hd2@Base 1.11.0 + nghttp2_hd_inflate_hd3@Base 1.60.0 nghttp2_hd_inflate_new2@Base 1.3.0 nghttp2_hd_inflate_new@Base 1.3.0 nghttp2_http2_strerror@Base 1.9.1 @@ -49,6 +52,7 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_option_set_server_fallback_rfc7540_priorities@Base 1.48.0 nghttp2_option_set_stream_reset_rate_limit@Base 1.57.0 nghttp2_option_set_user_recv_extension_type@Base 1.8.0 + nghttp2_pack_settings_payload2@Base 1.60.0 nghttp2_pack_settings_payload@Base 1.3.0 nghttp2_priority_spec_check_default@Base 1.3.0 nghttp2_priority_spec_default_init@Base 1.3.0 @@ -62,6 +66,7 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_session_callbacks_del@Base 1.3.0 nghttp2_session_callbacks_new@Base 1.3.0 nghttp2_session_callbacks_set_before_frame_send_callback@Base 1.3.0 + nghttp2_session_callbacks_set_data_source_read_length_callback2@Base 1.60.0 nghttp2_session_callbacks_set_data_source_read_length_callback@Base 1.3.0 nghttp2_session_callbacks_set_error_callback2@Base 1.28.0 nghttp2_session_callbacks_set_error_callback@Base 1.9.1 @@ -78,9 +83,13 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_session_callbacks_set_on_invalid_header_callback2@Base 1.14.0 nghttp2_session_callbacks_set_on_invalid_header_callback@Base 1.14.0 nghttp2_session_callbacks_set_on_stream_close_callback@Base 1.3.0 + nghttp2_session_callbacks_set_pack_extension_callback2@Base 1.60.0 nghttp2_session_callbacks_set_pack_extension_callback@Base 1.8.0 + nghttp2_session_callbacks_set_recv_callback2@Base 1.60.0 nghttp2_session_callbacks_set_recv_callback@Base 1.3.0 + nghttp2_session_callbacks_set_select_padding_callback2@Base 1.60.0 nghttp2_session_callbacks_set_select_padding_callback@Base 1.3.0 + nghttp2_session_callbacks_set_send_callback2@Base 1.60.0 nghttp2_session_callbacks_set_send_callback@Base 1.3.0 nghttp2_session_callbacks_set_send_data_callback@Base 1.3.0 nghttp2_session_callbacks_set_unpack_extension_callback@Base 1.8.0 @@ -117,7 +126,9 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_session_get_stream_remote_close@Base 1.3.0 nghttp2_session_get_stream_remote_window_size@Base 1.3.0 nghttp2_session_get_stream_user_data@Base 1.3.0 + nghttp2_session_mem_recv2@Base 1.60.0 nghttp2_session_mem_recv@Base 1.3.0 + nghttp2_session_mem_send2@Base 1.60.0 nghttp2_session_mem_send@Base 1.3.0 nghttp2_session_recv@Base 1.3.0 nghttp2_session_resume_data@Base 1.3.0 @@ -146,6 +157,7 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_stream_get_weight@Base 1.3.0 nghttp2_strerror@Base 1.3.0 nghttp2_submit_altsvc@Base 1.10.0 + nghttp2_submit_data2@Base 1.60.0 nghttp2_submit_data@Base 1.3.0 nghttp2_submit_extension@Base 1.8.0 nghttp2_submit_goaway@Base 1.3.0 @@ -155,7 +167,9 @@ libnghttp2.so.14 libnghttp2-14 #MINVER# nghttp2_submit_priority@Base 1.3.0 nghttp2_submit_priority_update@Base 1.48.0 nghttp2_submit_push_promise@Base 1.3.0 + nghttp2_submit_request2@Base 1.60.0 nghttp2_submit_request@Base 1.3.0 + nghttp2_submit_response2@Base 1.60.0 nghttp2_submit_response@Base 1.3.0 nghttp2_submit_rst_stream@Base 1.3.0 nghttp2_submit_settings@Base 1.3.0 diff --git a/debian/patches/0001-Make-fetch-ocsp-response-use-python3.patch b/debian/patches/0001-Make-fetch-ocsp-response-use-python3.patch deleted file mode 100644 index 319ed21..0000000 --- a/debian/patches/0001-Make-fetch-ocsp-response-use-python3.patch +++ /dev/null @@ -1,18 +0,0 @@ -From: Tomasz Buchert <tomasz@debian.org> -Date: Tue, 2 Jan 2018 11:09:26 +0100 -Subject: Make fetch-ocsp-response use python3 - ---- - script/fetch-ocsp-response | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/script/fetch-ocsp-response b/script/fetch-ocsp-response -index 0ff7461..185116b 100755 ---- a/script/fetch-ocsp-response -+++ b/script/fetch-ocsp-response -@@ -1,4 +1,4 @@ --#!/usr/bin/env python -+#!/usr/bin/env python3 - # -*- coding: utf-8 -*- - - # nghttp2 - HTTP/2 C Library diff --git a/debian/patches/0002-add-munit-explicitly.patch b/debian/patches/0002-add-munit-explicitly.patch new file mode 100644 index 0000000..effb221 --- /dev/null +++ b/debian/patches/0002-add-munit-explicitly.patch @@ -0,0 +1,4100 @@ +From: Tomasz Buchert <tomasz@debian.org> +Date: Fri, 29 Mar 2024 13:04:39 +0100 +Subject: add munit explicitly + +--- + tests/munit/.appveyor.yml | 34 + + tests/munit/.clang-format | 215 ++++ + tests/munit/.dir-locals.el | 2 + + tests/munit/.gitignore | 8 + + tests/munit/.travis.yml | 149 +++ + tests/munit/COPYING | 21 + + tests/munit/README.md | 54 + + tests/munit/example.c | 351 +++++++ + tests/munit/meson.build | 37 + + tests/munit/munit.c | 2457 ++++++++++++++++++++++++++++++++++++++++++++ + tests/munit/munit.h | 575 +++++++++++ + tests/munit/munitxx.h | 94 ++ + 12 files changed, 3997 insertions(+) + create mode 100644 tests/munit/.appveyor.yml + create mode 100644 tests/munit/.clang-format + create mode 100644 tests/munit/.dir-locals.el + create mode 100644 tests/munit/.gitignore + create mode 100644 tests/munit/.travis.yml + create mode 100644 tests/munit/COPYING + create mode 100644 tests/munit/README.md + create mode 100644 tests/munit/example.c + create mode 100644 tests/munit/meson.build + create mode 100644 tests/munit/munit.c + create mode 100644 tests/munit/munit.h + create mode 100644 tests/munit/munitxx.h + +diff --git a/tests/munit/.appveyor.yml b/tests/munit/.appveyor.yml +new file mode 100644 +index 0000000..5572092 +--- /dev/null ++++ b/tests/munit/.appveyor.yml +@@ -0,0 +1,34 @@ ++version: "{build}" ++ ++environment: ++ matrix: ++ - ARCHITECTURE: x64 ++ MSVC_VER: 14 ++ - ARCHITECTURE: x86 ++ MSVC_VER: 14 ++ - ARCHITECTURE: x64 ++ MSVC_VER: 12 ++ - ARCHITECTURE: x86 ++ MSVC_VER: 12 ++ - ARCHITECTURE: x86 ++ MSVC_VER: 11 ++ - ARCHITECTURE: x86 ++ MSVC_VER: 10 ++ - ARCHITECTURE: x86 ++ MSVC_VER: 9 ++ ++branches: ++ except: ++ - master ++ - /^(wip\/)?(travis|osx|mingw|ipp)(\-.+)?$/ ++ ++configuration: Debug ++ ++install: ++ ++before_build: ++ - call "C:\Program Files (x86)\Microsoft Visual Studio %MSVC_VER%.0\VC\vcvarsall.bat" %ARCHITECTURE% ++ ++build_script: cl.exe /W4 /WX /Feexample munit.c example.c ++ ++test_script: example.exe --color always +diff --git a/tests/munit/.clang-format b/tests/munit/.clang-format +new file mode 100644 +index 0000000..4aa455a +--- /dev/null ++++ b/tests/munit/.clang-format +@@ -0,0 +1,215 @@ ++--- ++Language: Cpp ++AccessModifierOffset: -2 ++AlignAfterOpenBracket: Align ++AlignArrayOfStructures: None ++AlignConsecutiveAssignments: ++ Enabled: false ++ AcrossEmptyLines: false ++ AcrossComments: false ++ AlignCompound: false ++ PadOperators: true ++AlignConsecutiveBitFields: ++ Enabled: false ++ AcrossEmptyLines: false ++ AcrossComments: false ++ AlignCompound: false ++ PadOperators: true ++AlignConsecutiveDeclarations: ++ Enabled: false ++ AcrossEmptyLines: false ++ AcrossComments: false ++ AlignCompound: false ++ PadOperators: true ++AlignConsecutiveMacros: ++ Enabled: false ++ AcrossEmptyLines: false ++ AcrossComments: false ++ AlignCompound: false ++ PadOperators: true ++AlignEscapedNewlines: Right ++AlignOperands: Align ++AlignTrailingComments: true ++AllowAllArgumentsOnNextLine: true ++AllowAllParametersOfDeclarationOnNextLine: true ++AllowShortEnumsOnASingleLine: true ++AllowShortBlocksOnASingleLine: Never ++AllowShortCaseLabelsOnASingleLine: false ++AllowShortFunctionsOnASingleLine: All ++AllowShortLambdasOnASingleLine: All ++AllowShortIfStatementsOnASingleLine: Never ++AllowShortLoopsOnASingleLine: false ++AlwaysBreakAfterDefinitionReturnType: None ++AlwaysBreakAfterReturnType: None ++AlwaysBreakBeforeMultilineStrings: false ++AlwaysBreakTemplateDeclarations: MultiLine ++AttributeMacros: ++ - __capability ++BinPackArguments: true ++BinPackParameters: true ++BraceWrapping: ++ AfterCaseLabel: false ++ AfterClass: false ++ AfterControlStatement: Never ++ AfterEnum: false ++ AfterFunction: false ++ AfterNamespace: false ++ AfterObjCDeclaration: false ++ AfterStruct: false ++ AfterUnion: false ++ AfterExternBlock: false ++ BeforeCatch: false ++ BeforeElse: false ++ BeforeLambdaBody: false ++ BeforeWhile: false ++ IndentBraces: false ++ SplitEmptyFunction: true ++ SplitEmptyRecord: true ++ SplitEmptyNamespace: true ++BreakBeforeBinaryOperators: None ++BreakBeforeConceptDeclarations: Always ++BreakBeforeBraces: Attach ++BreakBeforeInheritanceComma: false ++BreakInheritanceList: BeforeColon ++BreakBeforeTernaryOperators: true ++BreakConstructorInitializersBeforeComma: false ++BreakConstructorInitializers: BeforeColon ++BreakAfterJavaFieldAnnotations: false ++BreakStringLiterals: true ++ColumnLimit: 80 ++CommentPragmas: '^ IWYU pragma:' ++QualifierAlignment: Leave ++CompactNamespaces: false ++ConstructorInitializerIndentWidth: 4 ++ContinuationIndentWidth: 4 ++Cpp11BracedListStyle: true ++DeriveLineEnding: true ++DerivePointerAlignment: false ++DisableFormat: false ++EmptyLineAfterAccessModifier: Never ++EmptyLineBeforeAccessModifier: LogicalBlock ++ExperimentalAutoDetectBinPacking: false ++PackConstructorInitializers: NextLine ++BasedOnStyle: '' ++ConstructorInitializerAllOnOneLineOrOnePerLine: false ++AllowAllConstructorInitializersOnNextLine: true ++FixNamespaceComments: true ++ForEachMacros: ++ - foreach ++ - Q_FOREACH ++ - BOOST_FOREACH ++IfMacros: ++ - KJ_IF_MAYBE ++IncludeBlocks: Preserve ++IncludeCategories: ++ - Regex: '^"(llvm|llvm-c|clang|clang-c)/' ++ Priority: 2 ++ SortPriority: 0 ++ CaseSensitive: false ++ - Regex: '^(<|"(gtest|isl|json)/)' ++ Priority: 3 ++ SortPriority: 0 ++ CaseSensitive: false ++ - Regex: '.*' ++ Priority: 1 ++ SortPriority: 0 ++ CaseSensitive: false ++IncludeIsMainRegex: '$' ++IncludeIsMainSourceRegex: '' ++IndentAccessModifiers: false ++IndentCaseLabels: false ++IndentCaseBlocks: false ++IndentGotoLabels: true ++IndentPPDirectives: AfterHash ++IndentExternBlock: AfterExternBlock ++IndentRequiresClause: false ++IndentWidth: 2 ++IndentWrappedFunctionNames: false ++InsertBraces: false ++InsertTrailingCommas: None ++JavaScriptQuotes: Leave ++JavaScriptWrapImports: true ++KeepEmptyLinesAtTheStartOfBlocks: true ++LambdaBodyIndentation: Signature ++MacroBlockBegin: '' ++MacroBlockEnd: '' ++MaxEmptyLinesToKeep: 1 ++NamespaceIndentation: None ++ObjCBinPackProtocolList: Auto ++ObjCBlockIndentWidth: 2 ++ObjCBreakBeforeNestedBlockParam: true ++ObjCSpaceAfterProperty: false ++ObjCSpaceBeforeProtocolList: true ++PenaltyBreakAssignment: 2 ++PenaltyBreakBeforeFirstCallParameter: 19 ++PenaltyBreakComment: 300 ++PenaltyBreakFirstLessLess: 120 ++PenaltyBreakOpenParenthesis: 0 ++PenaltyBreakString: 1000 ++PenaltyBreakTemplateDeclaration: 10 ++PenaltyExcessCharacter: 1000000 ++PenaltyReturnTypeOnItsOwnLine: 60 ++PenaltyIndentedWhitespace: 0 ++PointerAlignment: Right ++PPIndentWidth: -1 ++ReferenceAlignment: Pointer ++ReflowComments: true ++RemoveBracesLLVM: false ++RequiresClausePosition: OwnLine ++SeparateDefinitionBlocks: Leave ++ShortNamespaceLines: 1 ++SortIncludes: Never ++SortJavaStaticImport: Before ++SortUsingDeclarations: true ++SpaceAfterCStyleCast: false ++SpaceAfterLogicalNot: false ++SpaceAfterTemplateKeyword: true ++SpaceBeforeAssignmentOperators: true ++SpaceBeforeCaseColon: false ++SpaceBeforeCpp11BracedList: false ++SpaceBeforeCtorInitializerColon: true ++SpaceBeforeInheritanceColon: true ++SpaceBeforeParens: ControlStatements ++SpaceBeforeParensOptions: ++ AfterControlStatements: true ++ AfterForeachMacros: true ++ AfterFunctionDefinitionName: false ++ AfterFunctionDeclarationName: false ++ AfterIfMacros: true ++ AfterOverloadedOperator: false ++ AfterRequiresInClause: false ++ AfterRequiresInExpression: false ++ BeforeNonEmptyParentheses: false ++SpaceAroundPointerQualifiers: Default ++SpaceBeforeRangeBasedForLoopColon: true ++SpaceInEmptyBlock: false ++SpaceInEmptyParentheses: false ++SpacesBeforeTrailingComments: 1 ++SpacesInAngles: Never ++SpacesInConditionalStatement: false ++SpacesInContainerLiterals: true ++SpacesInCStyleCastParentheses: false ++SpacesInLineCommentPrefix: ++ Minimum: 1 ++ Maximum: -1 ++SpacesInParentheses: false ++SpacesInSquareBrackets: false ++SpaceBeforeSquareBrackets: false ++BitFieldColonSpacing: Both ++Standard: Latest ++StatementAttributeLikeMacros: ++ - Q_EMIT ++StatementMacros: ++ - Q_UNUSED ++ - QT_REQUIRE_VERSION ++TabWidth: 8 ++UseCRLF: false ++UseTab: Never ++WhitespaceSensitiveMacros: ++ - STRINGIZE ++ - PP_STRINGIZE ++ - BOOST_PP_STRINGIZE ++ - NS_SWIFT_NAME ++ - CF_SWIFT_NAME ++... ++ +diff --git a/tests/munit/.dir-locals.el b/tests/munit/.dir-locals.el +new file mode 100644 +index 0000000..4cc5d84 +--- /dev/null ++++ b/tests/munit/.dir-locals.el +@@ -0,0 +1,2 @@ ++((nil . ((indent-tabs-mode . nil) ++ (c-basic-offset . 2)))) +diff --git a/tests/munit/.gitignore b/tests/munit/.gitignore +new file mode 100644 +index 0000000..6ad0b44 +--- /dev/null ++++ b/tests/munit/.gitignore +@@ -0,0 +1,8 @@ ++*~ ++.#* ++/*.o ++/example ++/*.exe ++/*.dll ++.dirstamp ++.deps +diff --git a/tests/munit/.travis.yml b/tests/munit/.travis.yml +new file mode 100644 +index 0000000..6f221a8 +--- /dev/null ++++ b/tests/munit/.travis.yml +@@ -0,0 +1,149 @@ ++language: c ++sudo: false ++dist: trusty ++branches: ++ except: ++ - /^(wip\/)?(appveyor|msvc|mingw|windows)(\-.+)?$/ ++ # https://github.com/travis-ci/travis-ci/issues/6632 ++ # - /^master$/ ++matrix: ++ include: ++ ### ++ ## Linux builds using various versions of GCC. ++ ### ++ - env: C_COMPILER=gcc-6 ++ addons: ++ apt: ++ sources: ++ - ubuntu-toolchain-r-test ++ packages: ++ - gcc-6 ++ - g++-6 ++ - env: C_COMPILER=gcc-5 ++ addons: ++ apt: ++ sources: ++ - ubuntu-toolchain-r-test ++ packages: ++ - gcc-5 ++ - g++-5 ++ # - env: C_COMPILER=gcc-4.9 ++ # addons: ++ # apt: ++ # sources: ++ # - ubuntu-toolchain-r-test ++ # packages: ++ # - gcc-4.9 ++ # - g++-4.9 ++ - env: C_COMPILER=gcc-4.8 ++ addons: ++ apt: ++ sources: ++ - ubuntu-toolchain-r-test ++ packages: ++ - gcc-4.8 ++ - g++-4.8 ++ # - env: C_COMPILER=gcc-4.7 ++ # addons: ++ # apt: ++ # sources: ++ # - ubuntu-toolchain-r-test ++ # packages: ++ # - gcc-4.7 ++ # - g++-4.7 ++ - env: C_COMPILER=gcc-4.6 ++ addons: ++ apt: ++ sources: ++ - ubuntu-toolchain-r-test ++ packages: ++ - gcc-4.6 ++ - g++-4.6 ++ # - os: linux ++ # env: C_COMPILER=gcc-4.5 ++ # addons: ++ # apt: ++ # sources: ++ # - ubuntu-toolchain-r-test ++ # packages: ++ # - gcc-4.5 ++ # - g++-4.5 ++ - env: C_COMPILER=gcc-4.4 ++ addons: ++ apt: ++ sources: ++ - ubuntu-toolchain-r-test ++ packages: ++ - gcc-4.4 ++ - g++-4.4 ++ ++ ### ++ ## clang on Linux ++ ### ++ - env: C_COMPILER=clang-3.9 ++ addons: ++ apt: ++ sources: ++ - llvm-toolchain-precise-3.9 ++ - ubuntu-toolchain-r-test ++ packages: ++ - clang-3.9 ++ # - env: C_COMPILER=clang-3.8 ++ # addons: ++ # apt: ++ # sources: ++ # - llvm-toolchain-precise-3.8 ++ # - ubuntu-toolchain-r-test ++ # packages: ++ # - clang-3.8 ++ - env: C_COMPILER=clang-3.7 ++ addons: ++ apt: ++ sources: ++ - llvm-toolchain-precise-3.7 ++ - ubuntu-toolchain-r-test ++ packages: ++ - clang-3.7 ++ # - env: C_COMPILER=clang-3.6 ++ # addons: ++ # apt: ++ # sources: ++ # - llvm-toolchain-precise-3.6 ++ # - ubuntu-toolchain-r-test ++ # packages: ++ # - clang-3.6 ++ - env: C_COMPILER=clang-3.5 ++ addons: ++ apt: ++ sources: ++ - llvm-toolchain-precise-3.5 ++ - ubuntu-toolchain-r-test ++ packages: ++ - clang-3.5 ++ ++ ### ++ ## PGI ++ ### ++ - env: C_COMPILER=pgcc OPENMP=y ++ ++ ### ++ ## OS X ++ ### ++ - os: osx ++ ++ ### ++ ## Meson ++ ### ++ - env: BUILD_SYSTEM=meson ++ ++before_install: ++- if [ -n "${C_COMPILER}" ]; then export CC="${C_COMPILER}"; fi ++- if [ "${C_COMPILER}" = "pgcc" ]; then wget -q -O /dev/stdout 'https://raw.githubusercontent.com/nemequ/pgi-travis/master/install-pgi.sh' | /bin/sh; fi ++- if [ "${BUILD_SYSTEM}" = "meson" ]; then wget -O /tmp/ninja-linux.zip $(curl -s https://api.github.com/repos/ninja-build/ninja/releases/latest | grep -oP 'https://github.com/ninja-build/ninja/releases/download/v[0-9\.]+/ninja-linux.zip') && unzip -q /tmp/ninja-linux.zip -d ~/bin && pyenv local 3.6 && pip3 install meson; fi ++ ++script: ++ - if [ "${BUILD_SYSTEM}" = "meson" ]; then meson build && ninja -Cbuild; else make CC="${CC}" AGGRESSIVE_WARNINGS=y EXTENSION="${EXTENSION}" OPENMP="${OPENMP}" ASAN="${ASAN}" UBSAN="${UBSAN}"; fi ++ - if [ "${BUILD_SYSTEM}" = "meson" ]; then ninja -Cbuild test; else make test; fi ++ ++notifications: ++ email: false +diff --git a/tests/munit/COPYING b/tests/munit/COPYING +new file mode 100644 +index 0000000..2991ac7 +--- /dev/null ++++ b/tests/munit/COPYING +@@ -0,0 +1,21 @@ ++µnit Testing Framework ++Copyright (c) 2013-2016 Evan Nemerson <evan@nemerson.com> ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be ++included in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ++LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +diff --git a/tests/munit/README.md b/tests/munit/README.md +new file mode 100644 +index 0000000..9f861f2 +--- /dev/null ++++ b/tests/munit/README.md +@@ -0,0 +1,54 @@ ++# µnit ++ ++µnit is a small but full-featured unit testing framework for C. It has ++no dependencies (beyond libc), is permissively licensed (MIT), and is ++easy to include into any project. ++ ++For more information, see ++[the µnit web site](https://nemequ.github.io/munit). ++ ++[![Build status](https://travis-ci.org/nemequ/munit.svg?branch=master)](https://travis-ci.org/nemequ/munit) ++[![Windows build status](https://ci.appveyor.com/api/projects/status/db515g5ifcwjohq7/branch/master?svg=true)](https://ci.appveyor.com/project/quixdb/munit/branch/master) ++ ++## Features ++ ++Features µnit currently includes include: ++ ++ * Handy assertion macros which make for nice error messages. ++ * Reproducible cross-platform random number generation, including ++ support for supplying a seed via CLI. ++ * Timing of both wall-clock and CPU time. ++ * Parameterized tests. ++ * Nested test suites. ++ * Flexible CLI. ++ * Forking ++ ([except on Windows](https://github.com/nemequ/munit/issues/2)). ++ * Hiding output of successful tests. ++ ++Features µnit does not currently include, but some day may include ++(a.k.a., if you file a PR…), include: ++ ++ * [TAP](http://testanything.org/) support; feel free to discuss in ++ [issue #1](https://github.com/nemequ/munit/issues/1) ++ ++### Include into your project with meson ++ ++In your `subprojects` folder put a `munit.wrap` file containing: ++ ++``` ++[wrap-git] ++directory=munit ++url=https://github.com/nemequ/munit/ ++revision=head ++``` ++ ++Then you can use a subproject fallback when you include munit as a ++dependency to your project: `dependency('munit', fallback: ['munit', 'munit_dep'])` ++ ++## Documentation ++ ++See [the µnit web site](https://nemequ.github.io/munit). ++ ++Additionally, there is a heavily-commented ++[example.c](https://github.com/nemequ/munit/blob/master/example.c) in ++the repository. +diff --git a/tests/munit/example.c b/tests/munit/example.c +new file mode 100644 +index 0000000..d238d09 +--- /dev/null ++++ b/tests/munit/example.c +@@ -0,0 +1,351 @@ ++/* Example file for using µnit. ++ * ++ * µnit is MIT-licensed, but for this file and this file alone: ++ * ++ * To the extent possible under law, the author(s) of this file have ++ * waived all copyright and related or neighboring rights to this ++ * work. See <https://creativecommons.org/publicdomain/zero/1.0/> for ++ * details. ++ *********************************************************************/ ++ ++#include "munit.h" ++ ++/* This is just to disable an MSVC warning about conditional ++ * expressions being constant, which you shouldn't have to do for your ++ * code. It's only here because we want to be able to do silly things ++ * like assert that 0 != 1 for our demo. */ ++#if defined(_MSC_VER) ++#pragma warning(disable: 4127) ++#endif ++ ++/* Tests are functions that return void, and take a single void* ++ * parameter. We'll get to what that parameter is later. */ ++static MunitResult ++test_compare(const MunitParameter params[], void* data) { ++ /* We'll use these later */ ++ const unsigned char val_uchar = 'b'; ++ const short val_short = 1729; ++ double pi = 3.141592654; ++ char* stewardesses = "stewardesses"; ++ char* most_fun_word_to_type; ++ ++ /* These are just to silence compiler warnings about the parameters ++ * being unused. */ ++ (void) params; ++ (void) data; ++ ++ /* Let's start with the basics. */ ++ munit_assert(0 != 1); ++ ++ /* There is also the more verbose, though slightly more descriptive ++ munit_assert_true/false: */ ++ munit_assert_false(0); ++ ++ /* You can also call munit_error and munit_errorf yourself. We ++ * won't do it is used to indicate a failure, but here is what it ++ * would look like: */ ++ /* munit_error("FAIL"); */ ++ /* munit_errorf("Goodbye, cruel %s", "world"); */ ++ ++ /* There are macros for comparing lots of types. */ ++ munit_assert_char('a', ==, 'a'); ++ ++ /* Sure, you could just assert('a' == 'a'), but if you did that, a ++ * failed assertion would just say something like "assertion failed: ++ * val_uchar == 'b'". µnit will tell you the actual values, so a ++ * failure here would result in something like "assertion failed: ++ * val_uchar == 'b' ('X' == 'b')." */ ++ munit_assert_uchar(val_uchar, ==, 'b'); ++ ++ /* Obviously we can handle values larger than 'char' and 'uchar'. ++ * There are versions for char, short, int, long, long long, ++ * int8/16/32/64_t, as well as the unsigned versions of them all. */ ++ munit_assert_short(42, <, val_short); ++ ++ /* There is also support for size_t. ++ * ++ * The longest word in English without repeating any letters is ++ * "uncopyrightables", which has uncopyrightable (and ++ * dermatoglyphics, which is the study of fingerprints) beat by a ++ * character */ ++ munit_assert_size(strlen("uncopyrightables"), >, strlen("dermatoglyphics")); ++ ++ /* Of course there is also support for doubles and floats. */ ++ munit_assert_double(pi, ==, 3.141592654); ++ ++ /* If you want to compare two doubles for equality, you might want ++ * to consider using munit_assert_double_equal. It compares two ++ * doubles for equality within a precison of 1.0 x 10^-(precision). ++ * Note that precision (the third argument to the macro) needs to be ++ * fully evaluated to an integer by the preprocessor so µnit doesn't ++ * have to depend pow, which is often in libm not libc. */ ++ munit_assert_double_equal(3.141592654, 3.141592653589793, 9); ++ ++ /* And if you want to check strings for equality (or inequality), ++ * there is munit_assert_string_equal/not_equal. ++ * ++ * "stewardesses" is the longest word you can type on a QWERTY ++ * keyboard with only one hand, which makes it loads of fun to type. ++ * If I'm going to have to type a string repeatedly, let's make it a ++ * good one! */ ++ munit_assert_string_equal(stewardesses, "stewardesses"); ++ ++ /* A personal favorite macro which is fantastic if you're working ++ * with binary data, is the one which naïvely checks two blobs of ++ * memory for equality. If this fails it will tell you the offset ++ * of the first differing byte. */ ++ munit_assert_memory_equal(7, stewardesses, "steward"); ++ ++ /* You can also make sure that two blobs differ *somewhere*: */ ++ munit_assert_memory_not_equal(8, stewardesses, "steward"); ++ ++ /* There are equal/not_equal macros for pointers, too: */ ++ most_fun_word_to_type = stewardesses; ++ munit_assert_ptr_equal(most_fun_word_to_type, stewardesses); ++ ++ /* And null/not_null */ ++ munit_assert_null(NULL); ++ munit_assert_not_null(most_fun_word_to_type); ++ ++ /* Lets verify that the data parameter is what we expected. We'll ++ * see where this comes from in a bit. ++ * ++ * Note that the casting isn't usually required; if you give this ++ * function a real pointer (instead of a number like 0xdeadbeef) it ++ * would work as expected. */ ++ munit_assert_ptr_equal(data, (void*)(uintptr_t)0xdeadbeef); ++ ++ return MUNIT_OK; ++} ++ ++static MunitResult ++test_rand(const MunitParameter params[], void* user_data) { ++ int random_int; ++ double random_dbl; ++ munit_uint8_t data[5]; ++ ++ (void) params; ++ (void) user_data; ++ ++ /* One thing missing from a lot of unit testing frameworks is a ++ * random number generator. You can't just use srand/rand because ++ * the implementation varies across different platforms, and it's ++ * important to be able to look at the seed used in a failing test ++ * to see if you can reproduce it. Some randomness is a fantastic ++ * thing to have in your tests, I don't know why more people don't ++ * do it... ++ * ++ * µnit's PRNG is re-seeded with the same value for each iteration ++ * of each test. The seed is retrieved from the MUNIT_SEED ++ * envirnment variable or, if none is provided, one will be ++ * (pseudo-)randomly generated. */ ++ ++ /* If you need an integer in a given range */ ++ random_int = munit_rand_int_range(128, 4096); ++ munit_assert_int(random_int, >=, 128); ++ munit_assert_int(random_int, <=, 4096); ++ ++ /* Or maybe you want a double, between 0 and 1: */ ++ random_dbl = munit_rand_double(); ++ munit_assert_double(random_dbl, >=, 0.0); ++ munit_assert_double(random_dbl, <=, 1.0); ++ ++ /* Of course, you want to be able to reproduce bugs discovered ++ * during testing, so every time the tests are run they print the ++ * random seed used. When you want to reproduce a result, just put ++ * that random seed in the MUNIT_SEED environment variable; it even ++ * works on different platforms. ++ * ++ * If you want this to pass, use 0xdeadbeef as the random seed and ++ * uncomment the next line of code. Note that the PRNG is not ++ * re-seeded between iterations of the same test, so this will only ++ * work on the first iteration. */ ++ /* munit_assert_uint32(munit_rand_uint32(), ==, 1306447409); */ ++ ++ /* You can also get blobs of random memory: */ ++ munit_rand_memory(sizeof(data), data); ++ ++ return MUNIT_OK; ++} ++ ++/* This test case shows how to accept parameters. We'll see how to ++ * specify them soon. ++ * ++ * By default, every possible variation of a parameterized test is ++ * run, but you can specify parameters manually if you want to only ++ * run specific test(s), or you can pass the --single argument to the ++ * CLI to have the harness simply choose one variation at random ++ * instead of running them all. */ ++static MunitResult ++test_parameters(const MunitParameter params[], void* user_data) { ++ const char* foo; ++ const char* bar; ++ ++ (void) user_data; ++ ++ /* The "foo" parameter is specified as one of the following values: ++ * "one", "two", or "three". */ ++ foo = munit_parameters_get(params, "foo"); ++ /* Similarly, "bar" is one of "four", "five", or "six". */ ++ bar = munit_parameters_get(params, "bar"); ++ /* "baz" is a bit more complicated. We don't actually specify a ++ * list of valid values, so by default NULL is passed. However, the ++ * CLI will accept any value. This is a good way to have a value ++ * that is usually selected randomly by the test, but can be ++ * overridden on the command line if desired. */ ++ /* const char* baz = munit_parameters_get(params, "baz"); */ ++ ++ /* Notice that we're returning MUNIT_FAIL instead of writing an ++ * error message. Error messages are generally preferable, since ++ * they make it easier to diagnose the issue, but this is an ++ * option. ++ * ++ * Possible values are: ++ * - MUNIT_OK: Sucess ++ * - MUNIT_FAIL: Failure ++ * - MUNIT_SKIP: The test was skipped; usually this happens when a ++ * particular feature isn't in use. For example, if you're ++ * writing a test which uses a Wayland-only feature, but your ++ * application is running on X11. ++ * - MUNIT_ERROR: The test failed, but not because of anything you ++ * wanted to test. For example, maybe your test downloads a ++ * remote resource and tries to parse it, but the network was ++ * down. ++ */ ++ ++ if (strcmp(foo, "one") != 0 && ++ strcmp(foo, "two") != 0 && ++ strcmp(foo, "three") != 0) ++ return MUNIT_FAIL; ++ ++ if (strcmp(bar, "red") != 0 && ++ strcmp(bar, "green") != 0 && ++ strcmp(bar, "blue") != 0) ++ return MUNIT_FAIL; ++ ++ return MUNIT_OK; ++} ++ ++/* The setup function, if you provide one, for a test will be run ++ * before the test, and the return value will be passed as the sole ++ * parameter to the test function. */ ++static void* ++test_compare_setup(const MunitParameter params[], void* user_data) { ++ (void) params; ++ ++ munit_assert_string_equal(user_data, "µnit"); ++ return (void*) (uintptr_t) 0xdeadbeef; ++} ++ ++/* To clean up after a test, you can use a tear down function. The ++ * fixture argument is the value returned by the setup function ++ * above. */ ++static void ++test_compare_tear_down(void* fixture) { ++ munit_assert_ptr_equal(fixture, (void*)(uintptr_t)0xdeadbeef); ++} ++ ++static char* foo_params[] = { ++ (char*) "one", (char*) "two", (char*) "three", NULL ++}; ++ ++static char* bar_params[] = { ++ (char*) "red", (char*) "green", (char*) "blue", NULL ++}; ++ ++static MunitParameterEnum test_params[] = { ++ { (char*) "foo", foo_params }, ++ { (char*) "bar", bar_params }, ++ { (char*) "baz", NULL }, ++ { NULL, NULL }, ++}; ++ ++/* Creating a test suite is pretty simple. First, you'll need an ++ * array of tests: */ ++static MunitTest test_suite_tests[] = { ++ { ++ /* The name is just a unique human-readable way to identify the ++ * test. You can use it to run a specific test if you want, but ++ * usually it's mostly decorative. */ ++ (char*) "/example/compare", ++ /* You probably won't be surprised to learn that the tests are ++ * functions. */ ++ test_compare, ++ /* If you want, you can supply a function to set up a fixture. If ++ * you supply NULL, the user_data parameter from munit_suite_main ++ * will be used directly. If, however, you provide a callback ++ * here the user_data parameter will be passed to this callback, ++ * and the return value from this callback will be passed to the ++ * test function. ++ * ++ * For our example we don't really need a fixture, but lets ++ * provide one anyways. */ ++ test_compare_setup, ++ /* If you passed a callback for the fixture setup function, you ++ * may want to pass a corresponding callback here to reverse the ++ * operation. */ ++ test_compare_tear_down, ++ /* Finally, there is a bitmask for options you can pass here. You ++ * can provide either MUNIT_TEST_OPTION_NONE or 0 here to use the ++ * defaults. */ ++ MUNIT_TEST_OPTION_NONE, ++ NULL ++ }, ++ /* Usually this is written in a much more compact format; all these ++ * comments kind of ruin that, though. Here is how you'll usually ++ * see entries written: */ ++ { (char*) "/example/rand", test_rand, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, ++ /* To tell the test runner when the array is over, just add a NULL ++ * entry at the end. */ ++ { (char*) "/example/parameters", test_parameters, NULL, NULL, MUNIT_TEST_OPTION_NONE, test_params }, ++ { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } ++}; ++ ++/* If you wanted to have your test suite run other test suites you ++ * could declare an array of them. Of course each sub-suite can ++ * contain more suites, etc. */ ++/* static const MunitSuite other_suites[] = { */ ++/* { "/second", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE }, */ ++/* { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } */ ++/* }; */ ++ ++/* Now we'll actually declare the test suite. You could do this in ++ * the main function, or on the heap, or whatever you want. */ ++static const MunitSuite test_suite = { ++ /* This string will be prepended to all test names in this suite; ++ * for example, "/example/rand" will become "/µnit/example/rand". ++ * Note that, while it doesn't really matter for the top-level ++ * suite, NULL signal the end of an array of tests; you should use ++ * an empty string ("") instead. */ ++ (char*) "", ++ /* The first parameter is the array of test suites. */ ++ test_suite_tests, ++ /* In addition to containing test cases, suites can contain other ++ * test suites. This isn't necessary in this example, but it can be ++ * a great help to projects with lots of tests by making it easier ++ * to spread the tests across many files. This is where you would ++ * put "other_suites" (which is commented out above). */ ++ NULL, ++ /* An interesting feature of µnit is that it supports automatically ++ * running multiple iterations of the tests. This is usually only ++ * interesting if you make use of the PRNG to randomize your tests ++ * cases a bit, or if you are doing performance testing and want to ++ * average multiple runs. 0 is an alias for 1. */ ++ 1, ++ /* Just like MUNIT_TEST_OPTION_NONE, you can provide ++ * MUNIT_SUITE_OPTION_NONE or 0 to use the default settings. */ ++ MUNIT_SUITE_OPTION_NONE ++}; ++ ++/* This is only necessary for EXIT_SUCCESS and EXIT_FAILURE, which you ++ * *should* be using but probably aren't (no, zero and non-zero don't ++ * always mean success and failure). I guess my point is that nothing ++ * about µnit requires it. */ ++#include <stdlib.h> ++ ++int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) { ++ /* Finally, we'll actually run our test suite! That second argument ++ * is the user_data parameter which will be passed either to the ++ * test or (if provided) the fixture setup function. */ ++ return munit_suite_main(&test_suite, (void*) "µnit", argc, argv); ++} +diff --git a/tests/munit/meson.build b/tests/munit/meson.build +new file mode 100644 +index 0000000..c15b405 +--- /dev/null ++++ b/tests/munit/meson.build +@@ -0,0 +1,37 @@ ++project('munit', 'c') ++ ++conf_data = configuration_data() ++conf_data.set('version', '0.2.0') ++ ++add_project_arguments('-std=c99', language : 'c') ++ ++cc = meson.get_compiler('c') ++ ++root_include = include_directories('.') ++ ++munit = library('munit', ++ ['munit.c'], ++ install: meson.is_subproject()) ++ ++if meson.is_subproject() ++ munit_dep = declare_dependency( ++ include_directories : root_include, ++ link_with : munit) ++else ++ # standalone install ++ install_headers('munit.h') ++ ++ pkg = import('pkgconfig') ++ pkg.generate(name: 'munit', ++ description: 'µnit Testing Library for C', ++ version: conf_data.get('version'), ++ libraries: munit) ++ ++ # compile the demo project ++ munit_example_src = files('example.c') ++ munit_example = executable('munit_example', munit_example_src, ++ include_directories: root_include, ++ link_with: munit) ++ ++ test('munit example test', munit_example) ++endif +diff --git a/tests/munit/munit.c b/tests/munit/munit.c +new file mode 100644 +index 0000000..d6a0ec6 +--- /dev/null ++++ b/tests/munit/munit.c +@@ -0,0 +1,2457 @@ ++/* Copyright (c) 2013-2018 Evan Nemerson <evan@nemerson.com> ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++/*** Configuration ***/ ++ ++/* This is just where the output from the test goes. It's really just ++ * meant to let you choose stdout or stderr, but if anyone really want ++ * to direct it to a file let me know, it would be fairly easy to ++ * support. */ ++#if !defined(MUNIT_OUTPUT_FILE) ++# define MUNIT_OUTPUT_FILE stdout ++#endif ++ ++/* This is a bit more useful; it tells µnit how to format the seconds in ++ * timed tests. If your tests run for longer you might want to reduce ++ * it, and if your computer is really fast and your tests are tiny you ++ * can increase it. */ ++#if !defined(MUNIT_TEST_TIME_FORMAT) ++# define MUNIT_TEST_TIME_FORMAT "0.8f" ++#endif ++ ++/* If you have long test names you might want to consider bumping ++ * this. The result information takes 43 characters. */ ++#if !defined(MUNIT_TEST_NAME_LEN) ++# define MUNIT_TEST_NAME_LEN 37 ++#endif ++ ++/* If you don't like the timing information, you can disable it by ++ * defining MUNIT_DISABLE_TIMING. */ ++#if !defined(MUNIT_DISABLE_TIMING) ++# define MUNIT_ENABLE_TIMING ++#endif ++ ++/*** End configuration ***/ ++ ++#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE < 200809L) ++# undef _POSIX_C_SOURCE ++#endif ++#if !defined(_POSIX_C_SOURCE) ++# define _POSIX_C_SOURCE 200809L ++#endif ++ ++/* Solaris freaks out if you try to use a POSIX or SUS standard without ++ * the "right" C standard. */ ++#if defined(_XOPEN_SOURCE) ++# undef _XOPEN_SOURCE ++#endif ++ ++#if defined(__STDC_VERSION__) ++# if __STDC_VERSION__ >= 201112L ++# define _XOPEN_SOURCE 700 ++# elif __STDC_VERSION__ >= 199901L ++# define _XOPEN_SOURCE 600 ++# endif ++#endif ++ ++/* Because, according to Microsoft, POSIX is deprecated. You've got ++ * to appreciate the chutzpah. */ ++#if defined(_MSC_VER) && !defined(_CRT_NONSTDC_NO_DEPRECATE) ++# define _CRT_NONSTDC_NO_DEPRECATE ++#endif ++ ++#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) ++# include <stdbool.h> ++#elif defined(_WIN32) ++/* https://msdn.microsoft.com/en-us/library/tf4dy80a.aspx */ ++#endif ++ ++#include <limits.h> ++#include <time.h> ++#include <errno.h> ++#include <string.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <stdarg.h> ++#include <setjmp.h> ++ ++#if !defined(MUNIT_NO_NL_LANGINFO) && !defined(_WIN32) ++# define MUNIT_NL_LANGINFO ++# include <locale.h> ++# include <langinfo.h> ++# include <strings.h> ++#endif ++ ++#if !defined(_WIN32) ++# include <unistd.h> ++# include <sys/types.h> ++# include <sys/wait.h> ++#else ++# include <windows.h> ++# include <io.h> ++# include <fcntl.h> ++# if !defined(STDERR_FILENO) ++# define STDERR_FILENO _fileno(stderr) ++# endif ++#endif ++ ++#include "munit.h" ++ ++#define MUNIT_STRINGIFY(x) #x ++#define MUNIT_XSTRINGIFY(x) MUNIT_STRINGIFY(x) ++ ++#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || \ ++ defined(__IBMCPP__) ++# define MUNIT_THREAD_LOCAL __thread ++#elif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) || \ ++ defined(_Thread_local) ++# define MUNIT_THREAD_LOCAL _Thread_local ++#elif defined(_WIN32) ++# define MUNIT_THREAD_LOCAL __declspec(thread) ++#endif ++ ++/* MSVC 12.0 will emit a warning at /W4 for code like 'do { ... } ++ * while (0)', or 'do { ... } while (1)'. I'm pretty sure nobody ++ * at Microsoft compiles with /W4. */ ++#if defined(_MSC_VER) && (_MSC_VER <= 1800) ++# pragma warning(disable : 4127) ++#endif ++ ++#if defined(_WIN32) || defined(__EMSCRIPTEN__) ++# define MUNIT_NO_FORK ++#endif ++ ++#if defined(__EMSCRIPTEN__) ++# define MUNIT_NO_BUFFER ++#endif ++ ++/*** Logging ***/ ++ ++static MunitLogLevel munit_log_level_visible = MUNIT_LOG_INFO; ++static MunitLogLevel munit_log_level_fatal = MUNIT_LOG_ERROR; ++ ++#if defined(MUNIT_THREAD_LOCAL) ++static MUNIT_THREAD_LOCAL munit_bool munit_error_jmp_buf_valid = 0; ++static MUNIT_THREAD_LOCAL jmp_buf munit_error_jmp_buf; ++#endif ++ ++/* At certain warning levels, mingw will trigger warnings about ++ * suggesting the format attribute, which we've explicity *not* set ++ * because it will then choke on our attempts to use the MS-specific ++ * I64 modifier for size_t (which we have to use since MSVC doesn't ++ * support the C99 z modifier). */ ++ ++#if defined(__MINGW32__) || defined(__MINGW64__) ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wsuggest-attribute=format" ++#endif ++ ++MUNIT_PRINTF(5, 0) ++static void munit_logf_exv(MunitLogLevel level, FILE *fp, const char *filename, ++ int line, const char *format, va_list ap) { ++ if (level < munit_log_level_visible) ++ return; ++ ++ switch (level) { ++ case MUNIT_LOG_DEBUG: ++ fputs("Debug", fp); ++ break; ++ case MUNIT_LOG_INFO: ++ fputs("Info", fp); ++ break; ++ case MUNIT_LOG_WARNING: ++ fputs("Warning", fp); ++ break; ++ case MUNIT_LOG_ERROR: ++ fputs("Error", fp); ++ break; ++ default: ++ munit_logf_ex(MUNIT_LOG_ERROR, filename, line, "Invalid log level (%d)", ++ level); ++ return; ++ } ++ ++ fputs(": ", fp); ++ if (filename != NULL) ++ fprintf(fp, "%s:%d: ", filename, line); ++ vfprintf(fp, format, ap); ++ fputc('\n', fp); ++} ++ ++MUNIT_PRINTF(3, 4) ++static void munit_logf_internal(MunitLogLevel level, FILE *fp, ++ const char *format, ...) { ++ va_list ap; ++ ++ va_start(ap, format); ++ munit_logf_exv(level, fp, NULL, 0, format, ap); ++ va_end(ap); ++} ++ ++static void munit_log_internal(MunitLogLevel level, FILE *fp, ++ const char *message) { ++ munit_logf_internal(level, fp, "%s", message); ++} ++ ++void munit_logf_ex(MunitLogLevel level, const char *filename, int line, ++ const char *format, ...) { ++ va_list ap; ++ ++ va_start(ap, format); ++ munit_logf_exv(level, stderr, filename, line, format, ap); ++ va_end(ap); ++ ++ if (level >= munit_log_level_fatal) { ++#if defined(MUNIT_THREAD_LOCAL) ++ if (munit_error_jmp_buf_valid) ++ longjmp(munit_error_jmp_buf, 1); ++#endif ++ abort(); ++ } ++} ++ ++void munit_errorf_ex(const char *filename, int line, const char *format, ...) { ++ va_list ap; ++ ++ va_start(ap, format); ++ munit_logf_exv(MUNIT_LOG_ERROR, stderr, filename, line, format, ap); ++ va_end(ap); ++ ++#if defined(MUNIT_THREAD_LOCAL) ++ if (munit_error_jmp_buf_valid) ++ longjmp(munit_error_jmp_buf, 1); ++#endif ++ abort(); ++} ++ ++#if defined(__MINGW32__) || defined(__MINGW64__) ++# pragma GCC diagnostic pop ++#endif ++ ++#if !defined(MUNIT_STRERROR_LEN) ++# define MUNIT_STRERROR_LEN 80 ++#endif ++ ++static void munit_log_errno(MunitLogLevel level, FILE *fp, const char *msg) { ++#if defined(MUNIT_NO_STRERROR_R) || \ ++ (defined(__MINGW32__) && !defined(MINGW_HAS_SECURE_API)) ++ munit_logf_internal(level, fp, "%s: %s (%d)", msg, strerror(errno), errno); ++#else ++ char munit_error_str[MUNIT_STRERROR_LEN]; ++ munit_error_str[0] = '\0'; ++ ++# if !defined(_WIN32) ++ strerror_r(errno, munit_error_str, MUNIT_STRERROR_LEN); ++# else ++ strerror_s(munit_error_str, MUNIT_STRERROR_LEN, errno); ++# endif ++ ++ munit_logf_internal(level, fp, "%s: %s (%d)", msg, munit_error_str, errno); ++#endif ++} ++ ++/*** Memory allocation ***/ ++ ++void *munit_malloc_ex(const char *filename, int line, size_t size) { ++ void *ptr; ++ ++ if (size == 0) ++ return NULL; ++ ++ ptr = calloc(1, size); ++ if (MUNIT_UNLIKELY(ptr == NULL)) { ++ munit_logf_ex(MUNIT_LOG_ERROR, filename, line, ++ "Failed to allocate %" MUNIT_SIZE_MODIFIER "u bytes.", size); ++ } ++ ++ return ptr; ++} ++ ++/*** Timer code ***/ ++ ++#if defined(MUNIT_ENABLE_TIMING) ++ ++# define psnip_uint64_t munit_uint64_t ++# define psnip_uint32_t munit_uint32_t ++ ++/* Code copied from portable-snippets ++ * <https://github.com/nemequ/portable-snippets/>. If you need to ++ * change something, please do it there so we can keep the code in ++ * sync. */ ++ ++/* Clocks (v1) ++ * Portable Snippets - https://gitub.com/nemequ/portable-snippets ++ * Created by Evan Nemerson <evan@nemerson.com> ++ * ++ * To the extent possible under law, the authors have waived all ++ * copyright and related or neighboring rights to this code. For ++ * details, see the Creative Commons Zero 1.0 Universal license at ++ * https://creativecommons.org/publicdomain/zero/1.0/ ++ */ ++ ++# if !defined(PSNIP_CLOCK_H) ++# define PSNIP_CLOCK_H ++ ++# if !defined(psnip_uint64_t) ++# include "../exact-int/exact-int.h" ++# endif ++ ++# if !defined(PSNIP_CLOCK_STATIC_INLINE) ++# if defined(__GNUC__) ++# define PSNIP_CLOCK__COMPILER_ATTRIBUTES __attribute__((__unused__)) ++# else ++# define PSNIP_CLOCK__COMPILER_ATTRIBUTES ++# endif ++ ++# define PSNIP_CLOCK__FUNCTION PSNIP_CLOCK__COMPILER_ATTRIBUTES static ++# endif ++ ++enum PsnipClockType { ++ /* This clock provides the current time, in units since 1970-01-01 ++ * 00:00:00 UTC not including leap seconds. In other words, UNIX ++ * time. Keep in mind that this clock doesn't account for leap ++ * seconds, and can go backwards (think NTP adjustments). */ ++ PSNIP_CLOCK_TYPE_WALL = 1, ++ /* The CPU time is a clock which increases only when the current ++ * process is active (i.e., it doesn't increment while blocking on ++ * I/O). */ ++ PSNIP_CLOCK_TYPE_CPU = 2, ++ /* Monotonic time is always running (unlike CPU time), but it only ++ ever moves forward unless you reboot the system. Things like NTP ++ adjustments have no effect on this clock. */ ++ PSNIP_CLOCK_TYPE_MONOTONIC = 3 ++}; ++ ++struct PsnipClockTimespec { ++ psnip_uint64_t seconds; ++ psnip_uint64_t nanoseconds; ++}; ++ ++/* Methods we support: */ ++ ++# define PSNIP_CLOCK_METHOD_CLOCK_GETTIME 1 ++# define PSNIP_CLOCK_METHOD_TIME 2 ++# define PSNIP_CLOCK_METHOD_GETTIMEOFDAY 3 ++# define PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER 4 ++# define PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME 5 ++# define PSNIP_CLOCK_METHOD_CLOCK 6 ++# define PSNIP_CLOCK_METHOD_GETPROCESSTIMES 7 ++# define PSNIP_CLOCK_METHOD_GETRUSAGE 8 ++# define PSNIP_CLOCK_METHOD_GETSYSTEMTIMEPRECISEASFILETIME 9 ++# define PSNIP_CLOCK_METHOD_GETTICKCOUNT64 10 ++ ++# include <assert.h> ++ ++# if defined(HEDLEY_UNREACHABLE) ++# define PSNIP_CLOCK_UNREACHABLE() HEDLEY_UNREACHABLE() ++# else ++# define PSNIP_CLOCK_UNREACHABLE() assert(0) ++# endif ++ ++/* Choose an implementation */ ++ ++/* #undef PSNIP_CLOCK_WALL_METHOD */ ++/* #undef PSNIP_CLOCK_CPU_METHOD */ ++/* #undef PSNIP_CLOCK_MONOTONIC_METHOD */ ++ ++/* We want to be able to detect the libc implementation, so we include ++ <limits.h> (<features.h> isn't available everywhere). */ ++ ++# if defined(__unix__) || defined(__unix) || defined(__linux__) ++# include <limits.h> ++# include <unistd.h> ++# endif ++ ++# if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) ++/* These are known to work without librt. If you know of others ++ * please let us know so we can add them. */ ++# if (defined(__GLIBC__) && \ ++ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 17))) || \ ++ (defined(__FreeBSD__)) ++# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME ++# elif !defined(PSNIP_CLOCK_NO_LIBRT) ++# define PSNIP_CLOCK_HAVE_CLOCK_GETTIME ++# endif ++# endif ++ ++# if defined(_WIN32) ++# if !defined(PSNIP_CLOCK_CPU_METHOD) ++# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_GETPROCESSTIMES ++# endif ++# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) ++# define PSNIP_CLOCK_MONOTONIC_METHOD \ ++ PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER ++# endif ++# endif ++ ++# if defined(__MACH__) && !defined(__gnu_hurd__) ++# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) ++# define PSNIP_CLOCK_MONOTONIC_METHOD \ ++ PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME ++# endif ++# endif ++ ++# if defined(PSNIP_CLOCK_HAVE_CLOCK_GETTIME) ++# include <time.h> ++# if !defined(PSNIP_CLOCK_WALL_METHOD) ++# if defined(CLOCK_REALTIME_PRECISE) ++# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME_PRECISE ++# elif !defined(__sun) ++# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_WALL CLOCK_REALTIME ++# endif ++# endif ++# if !defined(PSNIP_CLOCK_CPU_METHOD) ++# if defined(_POSIX_CPUTIME) || defined(CLOCK_PROCESS_CPUTIME_ID) ++# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_PROCESS_CPUTIME_ID ++# elif defined(CLOCK_VIRTUAL) ++# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_CPU CLOCK_VIRTUAL ++# endif ++# endif ++# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) ++# if defined(CLOCK_MONOTONIC_RAW) ++# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC ++# elif defined(CLOCK_MONOTONIC_PRECISE) ++# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC_PRECISE ++# elif defined(_POSIX_MONOTONIC_CLOCK) || defined(CLOCK_MONOTONIC) ++# define PSNIP_CLOCK_MONOTONIC_METHOD PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++# define PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC CLOCK_MONOTONIC ++# endif ++# endif ++# endif ++ ++# if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L) ++# if !defined(PSNIP_CLOCK_WALL_METHOD) ++# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_GETTIMEOFDAY ++# endif ++# endif ++ ++# if !defined(PSNIP_CLOCK_WALL_METHOD) ++# define PSNIP_CLOCK_WALL_METHOD PSNIP_CLOCK_METHOD_TIME ++# endif ++ ++# if !defined(PSNIP_CLOCK_CPU_METHOD) ++# define PSNIP_CLOCK_CPU_METHOD PSNIP_CLOCK_METHOD_CLOCK ++# endif ++ ++/* Primarily here for testing. */ ++# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ defined(PSNIP_CLOCK_REQUIRE_MONOTONIC) ++# error No monotonic clock found. ++# endif ++ ++/* Implementations */ ++ ++# if (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == \ ++ PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ ++ (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK)) || \ ++ (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_TIME)) ++# include <time.h> ++# endif ++ ++# if (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY)) ++# include <sys/time.h> ++# endif ++ ++# if (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == \ ++ PSNIP_CLOCK_METHOD_GETPROCESSTIMES)) || \ ++ (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64)) ++# include <windows.h> ++# endif ++ ++# if (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE)) ++# include <sys/time.h> ++# include <sys/resource.h> ++# endif ++ ++# if (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == \ ++ PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == \ ++ PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME)) ++# include <CoreServices/CoreServices.h> ++# include <mach/mach.h> ++# include <mach/mach_time.h> ++# endif ++ ++/*** Implementations ***/ ++ ++# define PSNIP_CLOCK_NSEC_PER_SEC ((psnip_uint32_t)(1000000000ULL)) ++ ++# if (defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ (PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ ++ (defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ (PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) || \ ++ (defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ (PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME)) ++PSNIP_CLOCK__FUNCTION psnip_uint32_t ++psnip_clock__clock_getres(clockid_t clk_id) { ++ struct timespec res; ++ int r; ++ ++ r = clock_getres(clk_id, &res); ++ if (r != 0) ++ return 0; ++ ++ return (psnip_uint32_t)(PSNIP_CLOCK_NSEC_PER_SEC / ++ (psnip_uint64_t)res.tv_nsec); ++} ++ ++PSNIP_CLOCK__FUNCTION int ++psnip_clock__clock_gettime(clockid_t clk_id, struct PsnipClockTimespec *res) { ++ struct timespec ts; ++ ++ if (clock_gettime(clk_id, &ts) != 0) ++ return -10; ++ ++ res->seconds = (psnip_uint64_t)(ts.tv_sec); ++ res->nanoseconds = (psnip_uint64_t)(ts.tv_nsec); ++ ++ return 0; ++} ++# endif ++ ++PSNIP_CLOCK__FUNCTION psnip_uint32_t psnip_clock_wall_get_precision(void) { ++# if !defined(PSNIP_CLOCK_WALL_METHOD) ++ return 0; ++# elif defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++ return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_WALL); ++# elif defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY ++ return 1000000; ++# elif defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME ++ return 1; ++# else ++ return 0; ++# endif ++} ++ ++PSNIP_CLOCK__FUNCTION int ++psnip_clock_wall_get_time(struct PsnipClockTimespec *res) { ++ (void)res; ++ ++# if !defined(PSNIP_CLOCK_WALL_METHOD) ++ return -2; ++# elif defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++ return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_WALL, res); ++# elif defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_TIME ++ res->seconds = time(NULL); ++ res->nanoseconds = 0; ++# elif defined(PSNIP_CLOCK_WALL_METHOD) && \ ++ PSNIP_CLOCK_WALL_METHOD == PSNIP_CLOCK_METHOD_GETTIMEOFDAY ++ struct timeval tv; ++ ++ if (gettimeofday(&tv, NULL) != 0) ++ return -6; ++ ++ res->seconds = (psnip_uint64_t)tv.tv_sec; ++ res->nanoseconds = (psnip_uint64_t)tv.tv_usec * 1000; ++# else ++ return -2; ++# endif ++ ++ return 0; ++} ++ ++PSNIP_CLOCK__FUNCTION psnip_uint32_t psnip_clock_cpu_get_precision(void) { ++# if !defined(PSNIP_CLOCK_CPU_METHOD) ++ return 0; ++# elif defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++ return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_CPU); ++# elif defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK ++ return CLOCKS_PER_SEC; ++# elif defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES ++ return PSNIP_CLOCK_NSEC_PER_SEC / 100; ++# else ++ return 0; ++# endif ++} ++ ++PSNIP_CLOCK__FUNCTION int ++psnip_clock_cpu_get_time(struct PsnipClockTimespec *res) { ++# if !defined(PSNIP_CLOCK_CPU_METHOD) ++ (void)res; ++ return -2; ++# elif defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++ return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_CPU, res); ++# elif defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_CLOCK ++ clock_t t = clock(); ++ if (t == ((clock_t)-1)) ++ return -5; ++ res->seconds = t / CLOCKS_PER_SEC; ++ res->nanoseconds = ++ (t % CLOCKS_PER_SEC) * (PSNIP_CLOCK_NSEC_PER_SEC / CLOCKS_PER_SEC); ++# elif defined(PSNIP_CLOCK_CPU_METHOD) && \ ++ PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETPROCESSTIMES ++ FILETIME CreationTime, ExitTime, KernelTime, UserTime; ++ LARGE_INTEGER date, adjust; ++ ++ if (!GetProcessTimes(GetCurrentProcess(), &CreationTime, &ExitTime, ++ &KernelTime, &UserTime)) ++ return -7; ++ ++ /* http://www.frenk.com/2009/12/convert-filetime-to-unix-timestamp/ */ ++ date.HighPart = (LONG)UserTime.dwHighDateTime; ++ date.LowPart = UserTime.dwLowDateTime; ++ adjust.QuadPart = 11644473600000 * 10000; ++ date.QuadPart -= adjust.QuadPart; ++ ++ res->seconds = (psnip_uint64_t)(date.QuadPart / 10000000); ++ res->nanoseconds = (psnip_uint64_t)(date.QuadPart % 10000000) * ++ (PSNIP_CLOCK_NSEC_PER_SEC / 100); ++# elif PSNIP_CLOCK_CPU_METHOD == PSNIP_CLOCK_METHOD_GETRUSAGE ++ struct rusage usage; ++ if (getrusage(RUSAGE_SELF, &usage) != 0) ++ return -8; ++ ++ res->seconds = usage.ru_utime.tv_sec; ++ res->nanoseconds = tv.tv_usec * 1000; ++# else ++ (void)res; ++ return -2; ++# endif ++ ++ return 0; ++} ++ ++PSNIP_CLOCK__FUNCTION psnip_uint32_t psnip_clock_monotonic_get_precision(void) { ++# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) ++ return 0; ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++ return psnip_clock__clock_getres(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC); ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME ++ static mach_timebase_info_data_t tbi = { ++ 0, ++ }; ++ if (tbi.denom == 0) ++ mach_timebase_info(&tbi); ++ return (psnip_uint32_t)(tbi.numer / tbi.denom); ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64 ++ return 1000; ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == \ ++ PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER ++ LARGE_INTEGER Frequency; ++ QueryPerformanceFrequency(&Frequency); ++ return (psnip_uint32_t)((Frequency.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) ++ ? PSNIP_CLOCK_NSEC_PER_SEC ++ : Frequency.QuadPart); ++# else ++ return 0; ++# endif ++} ++ ++PSNIP_CLOCK__FUNCTION int ++psnip_clock_monotonic_get_time(struct PsnipClockTimespec *res) { ++# if !defined(PSNIP_CLOCK_MONOTONIC_METHOD) ++ (void)res; ++ return -2; ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_CLOCK_GETTIME ++ return psnip_clock__clock_gettime(PSNIP_CLOCK_CLOCK_GETTIME_MONOTONIC, res); ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_MACH_ABSOLUTE_TIME ++ psnip_uint64_t nsec = mach_absolute_time(); ++ static mach_timebase_info_data_t tbi = { ++ 0, ++ }; ++ if (tbi.denom == 0) ++ mach_timebase_info(&tbi); ++ nsec *= ((psnip_uint64_t)tbi.numer) / ((psnip_uint64_t)tbi.denom); ++ res->seconds = nsec / PSNIP_CLOCK_NSEC_PER_SEC; ++ res->nanoseconds = nsec % PSNIP_CLOCK_NSEC_PER_SEC; ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == \ ++ PSNIP_CLOCK_METHOD_QUERYPERFORMANCECOUNTER ++ LARGE_INTEGER t, f; ++ if (QueryPerformanceCounter(&t) == 0) ++ return -12; ++ ++ QueryPerformanceFrequency(&f); ++ res->seconds = (psnip_uint64_t)(t.QuadPart / f.QuadPart); ++ res->nanoseconds = (psnip_uint64_t)(t.QuadPart % f.QuadPart); ++ if (f.QuadPart > PSNIP_CLOCK_NSEC_PER_SEC) ++ res->nanoseconds /= (psnip_uint64_t)f.QuadPart / PSNIP_CLOCK_NSEC_PER_SEC; ++ else ++ res->nanoseconds *= PSNIP_CLOCK_NSEC_PER_SEC / (psnip_uint64_t)f.QuadPart; ++# elif defined(PSNIP_CLOCK_MONOTONIC_METHOD) && \ ++ PSNIP_CLOCK_MONOTONIC_METHOD == PSNIP_CLOCK_METHOD_GETTICKCOUNT64 ++ const ULONGLONG msec = GetTickCount64(); ++ res->seconds = msec / 1000; ++ res->nanoseconds = sec % 1000; ++# else ++ return -2; ++# endif ++ ++ return 0; ++} ++ ++/* Returns the number of ticks per second for the specified clock. ++ * For example, a clock with millisecond precision would return 1000, ++ * and a clock with 1 second (such as the time() function) would ++ * return 1. ++ * ++ * If the requested clock isn't available, it will return 0. ++ * Hopefully this will be rare, but if it happens to you please let us ++ * know so we can work on finding a way to support your system. ++ * ++ * Note that different clocks on the same system often have a ++ * different precisions. ++ */ ++PSNIP_CLOCK__FUNCTION psnip_uint32_t ++psnip_clock_get_precision(enum PsnipClockType clock_type) { ++ switch (clock_type) { ++ case PSNIP_CLOCK_TYPE_MONOTONIC: ++ return psnip_clock_monotonic_get_precision(); ++ case PSNIP_CLOCK_TYPE_CPU: ++ return psnip_clock_cpu_get_precision(); ++ case PSNIP_CLOCK_TYPE_WALL: ++ return psnip_clock_wall_get_precision(); ++ } ++ ++ PSNIP_CLOCK_UNREACHABLE(); ++ return 0; ++} ++ ++/* Set the provided timespec to the requested time. Returns 0 on ++ * success, or a negative value on failure. */ ++PSNIP_CLOCK__FUNCTION int psnip_clock_get_time(enum PsnipClockType clock_type, ++ struct PsnipClockTimespec *res) { ++ assert(res != NULL); ++ ++ switch (clock_type) { ++ case PSNIP_CLOCK_TYPE_MONOTONIC: ++ return psnip_clock_monotonic_get_time(res); ++ case PSNIP_CLOCK_TYPE_CPU: ++ return psnip_clock_cpu_get_time(res); ++ case PSNIP_CLOCK_TYPE_WALL: ++ return psnip_clock_wall_get_time(res); ++ } ++ ++ return -1; ++} ++ ++# endif /* !defined(PSNIP_CLOCK_H) */ ++ ++static psnip_uint64_t munit_clock_get_elapsed(struct PsnipClockTimespec *start, ++ struct PsnipClockTimespec *end) { ++ psnip_uint64_t r = (end->seconds - start->seconds) * PSNIP_CLOCK_NSEC_PER_SEC; ++ if (end->nanoseconds < start->nanoseconds) { ++ return r - (start->nanoseconds - end->nanoseconds); ++ } ++ ++ return r + (end->nanoseconds - start->nanoseconds); ++} ++ ++#else ++# include <time.h> ++#endif /* defined(MUNIT_ENABLE_TIMING) */ ++ ++/*** PRNG stuff ***/ ++ ++/* This is (unless I screwed up, which is entirely possible) the ++ * version of PCG with 32-bit state. It was chosen because it has a ++ * small enough state that we should reliably be able to use CAS ++ * instead of requiring a lock for thread-safety. ++ * ++ * If I did screw up, I probably will not bother changing it unless ++ * there is a significant bias. It's really not important this be ++ * particularly strong, as long as it is fairly random it's much more ++ * important that it be reproducible, so bug reports have a better ++ * chance of being reproducible. */ ++ ++#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ ++ !defined(__STDC_NO_ATOMICS__) && !defined(__EMSCRIPTEN__) && \ ++ (!defined(__GNUC_MINOR__) || (__GNUC__ > 4) || \ ++ (__GNUC__ == 4 && __GNUC_MINOR__ > 8)) ++# define HAVE_STDATOMIC ++#elif defined(__clang__) ++# if __has_extension(c_atomic) ++# define HAVE_CLANG_ATOMICS ++# endif ++#endif ++ ++/* Workaround for http://llvm.org/bugs/show_bug.cgi?id=26911 */ ++#if defined(__clang__) && defined(_WIN32) ++# undef HAVE_STDATOMIC ++# if defined(__c2__) ++# undef HAVE_CLANG_ATOMICS ++# endif ++#endif ++ ++#if defined(_OPENMP) ++# define ATOMIC_UINT32_T uint32_t ++# define ATOMIC_UINT32_INIT(x) (x) ++#elif defined(HAVE_STDATOMIC) ++# include <stdatomic.h> ++# define ATOMIC_UINT32_T _Atomic uint32_t ++# define ATOMIC_UINT32_INIT(x) ATOMIC_VAR_INIT(x) ++#elif defined(HAVE_CLANG_ATOMICS) ++# define ATOMIC_UINT32_T _Atomic uint32_t ++# define ATOMIC_UINT32_INIT(x) (x) ++#elif defined(_WIN32) ++# define ATOMIC_UINT32_T volatile LONG ++# define ATOMIC_UINT32_INIT(x) (x) ++#else ++# define ATOMIC_UINT32_T volatile uint32_t ++# define ATOMIC_UINT32_INIT(x) (x) ++#endif ++ ++static ATOMIC_UINT32_T munit_rand_state = ATOMIC_UINT32_INIT(42); ++ ++#if defined(_OPENMP) ++static inline void munit_atomic_store(ATOMIC_UINT32_T *dest, ++ ATOMIC_UINT32_T value) { ++# pragma omp critical(munit_atomics) ++ *dest = value; ++} ++ ++static inline uint32_t munit_atomic_load(ATOMIC_UINT32_T *src) { ++ int ret; ++# pragma omp critical(munit_atomics) ++ ret = *src; ++ return ret; ++} ++ ++static inline uint32_t munit_atomic_cas(ATOMIC_UINT32_T *dest, ++ ATOMIC_UINT32_T *expected, ++ ATOMIC_UINT32_T desired) { ++ munit_bool ret; ++ ++# pragma omp critical(munit_atomics) ++ { ++ if (*dest == *expected) { ++ *dest = desired; ++ ret = 1; ++ } else { ++ ret = 0; ++ } ++ } ++ ++ return ret; ++} ++#elif defined(HAVE_STDATOMIC) ++# define munit_atomic_store(dest, value) atomic_store(dest, value) ++# define munit_atomic_load(src) atomic_load(src) ++# define munit_atomic_cas(dest, expected, value) \ ++ atomic_compare_exchange_weak(dest, expected, value) ++#elif defined(HAVE_CLANG_ATOMICS) ++# define munit_atomic_store(dest, value) \ ++ __c11_atomic_store(dest, value, __ATOMIC_SEQ_CST) ++# define munit_atomic_load(src) __c11_atomic_load(src, __ATOMIC_SEQ_CST) ++# define munit_atomic_cas(dest, expected, value) \ ++ __c11_atomic_compare_exchange_weak(dest, expected, value, \ ++ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ++#elif defined(__GNUC__) && (__GNUC__ > 4) || \ ++ (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) ++# define munit_atomic_store(dest, value) \ ++ __atomic_store_n(dest, value, __ATOMIC_SEQ_CST) ++# define munit_atomic_load(src) __atomic_load_n(src, __ATOMIC_SEQ_CST) ++# define munit_atomic_cas(dest, expected, value) \ ++ __atomic_compare_exchange_n(dest, expected, value, 1, __ATOMIC_SEQ_CST, \ ++ __ATOMIC_SEQ_CST) ++#elif defined(__GNUC__) && (__GNUC__ >= 4) ++# define munit_atomic_store(dest, value) \ ++ do { \ ++ *(dest) = (value); \ ++ } while (0) ++# define munit_atomic_load(src) (*(src)) ++# define munit_atomic_cas(dest, expected, value) \ ++ __sync_bool_compare_and_swap(dest, *expected, value) ++#elif defined(_WIN32) /* Untested */ ++# define munit_atomic_store(dest, value) \ ++ do { \ ++ *(dest) = (value); \ ++ } while (0) ++# define munit_atomic_load(src) (*(src)) ++# define munit_atomic_cas(dest, expected, value) \ ++ InterlockedCompareExchange((dest), (value), *(expected)) ++#else ++# warning No atomic implementation, PRNG will not be thread-safe ++# define munit_atomic_store(dest, value) \ ++ do { \ ++ *(dest) = (value); \ ++ } while (0) ++# define munit_atomic_load(src) (*(src)) ++static inline munit_bool munit_atomic_cas(ATOMIC_UINT32_T *dest, ++ ATOMIC_UINT32_T *expected, ++ ATOMIC_UINT32_T desired) { ++ if (*dest == *expected) { ++ *dest = desired; ++ return 1; ++ } else { ++ return 0; ++ } ++} ++#endif ++ ++#define MUNIT_PRNG_MULTIPLIER (747796405U) ++#define MUNIT_PRNG_INCREMENT (1729U) ++ ++static munit_uint32_t munit_rand_next_state(munit_uint32_t state) { ++ return state * MUNIT_PRNG_MULTIPLIER + MUNIT_PRNG_INCREMENT; ++} ++ ++static munit_uint32_t munit_rand_from_state(munit_uint32_t state) { ++ munit_uint32_t res = ((state >> ((state >> 28) + 4)) ^ state) * (277803737U); ++ res ^= res >> 22; ++ return res; ++} ++ ++void munit_rand_seed(munit_uint32_t seed) { ++ munit_uint32_t state = munit_rand_next_state(seed + MUNIT_PRNG_INCREMENT); ++ munit_atomic_store(&munit_rand_state, state); ++} ++ ++static munit_uint32_t munit_rand_generate_seed(void) { ++ munit_uint32_t seed, state; ++#if defined(MUNIT_ENABLE_TIMING) ++ struct PsnipClockTimespec wc = { ++ 0, ++ }; ++ ++ psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wc); ++ seed = (munit_uint32_t)wc.nanoseconds; ++#else ++ seed = (munit_uint32_t)time(NULL); ++#endif ++ ++ state = munit_rand_next_state(seed + MUNIT_PRNG_INCREMENT); ++ return munit_rand_from_state(state); ++} ++ ++static munit_uint32_t munit_rand_state_uint32(munit_uint32_t *state) { ++ const munit_uint32_t old = *state; ++ *state = munit_rand_next_state(old); ++ return munit_rand_from_state(old); ++} ++ ++munit_uint32_t munit_rand_uint32(void) { ++ munit_uint32_t old, state; ++ ++ do { ++ old = munit_atomic_load(&munit_rand_state); ++ state = munit_rand_next_state(old); ++ } while (!munit_atomic_cas(&munit_rand_state, &old, state)); ++ ++ return munit_rand_from_state(old); ++} ++ ++static void munit_rand_state_memory(munit_uint32_t *state, size_t size, ++ munit_uint8_t *data) { ++ size_t members_remaining = size / sizeof(munit_uint32_t); ++ size_t bytes_remaining = size % sizeof(munit_uint32_t); ++ munit_uint8_t *b = data; ++ munit_uint32_t rv; ++ while (members_remaining-- > 0) { ++ rv = munit_rand_state_uint32(state); ++ memcpy(b, &rv, sizeof(munit_uint32_t)); ++ b += sizeof(munit_uint32_t); ++ } ++ if (bytes_remaining != 0) { ++ rv = munit_rand_state_uint32(state); ++ memcpy(b, &rv, bytes_remaining); ++ } ++} ++ ++void munit_rand_memory(size_t size, munit_uint8_t *data) { ++ munit_uint32_t old, state; ++ ++ do { ++ state = old = munit_atomic_load(&munit_rand_state); ++ munit_rand_state_memory(&state, size, data); ++ } while (!munit_atomic_cas(&munit_rand_state, &old, state)); ++} ++ ++static munit_uint32_t munit_rand_state_at_most(munit_uint32_t *state, ++ munit_uint32_t salt, ++ munit_uint32_t max) { ++ /* We want (UINT32_MAX + 1) % max, which in unsigned arithmetic is the same ++ * as (UINT32_MAX + 1 - max) % max = -max % max. We compute -max using not ++ * to avoid compiler warnings. ++ */ ++ const munit_uint32_t min = (~max + 1U) % max; ++ munit_uint32_t x; ++ ++ if (max == (~((munit_uint32_t)0U))) ++ return munit_rand_state_uint32(state) ^ salt; ++ ++ max++; ++ ++ do { ++ x = munit_rand_state_uint32(state) ^ salt; ++ } while (x < min); ++ ++ return x % max; ++} ++ ++static munit_uint32_t munit_rand_at_most(munit_uint32_t salt, ++ munit_uint32_t max) { ++ munit_uint32_t old, state; ++ munit_uint32_t retval; ++ ++ do { ++ state = old = munit_atomic_load(&munit_rand_state); ++ retval = munit_rand_state_at_most(&state, salt, max); ++ } while (!munit_atomic_cas(&munit_rand_state, &old, state)); ++ ++ return retval; ++} ++ ++int munit_rand_int_range(int min, int max) { ++ munit_uint64_t range = (munit_uint64_t)max - (munit_uint64_t)min; ++ ++ if (min > max) ++ return munit_rand_int_range(max, min); ++ ++ if (range > (~((munit_uint32_t)0U))) ++ range = (~((munit_uint32_t)0U)); ++ ++ return min + (int)munit_rand_at_most(0, (munit_uint32_t)range); ++} ++ ++double munit_rand_double(void) { ++ munit_uint32_t old, state; ++ double retval = 0.0; ++ ++ do { ++ state = old = munit_atomic_load(&munit_rand_state); ++ ++ /* See http://mumble.net/~campbell/tmp/random_real.c for how to do ++ * this right. Patches welcome if you feel that this is too ++ * biased. */ ++ retval = munit_rand_state_uint32(&state) / ((~((munit_uint32_t)0U)) + 1.0); ++ } while (!munit_atomic_cas(&munit_rand_state, &old, state)); ++ ++ return retval; ++} ++ ++/*** Test suite handling ***/ ++ ++typedef struct { ++ unsigned int successful; ++ unsigned int skipped; ++ unsigned int failed; ++ unsigned int errored; ++#if defined(MUNIT_ENABLE_TIMING) ++ munit_uint64_t cpu_clock; ++ munit_uint64_t wall_clock; ++#endif ++} MunitReport; ++ ++typedef struct { ++ const char *prefix; ++ const MunitSuite *suite; ++ const char **tests; ++ munit_uint32_t seed; ++ unsigned int iterations; ++ MunitParameter *parameters; ++ munit_bool single_parameter_mode; ++ void *user_data; ++ MunitReport report; ++ munit_bool colorize; ++ munit_bool fork; ++ munit_bool show_stderr; ++ munit_bool fatal_failures; ++} MunitTestRunner; ++ ++const char *munit_parameters_get(const MunitParameter params[], ++ const char *key) { ++ const MunitParameter *param; ++ ++ for (param = params; param != NULL && param->name != NULL; param++) ++ if (strcmp(param->name, key) == 0) ++ return param->value; ++ return NULL; ++} ++ ++#if defined(MUNIT_ENABLE_TIMING) ++static void munit_print_time(FILE *fp, munit_uint64_t nanoseconds) { ++ fprintf(fp, "%" MUNIT_TEST_TIME_FORMAT, ++ ((double)nanoseconds) / ((double)PSNIP_CLOCK_NSEC_PER_SEC)); ++} ++#endif ++ ++/* Add a paramter to an array of parameters. */ ++static MunitResult munit_parameters_add(size_t *params_size, ++ MunitParameter **params, char *name, ++ char *value) { ++ *params = realloc(*params, sizeof(MunitParameter) * (*params_size + 2)); ++ if (*params == NULL) ++ return MUNIT_ERROR; ++ ++ (*params)[*params_size].name = name; ++ (*params)[*params_size].value = value; ++ (*params_size)++; ++ (*params)[*params_size].name = NULL; ++ (*params)[*params_size].value = NULL; ++ ++ return MUNIT_OK; ++} ++ ++/* Concatenate two strings, but just return one of the components ++ * unaltered if the other is NULL or "". */ ++static char *munit_maybe_concat(size_t *len, char *prefix, char *suffix) { ++ char *res; ++ size_t res_l; ++ const size_t prefix_l = prefix != NULL ? strlen(prefix) : 0; ++ const size_t suffix_l = suffix != NULL ? strlen(suffix) : 0; ++ if (prefix_l == 0 && suffix_l == 0) { ++ res = NULL; ++ res_l = 0; ++ } else if (prefix_l == 0 && suffix_l != 0) { ++ res = suffix; ++ res_l = suffix_l; ++ } else if (prefix_l != 0 && suffix_l == 0) { ++ res = prefix; ++ res_l = prefix_l; ++ } else { ++ res_l = prefix_l + suffix_l; ++ res = malloc(res_l + 1); ++ memcpy(res, prefix, prefix_l); ++ memcpy(res + prefix_l, suffix, suffix_l); ++ res[res_l] = 0; ++ } ++ ++ if (len != NULL) ++ *len = res_l; ++ ++ return res; ++} ++ ++/* Possbily free a string returned by munit_maybe_concat. */ ++static void munit_maybe_free_concat(char *s, const char *prefix, ++ const char *suffix) { ++ if (prefix != s && suffix != s) ++ free(s); ++} ++ ++/* Cheap string hash function, just used to salt the PRNG. */ ++static munit_uint32_t munit_str_hash(const char *name) { ++ const char *p; ++ munit_uint32_t h = 5381U; ++ ++ for (p = name; *p != '\0'; p++) ++ h = (munit_uint32_t)(h << 5) + h + (munit_uint32_t)*p; ++ ++ return h; ++} ++ ++static void munit_splice(int from, int to) { ++ munit_uint8_t buf[1024]; ++#if !defined(_WIN32) ++ ssize_t len; ++ ssize_t bytes_written; ++ ssize_t write_res; ++#else ++ int len; ++ int bytes_written; ++ int write_res; ++#endif ++ do { ++ len = read(from, buf, sizeof(buf)); ++ if (len > 0) { ++ bytes_written = 0; ++ do { ++ write_res = write(to, buf + bytes_written, ++#if !defined(_WIN32) ++ (size_t) ++#else ++ (unsigned int) ++#endif ++ (len - bytes_written)); ++ if (write_res < 0) ++ break; ++ bytes_written += write_res; ++ } while (bytes_written < len); ++ } else ++ break; ++ } while (1); ++} ++ ++/* This is the part that should be handled in the child process */ ++static MunitResult munit_test_runner_exec(MunitTestRunner *runner, ++ const MunitTest *test, ++ const MunitParameter params[], ++ MunitReport *report) { ++ unsigned int iterations = runner->iterations; ++ MunitResult result = MUNIT_FAIL; ++#if defined(MUNIT_ENABLE_TIMING) ++ struct PsnipClockTimespec wall_clock_begin = ++ { ++ 0, ++ }, ++ wall_clock_end = { ++ 0, ++ }; ++ struct PsnipClockTimespec cpu_clock_begin = ++ { ++ 0, ++ }, ++ cpu_clock_end = { ++ 0, ++ }; ++#endif ++ unsigned int i = 0; ++ ++ if ((test->options & MUNIT_TEST_OPTION_SINGLE_ITERATION) == ++ MUNIT_TEST_OPTION_SINGLE_ITERATION) ++ iterations = 1; ++ else if (iterations == 0) ++ iterations = runner->suite->iterations; ++ ++ munit_rand_seed(runner->seed); ++ ++ do { ++ void *data = (test->setup == NULL) ? runner->user_data ++ : test->setup(params, runner->user_data); ++ ++#if defined(MUNIT_ENABLE_TIMING) ++ psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wall_clock_begin); ++ psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cpu_clock_begin); ++#endif ++ ++ result = test->test(params, data); ++ ++#if defined(MUNIT_ENABLE_TIMING) ++ psnip_clock_get_time(PSNIP_CLOCK_TYPE_WALL, &wall_clock_end); ++ psnip_clock_get_time(PSNIP_CLOCK_TYPE_CPU, &cpu_clock_end); ++#endif ++ ++ if (test->tear_down != NULL) ++ test->tear_down(data); ++ ++ if (MUNIT_LIKELY(result == MUNIT_OK)) { ++ report->successful++; ++#if defined(MUNIT_ENABLE_TIMING) ++ report->wall_clock += ++ munit_clock_get_elapsed(&wall_clock_begin, &wall_clock_end); ++ report->cpu_clock += ++ munit_clock_get_elapsed(&cpu_clock_begin, &cpu_clock_end); ++#endif ++ } else { ++ switch ((int)result) { ++ case MUNIT_SKIP: ++ report->skipped++; ++ break; ++ case MUNIT_FAIL: ++ report->failed++; ++ break; ++ case MUNIT_ERROR: ++ report->errored++; ++ break; ++ default: ++ break; ++ } ++ break; ++ } ++ } while (++i < iterations); ++ ++ return result; ++} ++ ++#if defined(MUNIT_EMOTICON) ++# define MUNIT_RESULT_STRING_OK ":)" ++# define MUNIT_RESULT_STRING_SKIP ":|" ++# define MUNIT_RESULT_STRING_FAIL ":(" ++# define MUNIT_RESULT_STRING_ERROR ":o" ++# define MUNIT_RESULT_STRING_TODO ":/" ++#else ++# define MUNIT_RESULT_STRING_OK "OK " ++# define MUNIT_RESULT_STRING_SKIP "SKIP " ++# define MUNIT_RESULT_STRING_FAIL "FAIL " ++# define MUNIT_RESULT_STRING_ERROR "ERROR" ++# define MUNIT_RESULT_STRING_TODO "TODO " ++#endif ++ ++static void munit_test_runner_print_color(const MunitTestRunner *runner, ++ const char *string, char color) { ++ if (runner->colorize) ++ fprintf(MUNIT_OUTPUT_FILE, "\x1b[3%cm%s\x1b[39m", color, string); ++ else ++ fputs(string, MUNIT_OUTPUT_FILE); ++} ++ ++#if !defined(MUNIT_NO_BUFFER) ++static int munit_replace_stderr(FILE *stderr_buf) { ++ if (stderr_buf != NULL) { ++ const int orig_stderr = dup(STDERR_FILENO); ++ ++ int errfd = fileno(stderr_buf); ++ if (MUNIT_UNLIKELY(errfd == -1)) { ++ exit(EXIT_FAILURE); ++ } ++ ++ dup2(errfd, STDERR_FILENO); ++ ++ return orig_stderr; ++ } ++ ++ return -1; ++} ++ ++static void munit_restore_stderr(int orig_stderr) { ++ if (orig_stderr != -1) { ++ dup2(orig_stderr, STDERR_FILENO); ++ close(orig_stderr); ++ } ++} ++#endif /* !defined(MUNIT_NO_BUFFER) */ ++ ++/* Run a test with the specified parameters. */ ++static void ++munit_test_runner_run_test_with_params(MunitTestRunner *runner, ++ const MunitTest *test, ++ const MunitParameter params[]) { ++ MunitResult result = MUNIT_OK; ++ MunitReport report = { ++ 0, ++ 0, ++ 0, ++ 0, ++#if defined(MUNIT_ENABLE_TIMING) ++ 0, ++ 0 ++#endif ++ }; ++ unsigned int output_l; ++ munit_bool first; ++ const MunitParameter *param; ++ FILE *stderr_buf; ++#if !defined(MUNIT_NO_FORK) ++ int pipefd[2]; ++ pid_t fork_pid; ++ ssize_t bytes_written = 0; ++ ssize_t write_res; ++ ssize_t bytes_read = 0; ++ ssize_t read_res; ++ int status = 0; ++ pid_t changed_pid; ++#endif ++ ++ if (params != NULL) { ++ output_l = 2; ++ fputs(" ", MUNIT_OUTPUT_FILE); ++ first = 1; ++ for (param = params; param != NULL && param->name != NULL; param++) { ++ if (!first) { ++ fputs(", ", MUNIT_OUTPUT_FILE); ++ output_l += 2; ++ } else { ++ first = 0; ++ } ++ ++ output_l += (unsigned int)fprintf(MUNIT_OUTPUT_FILE, "%s=%s", param->name, ++ param->value); ++ } ++ while (output_l++ < MUNIT_TEST_NAME_LEN) { ++ fputc(' ', MUNIT_OUTPUT_FILE); ++ } ++ } ++ ++ fflush(MUNIT_OUTPUT_FILE); ++ ++ stderr_buf = NULL; ++#if !defined(_WIN32) || defined(__MINGW32__) ++ stderr_buf = tmpfile(); ++#else ++ tmpfile_s(&stderr_buf); ++#endif ++ if (stderr_buf == NULL) { ++ munit_log_errno(MUNIT_LOG_ERROR, stderr, ++ "unable to create buffer for stderr"); ++ result = MUNIT_ERROR; ++ goto print_result; ++ } ++ ++#if !defined(MUNIT_NO_FORK) ++ if (runner->fork) { ++ pipefd[0] = -1; ++ pipefd[1] = -1; ++ if (pipe(pipefd) != 0) { ++ munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to create pipe"); ++ result = MUNIT_ERROR; ++ goto print_result; ++ } ++ ++ fork_pid = fork(); ++ if (fork_pid == 0) { ++ int orig_stderr; ++ ++ close(pipefd[0]); ++ ++ orig_stderr = munit_replace_stderr(stderr_buf); ++ munit_test_runner_exec(runner, test, params, &report); ++ ++ /* Note that we don't restore stderr. This is so we can buffer ++ * things written to stderr later on (such as by ++ * asan/tsan/ubsan, valgrind, etc.) */ ++ close(orig_stderr); ++ ++ do { ++ write_res = ++ write(pipefd[1], ((munit_uint8_t *)(&report)) + bytes_written, ++ sizeof(report) - (size_t)bytes_written); ++ if (write_res < 0) { ++ if (stderr_buf != NULL) { ++ munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to write to pipe"); ++ } ++ exit(EXIT_FAILURE); ++ } ++ bytes_written += write_res; ++ } while ((size_t)bytes_written < sizeof(report)); ++ ++ if (stderr_buf != NULL) ++ fclose(stderr_buf); ++ close(pipefd[1]); ++ ++ exit(EXIT_SUCCESS); ++ } else if (fork_pid == -1) { ++ close(pipefd[0]); ++ close(pipefd[1]); ++ if (stderr_buf != NULL) { ++ munit_log_errno(MUNIT_LOG_ERROR, stderr, "unable to fork"); ++ } ++ report.errored++; ++ result = MUNIT_ERROR; ++ } else { ++ close(pipefd[1]); ++ do { ++ read_res = read(pipefd[0], ((munit_uint8_t *)(&report)) + bytes_read, ++ sizeof(report) - (size_t)bytes_read); ++ if (read_res < 1) ++ break; ++ bytes_read += read_res; ++ } while (bytes_read < (ssize_t)sizeof(report)); ++ ++ changed_pid = waitpid(fork_pid, &status, 0); ++ ++ if (MUNIT_LIKELY(changed_pid == fork_pid) && ++ MUNIT_LIKELY(WIFEXITED(status))) { ++ if (bytes_read != sizeof(report)) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, ++ "child exited unexpectedly with status %d", ++ WEXITSTATUS(status)); ++ report.errored++; ++ } else if (WEXITSTATUS(status) != EXIT_SUCCESS) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, ++ "child exited with status %d", ++ WEXITSTATUS(status)); ++ report.errored++; ++ } ++ } else { ++ if (WIFSIGNALED(status)) { ++# if defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 700) ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, ++ "child killed by signal %d (%s)", ++ WTERMSIG(status), strsignal(WTERMSIG(status))); ++# else ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, ++ "child killed by signal %d", WTERMSIG(status)); ++# endif ++ } else if (WIFSTOPPED(status)) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr_buf, ++ "child stopped by signal %d", WSTOPSIG(status)); ++ } ++ report.errored++; ++ } ++ ++ close(pipefd[0]); ++ waitpid(fork_pid, NULL, 0); ++ } ++ } else ++#endif ++ { ++#if !defined(MUNIT_NO_BUFFER) ++ const volatile int orig_stderr = munit_replace_stderr(stderr_buf); ++#endif ++ ++#if defined(MUNIT_THREAD_LOCAL) ++ if (MUNIT_UNLIKELY(setjmp(munit_error_jmp_buf) != 0)) { ++ result = MUNIT_FAIL; ++ report.failed++; ++ } else { ++ munit_error_jmp_buf_valid = 1; ++ result = munit_test_runner_exec(runner, test, params, &report); ++ } ++#else ++ result = munit_test_runner_exec(runner, test, params, &report); ++#endif ++ ++#if !defined(MUNIT_NO_BUFFER) ++ munit_restore_stderr(orig_stderr); ++#endif ++ ++ /* Here just so that the label is used on Windows and we don't get ++ * a warning */ ++ goto print_result; ++ } ++ ++print_result: ++ ++ fputs("[ ", MUNIT_OUTPUT_FILE); ++ if ((test->options & MUNIT_TEST_OPTION_TODO) == MUNIT_TEST_OPTION_TODO) { ++ if (report.failed != 0 || report.errored != 0 || report.skipped != 0) { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_TODO, '3'); ++ result = MUNIT_OK; ++ } else { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1'); ++ if (MUNIT_LIKELY(stderr_buf != NULL)) ++ munit_log_internal(MUNIT_LOG_ERROR, stderr_buf, ++ "Test marked TODO, but was successful."); ++ runner->report.failed++; ++ result = MUNIT_ERROR; ++ } ++ } else if (report.failed > 0) { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_FAIL, '1'); ++ runner->report.failed++; ++ result = MUNIT_FAIL; ++ } else if (report.errored > 0) { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_ERROR, '1'); ++ runner->report.errored++; ++ result = MUNIT_ERROR; ++ } else if (report.skipped > 0) { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_SKIP, '3'); ++ runner->report.skipped++; ++ result = MUNIT_SKIP; ++ } else if (report.successful > 1) { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2'); ++#if defined(MUNIT_ENABLE_TIMING) ++ fputs(" ] [ ", MUNIT_OUTPUT_FILE); ++ munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock / report.successful); ++ fputs(" / ", MUNIT_OUTPUT_FILE); ++ munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock / report.successful); ++ fprintf(MUNIT_OUTPUT_FILE, ++ " CPU ]\n %-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s Total: [ ", ++ ""); ++ munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock); ++ fputs(" / ", MUNIT_OUTPUT_FILE); ++ munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock); ++ fputs(" CPU", MUNIT_OUTPUT_FILE); ++#endif ++ runner->report.successful++; ++ result = MUNIT_OK; ++ } else if (report.successful > 0) { ++ munit_test_runner_print_color(runner, MUNIT_RESULT_STRING_OK, '2'); ++#if defined(MUNIT_ENABLE_TIMING) ++ fputs(" ] [ ", MUNIT_OUTPUT_FILE); ++ munit_print_time(MUNIT_OUTPUT_FILE, report.wall_clock); ++ fputs(" / ", MUNIT_OUTPUT_FILE); ++ munit_print_time(MUNIT_OUTPUT_FILE, report.cpu_clock); ++ fputs(" CPU", MUNIT_OUTPUT_FILE); ++#endif ++ runner->report.successful++; ++ result = MUNIT_OK; ++ } ++ fputs(" ]\n", MUNIT_OUTPUT_FILE); ++ ++ if (stderr_buf != NULL) { ++ if (result == MUNIT_FAIL || result == MUNIT_ERROR || runner->show_stderr) { ++ fflush(MUNIT_OUTPUT_FILE); ++ ++ rewind(stderr_buf); ++ munit_splice(fileno(stderr_buf), STDERR_FILENO); ++ ++ fflush(stderr); ++ } ++ ++ fclose(stderr_buf); ++ } ++} ++ ++static void munit_test_runner_run_test_wild(MunitTestRunner *runner, ++ const MunitTest *test, ++ const char *test_name, ++ MunitParameter *params, ++ MunitParameter *p) { ++ const MunitParameterEnum *pe; ++ char **values; ++ MunitParameter *next; ++ ++ for (pe = test->parameters; pe != NULL && pe->name != NULL; pe++) { ++ if (p->name == pe->name) ++ break; ++ } ++ ++ if (pe == NULL) ++ return; ++ ++ for (values = pe->values; *values != NULL; values++) { ++ next = p + 1; ++ p->value = *values; ++ if (next->name == NULL) { ++ munit_test_runner_run_test_with_params(runner, test, params); ++ } else { ++ munit_test_runner_run_test_wild(runner, test, test_name, params, next); ++ } ++ if (runner->fatal_failures && ++ (runner->report.failed != 0 || runner->report.errored != 0)) ++ break; ++ } ++} ++ ++/* Run a single test, with every combination of parameters ++ * requested. */ ++static void munit_test_runner_run_test(MunitTestRunner *runner, ++ const MunitTest *test, ++ const char *prefix) { ++ char *test_name = ++ munit_maybe_concat(NULL, (char *)prefix, (char *)test->name); ++ /* The array of parameters to pass to ++ * munit_test_runner_run_test_with_params */ ++ MunitParameter *params = NULL; ++ size_t params_l = 0; ++ /* Wildcard parameters are parameters which have possible values ++ * specified in the test, but no specific value was passed to the ++ * CLI. That means we want to run the test once for every ++ * possible combination of parameter values or, if --single was ++ * passed to the CLI, a single time with a random set of ++ * parameters. */ ++ MunitParameter *wild_params = NULL; ++ size_t wild_params_l = 0; ++ const MunitParameterEnum *pe; ++ const MunitParameter *cli_p; ++ munit_bool filled; ++ unsigned int possible; ++ char **vals; ++ size_t first_wild; ++ const MunitParameter *wp; ++ int pidx; ++ ++ munit_rand_seed(runner->seed); ++ ++ fprintf(MUNIT_OUTPUT_FILE, "%-" MUNIT_XSTRINGIFY(MUNIT_TEST_NAME_LEN) "s", ++ test_name); ++ ++ if (test->parameters == NULL) { ++ /* No parameters. Simple, nice. */ ++ munit_test_runner_run_test_with_params(runner, test, NULL); ++ } else { ++ fputc('\n', MUNIT_OUTPUT_FILE); ++ ++ for (pe = test->parameters; pe != NULL && pe->name != NULL; pe++) { ++ /* Did we received a value for this parameter from the CLI? */ ++ filled = 0; ++ for (cli_p = runner->parameters; cli_p != NULL && cli_p->name != NULL; ++ cli_p++) { ++ if (strcmp(cli_p->name, pe->name) == 0) { ++ if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms, pe->name, ++ cli_p->value) != MUNIT_OK)) ++ goto cleanup; ++ filled = 1; ++ break; ++ } ++ } ++ if (filled) ++ continue; ++ ++ /* Nothing from CLI, is the enum NULL/empty? We're not a ++ * fuzzer… */ ++ if (pe->values == NULL || pe->values[0] == NULL) ++ continue; ++ ++ /* If --single was passed to the CLI, choose a value from the ++ * list of possibilities randomly. */ ++ if (runner->single_parameter_mode) { ++ possible = 0; ++ for (vals = pe->values; *vals != NULL; vals++) ++ possible++; ++ /* We want the tests to be reproducible, even if you're only ++ * running a single test, but we don't want every test with ++ * the same number of parameters to choose the same parameter ++ * number, so use the test name as a primitive salt. */ ++ pidx = (int)munit_rand_at_most(munit_str_hash(test_name), possible - 1); ++ if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms, pe->name, ++ pe->values[pidx]) != MUNIT_OK)) ++ goto cleanup; ++ } else { ++ /* We want to try every permutation. Put in a placeholder ++ * entry, we'll iterate through them later. */ ++ if (MUNIT_UNLIKELY(munit_parameters_add(&wild_params_l, &wild_params, ++ pe->name, NULL) != MUNIT_OK)) ++ goto cleanup; ++ } ++ } ++ ++ if (wild_params_l != 0) { ++ first_wild = params_l; ++ for (wp = wild_params; wp != NULL && wp->name != NULL; wp++) { ++ for (pe = test->parameters; ++ pe != NULL && pe->name != NULL && pe->values != NULL; pe++) { ++ if (strcmp(wp->name, pe->name) == 0) { ++ if (MUNIT_UNLIKELY(munit_parameters_add(¶ms_l, ¶ms, ++ pe->name, ++ pe->values[0]) != MUNIT_OK)) ++ goto cleanup; ++ } ++ } ++ } ++ ++ munit_test_runner_run_test_wild(runner, test, test_name, params, ++ params + first_wild); ++ } else { ++ munit_test_runner_run_test_with_params(runner, test, params); ++ } ++ ++ cleanup: ++ free(params); ++ free(wild_params); ++ } ++ ++ munit_maybe_free_concat(test_name, prefix, test->name); ++} ++ ++/* Recurse through the suite and run all the tests. If a list of ++ * tests to run was provied on the command line, run only those ++ * tests. */ ++static void munit_test_runner_run_suite(MunitTestRunner *runner, ++ const MunitSuite *suite, ++ const char *prefix) { ++ size_t pre_l; ++ char *pre = munit_maybe_concat(&pre_l, (char *)prefix, (char *)suite->prefix); ++ const MunitTest *test; ++ const char **test_name; ++ const MunitSuite *child_suite; ++ ++ /* Run the tests. */ ++ for (test = suite->tests; test != NULL && test->test != NULL; test++) { ++ if (runner->tests != NULL) { /* Specific tests were requested on the CLI */ ++ for (test_name = runner->tests; test_name != NULL && *test_name != NULL; ++ test_name++) { ++ if ((pre_l == 0 || strncmp(pre, *test_name, pre_l) == 0) && ++ strncmp(test->name, *test_name + pre_l, ++ strlen(*test_name + pre_l)) == 0) { ++ munit_test_runner_run_test(runner, test, pre); ++ if (runner->fatal_failures && ++ (runner->report.failed != 0 || runner->report.errored != 0)) ++ goto cleanup; ++ } ++ } ++ } else { /* Run all tests */ ++ munit_test_runner_run_test(runner, test, pre); ++ } ++ } ++ ++ if (runner->fatal_failures && ++ (runner->report.failed != 0 || runner->report.errored != 0)) ++ goto cleanup; ++ ++ /* Run any child suites. */ ++ for (child_suite = suite->suites; ++ child_suite != NULL && child_suite->prefix != NULL; child_suite++) { ++ munit_test_runner_run_suite(runner, child_suite, pre); ++ } ++ ++cleanup: ++ ++ munit_maybe_free_concat(pre, prefix, suite->prefix); ++} ++ ++static void munit_test_runner_run(MunitTestRunner *runner) { ++ munit_test_runner_run_suite(runner, runner->suite, NULL); ++} ++ ++static void munit_print_help(int argc, char *const *argv, void *user_data, ++ const MunitArgument arguments[]) { ++ const MunitArgument *arg; ++ (void)argc; ++ ++ printf("USAGE: %s [OPTIONS...] [TEST...]\n\n", argv[0]); ++ puts( ++ " --seed SEED\n" ++ " Value used to seed the PRNG. Must be a 32-bit integer in " ++ "decimal\n" ++ " notation with no separators (commas, decimals, spaces, " ++ "etc.), or\n" ++ " hexidecimal prefixed by \"0x\".\n" ++ " --iterations N\n" ++ " Run each test N times. 0 means the default number.\n" ++ " --param name value\n" ++ " A parameter key/value pair which will be passed to any test " ++ "with\n" ++ " takes a parameter of that name. If not provided, the test " ++ "will be\n" ++ " run once for each possible parameter value.\n" ++ " --list Write a list of all available tests.\n" ++ " --list-params\n" ++ " Write a list of all available tests and their possible " ++ "parameters.\n" ++ " --single Run each parameterized test in a single configuration " ++ "instead of\n" ++ " every possible combination\n" ++ " --log-visible debug|info|warning|error\n" ++ " --log-fatal debug|info|warning|error\n" ++ " Set the level at which messages of different severities are " ++ "visible,\n" ++ " or cause the test to terminate.\n" ++#if !defined(MUNIT_NO_FORK) ++ " --no-fork Do not execute tests in a child process. If this option is " ++ "supplied\n" ++ " and a test crashes (including by failing an assertion), no " ++ "further\n" ++ " tests will be performed.\n" ++#endif ++ " --fatal-failures\n" ++ " Stop executing tests as soon as a failure is found.\n" ++ " --show-stderr\n" ++ " Show data written to stderr by the tests, even if the test " ++ "succeeds.\n" ++ " --color auto|always|never\n" ++ " Colorize (or don't) the output.\n" ++ /* 12345678901234567890123456789012345678901234567890123456789012345678901234567890 ++ */ ++ " --help Print this help message and exit.\n"); ++#if defined(MUNIT_NL_LANGINFO) ++ setlocale(LC_ALL, ""); ++ fputs((strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) ? "µnit" : "munit", ++ stdout); ++#else ++ puts("munit"); ++#endif ++ printf(" %d.%d.%d\n" ++ "Full documentation at: https://nemequ.github.io/munit/\n", ++ (MUNIT_CURRENT_VERSION >> 16) & 0xff, ++ (MUNIT_CURRENT_VERSION >> 8) & 0xff, ++ (MUNIT_CURRENT_VERSION >> 0) & 0xff); ++ for (arg = arguments; arg != NULL && arg->name != NULL; arg++) ++ arg->write_help(arg, user_data); ++} ++ ++static const MunitArgument * ++munit_arguments_find(const MunitArgument arguments[], const char *name) { ++ const MunitArgument *arg; ++ ++ for (arg = arguments; arg != NULL && arg->name != NULL; arg++) ++ if (strcmp(arg->name, name) == 0) ++ return arg; ++ ++ return NULL; ++} ++ ++static void munit_suite_list_tests(const MunitSuite *suite, ++ munit_bool show_params, const char *prefix) { ++ size_t pre_l; ++ char *pre = munit_maybe_concat(&pre_l, (char *)prefix, (char *)suite->prefix); ++ const MunitTest *test; ++ const MunitParameterEnum *params; ++ munit_bool first; ++ char **val; ++ const MunitSuite *child_suite; ++ ++ for (test = suite->tests; test != NULL && test->name != NULL; test++) { ++ if (pre != NULL) ++ fputs(pre, stdout); ++ puts(test->name); ++ ++ if (show_params) { ++ for (params = test->parameters; params != NULL && params->name != NULL; ++ params++) { ++ fprintf(stdout, " - %s: ", params->name); ++ if (params->values == NULL) { ++ puts("Any"); ++ } else { ++ first = 1; ++ for (val = params->values; *val != NULL; val++) { ++ if (!first) { ++ fputs(", ", stdout); ++ } else { ++ first = 0; ++ } ++ fputs(*val, stdout); ++ } ++ putc('\n', stdout); ++ } ++ } ++ } ++ } ++ ++ for (child_suite = suite->suites; ++ child_suite != NULL && child_suite->prefix != NULL; child_suite++) { ++ munit_suite_list_tests(child_suite, show_params, pre); ++ } ++ ++ munit_maybe_free_concat(pre, prefix, suite->prefix); ++} ++ ++static munit_bool munit_stream_supports_ansi(FILE *stream) { ++#if !defined(_WIN32) ++ return isatty(fileno(stream)); ++#else ++ ++# if !defined(__MINGW32__) ++ size_t ansicon_size = 0; ++# endif ++ ++ if (isatty(fileno(stream))) { ++# if !defined(__MINGW32__) ++ getenv_s(&ansicon_size, NULL, 0, "ANSICON"); ++ return ansicon_size != 0; ++# else ++ return getenv("ANSICON") != NULL; ++# endif ++ } ++ return 0; ++#endif ++} ++ ++int munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc, ++ char *const *argv, ++ const MunitArgument arguments[]) { ++ int result = EXIT_FAILURE; ++ MunitTestRunner runner; ++ size_t parameters_size = 0; ++ size_t tests_size = 0; ++ int arg; ++ ++ char *envptr; ++ unsigned long ts; ++ char *endptr; ++ unsigned long long iterations; ++ MunitLogLevel level; ++ const MunitArgument *argument; ++ const char **runner_tests; ++ unsigned int tests_run; ++ unsigned int tests_total; ++ ++ runner.prefix = NULL; ++ runner.suite = NULL; ++ runner.tests = NULL; ++ runner.seed = 0; ++ runner.iterations = 0; ++ runner.parameters = NULL; ++ runner.single_parameter_mode = 0; ++ runner.user_data = NULL; ++ ++ runner.report.successful = 0; ++ runner.report.skipped = 0; ++ runner.report.failed = 0; ++ runner.report.errored = 0; ++#if defined(MUNIT_ENABLE_TIMING) ++ runner.report.cpu_clock = 0; ++ runner.report.wall_clock = 0; ++#endif ++ ++ runner.colorize = 0; ++#if !defined(_WIN32) ++ runner.fork = 1; ++#else ++ runner.fork = 0; ++#endif ++ runner.show_stderr = 0; ++ runner.fatal_failures = 0; ++ runner.suite = suite; ++ runner.user_data = user_data; ++ runner.seed = munit_rand_generate_seed(); ++ runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE); ++ ++ for (arg = 1; arg < argc; arg++) { ++ if (strncmp("--", argv[arg], 2) == 0) { ++ if (strcmp("seed", argv[arg] + 2) == 0) { ++ if (arg + 1 >= argc) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "%s requires an argument", argv[arg]); ++ goto cleanup; ++ } ++ ++ envptr = argv[arg + 1]; ++ ts = strtoul(argv[arg + 1], &envptr, 0); ++ if (*envptr != '\0' || ts > (~((munit_uint32_t)0U))) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "invalid value ('%s') passed to %s", ++ argv[arg + 1], argv[arg]); ++ goto cleanup; ++ } ++ runner.seed = (munit_uint32_t)ts; ++ ++ arg++; ++ } else if (strcmp("iterations", argv[arg] + 2) == 0) { ++ if (arg + 1 >= argc) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "%s requires an argument", argv[arg]); ++ goto cleanup; ++ } ++ ++ endptr = argv[arg + 1]; ++ iterations = strtoul(argv[arg + 1], &endptr, 0); ++ if (*endptr != '\0' || iterations > UINT_MAX) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "invalid value ('%s') passed to %s", ++ argv[arg + 1], argv[arg]); ++ goto cleanup; ++ } ++ ++ runner.iterations = (unsigned int)iterations; ++ ++ arg++; ++ } else if (strcmp("param", argv[arg] + 2) == 0) { ++ if (arg + 2 >= argc) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "%s requires two arguments", argv[arg]); ++ goto cleanup; ++ } ++ ++ runner.parameters = realloc( ++ runner.parameters, sizeof(MunitParameter) * (parameters_size + 2)); ++ if (runner.parameters == NULL) { ++ munit_log_internal(MUNIT_LOG_ERROR, stderr, ++ "failed to allocate memory"); ++ goto cleanup; ++ } ++ runner.parameters[parameters_size].name = (char *)argv[arg + 1]; ++ runner.parameters[parameters_size].value = (char *)argv[arg + 2]; ++ parameters_size++; ++ runner.parameters[parameters_size].name = NULL; ++ runner.parameters[parameters_size].value = NULL; ++ arg += 2; ++ } else if (strcmp("color", argv[arg] + 2) == 0) { ++ if (arg + 1 >= argc) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "%s requires an argument", argv[arg]); ++ goto cleanup; ++ } ++ ++ if (strcmp(argv[arg + 1], "always") == 0) ++ runner.colorize = 1; ++ else if (strcmp(argv[arg + 1], "never") == 0) ++ runner.colorize = 0; ++ else if (strcmp(argv[arg + 1], "auto") == 0) ++ runner.colorize = munit_stream_supports_ansi(MUNIT_OUTPUT_FILE); ++ else { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "invalid value ('%s') passed to %s", ++ argv[arg + 1], argv[arg]); ++ goto cleanup; ++ } ++ ++ arg++; ++ } else if (strcmp("help", argv[arg] + 2) == 0) { ++ munit_print_help(argc, argv, user_data, arguments); ++ result = EXIT_SUCCESS; ++ goto cleanup; ++ } else if (strcmp("single", argv[arg] + 2) == 0) { ++ runner.single_parameter_mode = 1; ++ } else if (strcmp("show-stderr", argv[arg] + 2) == 0) { ++ runner.show_stderr = 1; ++#if !defined(_WIN32) ++ } else if (strcmp("no-fork", argv[arg] + 2) == 0) { ++ runner.fork = 0; ++#endif ++ } else if (strcmp("fatal-failures", argv[arg] + 2) == 0) { ++ runner.fatal_failures = 1; ++ } else if (strcmp("log-visible", argv[arg] + 2) == 0 || ++ strcmp("log-fatal", argv[arg] + 2) == 0) { ++ if (arg + 1 >= argc) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "%s requires an argument", argv[arg]); ++ goto cleanup; ++ } ++ ++ if (strcmp(argv[arg + 1], "debug") == 0) ++ level = MUNIT_LOG_DEBUG; ++ else if (strcmp(argv[arg + 1], "info") == 0) ++ level = MUNIT_LOG_INFO; ++ else if (strcmp(argv[arg + 1], "warning") == 0) ++ level = MUNIT_LOG_WARNING; ++ else if (strcmp(argv[arg + 1], "error") == 0) ++ level = MUNIT_LOG_ERROR; ++ else { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "invalid value ('%s') passed to %s", ++ argv[arg + 1], argv[arg]); ++ goto cleanup; ++ } ++ ++ if (strcmp("log-visible", argv[arg] + 2) == 0) ++ munit_log_level_visible = level; ++ else ++ munit_log_level_fatal = level; ++ ++ arg++; ++ } else if (strcmp("list", argv[arg] + 2) == 0) { ++ munit_suite_list_tests(suite, 0, NULL); ++ result = EXIT_SUCCESS; ++ goto cleanup; ++ } else if (strcmp("list-params", argv[arg] + 2) == 0) { ++ munit_suite_list_tests(suite, 1, NULL); ++ result = EXIT_SUCCESS; ++ goto cleanup; ++ } else { ++ argument = munit_arguments_find(arguments, argv[arg] + 2); ++ if (argument == NULL) { ++ munit_logf_internal(MUNIT_LOG_ERROR, stderr, ++ "unknown argument ('%s')", argv[arg]); ++ goto cleanup; ++ } ++ ++ if (!argument->parse_argument(suite, user_data, &arg, argc, argv)) ++ goto cleanup; ++ } ++ } else { ++ runner_tests = ++ realloc((void *)runner.tests, sizeof(char *) * (tests_size + 2)); ++ if (runner_tests == NULL) { ++ munit_log_internal(MUNIT_LOG_ERROR, stderr, ++ "failed to allocate memory"); ++ goto cleanup; ++ } ++ runner.tests = runner_tests; ++ runner.tests[tests_size++] = argv[arg]; ++ runner.tests[tests_size] = NULL; ++ } ++ } ++ ++ fflush(stderr); ++ fprintf(MUNIT_OUTPUT_FILE, ++ "Running test suite with seed 0x%08" PRIx32 "...\n", runner.seed); ++ ++ munit_test_runner_run(&runner); ++ ++ tests_run = ++ runner.report.successful + runner.report.failed + runner.report.errored; ++ tests_total = tests_run + runner.report.skipped; ++ if (tests_run == 0) { ++ fprintf(stderr, "No tests run, %d (100%%) skipped.\n", ++ runner.report.skipped); ++ } else { ++ fprintf(MUNIT_OUTPUT_FILE, ++ "%d of %d (%0.0f%%) tests successful, %d (%0.0f%%) test skipped.\n", ++ runner.report.successful, tests_run, ++ (((double)runner.report.successful) / ((double)tests_run)) * 100.0, ++ runner.report.skipped, ++ (((double)runner.report.skipped) / ((double)tests_total)) * 100.0); ++ } ++ ++ if (runner.report.failed == 0 && runner.report.errored == 0) { ++ result = EXIT_SUCCESS; ++ } ++ ++cleanup: ++ free(runner.parameters); ++ free((void *)runner.tests); ++ ++ return result; ++} ++ ++int munit_suite_main(const MunitSuite *suite, void *user_data, int argc, ++ char *const *argv) { ++ return munit_suite_main_custom(suite, user_data, argc, argv, NULL); ++} ++ ++static uint8_t hexchars[] = "0123456789abcdef"; ++ ++static uint8_t *hexdump_addr(uint8_t *dest, size_t addr) { ++ size_t i; ++ uint8_t a; ++ ++ for (i = 0; i < 4; ++i) { ++ a = (addr >> (3 - i) * 8) & 0xff; ++ ++ *dest++ = hexchars[a >> 4]; ++ *dest++ = hexchars[a & 0xf]; ++ } ++ ++ return dest; ++} ++ ++static uint8_t *asciidump(uint8_t *dest, const uint8_t *data, size_t datalen) { ++ size_t i; ++ ++ *dest++ = '|'; ++ ++ for (i = 0; i < datalen; ++i) { ++ if (0x20 <= data[i] && data[i] <= 0x7e) { ++ *dest++ = data[i]; ++ } else { ++ *dest++ = '.'; ++ } ++ } ++ ++ *dest++ = '|'; ++ ++ return dest; ++} ++ ++static uint8_t *hexdump8(uint8_t *dest, const uint8_t *data, size_t datalen) { ++ size_t i; ++ ++ for (i = 0; i < datalen; ++i) { ++ *dest++ = hexchars[data[i] >> 4]; ++ *dest++ = hexchars[data[i] & 0xf]; ++ *dest++ = ' '; ++ } ++ ++ for (; i < 8; ++i) { ++ *dest++ = ' '; ++ *dest++ = ' '; ++ *dest++ = ' '; ++ } ++ ++ return dest; ++} ++ ++static uint8_t *hexdump16(uint8_t *dest, const uint8_t *data, size_t datalen) { ++ dest = hexdump8(dest, data, datalen < 8 ? datalen : 8); ++ *dest++ = ' '; ++ ++ if (datalen < 8) { ++ data = NULL; ++ datalen = 0; ++ } else { ++ data += 8; ++ datalen -= 8; ++ } ++ ++ dest = hexdump8(dest, data, datalen); ++ *dest++ = ' '; ++ ++ return dest; ++} ++ ++static uint8_t *hexdump_line(uint8_t *dest, const uint8_t *data, size_t datalen, ++ size_t addr) { ++ dest = hexdump_addr(dest, addr); ++ *dest++ = ' '; ++ *dest++ = ' '; ++ ++ dest = hexdump16(dest, data, datalen); ++ ++ dest = asciidump(dest, data, datalen); ++ ++ return dest; ++} ++ ++int munit_hexdump(FILE *fp, const void *data, size_t datalen) { ++ size_t offset = 0, n, len; ++ uint8_t buf[128], *p; ++ const uint8_t *s; ++ int repeated = 0; ++ ++ if (datalen == 0) { ++ return 0; ++ } ++ ++ for (; offset < datalen; offset += 16) { ++ n = datalen - offset; ++ s = (const uint8_t *)data + offset; ++ ++ if (n >= 16) { ++ n = 16; ++ ++ if (offset > 0) { ++ if (memcmp(s - 16, s, 16) == 0) { ++ if (repeated) { ++ continue; ++ } ++ ++ repeated = 1; ++ ++ if (fwrite("*\n", 1, 2, fp) < 2) { ++ return -1; ++ } ++ ++ continue; ++ } ++ ++ repeated = 0; ++ } ++ } ++ ++ p = hexdump_line(buf, s, n, offset); ++ *p++ = '\n'; ++ ++ len = (size_t)(p - buf); ++ ++ if (fwrite(buf, 1, len, fp) < len) { ++ return -1; ++ } ++ } ++ ++ p = hexdump_addr(buf, datalen); ++ *p++ = '\n'; ++ ++ len = (size_t)(p - buf); ++ ++ if (fwrite(buf, 1, len, fp) < len) { ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int munit_hexdump_diff(FILE *fp, const void *a, size_t alen, const void *b, ++ size_t blen) { ++ size_t offset = 0, k, i, len, ncomp, maxlen, adoff = 0; ++ uint8_t buf[128], *p; ++ const uint8_t mk[2] = {'-', '+'}; ++ struct datasource { ++ const uint8_t *data; ++ size_t datalen; ++ const uint8_t *s; ++ size_t n; ++ } ds[] = {{a, alen, NULL, 0}, {b, blen, NULL, 0}}, *dp; ++ ++ maxlen = alen < blen ? blen : alen; ++ ++ for (; offset < maxlen; offset += 16) { ++ for (k = 0; k < 2; ++k) { ++ dp = &ds[k]; ++ ++ if (offset < dp->datalen) { ++ dp->s = (const uint8_t *)dp->data + offset; ++ dp->n = dp->datalen - offset; ++ ++ if (dp->n > 16) { ++ dp->n = 16; ++ } ++ } else { ++ dp->s = NULL; ++ dp->n = 0; ++ } ++ } ++ ++ if (ds[0].n == ds[1].n && memcmp(ds[0].s, ds[1].s, ds[0].n) == 0) { ++ continue; ++ } ++ ++ for (k = 0; k < 2; ++k) { ++ dp = &ds[k]; ++ ++ if (!dp->n) { ++ continue; ++ } ++ ++ p = buf; ++ *p++ = mk[k]; ++ *p++ = mk[k]; ++ *p++ = mk[k]; ++ *p++ = mk[k]; ++ ++ p = hexdump_line(p, dp->s, dp->n, offset); ++ *p++ = '\n'; ++ ++ len = (size_t)(p - buf); ++ ++ if (fwrite(buf, 1, len, fp) < len) { ++ return -1; ++ } ++ } ++ ++ if (!ds[0].n || !ds[1].n) { ++ continue; ++ } ++ ++ ncomp = ds[0].n < ds[1].n ? ds[0].n : ds[1].n; ++ ++ p = buf + 4 + 10; ++ ++ memset(buf, ' ', 4 + 78); ++ ++ for (i = 0; i < ncomp; ++i) { ++ if (ds[0].s[i] == ds[1].s[i]) { ++ *p++ = ' '; ++ *p++ = ' '; ++ } else { ++ adoff = 4 + 10 + 51 + i; ++ *(buf + adoff) = '^'; ++ ++ *p++ = '^'; ++ *p++ = '^'; ++ } ++ ++ *p++ = ' '; ++ ++ if (i == 7) { ++ *p++ = ' '; ++ } ++ } ++ ++ if (adoff) { ++ len = adoff + 1; ++ } else { ++ len = (size_t)(p - buf); ++ } ++ ++ buf[len++] = '\n'; ++ ++ if (fwrite(buf, 1, len, fp) < len) { ++ return -1; ++ } ++ } ++ ++ return 0; ++} +diff --git a/tests/munit/munit.h b/tests/munit/munit.h +new file mode 100644 +index 0000000..3bdcca0 +--- /dev/null ++++ b/tests/munit/munit.h +@@ -0,0 +1,575 @@ ++/* µnit Testing Framework ++ * Copyright (c) 2013-2017 Evan Nemerson <evan@nemerson.com> ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef MUNIT_H ++#define MUNIT_H ++ ++#include <stdarg.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <stddef.h> ++ ++#define MUNIT_VERSION(major, minor, revision) \ ++ (((major) << 16) | ((minor) << 8) | (revision)) ++ ++#define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1) ++ ++#if defined(_MSC_VER) && (_MSC_VER < 1600) ++# define munit_int8_t __int8 ++# define munit_uint8_t unsigned __int8 ++# define munit_int16_t __int16 ++# define munit_uint16_t unsigned __int16 ++# define munit_int32_t __int32 ++# define munit_uint32_t unsigned __int32 ++# define munit_int64_t __int64 ++# define munit_uint64_t unsigned __int64 ++#else ++# include <stdint.h> ++# define munit_int8_t int8_t ++# define munit_uint8_t uint8_t ++# define munit_int16_t int16_t ++# define munit_uint16_t uint16_t ++# define munit_int32_t int32_t ++# define munit_uint32_t uint32_t ++# define munit_int64_t int64_t ++# define munit_uint64_t uint64_t ++#endif ++ ++#if defined(_MSC_VER) && (_MSC_VER < 1800) ++# if !defined(PRIi8) ++# define PRIi8 "i" ++# endif ++# if !defined(PRIi16) ++# define PRIi16 "i" ++# endif ++# if !defined(PRIi32) ++# define PRIi32 "i" ++# endif ++# if !defined(PRIi64) ++# define PRIi64 "I64i" ++# endif ++# if !defined(PRId8) ++# define PRId8 "d" ++# endif ++# if !defined(PRId16) ++# define PRId16 "d" ++# endif ++# if !defined(PRId32) ++# define PRId32 "d" ++# endif ++# if !defined(PRId64) ++# define PRId64 "I64d" ++# endif ++# if !defined(PRIx8) ++# define PRIx8 "x" ++# endif ++# if !defined(PRIx16) ++# define PRIx16 "x" ++# endif ++# if !defined(PRIx32) ++# define PRIx32 "x" ++# endif ++# if !defined(PRIx64) ++# define PRIx64 "I64x" ++# endif ++# if !defined(PRIu8) ++# define PRIu8 "u" ++# endif ++# if !defined(PRIu16) ++# define PRIu16 "u" ++# endif ++# if !defined(PRIu32) ++# define PRIu32 "u" ++# endif ++# if !defined(PRIu64) ++# define PRIu64 "I64u" ++# endif ++#else ++# include <inttypes.h> ++#endif ++ ++#if !defined(munit_bool) ++# if defined(bool) ++# define munit_bool bool ++# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) ++# define munit_bool _Bool ++# else ++# define munit_bool int ++# endif ++#endif ++ ++#if defined(__cplusplus) ++extern "C" { ++#endif ++ ++#if defined(__GNUC__) ++# define MUNIT_LIKELY(expr) (__builtin_expect((expr), 1)) ++# define MUNIT_UNLIKELY(expr) (__builtin_expect((expr), 0)) ++# define MUNIT_UNUSED __attribute__((__unused__)) ++#else ++# define MUNIT_LIKELY(expr) (expr) ++# define MUNIT_UNLIKELY(expr) (expr) ++# define MUNIT_UNUSED ++#endif ++ ++#if !defined(_WIN32) ++# define MUNIT_SIZE_MODIFIER "z" ++# define MUNIT_CHAR_MODIFIER "hh" ++# define MUNIT_SHORT_MODIFIER "h" ++#else ++# if defined(_M_X64) || defined(__amd64__) ++# define MUNIT_SIZE_MODIFIER "I64" ++# else ++# define MUNIT_SIZE_MODIFIER "" ++# endif ++# define MUNIT_CHAR_MODIFIER "" ++# define MUNIT_SHORT_MODIFIER "" ++#endif ++ ++#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L ++# define MUNIT_NO_RETURN _Noreturn ++#elif defined(__GNUC__) ++# define MUNIT_NO_RETURN __attribute__((__noreturn__)) ++#elif defined(_MSC_VER) ++# define MUNIT_NO_RETURN __declspec(noreturn) ++#else ++# define MUNIT_NO_RETURN ++#endif ++ ++#if defined(_MSC_VER) && (_MSC_VER >= 1500) ++# define MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ __pragma(warning(push)) __pragma(warning(disable : 4127)) ++# define MUNIT_POP_DISABLE_MSVC_C4127_ __pragma(warning(pop)) ++#else ++# define MUNIT_PUSH_DISABLE_MSVC_C4127_ ++# define MUNIT_POP_DISABLE_MSVC_C4127_ ++#endif ++ ++typedef enum { ++ MUNIT_LOG_DEBUG, ++ MUNIT_LOG_INFO, ++ MUNIT_LOG_WARNING, ++ MUNIT_LOG_ERROR ++} MunitLogLevel; ++ ++#if defined(__GNUC__) && !defined(__MINGW32__) ++# define MUNIT_PRINTF(string_index, first_to_check) \ ++ __attribute__((format(printf, string_index, first_to_check))) ++#else ++# define MUNIT_PRINTF(string_index, first_to_check) ++#endif ++ ++MUNIT_PRINTF(4, 5) ++void munit_logf_ex(MunitLogLevel level, const char *filename, int line, ++ const char *format, ...); ++ ++#define munit_logf(level, format, ...) \ ++ munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__) ++ ++#define munit_log(level, msg) munit_logf(level, "%s", msg) ++ ++MUNIT_NO_RETURN ++MUNIT_PRINTF(3, 4) ++void munit_errorf_ex(const char *filename, int line, const char *format, ...); ++ ++#define munit_errorf(format, ...) \ ++ munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__) ++ ++#define munit_error(msg) munit_errorf("%s", msg) ++ ++#define munit_assert(expr) \ ++ do { \ ++ if (!MUNIT_LIKELY(expr)) { \ ++ munit_error("assertion failed: " #expr); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_true(expr) \ ++ do { \ ++ if (!MUNIT_LIKELY(expr)) { \ ++ munit_error("assertion failed: " #expr " is not true"); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_false(expr) \ ++ do { \ ++ if (!MUNIT_LIKELY(!(expr))) { \ ++ munit_error("assertion failed: " #expr " is not false"); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b) \ ++ do { \ ++ T munit_tmp_a_ = (a); \ ++ T munit_tmp_b_ = (b); \ ++ if (!(munit_tmp_a_ op munit_tmp_b_)) { \ ++ munit_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix \ ++ " %s " prefix "%" fmt suffix ")", \ ++ #a, #op, #b, munit_tmp_a_, #op, munit_tmp_b_); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_type(T, fmt, a, op, b) \ ++ munit_assert_type_full("", "", T, fmt, a, op, b) ++ ++#define munit_assert_char(a, op, b) \ ++ munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, \ ++ op, b) ++#define munit_assert_uchar(a, op, b) \ ++ munit_assert_type_full("'\\x", "'", unsigned char, \ ++ "02" MUNIT_CHAR_MODIFIER "x", a, op, b) ++#define munit_assert_short(a, op, b) \ ++ munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b) ++#define munit_assert_ushort(a, op, b) \ ++ munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b) ++#define munit_assert_int(a, op, b) munit_assert_type(int, "d", a, op, b) ++#define munit_assert_uint(a, op, b) \ ++ munit_assert_type(unsigned int, "u", a, op, b) ++#define munit_assert_long(a, op, b) munit_assert_type(long int, "ld", a, op, b) ++#define munit_assert_ulong(a, op, b) \ ++ munit_assert_type(unsigned long int, "lu", a, op, b) ++#define munit_assert_llong(a, op, b) \ ++ munit_assert_type(long long int, "lld", a, op, b) ++#define munit_assert_ullong(a, op, b) \ ++ munit_assert_type(unsigned long long int, "llu", a, op, b) ++ ++#define munit_assert_size(a, op, b) \ ++ munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b) ++#define munit_assert_ssize(a, op, b) \ ++ munit_assert_type(ssize_t, MUNIT_SIZE_MODIFIER "d", a, op, b) ++ ++#define munit_assert_float(a, op, b) munit_assert_type(float, "f", a, op, b) ++#define munit_assert_double(a, op, b) munit_assert_type(double, "g", a, op, b) ++#define munit_assert_ptr(a, op, b) \ ++ munit_assert_type(const void *, "p", a, op, b) ++ ++#define munit_assert_int8(a, op, b) \ ++ munit_assert_type(munit_int8_t, PRIi8, a, op, b) ++#define munit_assert_uint8(a, op, b) \ ++ munit_assert_type(munit_uint8_t, PRIu8, a, op, b) ++#define munit_assert_int16(a, op, b) \ ++ munit_assert_type(munit_int16_t, PRIi16, a, op, b) ++#define munit_assert_uint16(a, op, b) \ ++ munit_assert_type(munit_uint16_t, PRIu16, a, op, b) ++#define munit_assert_int32(a, op, b) \ ++ munit_assert_type(munit_int32_t, PRIi32, a, op, b) ++#define munit_assert_uint32(a, op, b) \ ++ munit_assert_type(munit_uint32_t, PRIu32, a, op, b) ++#define munit_assert_int64(a, op, b) \ ++ munit_assert_type(munit_int64_t, PRIi64, a, op, b) ++#define munit_assert_uint64(a, op, b) \ ++ munit_assert_type(munit_uint64_t, PRIu64, a, op, b) ++ ++#define munit_assert_ptrdiff(a, op, b) \ ++ munit_assert_type(ptrdiff_t, "td", a, op, b) ++ ++#define munit_assert_enum(T, a, op, b) munit_assert_type(T, "d", a, op, b) ++ ++#define munit_assert_double_equal(a, b, precision) \ ++ do { \ ++ const double munit_tmp_a_ = (a); \ ++ const double munit_tmp_b_ = (b); \ ++ const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) \ ++ ? -(munit_tmp_a_ - munit_tmp_b_) \ ++ : (munit_tmp_a_ - munit_tmp_b_); \ ++ if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \ ++ munit_errorf("assertion failed: %s == %s (%0." #precision \ ++ "g == %0." #precision "g)", \ ++ #a, #b, munit_tmp_a_, munit_tmp_b_); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#include <string.h> ++#define munit_assert_string_equal(a, b) \ ++ do { \ ++ const char *munit_tmp_a_ = a; \ ++ const char *munit_tmp_b_ = b; \ ++ if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \ ++ munit_hexdump_diff(stderr, munit_tmp_a_, strlen(munit_tmp_a_), \ ++ munit_tmp_b_, strlen(munit_tmp_b_)); \ ++ munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", #a, \ ++ #b, munit_tmp_a_, munit_tmp_b_); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_string_not_equal(a, b) \ ++ do { \ ++ const char *munit_tmp_a_ = a; \ ++ const char *munit_tmp_b_ = b; \ ++ if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \ ++ munit_errorf("assertion failed: string %s != %s (\"%s\" == \"%s\")", #a, \ ++ #b, munit_tmp_a_, munit_tmp_b_); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_memory_equal(size, a, b) \ ++ do { \ ++ const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \ ++ const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \ ++ const size_t munit_tmp_size_ = (size); \ ++ if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != \ ++ 0) { \ ++ size_t munit_tmp_pos_; \ ++ for (munit_tmp_pos_ = 0; munit_tmp_pos_ < munit_tmp_size_; \ ++ munit_tmp_pos_++) { \ ++ if (munit_tmp_a_[munit_tmp_pos_] != munit_tmp_b_[munit_tmp_pos_]) { \ ++ munit_hexdump_diff(stderr, munit_tmp_a_, size, munit_tmp_b_, size); \ ++ munit_errorf("assertion failed: memory %s == %s, at offset " \ ++ "%" MUNIT_SIZE_MODIFIER "u", \ ++ #a, #b, munit_tmp_pos_); \ ++ break; \ ++ } \ ++ } \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_memn_equal(a, a_size, b, b_size) \ ++ do { \ ++ const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \ ++ const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \ ++ const size_t munit_tmp_a_size_ = (a_size); \ ++ const size_t munit_tmp_b_size_ = (b_size); \ ++ if (MUNIT_UNLIKELY(munit_tmp_a_size_ != munit_tmp_b_size_) || \ ++ MUNIT_UNLIKELY(munit_tmp_a_size_ && memcmp(munit_tmp_a_, munit_tmp_b_, \ ++ munit_tmp_a_size_)) != 0) { \ ++ munit_hexdump_diff(stderr, munit_tmp_a_, munit_tmp_a_size_, \ ++ munit_tmp_b_, munit_tmp_b_size_); \ ++ munit_errorf("assertion failed: memory %s == %s", #a, #b); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_memory_not_equal(size, a, b) \ ++ do { \ ++ const unsigned char *munit_tmp_a_ = (const unsigned char *)(a); \ ++ const unsigned char *munit_tmp_b_ = (const unsigned char *)(b); \ ++ const size_t munit_tmp_size_ = (size); \ ++ if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == \ ++ 0) { \ ++ munit_errorf("assertion failed: memory %s != %s (%zu bytes)", #a, #b, \ ++ munit_tmp_size_); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#define munit_assert_ptr_equal(a, b) munit_assert_ptr(a, ==, b) ++#define munit_assert_ptr_not_equal(a, b) munit_assert_ptr(a, !=, b) ++#define munit_assert_null(ptr) munit_assert_ptr(ptr, ==, NULL) ++#define munit_assert_not_null(ptr) munit_assert_ptr(ptr, !=, NULL) ++#define munit_assert_ptr_null(ptr) munit_assert_ptr(ptr, ==, NULL) ++#define munit_assert_ptr_not_null(ptr) munit_assert_ptr(ptr, !=, NULL) ++ ++/*** Memory allocation ***/ ++ ++void *munit_malloc_ex(const char *filename, int line, size_t size); ++ ++#define munit_malloc(size) munit_malloc_ex(__FILE__, __LINE__, (size)) ++ ++#define munit_new(type) ((type *)munit_malloc(sizeof(type))) ++ ++#define munit_calloc(nmemb, size) munit_malloc((nmemb) * (size)) ++ ++#define munit_newa(type, nmemb) ((type *)munit_calloc((nmemb), sizeof(type))) ++ ++/*** Random number generation ***/ ++ ++void munit_rand_seed(munit_uint32_t seed); ++munit_uint32_t munit_rand_uint32(void); ++int munit_rand_int_range(int min, int max); ++double munit_rand_double(void); ++void munit_rand_memory(size_t size, munit_uint8_t *buffer); ++ ++/*** Tests and Suites ***/ ++ ++typedef enum { ++ /* Test successful */ ++ MUNIT_OK, ++ /* Test failed */ ++ MUNIT_FAIL, ++ /* Test was skipped */ ++ MUNIT_SKIP, ++ /* Test failed due to circumstances not intended to be tested ++ * (things like network errors, invalid parameter value, failure to ++ * allocate memory in the test harness, etc.). */ ++ MUNIT_ERROR ++} MunitResult; ++ ++typedef struct { ++ char *name; ++ char **values; ++} MunitParameterEnum; ++ ++typedef struct { ++ char *name; ++ char *value; ++} MunitParameter; ++ ++const char *munit_parameters_get(const MunitParameter params[], ++ const char *key); ++ ++typedef enum { ++ MUNIT_TEST_OPTION_NONE = 0, ++ MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0, ++ MUNIT_TEST_OPTION_TODO = 1 << 1 ++} MunitTestOptions; ++ ++typedef MunitResult (*MunitTestFunc)(const MunitParameter params[], ++ void *user_data_or_fixture); ++typedef void *(*MunitTestSetup)(const MunitParameter params[], void *user_data); ++typedef void (*MunitTestTearDown)(void *fixture); ++ ++typedef struct { ++ const char *name; ++ MunitTestFunc test; ++ MunitTestSetup setup; ++ MunitTestTearDown tear_down; ++ MunitTestOptions options; ++ MunitParameterEnum *parameters; ++} MunitTest; ++ ++typedef enum { MUNIT_SUITE_OPTION_NONE = 0 } MunitSuiteOptions; ++ ++typedef struct MunitSuite_ MunitSuite; ++ ++struct MunitSuite_ { ++ const char *prefix; ++ const MunitTest *tests; ++ const MunitSuite *suites; ++ unsigned int iterations; ++ MunitSuiteOptions options; ++}; ++ ++int munit_suite_main(const MunitSuite *suite, void *user_data, int argc, ++ char *const *argv); ++ ++/* Note: I'm not very happy with this API; it's likely to change if I ++ * figure out something better. Suggestions welcome. */ ++ ++typedef struct MunitArgument_ MunitArgument; ++ ++struct MunitArgument_ { ++ char *name; ++ munit_bool (*parse_argument)(const MunitSuite *suite, void *user_data, ++ int *arg, int argc, char *const *argv); ++ void (*write_help)(const MunitArgument *argument, void *user_data); ++}; ++ ++int munit_suite_main_custom(const MunitSuite *suite, void *user_data, int argc, ++ char *const *argv, const MunitArgument arguments[]); ++ ++#if defined(MUNIT_ENABLE_ASSERT_ALIASES) ++ ++# define assert_true(expr) munit_assert_true(expr) ++# define assert_false(expr) munit_assert_false(expr) ++# define assert_char(a, op, b) munit_assert_char(a, op, b) ++# define assert_uchar(a, op, b) munit_assert_uchar(a, op, b) ++# define assert_short(a, op, b) munit_assert_short(a, op, b) ++# define assert_ushort(a, op, b) munit_assert_ushort(a, op, b) ++# define assert_int(a, op, b) munit_assert_int(a, op, b) ++# define assert_uint(a, op, b) munit_assert_uint(a, op, b) ++# define assert_long(a, op, b) munit_assert_long(a, op, b) ++# define assert_ulong(a, op, b) munit_assert_ulong(a, op, b) ++# define assert_llong(a, op, b) munit_assert_llong(a, op, b) ++# define assert_ullong(a, op, b) munit_assert_ullong(a, op, b) ++# define assert_size(a, op, b) munit_assert_size(a, op, b) ++# define assert_ssize(a, op, b) munit_assert_ssize(a, op, b) ++# define assert_float(a, op, b) munit_assert_float(a, op, b) ++# define assert_double(a, op, b) munit_assert_double(a, op, b) ++# define assert_ptr(a, op, b) munit_assert_ptr(a, op, b) ++ ++# define assert_int8(a, op, b) munit_assert_int8(a, op, b) ++# define assert_uint8(a, op, b) munit_assert_uint8(a, op, b) ++# define assert_int16(a, op, b) munit_assert_int16(a, op, b) ++# define assert_uint16(a, op, b) munit_assert_uint16(a, op, b) ++# define assert_int32(a, op, b) munit_assert_int32(a, op, b) ++# define assert_uint32(a, op, b) munit_assert_uint32(a, op, b) ++# define assert_int64(a, op, b) munit_assert_int64(a, op, b) ++# define assert_uint64(a, op, b) munit_assert_uint64(a, op, b) ++ ++# define assert_ptrdiff(a, op, b) munit_assert_ptrdiff(a, op, b) ++ ++# define assert_enum(T, a, op, b) munit_assert_enum(T, a, op, b) ++ ++# define assert_double_equal(a, b, precision) \ ++ munit_assert_double_equal(a, b, precision) ++# define assert_string_equal(a, b) munit_assert_string_equal(a, b) ++# define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b) ++# define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b) ++# define assert_memn_equal(a, a_size, b, b_size) \ ++ munit_assert_memn_equal(a, a_size, b, b_size) ++# define assert_memory_not_equal(size, a, b) \ ++ munit_assert_memory_not_equal(size, a, b) ++# define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b) ++# define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b) ++# define assert_ptr_null(ptr) munit_assert_null_equal(ptr) ++# define assert_ptr_not_null(ptr) munit_assert_not_null(ptr) ++ ++# define assert_null(ptr) munit_assert_null(ptr) ++# define assert_not_null(ptr) munit_assert_not_null(ptr) ++ ++#endif /* defined(MUNIT_ENABLE_ASSERT_ALIASES) */ ++ ++#define munit_void_test_decl(func) \ ++ void func(void); \ ++ \ ++ static inline MunitResult wrap_##func(const MunitParameter params[], \ ++ void *fixture) { \ ++ (void)params; \ ++ (void)fixture; \ ++ \ ++ func(); \ ++ return MUNIT_OK; \ ++ } ++ ++#define munit_void_test(func) \ ++ { "/" #func, wrap_##func, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } ++ ++#define munit_test_end() \ ++ { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } ++ ++int munit_hexdump(FILE *fp, const void *data, size_t datalen); ++ ++int munit_hexdump_diff(FILE *fp, const void *a, size_t alen, const void *b, ++ size_t blen); ++ ++#if defined(__cplusplus) ++} ++#endif ++ ++#endif /* !defined(MUNIT_H) */ ++ ++#if defined(MUNIT_ENABLE_ASSERT_ALIASES) ++#if defined(assert) ++# undef assert ++#endif ++#define assert(expr) munit_assert(expr) ++#endif +diff --git a/tests/munit/munitxx.h b/tests/munit/munitxx.h +new file mode 100644 +index 0000000..5e50921 +--- /dev/null ++++ b/tests/munit/munitxx.h +@@ -0,0 +1,94 @@ ++/* µnit Testing Framework ++ * Copyright (c) 2013-2017 Evan Nemerson <evan@nemerson.com> ++ * Copyright (c) 2023 munit contributors ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ */ ++ ++#ifndef MUNITXX_H ++#define MUNITXX_H ++ ++#include <munit.h> ++ ++#include <type_traits> ++#include <string> ++#if __cplusplus >= 201703L ++# include <string_view> ++#endif // __cplusplus >= 201703L ++ ++#define munit_assert_stdstring_equal(a, b) \ ++ do { \ ++ const std::string munit_tmp_a_ = a; \ ++ const std::string munit_tmp_b_ = b; \ ++ if (MUNIT_UNLIKELY(a != b)) { \ ++ munit_hexdump_diff(stderr, munit_tmp_a_.c_str(), munit_tmp_a_.size(), \ ++ munit_tmp_b_.c_str(), munit_tmp_b_.size()); \ ++ munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", #a, \ ++ #b, munit_tmp_a_.c_str(), munit_tmp_b_.c_str()); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#if __cplusplus >= 201703L ++# define munit_assert_stdsv_equal(a, b) \ ++ do { \ ++ const std::string_view munit_tmp_a_ = a; \ ++ const std::string_view munit_tmp_b_ = b; \ ++ if (MUNIT_UNLIKELY(a != b)) { \ ++ munit_hexdump_diff(stderr, munit_tmp_a_.data(), munit_tmp_a_.size(), \ ++ munit_tmp_b_.data(), munit_tmp_b_.size()); \ ++ munit_errorf( \ ++ "assertion failed: string %s == %s (\"%.*s\" == \"%.*s\")", #a, \ ++ #b, (int)munit_tmp_a_.size(), munit_tmp_a_.data(), \ ++ (int)munit_tmp_b_.size(), munit_tmp_b_.data()); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++#endif // __cplusplus >= 201703L ++ ++#define munit_assert_enum_class(a, op, b) \ ++ do { \ ++ auto munit_tmp_a_ = (a); \ ++ auto munit_tmp_b_ = (b); \ ++ if (!(munit_tmp_a_ op munit_tmp_b_)) { \ ++ auto munit_tmp_a_str_ = std::to_string( \ ++ static_cast<std::underlying_type_t<decltype(munit_tmp_a_)>>( \ ++ munit_tmp_a_)); \ ++ auto munit_tmp_b_str_ = std::to_string( \ ++ static_cast<std::underlying_type_t<decltype(munit_tmp_b_)>>( \ ++ munit_tmp_b_)); \ ++ munit_errorf("assertion failed: %s %s %s (%s %s %s)", #a, #op, #b, \ ++ munit_tmp_a_str_.c_str(), #op, munit_tmp_b_str_.c_str()); \ ++ } \ ++ MUNIT_PUSH_DISABLE_MSVC_C4127_ \ ++ } while (0) MUNIT_POP_DISABLE_MSVC_C4127_ ++ ++#if defined(MUNIT_ENABLE_ASSERT_ALIASES) ++ ++# define assert_stdstring_equal(a, b) munit_assert_stdstring_equal(a, b) ++# if __cplusplus >= 201703L ++# define assert_stdsv_equal(a, b) munit_assert_stdsv_equal(a, b) ++# endif // __cplusplus >= 201703L ++# define assert_enum_class(a, op, b) munit_assert_enum_class(a, op, b) ++ ++#endif /* defined(MUNIT_ENABLE_ASSERT_ALIASES) */ ++ ++#endif // MUNITXX_H diff --git a/debian/patches/series b/debian/patches/series index 8670f6c..079921e 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,2 @@ -0001-Make-fetch-ocsp-response-use-python3.patch 0002-Workaround-for-963648.patch +0002-add-munit-explicitly.patch |