diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0b5ff62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.idea* +cmake-build-debug +*__pycache__* diff --git a/FlippR-Driver/.bash_aliases b/FlippR-Driver/.bash_aliases deleted file mode 100644 index fa40af8..0000000 --- a/FlippR-Driver/.bash_aliases +++ /dev/null @@ -1,10 +0,0 @@ -alias ll='ls -alF' -alias la='ls -A' -alias l='ls -lA' -alias cat='cat -n' -alias ncat='cat' -alias mkdir='mkdir -p' -alias pdfmerge='gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOUTPUTFILE=' -alias sync_bash_rc='sync_bash .bashrc_ssh' -alias sync_bash_aliases='sync_bash .bash_aliases' -alias sync_bash_functions='sync_bash .bash_functions' diff --git a/FlippR-Driver/.bash_functions b/FlippR-Driver/.bash_functions deleted file mode 100644 index d5b30e0..0000000 --- a/FlippR-Driver/.bash_functions +++ /dev/null @@ -1,79 +0,0 @@ -function up { -[ "${1/[^0-9]/}" == "$1" ] && { - local ups="" - for i in $(seq 1 $1) - do - ups=$ups"../" - done - cd $ups - } || cd ../ -} - -function ccat { - pygmentize -g $1 | cat -n -} - -function sync_bash { - if [ -z "$1" ] - then - exit 1 - fi - echo $BASHRC_DIR - echo $1 - rsync -avzhe ssh $1 $BASHRC_USER@$BASHRC_SERVER:$BASHRC_DIR/$1 -} - -function get_bash_file { - if [ -z "$1" ] - then - exit 1 - fi - echo $BASHRC_DIR - echo $1 - rsync -avzhe ssh $BASHRC_USER@$BASHRC_SERVER:$BASHRC_DIR/$1 $1 -} - -SAVEIFS=$IFS -IFS=$(echo -en "\n\b") - -function extract { - if [ -z "$1" ]; then - # display usage if no parameters given - echo "Usage: extract ." - echo " extract [path/file_name_2.ext] [path/file_name_3.ext]" - else - for n in "$@" - do - if [ -f "$n" ] ; then - case "${n%,}" in - *.tar.bz2|*.tar.gz|*.tar.xz|*.tbz2|*.tgz|*.txz|*.tar) - tar xvf "$n" ;; - *.lzma) unlzma ./"$n" ;; - *.bz2) bunzip2 ./"$n" ;; - *.rar) unrar x -ad ./"$n" ;; - *.gz) gunzip ./"$n" ;; - *.zip) unzip ./"$n" ;; - *.z) uncompress ./"$n" ;; - *.7z|*.arj|*.cab|*.chm|*.deb|*.dmg|*.iso|*.lzh|*.msi|*.rpm|*.udf|*.wim|*.xar) - 7z x ./"$n" ;; - *.xz) unxz ./"$n" ;; - *.exe) cabextract ./"$n" ;; - *.cpio) cpio -id < ./"$n" ;; - *) - echo "extract: '$n' - unknown archive method" - return 1 - ;; - esac - else - echo "'$n' - file does not exist" - return 1 - fi - done -fi -} - -IFS=$SAVEIFS - -calc() { - echo "scale=3;$@" | bc -l -} diff --git a/FlippR-Driver/.cproject b/FlippR-Driver/.cproject deleted file mode 100644 index 1251af0..0000000 --- a/FlippR-Driver/.cproject +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FlippR-Driver/.gitignore b/FlippR-Driver/.gitignore index f490952..bacf957 100644 --- a/FlippR-Driver/.gitignore +++ b/FlippR-Driver/.gitignore @@ -1,4 +1,16 @@ +.csettings/* build -src/Debug -/Debug/ +CMakeFiles +CMakeCache.txt +bin +*.log .settings/* +*.bin +*.cmake +*.out +.settings/* +Makefile +.project +.cproject +.idea* +nbproject* diff --git a/FlippR-Driver/.project b/FlippR-Driver/.project deleted file mode 100644 index 7cb6a73..0000000 --- a/FlippR-Driver/.project +++ /dev/null @@ -1,27 +0,0 @@ - - - FlippR-Driver - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - diff --git a/FlippR-Driver/.settings/language.settings.xml b/FlippR-Driver/.settings/language.settings.xml deleted file mode 100644 index d3526a4..0000000 --- a/FlippR-Driver/.settings/language.settings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/FlippR-Driver/.settings/org.eclipse.cdt.codan.core.prefs b/FlippR-Driver/.settings/org.eclipse.cdt.codan.core.prefs deleted file mode 100644 index 812e407..0000000 --- a/FlippR-Driver/.settings/org.eclipse.cdt.codan.core.prefs +++ /dev/null @@ -1,71 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.cdt.codan.checkers.errnoreturn=Warning -org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return\\")",implicit\=>false} -org.eclipse.cdt.codan.checkers.errreturnvalue=Error -org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused return value\\")"} -org.eclipse.cdt.codan.checkers.nocommentinside=-Error -org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Nesting comments\\")"} -org.eclipse.cdt.codan.checkers.nolinecomment=-Error -org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Line comments\\")"} -org.eclipse.cdt.codan.checkers.noreturn=Error -org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return value\\")",implicit\=>false} -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error -org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Abstract class cannot be instantiated\\")"} -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error -org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Ambiguous problem\\")"} -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment in condition\\")"} -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error -org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment to itself\\")"} -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning -org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No break at end of case\\")",no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false,enable_fallthrough_quickfix_param\=>false} -org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning -org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Catching by reference is recommended\\")",unknown\=>false,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error -org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Circular inheritance\\")"} -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning -org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class members should be properly initialized\\")",skip\=>true} -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Field cannot be resolved\\")"} -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Function cannot be resolved\\")"} -org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error -org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid arguments\\")"} -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error -org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid template argument\\")"} -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error -org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Label statement not found\\")"} -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error -org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Member declaration not found\\")"} -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Method cannot be resolved\\")"} -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info -org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Name convention for function\\")",pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning -org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class has a virtual method and non-virtual destructor\\")"} -org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error -org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid overload\\")"} -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error -org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redeclaration\\")"} -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error -org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redefinition\\")"} -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Return with parenthesis\\")"} -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning -org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Format String Vulnerability\\")"} -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning -org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Statement has no effect\\")",macro\=>true,exceptions\=>()} -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suggested parenthesis around expression\\")",paramNot\=>false} -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning -org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suspicious semicolon\\")",else\=>false,afterelse\=>false} -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Type cannot be resolved\\")"} -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused function declaration\\")",macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused static function\\")",macro\=>true} -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning -org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused variable declaration in file scope\\")",macro\=>true,exceptions\=>("@(\#)","$Id")} -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error -org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Symbol is not resolved\\")"} diff --git a/FlippR-Driver/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/FlippR-Driver/.settings/org.eclipse.cdt.managedbuilder.core.prefs deleted file mode 100644 index c9cd6c6..0000000 --- a/FlippR-Driver/.settings/org.eclipse.cdt.managedbuilder.core.prefs +++ /dev/null @@ -1,13 +0,0 @@ -eclipse.preferences.version=1 -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/CPATH/delimiter=\: -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/CPATH/operation=remove -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/CPLUS_INCLUDE_PATH/delimiter=\: -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/CPLUS_INCLUDE_PATH/operation=remove -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/C_INCLUDE_PATH/delimiter=\: -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/C_INCLUDE_PATH/operation=remove -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/append=true -environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.exe.debug.1796611039/appendContributed=true -environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1796611039/LIBRARY_PATH/delimiter=\: -environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1796611039/LIBRARY_PATH/operation=remove -environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1796611039/append=true -environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.exe.debug.1796611039/appendContributed=true diff --git a/FlippR-Driver/CMakeLists.txt b/FlippR-Driver/CMakeLists.txt index 46d36d9..a998016 100644 --- a/FlippR-Driver/CMakeLists.txt +++ b/FlippR-Driver/CMakeLists.txt @@ -1,3 +1,133 @@ -project(flippr-driver) +####################### OPTIONS ######################### +option(CROSS_COMPILE "Enables crosscompiling for raspberry pi" OFF) +option(BUILD_SHARED_LIB "Build a shared lib instead of a static." OFF) +option(ENABLE_TESTING "Enables testing." ON) +option(BUILD_NETWORKING "Build socket communication executable." ON) +option(BUILD_CLI "Makes a basic testing cli" OFF) -subdirs(build Debug etc json_example src) +#################### CONFIGURATION ###################### +set(OUTPUT_PATH bin) +set(LIB_DIR lib) +set(DEFAULT_BUILD_TYPE DEBUG) + +set(CMAKE_CXX_STANDARD 14) + +SET(CMAKE_CXX_FLAGS -pthread) + +IF(NOT_PI) + add_definitions(-DNOT_PI) + message("Compiling not for Pi") +ENDIF() + +project(FlippR-Driver) + +###################### START_CMAKE ####################### +cmake_minimum_required(VERSION 3.0.1) +project(FlippR-Driver VERSION 0.1.0)# LANGUAGES CXX) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + +#set easylogging flags +add_definitions(-DELPP_NO_DEFAULT_LOG_FILE) + +# Compile library to output_path +set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/${OUTPUT_PATH}) + + +# Default to Release build +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE ${DEFAULT_BUILD_TYPE}) +endif(NOT CMAKE_BUILD_TYPE) + + +#set code-coverage flags if Debug mode +IF(CMAKE_BUILD_TYPE MATCHES DEBUG) + message("Setting gcov flags") + SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage") + SET(GCC_COVERAGE_LINK_FLAGS "-lgcov") + + SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}" ) + SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}" ) +ENDIF(CMAKE_BUILD_TYPE MATCHES DEBUG) + +#################### Adding Library ##################### +file(GLOB_RECURSE SOURCES src/*.cpp) + +if(BUILD_SHARED_LIB) + add_library(${PROJECT_NAME} SHARED ${SOURCES}) +else() + add_library(${PROJECT_NAME} STATIC ${SOURCES} cli/OutputInterpreter.cpp cli/OutputInterpreter.h src/output/items/detail/DriverBoardItem.cpp src/output/items/detail/DriverBoardItem.h include/DriverFactory.h src/utility/Colors.h src/output/factories/SoundFactory.cpp src/output/factories/SoundFactory.h src/output/factories/ItemFactory.cpp src/output/factories/ItemFactory.h src/output/factories/FlipperFactory.cpp src/output/factories/FlipperFactory.h src/output/factories/LampFactory.cpp src/output/factories/LampFactory.h src/output/factories/DisplayFactory.cpp src/output/factories/DisplayFactory.h src/output/factories/SolenoidFactory.cpp src/output/factories/SolenoidFactory.h src/utility/helper_functions.hpp) +endif(BUILD_SHARED_LIB) + +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/include) + +# Set libraries include path +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/${LIB_DIR}) + +######################### BOOST ######################### +# Boost configuration +set(BOOST_COMPONENTS program_options thread timer chrono filesystem) +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +if(Boost_FOUND) + # Include and link with boost + target_include_directories(${PROJECT_NAME} PUBLIC ${Boost_INCLUDE_DIRS}) + LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) + target_link_libraries(${PROJECT_NAME} PUBLIC ${Boost_LIBRARIES}) + message ("Boost found and linked at ${Boost_INCLUDE_DIRS}") +else() + message (FATAL_ERROR "Can't find Boost.") +endif(Boost_FOUND) + +##################### WIRING_PI ########################## +find_library(wiringPi_LIB wiringPi) + +if(NOT wiringPi_LIB) + message(WARNING "Could not find wiringPi library, used testing wiring pi lib instead.") + add_definitions(-DNO_WIRING_PI) +else() + message(STATUS "Found wiring pi.") + target_include_directories(${PROJECT_NAME} PUBLIC ${wiringPi_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} PUBLIC ${wiringPi_LIB}) +endif() + +find_library(crypt_LIB crypt) +if(NOT crypt_LIB) + message(FATAL_ERROR "Could not find crypt library") +endif() +target_link_libraries(${PROJECT_NAME} PUBLIC ${crypt_LIB}) + +##################### EASYLOGGING ######################### +set(EASYLOGGING_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/${LIB_DIR}/easylogging) +add_library(Easylogging STATIC ${EASYLOGGING_INCLUDE_DIR}/easylogging++.cc) + +target_include_directories(${PROJECT_NAME} PUBLIC ${EASYLOGGING_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} PUBLIC Easylogging) + +######################## CATCH ############################ +set(CATCH_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/tests) + +add_library(Catch INTERFACE) +target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR}) + +####################### THREAD ############################ +find_package(Threads REQUIRED) + +if(NOT CMAKE_THREAD_LIBS_INIT) + message(FATAL_ERROR, "Could not find libthread") +endif() +target_link_libraries(${PROJECT_NAME} PRIVATE ${Threads_LIBRARIES}) + + +if(ENABLE_TESTING) + add_subdirectory(tests) +endif(ENABLE_TESTING) + +if(BUILD_NETWORKING) + add_subdirectory(networking) +endif(BUILD_NETWORKING) + +if(BUILD_CLI) + add_subdirectory(cli) +endif(BUILD_CLI) +####################### END_CMAKE ######################## diff --git a/FlippR-Driver/build/CMakeLists.txt b/FlippR-Driver/build/CMakeLists.txt deleted file mode 100644 index 7903515..0000000 --- a/FlippR-Driver/build/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -cmake_minimum_required(VERSION 3.9.1) -project(flippr-driver) - -set(CMAKE_BUILD_TYPE Debug) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # enable C++11 standard - -set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/bin) -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) -set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) -set(SOURCE_DIR ../src) - -find_package(Threads) -find_package(Boost) - -include_directories(${SOURCE_DIR}/input) -include_directories(${SOURCE_DIR}/output) -include_directories(${SOURCE_DIR}/lib) -include_directories(${SOURCE_DIR}/utilities) - -file(GLOB SOURCES ${SOURCE_DIR}/*/*.cpp) - -add_library(flippr_driver STATIC ${SOURCES}) - -target_link_libraries(flippr_driver ${CMAKE_SOURCE_DIR}/lib/libwiringPi.so.2.44) - -enable_testing(TRUE) - -# Prepare "Catch" library for other executables -set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../src/tests) -add_library(Catch INTERFACE) -target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR}/*) - -# Make test executable -set(TEST_SOURCES ${SOURCE_DIR}/../tests/input) -include_directories(${TEST_SOURCES}) -include_directories(${TEST_SOURCES}/mocks) - -file(GLOB SOURCES ${TEST_SOURCES}/*.cpp) -file(GLOB HEADER_SOURCES ${TEST_SOURCES}/*.hpp) - -add_executable(tests ${SOURCES} ${HEADER_SOURCES}) - -target_link_libraries(flippr_driver) -target_link_libraries(tests Catch) diff --git a/FlippR-Driver/build/bak/json_example/gpio_config.json b/FlippR-Driver/build/bak/json_example/gpio_config.json deleted file mode 100644 index cdb88e2..0000000 --- a/FlippR-Driver/build/bak/json_example/gpio_config.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "input": - { - "row": - { - "A":"GPIO_13", - "B":"GPIO_14", - "C":"GPIO_15", - }, - "column": - { - "A":"GPIO_17", - "B":"GPIO_18", - "C":"GPIO_19", - "input":"GPIO_20" - } - }, - "output": - { - } -} diff --git a/FlippR-Driver/cli/CMakeLists.txt b/FlippR-Driver/cli/CMakeLists.txt new file mode 100644 index 0000000..0c730a4 --- /dev/null +++ b/FlippR-Driver/cli/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.6.2) +project(flippR_driver_CLI) + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/${OUTPUT_PATH}/cli) +add_executable(${PROJECT_NAME} main.cpp PrintHandler.cpp) + +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) +target_link_libraries(${PROJECT_NAME} PRIVATE FlippR_Driver) diff --git a/FlippR-Driver/cli/OutputInterpreter.cpp b/FlippR-Driver/cli/OutputInterpreter.cpp new file mode 100644 index 0000000..efc858e --- /dev/null +++ b/FlippR-Driver/cli/OutputInterpreter.cpp @@ -0,0 +1,16 @@ +// +// Created by rhetenor on 5/5/19. +// + +#include "OutputInterpreter.h" + +#include +#include + +using namespace std; + +OutputInterpreter::OutputInterpreter(std::string output_lamp_config_file, std::string output_solenoid_config_file, + std::string output_sound_config_file, std::string output_display_config_file) +{ + output_driver = flippR_driver::get_OutputDriver(output_lamp_config_file, output_solenoid_config_file, output_sound_config_file, output_display_config_file); +} diff --git a/FlippR-Driver/cli/OutputInterpreter.h b/FlippR-Driver/cli/OutputInterpreter.h new file mode 100644 index 0000000..130314c --- /dev/null +++ b/FlippR-Driver/cli/OutputInterpreter.h @@ -0,0 +1,23 @@ +// +// Created by rhetenor on 5/5/19. +// + +#ifndef FLIPPR_DRIVER_OUTPUTINTERPRETER_H +#define FLIPPR_DRIVER_OUTPUTINTERPRETER_H + +#include "DriverFactory.h" + +class OutputInterpreter +{ +public: + OutputInterpreter(std::string output_lamp_config_file, std::string output_solenoid_config_file, + std::string output_sound_config_file, std::string output_display_config_file); + + void startInterpreter(); + +private: + std::shared_ptr output_driver; + +}; + +#endif //FLIPPR_DRIVER_OUTPUTINTERPRETER_H diff --git a/FlippR-Driver/cli/PrintHandler.cpp b/FlippR-Driver/cli/PrintHandler.cpp new file mode 100644 index 0000000..3e88ac7 --- /dev/null +++ b/FlippR-Driver/cli/PrintHandler.cpp @@ -0,0 +1,18 @@ +// +// Created by rhetenor on 13.09.18. +// + +#include "PrintHandler.h" +#include + +PrintHandler::PrintHandler(std::shared_ptr driver) : +flippR_driver::input::EventHandler(driver) + { + + } + + +void PrintHandler::handle(flippR_driver::input::Event &event) +{ + std::cout << "Event " << event.name << " (" << std::to_string(event.address) << ") occured!\n"; +} \ No newline at end of file diff --git a/FlippR-Driver/cli/PrintHandler.h b/FlippR-Driver/cli/PrintHandler.h new file mode 100644 index 0000000..36355d0 --- /dev/null +++ b/FlippR-Driver/cli/PrintHandler.h @@ -0,0 +1,21 @@ +// +// Created by rhetenor on 13.09.18. +// + +#ifndef flippR_driver_PRINTHANDLER_H +#define flippR_driver_PRINTHANDLER_H + +#include +#include "input/EventHandler.h" +#include "input/InputDriver.h" + +class PrintHandler : public flippR_driver::input::EventHandler +{ +public: + PrintHandler(std::shared_ptr driver); + + virtual void handle(flippR_driver::input::Event& event) override; +}; + + +#endif //flippR_driver_PRINTHANDLER_H diff --git a/FlippR-Driver/cli/main.cpp b/FlippR-Driver/cli/main.cpp new file mode 100644 index 0000000..9792750 --- /dev/null +++ b/FlippR-Driver/cli/main.cpp @@ -0,0 +1,101 @@ +// +// Created by rhetenor on 13.09.18. +// +#include + +#include +#include +#include +#include + +#include "DriverFactory.h" +#include "input/InputDriver.h" + +#include "PrintHandler.h" + +using namespace flippR_driver; +namespace po = boost::program_options; + +PrintHandler* print_handler = nullptr; + +void __sigint_handler(int param) +{ + printf("Caught SIGINT... aborting!\n"); + exit(EXIT_SUCCESS); +} + +static void show_usage(const std::string &name) +{ + std::cout << "Usage: " << name << " [-ipc= -imc=] " + << "[-opc= -odc= -olc=] " + << "-osolc= -osc=]"; + +} +static void register_program_options(po::options_description &po_desc, boost::optional &input_pin_config_file, std::string &input_matrix_config_file, + boost::optional &output_pin_config_file, std::string &output_display_config_file, std::string &output_lamp_config_file, std::string &output_solenoid_config_file, std::string &output_sound_config_file) +{ + po_desc.add_options() + ("help", "print_help_message") + ("input_pin_config,ipc", po::value>(&input_pin_config_file), "input pin config file") + ("input_matrix_config,imc", po::value(&input_matrix_config_file), "input matrix config file") + ("output_pin_config,opc", po::value>(&output_pin_config_file), "output pin config file") + ("output_display_config,idc", po::value(&output_display_config_file), "output display config file") + ("output_lamp_config,ilc", po::value(&output_lamp_config_file), "output lamp config file") + ("output_solenoid_config,isolc", po::value(&output_solenoid_config_file), "output solenoid config file") + ("output_sound_config,isc", po::value(&output_sound_config_file), "output sound config file") + ; +} + +static PrintHandler* start_print_handler(const std::string &input_config_file, const std::string &matrix_config_file) +{ + std::ifstream input_config; + std::ifstream matrix_config; + try + { + input_config.open(input_config_file); + matrix_config.open(matrix_config_file); + } + catch(const std::exception& e) + { + std::cout << e.what(); + exit(EXIT_FAILURE); + } + + std::shared_ptr driver = flippR_driver::get_InputDriver(input_config, matrix_config); + + return new PrintHandler(driver); +} + +int main (int argc, char *argv[]) +{ + if(argc < 3) + { + show_usage(argv[0]); + exit(EXIT_FAILURE); + } + + // registering sigint + signal(SIGINT, __sigint_handler); + + po::options_description po_desc("Options"); + boost::optional input_pin_config_file, output_pin_config_file; + + std::string input_matrix_config_file, output_display_config_file, output_lamp_config_file, output_solenoid_config_file, output_sound_config_file; + + register_program_options(po_desc, input_pin_config_file, input_matrix_config_file, output_pin_config_file, output_display_config_file, output_lamp_config_file, output_solenoid_config_file, output_sound_config_file); + + // todo parse + + if(input_pin_config_file) + { + print_handler = start_print_handler(*input_pin_config_file, input_matrix_config_file); + } + + if(output_pin_config_file) + { + start_output_driver(*output_pin_config_file, ) + } + while(1); + + return 0; +} diff --git a/FlippR-Driver/cli/networking/flippR_driver_networking b/FlippR-Driver/cli/networking/flippR_driver_networking new file mode 100755 index 0000000..9ff0543 Binary files /dev/null and b/FlippR-Driver/cli/networking/flippR_driver_networking differ diff --git a/FlippR-Driver/cli/networking/server_config.json b/FlippR-Driver/cli/networking/server_config.json new file mode 100644 index 0000000..efe81b5 --- /dev/null +++ b/FlippR-Driver/cli/networking/server_config.json @@ -0,0 +1,9 @@ +{ + "input-config" :"../../contrib/json_example/input/Input_Pin_Config.json", + "matrix-config" :"../../contrib/json_example/input/Input_Matrix_Config.json", + "lamp-config" :"../../contrib/json_example/output/Lamp_Config.json", + "solenoid-config" :"../../contrib/json_example/output/Solenoid_Config.json", + "sound-config" :"../../contrib/json_example/output/Sound_Config.json", + "display-config" :"../../contrib/json_example/output/Display_Config.json", + "lamp-config" :"../../contrib/json_example/output/Lamp_Config.json" +} diff --git a/FlippR-Driver/cmake/CXX1x.cmake b/FlippR-Driver/cmake/CXX1x.cmake new file mode 100644 index 0000000..5f48eb7 --- /dev/null +++ b/FlippR-Driver/cmake/CXX1x.cmake @@ -0,0 +1,81 @@ +# Copyright (c) 2013 Nathan Osman + +# 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. + +# Determines whether the compiler supports C++11 +macro(check_for_cxx11_compiler _VAR) + message(STATUS "Checking for C++11 compiler") + set(${_VAR}) + try_compile(_COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp CMAKE_FLAGS -DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD_REQUIRED=ON) + if(NOT _COMPILER_TEST_RESULT AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + try_compile(_COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp CMAKE_FLAGS -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_CXX_STANDARD=11 -DCMAKE_CXX_STANDARD_REQUIRED=ON) + if(_COMPILER_TEST_RESULT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + else() + message(STATUS "To enable C++11 install libc++ standard library from https://libcxx.llvm.org/") + endif() + endif() + if(_COMPILER_TEST_RESULT AND ((MSVC AND (MSVC10 OR MSVC11 OR MSVC12 OR MSVC14)) OR + (CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.8.1) OR + (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.3) OR + (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))) + set(${_VAR} 1) + message(STATUS "Checking for C++11 compiler - available") + else() + message(STATUS "Checking for C++11 compiler - unavailable") + endif() +endmacro() + +# Sets the appropriate flag to enable C++11 support +macro(enable_cxx11) + set (CMAKE_CXX_STANDARD 11) + set (CMAKE_CXX_STANDARD_REQUIRED ON) + add_definitions(-DPOCO_ENABLE_CPP11) +endmacro() + +# Determines whether the compiler supports C++14 +macro(check_for_cxx14_compiler _VAR) + message(STATUS "Checking for C++14 compiler") + set(${_VAR}) + try_compile(_COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp CMAKE_FLAGS -DCMAKE_CXX_STANDARD=14 -DCMAKE_CXX_STANDARD_REQUIRED=ON) + if(NOT _COMPILER_TEST_RESULT AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + try_compile(_COMPILER_TEST_RESULT ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/test_compiler.cpp CMAKE_FLAGS -DCMAKE_CXX_FLAGS="-stdlib=libc++" -DCMAKE_CXX_STANDARD=14 -DCMAKE_CXX_STANDARD_REQUIRED=ON) + if(_COMPILER_TEST_RESULT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + else() + message(STATUS "To enable C++14 install libc++ standard library from https://libcxx.llvm.org/") + endif() + endif() + if(_COMPILER_TEST_RESULT AND ((MSVC AND (MSVC14)) OR + (CMAKE_COMPILER_IS_GNUCXX AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 4.9.2) OR + (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 3.4) OR + (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang"))) + set(${_VAR} 1) + message(STATUS "Checking for C++14 compiler - available") + else() + message(STATUS "Checking for C++14 compiler - unavailable") + endif() +endmacro() + +# Sets the appropriate flag to enable C++14 support +macro(enable_cxx14) + set (CMAKE_CXX_STANDARD 14) + set (CMAKE_CXX_STANDARD_REQUIRED ON) + add_definitions(-DPOCO_ENABLE_CPP14) +endmacro() diff --git a/FlippR-Driver/cmake/DefinePlatformSpecifc.cmake b/FlippR-Driver/cmake/DefinePlatformSpecifc.cmake new file mode 100644 index 0000000..b296405 --- /dev/null +++ b/FlippR-Driver/cmake/DefinePlatformSpecifc.cmake @@ -0,0 +1,132 @@ +# http://www.cmake.org/Wiki/CMake_Useful_Variables : +# CMAKE_BUILD_TYPE +# Choose the type of build. CMake has default flags for these: +# +# * None (CMAKE_C_FLAGS or CMAKE_CXX_FLAGS used) +# * Debug (CMAKE_C_FLAGS_DEBUG or CMAKE_CXX_FLAGS_DEBUG) +# * Release (CMAKE_C_FLAGS_RELEASE or CMAKE_CXX_FLAGS_RELEASE) +# * RelWithDebInfo (CMAKE_C_FLAGS_RELWITHDEBINFO or CMAKE_CXX_FLAGS_RELWITHDEBINFO +# * MinSizeRel (CMAKE_C_FLAGS_MINSIZEREL or CMAKE_CXX_FLAGS_MINSIZEREL) + +# Setting CXX Flag /MD or /MT and POSTFIX values i.e MDd / MD / MTd / MT / d +# +# For visual studio the library naming is as following: +# Dynamic libraries: +# - PocoX.dll for release library +# - PocoXd.dll for debug library +# +# Static libraries: +# - PocoXmd.lib for /MD release build +# - PocoXtmt.lib for /MT release build +# +# - PocoXmdd.lib for /MD debug build +# - PocoXmtd.lib for /MT debug build + +if(MSVC) + if(POCO_MT) + set(CompilerFlags + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS + CMAKE_C_FLAGS_DEBUG + CMAKE_C_FLAGS_RELEASE + ) + foreach(CompilerFlag ${CompilerFlags}) + string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") + endforeach() + + set(STATIC_POSTFIX "mt" CACHE STRING "Set static library postfix" FORCE) + else(POCO_MT) + set(STATIC_POSTFIX "md" CACHE STRING "Set static library postfix" FORCE) + endif(POCO_MT) + + if (ENABLE_MSVC_MP) + add_definitions(/MP) + endif() + +else(MSVC) + # Other compilers then MSVC don't have a static STATIC_POSTFIX at the moment + set(STATIC_POSTFIX "" CACHE STRING "Set static library postfix" FORCE) + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") +endif(MSVC) + + + +# Add a d postfix to the debug libraries +if(POCO_STATIC) + set(CMAKE_DEBUG_POSTFIX "${STATIC_POSTFIX}d" CACHE STRING "Set Debug library postfix" FORCE) + set(CMAKE_RELEASE_POSTFIX "${STATIC_POSTFIX}" CACHE STRING "Set Release library postfix" FORCE) + set(CMAKE_MINSIZEREL_POSTFIX "${STATIC_POSTFIX}" CACHE STRING "Set MinSizeRel library postfix" FORCE) + set(CMAKE_RELWITHDEBINFO_POSTFIX "${STATIC_POSTFIX}" CACHE STRING "Set RelWithDebInfo library postfix" FORCE) +else(POCO_STATIC) + set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Set Debug library postfix" FORCE) + set(CMAKE_RELEASE_POSTFIX "" CACHE STRING "Set Release library postfix" FORCE) + set(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "Set MinSizeRel library postfix" FORCE) + set(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "Set RelWithDebInfo library postfix" FORCE) +endif() + + +# OS Detection +include(CheckTypeSize) +find_package(Cygwin) + +if(WIN32) + add_definitions( -DPOCO_OS_FAMILY_WINDOWS -DUNICODE -D_UNICODE -D__LCC__) #__LCC__ define used by MySQL.h +endif(WIN32) + +if (CYGWIN) + add_definitions(-DPOCO_NO_FPENVIRONMENT -DPOCO_NO_WSTRING) + add_definitions(-D_XOPEN_SOURCE=500 -D__BSD_VISIBLE) +else (CYGWIN) + if (UNIX AND NOT ANDROID ) + add_definitions( -DPOCO_OS_FAMILY_UNIX ) + # Standard 'must be' defines + if (APPLE) + add_definitions( -DPOCO_HAVE_IPv6 -DPOCO_NO_STAT64) + set(SYSLIBS ${CMAKE_DL_LIBS}) + else (APPLE) + add_definitions( -D_REENTRANT -D_THREAD_SAFE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ) + if (QNX) + add_definitions( -DPOCO_HAVE_FD_POLL) + set(SYSLIBS m socket) + else (QNX) + add_definitions( -D_XOPEN_SOURCE=500) + if (${CMAKE_SYSTEM} MATCHES "AIX") + add_definitions( -DPOCO_HAVE_FD_POLL) + else() + add_definitions( -DPOCO_HAVE_FD_EPOLL) + endif() + set(SYSLIBS pthread ${CMAKE_DL_LIBS} rt) + endif (QNX) + endif (APPLE) + endif(UNIX AND NOT ANDROID ) +endif (CYGWIN) + +if (CMAKE_SYSTEM MATCHES "SunOS") + add_definitions( -DPOCO_OS_FAMILY_UNIX ) + # Standard 'must be' defines + add_definitions( -D_XOPEN_SOURCE=500 -D_REENTRANT -D_THREAD_SAFE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ) + set(SYSLIBS pthread socket xnet nsl resolv rt ${CMAKE_DL_LIBS}) +endif(CMAKE_SYSTEM MATCHES "SunOS") + +if (CMAKE_COMPILER_IS_MINGW) + add_definitions(-DWC_NO_BEST_FIT_CHARS=0x400 -DPOCO_WIN32_UTF8) + add_definitions(-D_WIN32 -DMINGW32 -DWINVER=0x500 -DODBCVER=0x0300 -DPOCO_THREAD_STACK_SIZE) +endif (CMAKE_COMPILER_IS_MINGW) + +# SunPro C++ +if (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro") + add_definitions( -D_BSD_SOURCE -library=stlport4) +endif (${CMAKE_CXX_COMPILER_ID} MATCHES "SunPro") + +# iOS +if (IOS) + add_definitions( -DPOCO_HAVE_IPv6 -DPOCO_NO_FPENVIRONMENT -DPOCO_NO_STAT64 -DPOCO_NO_SHAREDLIBS -DPOCO_NO_NET_IFTYPES ) +endif(IOS) + +#Android +if (ANDROID) + add_definitions( -DPOCO_NO_FPENVIRONMENT -DPOCO_NO_WSTRING -DPOCO_NO_SHAREDMEMORY ) +endif(ANDROID) diff --git a/FlippR-Driver/cmake/ExecuteOnAndroid.cmake b/FlippR-Driver/cmake/ExecuteOnAndroid.cmake new file mode 100644 index 0000000..e944c23 --- /dev/null +++ b/FlippR-Driver/cmake/ExecuteOnAndroid.cmake @@ -0,0 +1,29 @@ + +get_filename_component(UNITTEST_FILENAME ${UNITTEST} NAME) +message(STATUS "Cleanup /data/local/tmp ...") +execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "rm -r /data/local/tmp/*" OUTPUT_QUIET) +foreach(_TEST_DATA IN ITEMS ${TEST_FILES}) + message(STATUS "Push ${_TEST_DATA} to android ...") + execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${_TEST_DATA} /data/local/tmp/ OUTPUT_QUIET) +endforeach() +message(STATUS "Push ${LIBRARY_DIR} to android ...") +execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${LIBRARY_DIR} /data/local/tmp/ OUTPUT_QUIET) +message(STATUS "Push ${UNITTEST} to android ...") +execute_process(COMMAND ${ANDROID_NDK}/../platform-tools/adb push ${UNITTEST} /data/local/tmp/ OUTPUT_QUIET) +message(STATUS "Execute ${UNITTEST_FILENAME} ${TEST_PARAMETER} on android ...") +execute_process( + COMMAND ${ANDROID_NDK}/../platform-tools/adb shell "cd /data/local/tmp;su root sh -c 'LD_LIBRARY_PATH=/data/local/tmp/lib TMPDIR=/data/local/tmp HOME=/data/local/tmp ./${UNITTEST_FILENAME} ${TEST_PARAMETER};echo exit code $?'" + RESULT_VARIABLE _RESULT + OUTPUT_VARIABLE _OUT + ERROR_VARIABLE _ERR +) + +if(_RESULT) + message(FATAL_ERROR "Execution of ${UNITTEST_FILENAME} failed") +else() + string(REGEX MATCH "exit code ([0-9]+)" _EXIT_CODE ${_OUT}) + if(NOT "${CMAKE_MATCH_1}" EQUAL 0) + string(REGEX REPLACE "exit code [0-9]+" "" _PRINT_OUT ${_OUT}) + message(FATAL_ERROR "${UNITTEST_FILENAME} execution error: ${_PRINT_OUT} ${_ERR}") + endif() +endif() diff --git a/FlippR-Driver/cmake/FindAPR.cmake b/FlippR-Driver/cmake/FindAPR.cmake new file mode 100644 index 0000000..3a7a11c --- /dev/null +++ b/FlippR-Driver/cmake/FindAPR.cmake @@ -0,0 +1,94 @@ +# -*- cmake -*- + +# - Find Apache Portable Runtime +# Find the APR includes and libraries +# This module defines +# APR_INCLUDE_DIR and APRUTIL_INCLUDE_DIR, where to find apr.h, etc. +# APR_LIBRARIES and APRUTIL_LIBRARIES, the libraries needed to use APR. +# APR_FOUND and APRUTIL_FOUND, If false, do not try to use APR. +# also defined, but not for general use are +# APR_LIBRARY and APRUTIL_LIBRARY, where to find the APR library. + +# APR first. + +FIND_PATH(APR_INCLUDE_DIR apr.h +/usr/local/include/apr-1 +/usr/local/include/apr-1.0 +/usr/include/apr-1 +/usr/include/apr-1.0 +) + +SET(APR_NAMES ${APR_NAMES} apr-1) +FIND_LIBRARY(APR_LIBRARY + NAMES ${APR_NAMES} + PATHS /usr/lib /usr/local/lib + ) + +IF (APR_LIBRARY AND APR_INCLUDE_DIR) + SET(APR_LIBRARIES ${APR_LIBRARY}) + SET(APR_FOUND "YES") +ELSE (APR_LIBRARY AND APR_INCLUDE_DIR) + SET(APR_FOUND "NO") +ENDIF (APR_LIBRARY AND APR_INCLUDE_DIR) + + +IF (APR_FOUND) + IF (NOT APR_FIND_QUIETLY) + MESSAGE(STATUS "Found APR: ${APR_LIBRARIES}") + ENDIF (NOT APR_FIND_QUIETLY) +ELSE (APR_FOUND) + IF (APR_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find APR library") + ENDIF (APR_FIND_REQUIRED) +ENDIF (APR_FOUND) + +# Deprecated declarations. +SET (NATIVE_APR_INCLUDE_PATH ${APR_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_APR_LIB_PATH ${APR_LIBRARY} PATH) + +MARK_AS_ADVANCED( + APR_LIBRARY + APR_INCLUDE_DIR + ) + +# Next, APRUTIL. + +FIND_PATH(APRUTIL_INCLUDE_DIR apu.h +/usr/local/include/apr-1 +/usr/local/include/apr-1.0 +/usr/include/apr-1 +/usr/include/apr-1.0 +) + +SET(APRUTIL_NAMES ${APRUTIL_NAMES} aprutil-1) +FIND_LIBRARY(APRUTIL_LIBRARY + NAMES ${APRUTIL_NAMES} + PATHS /usr/lib /usr/local/lib + ) + +IF (APRUTIL_LIBRARY AND APRUTIL_INCLUDE_DIR) + SET(APRUTIL_LIBRARIES ${APRUTIL_LIBRARY}) + SET(APRUTIL_FOUND "YES") +ELSE (APRUTIL_LIBRARY AND APRUTIL_INCLUDE_DIR) + SET(APRUTIL_FOUND "NO") +ENDIF (APRUTIL_LIBRARY AND APRUTIL_INCLUDE_DIR) + + +IF (APRUTIL_FOUND) + IF (NOT APRUTIL_FIND_QUIETLY) + MESSAGE(STATUS "Found APRUTIL: ${APRUTIL_LIBRARIES}") + ENDIF (NOT APRUTIL_FIND_QUIETLY) +ELSE (APRUTIL_FOUND) + IF (APRUTIL_FIND_REQUIRED) + MESSAGE(STATUS "Could not find APRUTIL library") + ENDIF (APRUTIL_FIND_REQUIRED) +ENDIF (APRUTIL_FOUND) + +# Deprecated declarations. +SET (NATIVE_APRUTIL_INCLUDE_PATH ${APRUTIL_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_APRUTIL_LIB_PATH ${APRUTIL_LIBRARY} PATH) + +MARK_AS_ADVANCED( + APRUTIL_LIBRARY + APRUTIL_INCLUDE_DIR + ) diff --git a/FlippR-Driver/cmake/FindApache2.cmake b/FlippR-Driver/cmake/FindApache2.cmake new file mode 100644 index 0000000..ea1dd02 --- /dev/null +++ b/FlippR-Driver/cmake/FindApache2.cmake @@ -0,0 +1,31 @@ +# -*- cmake -*- + +# - Find Apache Runtime +# Find the APACHE includes and libraries +# This module defines +# APACHE_INCLUDE_DIR and APACHEUTIL_INCLUDE_DIR, where to find APACHE.h, etc. +# APACHE_LIBRARIES and APACHEUTIL_LIBRARIES, the libraries needed to use APACHE. +# APACHE_FOUND and APACHEUTIL_FOUND, If false, do not try to use APACHE. +# also defined, but not for general use are +# APACHE_LIBRARY and APACHEUTIL_LIBRARY, where to find the APACHE library. + +FIND_PATH(APACHE_INCLUDE_DIR httpd.h +/usr/local/include/apache2 +/usr/include/apache2 +) + +IF (APACHE_INCLUDE_DIR) + SET(APACHE_FOUND "YES") +ELSE (APACHE_LIBRARY AND APACHE_INCLUDE_DIR) + SET(APACHE_FOUND "NO") +ENDIF (APACHE_INCLUDE_DIR) + + +IF (APACHE_FOUND) + MESSAGE(STATUS "Found APACHE: ${APACHE_INCLUDE_DIR}") +ENDIF (APACHE_FOUND) + +MARK_AS_ADVANCED( + APACHE_INCLUDE_DIR + ) + diff --git a/FlippR-Driver/cmake/FindMySQL.cmake b/FlippR-Driver/cmake/FindMySQL.cmake new file mode 100644 index 0000000..7499723 --- /dev/null +++ b/FlippR-Driver/cmake/FindMySQL.cmake @@ -0,0 +1,94 @@ +SET(BINDIR32_ENV_NAME "ProgramFiles(x86)") +SET(BINDIR32 $ENV{${BINDIR32_ENV_NAME}}) + +find_path(MYSQL_INCLUDE_DIR mysql.h + /usr/include/mysql + /usr/local/include/mysql + /opt/mysql/mysql/include + /opt/mysql/mysql/include/mysql + /usr/local/mysql/include + /usr/local/mysql/include/mysql + $ENV{MYSQL_INCLUDE_DIR} + $ENV{MYSQL_DIR}/include + $ENV{ProgramFiles}/MySQL/*/include + ${BINDIR32}/MySQL/include + $ENV{SystemDrive}/MySQL/*/include) + +if (NOT MYSQL_INCLUDE_DIR) + find_path(MARIADB_INCLUDE_DIR mysql.h + /usr/include/mariadb + /usr/local/include/mariadb + /opt/mariadb/mariadb/include + /opt/mariadb/mariadb/include/mariadb + /usr/local/mariadb/include + /usr/local/mariadb/include/mariadb + $ENV{MARIADB_INCLUDE_DIR} + $ENV{MARIADB_DIR}/include) +endif (NOT MYSQL_INCLUDE_DIR) + +if (WIN32) + if (CMAKE_BUILD_TYPE STREQUAL Debug) + set(libsuffixDist debug) + set(libsuffixBuild Debug) + else (CMAKE_BUILD_TYPE STREQUAL Debug) + set(libsuffixDist opt) + set(libsuffixBuild Release) + add_definitions(-DDBUG_OFF) + endif (CMAKE_BUILD_TYPE STREQUAL Debug) + + find_library(MYSQL_LIB NAMES mysqlclient + PATHS + $ENV{MYSQL_DIR}/lib/${libsuffixDist} + $ENV{MYSQL_DIR}/libmysql/${libsuffixBuild} + $ENV{MYSQL_DIR}/client/${libsuffixBuild} + $ENV{ProgramFiles}/MySQL/*/lib/${libsuffixDist} + ${BINDIR32}/MySQL/lib + $ENV{SystemDrive}/MySQL/*/lib/${libsuffixDist}) +else (WIN32) + find_library(MYSQL_LIB NAMES mysqlclient mysqlclient_r + PATHS + /usr/lib/mysql + /usr/local/lib/mysql + /usr/local/mysql/lib + /usr/local/mysql/lib/mysql + /opt/mysql/mysql/lib + /opt/mysql/mysql/lib/mysql + $ENV{MYSQL_DIR}/libmysql_r/.libs + $ENV{MYSQL_DIR}/lib + $ENV{MYSQL_DIR}/lib/mysql) + + if (NOT MYSQL_LIB) + find_library(MARIADB_LIB NAMES mariadbclient + PATHS + /usr/lib/mariadb + /usr/local/lib/mariadb + /usr/local/mariadb/lib + /usr/local/mariadb/lib/mariadb + /opt/mariadb/mariadb/lib + /opt/mariadb/mariadb/lib/mariadb + $ENV{MARIADB_DIR}/libmariadb/.libs + $ENV{MARIADB_DIR}/lib + $ENV{MARIADB_DIR}/lib/mariadb) + endif (NOT MYSQL_LIB) +endif (WIN32) + +if (MYSQL_INCLUDE_DIR AND MYSQL_LIB) + get_filename_component(MYSQL_LIB_DIR ${MYSQL_LIB} PATH) + set(MYSQL_FOUND TRUE) + message(STATUS "Found MySQL Include directory: ${MYSQL_INCLUDE_DIR} library directory: ${MYSQL_LIB_DIR}") + include_directories(${MYSQL_INCLUDE_DIR}) + link_directories(${MYSQL_LIB_DIR}) +elseif((MARIADB_INCLUDE_DIR OR MYSQL_INCLUDE_DIR) AND MARIADB_LIB) + get_filename_component(MYSQL_LIB_DIR ${MARIADB_LIB} PATH) + set(MYSQL_FOUND TRUE) + set(MYSQL_LIB ${MARIADB_LIB}) + if(MARIADB_INCLUDE_DIR) + set(MYSQL_INCLUDE_DIR ${MARIADB_INCLUDE_DIR}) + endif(MARIADB_INCLUDE_DIR) + message(STATUS "Found MariaDB Include directory: ${MYSQL_INCLUDE_DIR} library directory: ${MYSQL_LIB_DIR}") + message(STATUS "Use MariaDB for MySQL Support") + include_directories(${MYSQL_INCLUDE_DIR} ) + link_directories(${MYSQL_LIB_DIR}) +else ((MARIADB_INCLUDE_DIR OR MYSQL_INCLUDE_DIR) AND MARIADB_LIB) + message(STATUS "Couldn't find MySQL or MariaDB") +endif (MYSQL_INCLUDE_DIR AND MYSQL_LIB) diff --git a/FlippR-Driver/cmake/FindODBC.cmake b/FlippR-Driver/cmake/FindODBC.cmake new file mode 100644 index 0000000..b655b02 --- /dev/null +++ b/FlippR-Driver/cmake/FindODBC.cmake @@ -0,0 +1,61 @@ +# +# Find the ODBC driver manager includes and library. +# +# ODBC is an open standard for connecting to different databases in a +# semi-vendor-independent fashion. First you install the ODBC driver +# manager. Then you need a driver for each separate database you want +# to connect to (unless a generic one works). VTK includes neither +# the driver manager nor the vendor-specific drivers: you have to find +# those yourself. +# +# This module defines +# ODBC_INCLUDE_DIRECTORIES, where to find sql.h +# ODBC_LIBRARIES, the libraries to link against to use ODBC +# ODBC_FOUND. If false, you cannot build anything that requires MySQL. + +find_path(ODBC_INCLUDE_DIRECTORIES + NAMES sql.h + HINTS + /usr/include + /usr/include/odbc + /usr/include/iodbc + /usr/local/include + /usr/local/include/odbc + /usr/local/include/iodbc + /usr/local/odbc/include + /usr/local/iodbc/include + "C:/Program Files/ODBC/include" + "C:/Program Files/Microsoft SDKs/Windows/v7.0/include" + "C:/Program Files/Microsoft SDKs/Windows/v6.0a/include" + "C:/ODBC/include" + DOC "Specify the directory containing sql.h." +) + +find_library(ODBC_LIBRARIES + NAMES iodbc odbc odbcinst odbc32 + HINTS + /usr/lib + /usr/lib/odbc + /usr/local/lib + /usr/local/lib/odbc + /usr/local/odbc/lib + "C:/Program Files/ODBC/lib" + "C:/ODBC/lib/debug" + "C:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/Lib" + DOC "Specify the ODBC driver manager library here." +) + +# MinGW find usually fails +if(MINGW) + set(ODBC_INCLUDE_DIRECTORIES ".") + set(ODBC_LIBRARIES odbc32) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ODBC + DEFAULT_MSG + ODBC_INCLUDE_DIRECTORIES + ODBC_LIBRARIES + ) + +mark_as_advanced(ODBC_FOUND ODBC_LIBRARIES ODBC_INCLUDE_DIRECTORIES) diff --git a/FlippR-Driver/cmake/FindPCRE.cmake b/FlippR-Driver/cmake/FindPCRE.cmake new file mode 100644 index 0000000..41a99cb --- /dev/null +++ b/FlippR-Driver/cmake/FindPCRE.cmake @@ -0,0 +1,33 @@ +# +# - Find pcre +# Find the native PCRE includes and library +# +# PCRE_INCLUDE_DIRS - where to find pcre.h, etc. +# PCRE_LIBRARIES - List of libraries when using pcre. +# PCRE_FOUND - True if pcre found. + + +IF (PCRE_INCLUDE_DIRS) + # Already in cache, be silent + SET(PCRE_FIND_QUIETLY TRUE) +ENDIF (PCRE_INCLUDE_DIRS) + +FIND_PATH(PCRE_INCLUDE_DIR pcre.h) + +SET(PCRE_NAMES pcre) +FIND_LIBRARY(PCRE_LIBRARY NAMES ${PCRE_NAMES} ) + +# handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR) + +IF(PCRE_FOUND) + SET( PCRE_LIBRARIES ${PCRE_LIBRARY} ) + SET( PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR} ) +ELSE(PCRE_FOUND) + SET( PCRE_LIBRARIES ) + SET( PCRE_INCLUDE_DIRS ) +ENDIF(PCRE_FOUND) + +MARK_AS_ADVANCED( PCRE_LIBRARIES PCRE_INCLUDE_DIRS ) diff --git a/FlippR-Driver/cmake/FindPostgreSQL.cmake b/FlippR-Driver/cmake/FindPostgreSQL.cmake new file mode 100644 index 0000000..6c383f0 --- /dev/null +++ b/FlippR-Driver/cmake/FindPostgreSQL.cmake @@ -0,0 +1,66 @@ +# - Find libpq +# Find the native PostgreSQL includes and library +# +# PGSQL_INCLUDE_DIR - where to find libpq-fe.h, etc. +# PGSQL_LIBRARIES - List of libraries when using PGSQL. +# PGSQL_FOUND - True if PGSQL found. + +MACRO(FIND_PGSQL) +IF (PGSQL_INCLUDE_DIR) + # Already in cache, be silent + SET(PostgreSQL_FIND_QUIETLY TRUE) +ENDIF (PGSQL_INCLUDE_DIR) + +FIND_PATH(PGSQL_INCLUDE_DIR libpq-fe.h + $ENV{ProgramFiles}/PostgreSQL/*/include + $ENV{SystemDrive}/PostgreSQL/*/include + /usr/local/pgsql/include + /usr/local/postgresql/include + /usr/local/include/pgsql + /usr/local/include/postgresql + /usr/local/include + /usr/include/pgsql + /usr/include/postgresql + /usr/include + /usr/pgsql/include + /usr/postgresql/include +) + +SET(PGSQL_NAMES pq libpq) +SET(PGSQL_SEARCH_LIB_PATHS + ${PGSQL_SEARCH_LIB_PATHS} + $ENV{ProgramFiles}/PostgreSQL/*/lib + $ENV{SystemDrive}/PostgreSQL/*/lib + /usr/local/pgsql/lib + /usr/local/lib + /usr/lib +) +FIND_LIBRARY(PGSQL_LIBRARY + NAMES ${PGSQL_NAMES} + PATHS ${PGSQL_SEARCH_LIB_PATHS} +) + +IF (PGSQL_INCLUDE_DIR AND PGSQL_LIBRARY) + SET(PGSQL_FOUND TRUE) + SET( PGSQL_LIBRARIES ${PGSQL_LIBRARY} ) +ELSE (PGSQL_INCLUDE_DIR AND PGSQL_LIBRARY) + SET(PGSQL_FOUND FALSE) + SET( PGSQL_LIBRARIES ) +ENDIF (PGSQL_INCLUDE_DIR AND PGSQL_LIBRARY) + +IF (PGSQL_FOUND) + IF (NOT PostgreSQL_FIND_QUIETLY) + MESSAGE(STATUS "Found PostgreSQL: ${PGSQL_LIBRARY}") + ENDIF (NOT PostgreSQL_FIND_QUIETLY) +ELSE (PGSQL_FOUND) + IF (PostgreSQL_FIND_REQUIRED) + MESSAGE(STATUS "Looked for PostgreSQL libraries named ${PGSQL_NAMES}.") + MESSAGE(FATAL_ERROR "Could NOT find PostgreSQL library") + ENDIF (PostgreSQL_FIND_REQUIRED) +ENDIF (PGSQL_FOUND) + +MARK_AS_ADVANCED( + PGSQL_LIBRARY + PGSQL_INCLUDE_DIR +) +ENDMACRO(FIND_PGSQL) \ No newline at end of file diff --git a/FlippR-Driver/cmake/FindSQLite3.cmake b/FlippR-Driver/cmake/FindSQLite3.cmake new file mode 100644 index 0000000..aa650e3 --- /dev/null +++ b/FlippR-Driver/cmake/FindSQLite3.cmake @@ -0,0 +1,87 @@ +# - Try to find Sqlite3 +# Once done this will define +# +# SQLITE3_FOUND - system has Sqlite3 +# SQLITE3_INCLUDE_DIRS - the Sqlite3 include directory +# SQLITE3_LIBRARIES - Link these to use Sqlite3 +# SQLITE3_DEFINITIONS - Compiler switches required for using Sqlite3 +# +# Copyright (c) 2008 Andreas Schneider +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) + # in cache already + set(SQLITE3_FOUND TRUE) +else (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + include(UsePkgConfig) + pkgconfig(sqlite3 _SQLITE3_INCLUDEDIR _SQLITE3_LIBDIR _SQLITE3_LDFLAGS _SQLITE3_CFLAGS) + else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(_SQLITE3 sqlite3) + endif (PKG_CONFIG_FOUND) + endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4) + find_path(SQLITE3_INCLUDE_DIR + NAMES + sqlite3.h + PATHS + ${_SQLITE3_INCLUDEDIR} + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + + find_library(SQLITE3_LIBRARY + NAMES + sqlite3 + PATHS + ${_SQLITE3_LIBDIR} + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + if (SQLITE3_LIBRARY) + set(SQLITE3_FOUND TRUE) + endif (SQLITE3_LIBRARY) + + set(SQLITE3_INCLUDE_DIRS + ${SQLITE3_INCLUDE_DIR} + ) + + if (SQLITE3_FOUND) + set(SQLITE3_LIBRARIES + ${SQLITE3_LIBRARIES} + ${SQLITE3_LIBRARY} + ) + endif (SQLITE3_FOUND) + + if (SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES) + set(SQLITE3_FOUND TRUE) + endif (SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES) + + if (SQLITE3_FOUND) + if (NOT Sqlite3_FIND_QUIETLY) + message(STATUS "Found Sqlite3: ${SQLITE3_LIBRARIES}") + endif (NOT Sqlite3_FIND_QUIETLY) + else (SQLITE3_FOUND) + if (Sqlite3_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Sqlite3") + endif (Sqlite3_FIND_REQUIRED) + endif (SQLITE3_FOUND) + + # show the SQLITE3_INCLUDE_DIRS and SQLITE3_LIBRARIES variables only in the advanced view + mark_as_advanced(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES) + +endif (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) + diff --git a/FlippR-Driver/cmake/PocoConfig.cmake.in b/FlippR-Driver/cmake/PocoConfig.cmake.in new file mode 100644 index 0000000..173eacd --- /dev/null +++ b/FlippR-Driver/cmake/PocoConfig.cmake.in @@ -0,0 +1,53 @@ +if (CMAKE_VERSION VERSION_LESS 2.8.9) + message(FATAL_ERROR "Poco requires at least CMake version 2.8.9") +endif() + +if (NOT Poco_FIND_COMPONENTS) + set(Poco_NOT_FOUND_MESSAGE "The Poco package requires at least one component") + set(Poco_FOUND False) + return() +endif() + +set(_Poco_FIND_PARTS_REQUIRED) +if (Poco_FIND_REQUIRED) + set(_Poco_FIND_PARTS_REQUIRED REQUIRED) +endif() +set(_Poco_FIND_PARTS_QUIET) +if (Poco_FIND_QUIETLY) + set(_Poco_FIND_PARTS_QUIET QUIET) +endif() + +get_filename_component(_Poco_install_prefix "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE) + +set(_Poco_NOTFOUND_MESSAGE) + +# Let components find each other, but don't overwrite CMAKE_PREFIX_PATH +set(_Poco_CMAKE_PREFIX_PATH_old ${CMAKE_PREFIX_PATH}) +set(CMAKE_PREFIX_PATH ${_Poco_install_prefix}) + +foreach(module ${Poco_FIND_COMPONENTS}) + find_package(Poco${module} + ${_Poco_FIND_PARTS_QUIET} + ${_Poco_FIND_PARTS_REQUIRED} + PATHS "${_Poco_install_prefix}" NO_DEFAULT_PATH + ) + if (NOT Poco${module}_FOUND) + if (Poco_FIND_REQUIRED_${module}) + set(_Poco_NOTFOUND_MESSAGE "${_Poco_NOTFOUND_MESSAGE}Failed to find Poco component \"${module}\" config file at \"${_Poco_install_prefix}/Poco${module}/Poco${module}Config.cmake\"\n") + elseif(NOT Poco_FIND_QUIETLY) + message(WARNING "Failed to find Poco component \"${module}\" config file at \"${_Poco_install_prefix}/Poco${module}/Poco${module}Config.cmake\"") + endif() + endif() + + # For backward compatibility set the LIBRARIES variable + list(APPEND Poco_LIBRARIES "Poco::${module}") +endforeach() + +# Restore the original CMAKE_PREFIX_PATH value +set(CMAKE_PREFIX_PATH ${_Poco_CMAKE_PREFIX_PATH_old}) + +if (_Poco_NOTFOUND_MESSAGE) + set(Poco_NOT_FOUND_MESSAGE "${_Poco_NOTFOUND_MESSAGE}") + set(Poco_FOUND False) +endif() + diff --git a/FlippR-Driver/cmake/PocoConfigVersion.cmake.in b/FlippR-Driver/cmake/PocoConfigVersion.cmake.in new file mode 100644 index 0000000..98f292c --- /dev/null +++ b/FlippR-Driver/cmake/PocoConfigVersion.cmake.in @@ -0,0 +1,11 @@ +set(PACKAGE_VERSION @APPLICATION_VERSION@) + +# Check whether the requested PACKAGE_FIND_VERSION is compatible +if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/FlippR-Driver/cmake/PocoMacros.cmake b/FlippR-Driver/cmake/PocoMacros.cmake new file mode 100644 index 0000000..4490b7b --- /dev/null +++ b/FlippR-Driver/cmake/PocoMacros.cmake @@ -0,0 +1,304 @@ +# Copyright Siemens AG, 2014 +# Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. +# and Contributors. +# +# SPDX-License-Identifier: BSL-1.0 +# +# Collection of common functionality for Poco CMake + +# Find the Microsoft mc.exe message compiler +# +# CMAKE_MC_COMPILER - where to find mc.exe +if (WIN32) + # cmake has CMAKE_RC_COMPILER, but no message compiler + if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio") + # this path is only present for 2008+, but we currently require PATH to + # be set up anyway + get_filename_component(sdk_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]" REALPATH) + get_filename_component(kit_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot]" REALPATH) + get_filename_component(kit81_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot81]" REALPATH) + get_filename_component(kit10_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" REALPATH) + get_filename_component(kit10wow_dir "[HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" REALPATH) + file(GLOB kit10_list ${kit10_dir}/bin/10.* ${kit10wow_dir}/bin/10.*) + if (X64) + set(sdk_bindir "${sdk_dir}/bin/x64") + set(kit_bindir "${kit_dir}/bin/x64") + set(kit81_bindir "${kit81_dir}/bin/x64") + foreach (tmp_elem ${kit10_list}) + if (IS_DIRECTORY ${tmp_elem}) + list(APPEND kit10_bindir "${tmp_elem}/x64") + endif() + endforeach() + else (X64) + set(sdk_bindir "${sdk_dir}/bin") + set(kit_bindir "${kit_dir}/bin/x86") + set(kit81_bindir "${kit81_dir}/bin/x86") + foreach (tmp_elem ${kit10_list}) + if (IS_DIRECTORY ${tmp_elem}) + list(APPEND kit10_bindir "${tmp_elem}/x86") + endif() + endforeach() + endif (X64) + endif () + find_program(CMAKE_MC_COMPILER mc.exe HINTS "${sdk_bindir}" "${kit_bindir}" "${kit81_bindir}" ${kit10_bindir} + DOC "path to message compiler") + if (NOT CMAKE_MC_COMPILER) + message(FATAL_ERROR "message compiler not found: required to build") + endif (NOT CMAKE_MC_COMPILER) + message(STATUS "Found message compiler: ${CMAKE_MC_COMPILER}") + mark_as_advanced(CMAKE_MC_COMPILER) +endif(WIN32) + +#=============================================================================== +# Macros for Source file management +# +# POCO_SOURCES_PLAT - Adds a list of files to the sources of a components +# Usage: POCO_SOURCES_PLAT( out name platform sources) +# INPUT: +# out the variable the sources are added to +# name: the name of the components +# platform: the platform this sources are for (ON = All, OFF = None, WIN32, UNIX ...) +# sources: a list of files to add to ${out} +# Example: POCO_SOURCES_PLAT( SRCS Foundation ON src/Foundation.cpp ) +# +# POCO_SOURCES - Like POCO_SOURCES_PLAT with platform = ON (Built on all platforms) +# Usage: POCO_SOURCES( out name sources) +# Example: POCO_SOURCES( SRCS Foundation src/Foundation.cpp) +# +# POCO_SOURCES_AUTO - Like POCO_SOURCES but the name is read from the file header // Package: X +# Usage: POCO_SOURCES_AUTO( out sources) +# Example: POCO_SOURCES_AUTO( SRCS src/Foundation.cpp) +# +# POCO_SOURCES_AUTO_PLAT - Like POCO_SOURCES_PLAT but the name is read from the file header // Package: X +# Usage: POCO_SOURCES_AUTO_PLAT(out platform sources) +# Example: POCO_SOURCES_AUTO_PLAT( SRCS WIN32 src/Foundation.cpp) +# +# +# POCO_HEADERS - Adds a list of files to the headers of a components +# Usage: POCO_HEADERS( out name headers) +# INPUT: +# out the variable the headers are added to +# name: the name of the components +# headers: a list of files to add to HDRSt +# Example: POCO_HEADERS( HDRS Foundation include/Poco/Foundation.h ) +# +# POCO_HEADERS_AUTO - Like POCO_HEADERS but the name is read from the file header // Package: X +# Usage: POCO_HEADERS_AUTO( out headers) +# Example: POCO_HEADERS_AUTO( HDRS src/Foundation.cpp) +# +# +# POCO_MESSAGES - Adds a list of files to the messages of a components +# and adds the generated headers to the header list of the component. +# On platforms other then Windows this does nothing +# Usage: POCO_MESSAGES( out name messages) +# INPUT: +# out the variable the message and the resulting headers are added to +# name: the name of the components +# messages: a list of files to add to MSGS +# Example: POCO_MESSAGES( HDRS Foundation include/Poco/Foundation.mc ) +# + + +macro(POCO_SOURCES_PLAT out name platform) + source_group("${name}\\Source Files" FILES ${ARGN}) + list(APPEND ${out} ${ARGN}) + if(NOT (${platform})) + set_source_files_properties(${ARGN} PROPERTIES HEADER_FILE_ONLY TRUE) + endif() +endmacro() + +macro(POCO_SOURCES out name) + POCO_SOURCES_PLAT( ${out} ${name} ON ${ARGN}) +endmacro() + +macro(POCO_SOURCES_AUTO out) + POCO_SOURCES_AUTO_PLAT( ${out} ON ${ARGN}) +endmacro() + +macro(POCO_SOURCES_AUTO_PLAT out platform) + foreach( f ${ARGN}) + + get_filename_component(fname ${f} NAME) + + # Read the package name from the source file + file(STRINGS ${f} package REGEX "// Package: (.*)") + if(package) + string(REGEX REPLACE ".*: (.*)" "\\1" name ${package}) + + # Files of the Form X_UNIX.cpp are treated as headers + if(${fname} MATCHES ".*_.*\\..*") + #message(STATUS "Platform: ${name} ${f} ${platform}") + POCO_SOURCES_PLAT( ${out} ${name} OFF ${f}) + else() + #message(STATUS "Source: ${name} ${f} ${platform}") + POCO_SOURCES_PLAT( ${out} ${name} ${platform} ${f}) + endif() + else() + #message(STATUS "Source: Unknown ${f} ${platform}") + POCO_SOURCES_PLAT( ${out} Unknown ${platform} ${f}) + endif() + endforeach() +endmacro() + + +macro(POCO_HEADERS_AUTO out) + foreach( f ${ARGN}) + + get_filename_component(fname ${f} NAME) + + # Read the package name from the source file + file(STRINGS ${f} package REGEX "// Package: (.*)") + if(package) + string(REGEX REPLACE ".*: (.*)" "\\1" name ${package}) + #message(STATUS "Header: ${name} ${f}") + POCO_HEADERS( ${out} ${name} ${f}) + else() + #message(STATUS "Header: Unknown ${f}") + POCO_HEADERS( ${out} Unknown ${f}) + endif() + endforeach() +endmacro() + +macro(POCO_HEADERS out name) + set_source_files_properties(${ARGN} PROPERTIES HEADER_FILE_ONLY TRUE) + source_group("${name}\\Header Files" FILES ${ARGN}) + list(APPEND ${out} ${ARGN}) +endmacro() + + +macro(POCO_MESSAGES out name) + if (WIN32) + foreach(msg ${ARGN}) + get_filename_component(msg_name ${msg} NAME) + get_filename_component(msg_path ${msg} ABSOLUTE) + string(REPLACE ".mc" ".h" hdr ${msg_name}) + set_source_files_properties(${hdr} PROPERTIES GENERATED TRUE) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${hdr} + DEPENDS ${msg} + COMMAND ${CMAKE_MC_COMPILER} + ARGS + -h ${CMAKE_CURRENT_BINARY_DIR} + -r ${CMAKE_CURRENT_BINARY_DIR} + ${msg_path} + VERBATIM # recommended: p260 + ) + + # Add the generated file to the include directory + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + # Add the generated headers to POCO_HEADERS of the component + POCO_HEADERS( ${out} ${name} ${CMAKE_CURRENT_BINARY_DIR}/${hdr}) + + endforeach() + + set_source_files_properties(${ARGN} PROPERTIES HEADER_FILE_ONLY TRUE) + source_group("${name}\\Message Files" FILES ${ARGN}) + list(APPEND ${out} ${ARGN}) + + endif (WIN32) +endmacro() + + +#=============================================================================== +# Macros for Package generation +# +# POCO_GENERATE_PACKAGE - Generates *Config.cmake +# Usage: POCO_GENERATE_PACKAGE(target_name) +# INPUT: +# target_name the name of the target. e.g. Foundation for PocoFoundation +# Example: POCO_GENERATE_PACKAGE(Foundation) +macro(POCO_GENERATE_PACKAGE target_name) +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) +if ("${CMAKE_VERSION}" VERSION_LESS "3.0.0") + if (NOT EXISTS "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}Targets.cmake") + export(TARGETS "${target_name}" APPEND + FILE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + ) + endif () +else () + export(EXPORT "${target_name}Targets" + FILE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + ) +endif () +configure_file("cmake/Poco${target_name}Config.cmake" + "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}Config.cmake" + @ONLY +) + +set(ConfigPackageLocation "lib/cmake/${PROJECT_NAME}") + +install( + EXPORT "${target_name}Targets" + FILE "${PROJECT_NAME}${target_name}Targets.cmake" + NAMESPACE "${PROJECT_NAME}::" + DESTINATION "lib${LIB_SUFFIX}/cmake/${PROJECT_NAME}" + ) + +install( + FILES + "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}Config.cmake" + "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}${target_name}ConfigVersion.cmake" + DESTINATION "lib${LIB_SUFFIX}/cmake/${PROJECT_NAME}" + COMPONENT Devel + ) + +endmacro() + +#=============================================================================== +# Macros for simplified installation +# +# POCO_INSTALL - Install the given target +# Usage: POCO_INSTALL(target_name) +# INPUT: +# target_name the name of the target. e.g. Foundation for PocoFoundation +# Example: POCO_INSTALL(Foundation) +macro(POCO_INSTALL target_name) +install( + DIRECTORY include/Poco + DESTINATION include + COMPONENT Devel + PATTERN ".svn" EXCLUDE + ) + +install( + TARGETS "${target_name}" EXPORT "${target_name}Targets" + LIBRARY DESTINATION lib${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX} + RUNTIME DESTINATION bin + INCLUDES DESTINATION include + ) + +if (MSVC) +# install the targets pdb + POCO_INSTALL_PDB(${target_name}) +endif() + +endmacro() + +# POCO_INSTALL_PDB - Install the given target's companion pdb file (if present) +# Usage: POCO_INSTALL_PDB(target_name) +# INPUT: +# target_name the name of the target. e.g. Foundation for PocoFoundation +# Example: POCO_INSTALL_PDB(Foundation) +# +# This is an internal macro meant only to be used by POCO_INSTALL. +macro(POCO_INSTALL_PDB target_name) + + get_property(type TARGET ${target_name} PROPERTY TYPE) + if ("${type}" STREQUAL "SHARED_LIBRARY" OR "${type}" STREQUAL "EXECUTABLE") + install( + FILES $ + DESTINATION bin + COMPONENT Devel + OPTIONAL + ) + endif() +endmacro() diff --git a/FlippR-Driver/cmake/README b/FlippR-Driver/cmake/README new file mode 100644 index 0000000..fae4a15 --- /dev/null +++ b/FlippR-Driver/cmake/README @@ -0,0 +1,36 @@ +CMAKE Files contributed by Andrew J. P. Maclean + + +Put the following files in the directory where your source code is: + CMakeLists.txt + PocoConfig.cmake. + +Edit CMakeLists.txt to include your source and header files. The sections of interest are: +# Add any source files here. +SET( EXE_SRCS + "My File.cpp" +) +# Add any include files here. +SET( EXE_INCS + "My File.h" +) + +Then create a subdirectory called build. +In Linux: +cd build +ccmake .. +or +ccmake -GKDevelop3 .. +(This will set up everything so you can use KDevelop3). + +In Windows: +run CMakeSetup.exe and set the source code directory and where to build the libraries. + +If CMake cannot find Poco, you will see that the variable Poco_INCLUDE_DIR has the value Poco_INCLUDE_DIR-NOTFOUND. Just set this value to the top level direcotry of where the Poco includes are. + +If there is a different version of Poco, you may have to add edit the variables SUFFIX_FOR_INCLUDE_PATH, and SUFFIX_FOR_LIBRARY_PATH adding in the new Poco version in a similar manner to the existing ones in the file PocoConfig.cmake. + +Finally: +In Linux + Either type "make" or if you are using KDevelop, click on the .kdevelop file. +In Windows just use your IDE or nmake if you use nmake. diff --git a/FlippR-Driver/cmake/cmake_uninstall.cmake.in b/FlippR-Driver/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..03137d5 --- /dev/null +++ b/FlippR-Driver/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,22 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF("${rm_retval}" STREQUAL 0) + ELSE("${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF("${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/FlippR-Driver/cmake/test_compiler.cpp b/FlippR-Driver/cmake/test_compiler.cpp new file mode 100644 index 0000000..d9b7398 --- /dev/null +++ b/FlippR-Driver/cmake/test_compiler.cpp @@ -0,0 +1,9 @@ +#include +#include + +int main() +{ + std::string str = "Try to compile"; + std::cout << str << '\n'; + return 0; +} diff --git a/FlippR-Driver/contrib/ideen.txt b/FlippR-Driver/contrib/ideen.txt new file mode 100644 index 0000000..95eec6d --- /dev/null +++ b/FlippR-Driver/contrib/ideen.txt @@ -0,0 +1 @@ + input events entprellen über flanken statt zeit diff --git a/FlippR-Driver/contrib/json_example/input/Input_Matrix_Config.json b/FlippR-Driver/contrib/json_example/input/Input_Matrix_Config.json new file mode 100644 index 0000000..11d2216 --- /dev/null +++ b/FlippR-Driver/contrib/json_example/input/Input_Matrix_Config.json @@ -0,0 +1,193 @@ +{ + "global_bounce_time" : 10, + "input_matrix" : + [ + { + "name" : "Out hole", + "address" : 16, + "priority" : 99, + "bounce_time" : 10 + }, + { + "name" : "Left outer exit canal", + "address" : 17, + "priority" : 2 + }, + { + "name" : "Inner left canal", + "address" : 18, + "priority" : 2 + }, + { + "name" : "Left flap contacts", + "address" : 19, + "priority" : 2 + }, + { + "name" : "Right flap contacts", + "address" : 20, + "priority" : 2 + }, + { + "name" : "Right inner canal", + "address" : 21, + "priority" : 2 + }, + { + "name" : "Right central exit canal", + "address" : 22, + "priority" : 2 + }, + { + "name" : "Right kicker contact", + "address" : 23, + "priority" : 2 + }, + { + "name" : "Contacts", + "address" : 24, + "priority" : 2 + }, + { + "name" : "1st moving target bottom left bank", + "address" : 25, + "priority" : 2 + }, + { + "name" : "2nd moving target bottom left bank", + "address" : 26, + "priority" : 2 + }, + { + "name" : "3rd moving target bottom left bank", + "address" : 27, + "priority" : 2 + }, + { + "name" : "4th moving target bottom left bank", + "address" : 28, + "priority" : 2 + }, + { + "name" : "Fixed special red target", + "address" : 29, + "priority" : 2 + }, + { + "name" : "Fixed special orange target", + "address" : 30, + "priority" : 2 + }, + { + "name" : "1st moving target bottom right bank", + "address" : 31, + "priority" : 2 + }, + { + "name" : "2nd moving target bottom right bank", + "address" : 32, + "priority" : 2 + }, + { + "name" : "3rd moving target bottom right bank", + "address" : 33, + "priority" : 2 + }, + { + "name" : "Spinning target", + "address" : 34, + "priority" : 2 + }, + { + "name" : "1st Button", + "address" : 35, + "priority" : 2 + }, + { + "name" : "2nd button", + "address" : 36, + "priority" : 2 + }, + { + "name" : "3rd button", + "address" : 37, + "priority" : 2 + }, + { + "name" : "4th button", + "address" : 38, + "priority" : 2 + }, + { + "name" : "5th button", + "address" : 39, + "priority" : 2 + }, + { + "name" : "1st moving target top central bank", + "address" : 40, + "priority" : 2 + }, + { + "name" : "2nd moving target top central bank", + "address" : 41, + "priority" : 2 + }, + { + "name" : "3rd moving target top central bank", + "address" : 42, + "priority" : 2 + }, + { + "name" : "4th moving target top central bank", + "address" : 43, + "priority" : 2 + }, + { + "name" : "5th moving target top central bank", + "address" : 44, + "priority" : 2 + }, + { + "name" : "1st fixed target", + "address" : 45, + "priority" : 2 + }, + { + "name" : "2nd fixed target", + "address" : 46, + "priority" : 2 + }, + { + "name" : "Top left pop contact", + "address" : 47, + "priority" : 2 + }, + { + "name" : "Bottom right pop contact", + "address" : 48, + "priority" : 2 + }, + { + "name" : "5th fixed target", + "address" : 49, + "priority" : 2 + }, + { + "name" : "4th fixed target", + "address" : 50, + "priority" : 2 + }, + { + "name" : "3rd fixed target", + "address" : 51, + "priority" : 2 + }, + { + "name" : "Rising ball contact", + "address" : 52, + "priority" : 2 + } + ] +} + diff --git a/FlippR-Driver/contrib/json_example/input/Input_Pin_Config.json b/FlippR-Driver/contrib/json_example/input/Input_Pin_Config.json new file mode 100644 index 0000000..303c4a8 --- /dev/null +++ b/FlippR-Driver/contrib/json_example/input/Input_Pin_Config.json @@ -0,0 +1,14 @@ +{ + "update_frequency": 1000, + "row": { + "A": 15, + "B": 16, + "C": 1 + }, + "col": { + "A": 4, + "B": 5, + "C": 6 + }, + "data": 10 +} diff --git a/FlippR-Driver/contrib/json_example/output/Display_Config.json b/FlippR-Driver/contrib/json_example/output/Display_Config.json new file mode 100644 index 0000000..2998018 --- /dev/null +++ b/FlippR-Driver/contrib/json_example/output/Display_Config.json @@ -0,0 +1,48 @@ +{ + "update_frequency": 1000, + "display_board" : + { + "segment_select" : + { + "A" : 22, + "B" : 27, + "C" : 17 + }, + "digit_select" : + { + "A": 19, + "B": 13, + "C": 6, + "D": 5 + }, + "run" : 12 + }, + "displays" : + [ + { + "digits" : 8, + "name" : "Player_1", + "address" : 1 + }, + { + "digits" : 8, + "name" : "Player_2", + "address" : 20 + }, + { + "digits" : 8, + "name" : "Player_3", + "address" : 12 + }, + { + "digits" : 8, + "name" : "Player_4", + "address" : 16 + }, + { + "digits" : 8, + "name" : "Special_Display", + "address" : 4 + } + ] +} diff --git a/FlippR-Driver/contrib/json_example/output/Lamp_Config.json b/FlippR-Driver/contrib/json_example/output/Lamp_Config.json new file mode 100644 index 0000000..6e60bbd --- /dev/null +++ b/FlippR-Driver/contrib/json_example/output/Lamp_Config.json @@ -0,0 +1,417 @@ +{ + "port_extenders" : + [ + { + "name" : "extender_1", + "i2c_address" : 32, + "pin_base" : 65 + } + ], + "address_pins" : + { + "A0": + { + "address" : 9, + "extender" : "extender_1" + }, + "A1": + { + "address" : 8, + "extender" : "extender_1" + }, + "A2": + { + "address" : 1, + "extender" : "extender_1" + } + }, + "enable_pins": + { + "E1" : + { + "address" : 2, + "extender" : "extender_1" + }, + "E2" : + { + "address" : 10, + "extender" : "extender_1" + }, + "E3" : + { + "address" : 3, + "extender" : "extender_1" + }, + "E4" : + { + "address" : 11, + "extender" : "extender_1" + }, + "E5" : + { + "address" : 4, + "extender" : "extender_1" + }, + "E6" : + { + "address" : 12, + "extender" : "extender_1" + }, + "E7" : + { + "address" : 5, + "extender" : "extender_1" + }, + "E8" : + { + "address" : 13, + "extender" : "extender_1" + }, + "E9" : + { + "address" : 12 + }, + "E10" : + { + "address" : 13 + }, + "E11" : + { + "address" : 6, + "extender" : "extender_1" + }, + "E12" : + { + "address" : 14, + "extender" : "extender_1" + }, + "E13" : + { + "address" : 15, + "extender" : "extender_1" + } + }, + "data_pin" : { + "address" : 0, + "extender" : "extender_1" + }, + "run" : { + "address" : 7, + "extender" : "extender_1" + }, + "lamps" : + [ + { + "address" : 0, + "name" : "Special 100000 Points" + }, + { + "address" : 1, + "name" : "Special 200000 Points" + }, + { + "address" : 2, + "name" : "Woman Speech Lamp" + }, + { + "address" : 3, + "name" : "Highest Score" + }, + { + "address" : 4, + "name" : "Pop 2+4" + }, + { + "address" : 5, + "name" : "Special 300000 Points" + }, + { + "address" : 6, + "name" : "Pop 1+3" + }, + { + "address" : 7, + "name" : "Special Orange" + }, + { + "address" : 8, + "name" : "Down" + }, + { + "address" : 9, + "name" : "Lamp 30 Sec" + }, + { + "address" : 10, + "name" : "Lamp 20 Sec" + }, + { + "address" : 11, + "name" : "Lamp 10 Sec" + }, + { + "address" : 12, + "name" : "Lamp 5 Sec" + }, + { + "address" : 13, + "name" : "Can Play 4" + }, + { + "address" : 14, + "name" : "Can Play 3" + }, + { + "address" : 15, + "name" : "P Of Champ" + }, + { + "address" : 16, + "name" : "M Of Champ" + }, + { + "address" : 17, + "name" : "A Of Champ" + }, + { + "address" : 18, + "name" : "Can Play 2" + }, + { + "address" : 19, + "name" : "Big Bonus 20000" + }, + { + "address" : 20, + "name" : "Can Play 1" + }, + { + "address" : 21, + "name" : "H Of Champ" + }, + { + "address" : 22, + "name" : "C Of Champ" + }, + { + "address" : 23, + "name" : "Special Red" + }, + { + "address" : 24, + "name" : "Super Bonus" + }, + { + "address" : 25, + "name" : "Bonus 20000" + }, + { + "address" : 26, + "name" : "2nd Kicker Lamp" + }, + { + "address" : 27, + "name" : "Bonus 18000" + }, + { + "address" : 28, + "name" : "Bonus 17000" + }, + { + "address" : 29, + "name" : "Bonus 16000" + }, + { + "address" : 30, + "name" : "Man Speech Lamp" + }, + { + "address" : 31, + "name" : "Bonus 15000" + }, + { + "address" : 32, + "name" : "Bonus 14000" + }, + { + "address" : 33, + "name" : "Bonus 13000" + }, + { + "address" : 34, + "name" : "Bonus 12000" + }, + { + "address" : 35, + "name" : "Ball" + }, + { + "address" : 36, + "name" : "Bonus 11000" + }, + { + "address" : 37, + "name" : "Bonus 10000" + }, + { + "address" : 38, + "name" : "Bonus 9000" + }, + { + "address" : 39, + "name" : "Bonus 8000" + }, + { + "address" : 40, + "name" : "Bonus 7000" + }, + { + "address" : 41, + "name" : "Bonus 6000" + }, + { + "address" : 42, + "name" : "Bonus 5000" + }, + { + "address" : 43, + "name" : "Pop 5 Head Lamp" + }, + { + "address" : 44, + "name" : "Bonus 3000" + }, + { + "address" : 45, + "name" : "Bonus 2000" + }, + { + "address" : 46, + "name" : "Bonus 1000" + }, + { + "address" : 47, + "name" : "Bonus 4000" + }, + { + "address" : 48, + "name" : "Right Advance Time" + }, + { + "address" : 49, + "name" : "UP" + }, + { + "address" : 50, + "name" : "Bonux Multiplier x50" + }, + { + "address" : 51, + "name" : "Bonus Multiplier x20" + }, + { + "address" : 52, + "name" : "Bonus Multiplier x10" + }, + { + "address" : 53, + "name" : "Credit" + }, + { + "address" : 54, + "name" : "Bonus 19000" + }, + { + "address" : 55, + "name" : "5th Button" + }, + { + "address" : 56, + "name" : "4th Button" + }, + { + "address" : 57, + "name" : "3rd Button" + }, + { + "address" : 58, + "name" : "2nd Button" + }, + { + "address" : 59, + "name" : "1st Button" + }, + { + "address" : 61, + "name" : "Lamp 5" + }, + { + "address" : 62, + "name" : "Lamp 4" + }, + { + "address" : 63, + "name" : "Ball To Play" + }, + { + "address" : 64, + "name" : "Tunnel Lamp 20000 Points" + }, + { + "address" : 65, + "name" : "Tunnel Lamp 30000 Points" + }, + { + "address" : 66, + "name" : "Tunnel Lamp 50000 Points" + }, + { + "address" : 67, + "name" : "Match" + }, + { + "address" : 68, + "name" : "Lamp 3" + }, + { + "address" : 69, + "name" : "Lamp 2" + }, + { + "address" : 70, + "name" : "1st Kicker Lamp" + }, + { + "address" : 71, + "name" : "Lamp 1" + }, + { + "address" : 72, + "name" : "Left Advance Time" + }, + { + "address" : 73, + "name" : "Tilt" + }, + { + "address" : 74, + "name" : "Game Over" + }, + { + "address" : 75, + "name" : "500000 Points" + }, + { + "address" : 76, + "name" : "200000 Points" + }, + { + "address" : 77, + "name" : "150000 Points" + }, + { + "address" : 78, + "name" : "100000 Points" + } + ] +} diff --git a/FlippR-Driver/contrib/json_example/output/Solenoid_Config.json b/FlippR-Driver/contrib/json_example/output/Solenoid_Config.json new file mode 100644 index 0000000..0b637af --- /dev/null +++ b/FlippR-Driver/contrib/json_example/output/Solenoid_Config.json @@ -0,0 +1,71 @@ +{ + "port_extenders" : + [ + { + "name" : "extender_0", + "i2c_address" : 32, + "pin_base" : 65 + } + ], + "deactivation_time_milliseconds" : 10, + "flippers" : + [ + { + "address" : 60, + "name" : "Flipper Relay" + }, + { + "address" : 91, + "name" : "Top Flipper Relay" + } + ], + "solenoids" : + [ + { + "_comment" :"addresses relative to port_extender", + "address" : 79, + "name" : "Out Hole", + "deactivation_time_milliseconds" : 15 + }, + { + "address" : 82, + "name" : "Bottom Right Pop" + }, + { + "address" : 92, + "name" : "Right Kicker" + }, + { + "address" : 94, + "name" : "Top Central Bank" + }, + { + "address" : 95, + "name" : "Coin Mechanism Coil" + }, + { + "address" : 96, + "name" : "Top Left Pop" + }, + { + "address" : 97, + "name" : "Bottom Right Bank" + }, + { + "address" : 98, + "name" : "Bottom Left Bank" + }, + { + "address" : 99, + "name" : "Knocker" + }, + { + "address" : 100, + "name" : "Right Flap" + }, + { + "address" : 101, + "name" : "Left Flap" + } + ] +} diff --git a/FlippR-Driver/contrib/json_example/output/Sound_Config.json b/FlippR-Driver/contrib/json_example/output/Sound_Config.json new file mode 100644 index 0000000..f933db4 --- /dev/null +++ b/FlippR-Driver/contrib/json_example/output/Sound_Config.json @@ -0,0 +1,336 @@ +{ + "port_extenders" : + [ + { + "i2c_address" : 34, + "name" : "extender_0", + "pin_base" : 81 + } + ], + "fire_pin" : + { + "address" : 13, + "extender" : "extender_0" + }, + "address_pins" : + [ + { + "id" : 0, + "address" : 15, + "extender" : "extender_0" + }, + { + "id" : 1, + "address" : 14, + "extender" : "extender_0" + }, + { + "id" : 2, + "address" : 12, + "extender" : "extender_0" + }, + { + "id" : 3, + "address" : 10, + "extender" : "extender_0" + }, + { + "id" : 4, + "address" : 8, + "extender" : "extender_0" + }, + { + "id" : 5, + "address" : 9, + "extender" : "extender_0" + }, + { + "id" : 6, + "address" : 11, + "extender" : "extender_0" + } + ], + "sounds" : + [ + { + "id" : 255, + "address" : 0, + "name" : "Deactivation Sound" + }, + { + "id" : 0, + "address" : 22, + "name" : "Sound 1" + }, + { + "id" : 1, + "address" : 23, + "name" : "Sound 2" + }, + { + "id" : 2, + "address" : 24, + "name" : "Sound 3" + }, + { + "id" : 3, + "address" : 25, + "name" : "Sound 4" + }, + { + "id" : 4, + "address" : 26, + "name" : "Sound 5" + }, + { + "id" : 5, + "address" : 27, + "name" : "Sound 6" + }, + { + "id" : 6, + "address" : 28, + "name" : "Sound 7" + }, + { + "id" : 7, + "address" : 29, + "name" : "Sound 8" + }, + { + "id" : 8, + "address" : 30, + "name" : "Sound 9" + }, + { + "id" : 9, + "address" : 31, + "name" : "Sound 10" + }, + { + "id" : 10, + "address" : 32, + "name" : "Sound 11" + }, + { + "id" : 11, + "address" : 33, + "name" : "Sound 12" + }, + { + "id" : 12, + "address" : 34, + "name" : "Sound 13" + }, + { + "id" : 13, + "address" : 35, + "name" : "Sound 14" + }, + { + "id" : 14, + "address" : 36, + "name" : "Sound 15" + }, + { + "id" : 15, + "address" : 37, + "name" : "Sound 16" + }, + { + "id" : 16, + "address" : 38, + "name" : "Sound 17" + }, + { + "id" : 17, + "address" : 39, + "name" : "Sound 18" + }, + { + "id" : 18, + "address" : 40, + "name" : "Sound 19" + }, + { + "id" : 19, + "address" : 41, + "name" : "Sound 20" + }, + { + "id" : 20, + "address" : 42, + "name" : "Sound 21" + }, + { + "id" : 21, + "address" : 43, + "name" : "Sound 22" + }, + { + "id" : 22, + "address" : 44, + "name" : "Sound 23" + }, + { + "id" : 23, + "address" : 45, + "name" : "Sound 24" + }, + { + "id" : 24, + "address" : 46, + "name" : "Sound 25" + }, + { + "id" : 25, + "address" : 47, + "name" : "Sound 26" + }, + { + "id" : 26, + "address" : 48, + "name" : "Sound 27" + }, + { + "id" : 27, + "address" : 49, + "name" : "Sound 28" + }, + { + "id" : 28, + "address" : 50, + "name" : "Speech 1: \"You're good! But I'm still the Champ!\"" + }, + { + "id" : 29, + "address" : 51, + "name" : "Speech 2: \"Twenty\"" + }, + { + "id" : 30, + "address" : 52, + "name" : "Speech 3: \"Seconds\"" + }, + { + "id" : 31, + "address" : 53, + "name" : "Speech 4: \"Five, Four, Three, Two, One.\"" + }, + { + "id" : 32, + "address" : 54, + "name" : "Speech 5: \"Challenge the champ!\"" + }, + { + "id" : 33, + "address" : 55, + "name" : "Speech 6: \"Good. You're a champ!\"" + }, + { + "id" : 34, + "address" : 56, + "name" : "Speech 7: \"Wow.\"" + }, + { + "id" : 35, + "address" : 57, + "name" : "Speech 8: \"This is a maximum score.\"" + }, + { + "id" : 36, + "address" : 58, + "name" : "Speech 9: \"What a low score!\"" + }, + { + "id" : 37, + "address" : 59, + "name" : "Speech 10: \"Try harder!\"" + }, + { + "id" : 38, + "address" : 60, + "name" : "Speech 11: \"Be careful.\"" + }, + { + "id" : 39, + "address" : 61, + "name" : "Speech 12: \"The last ball.\"" + }, + { + "id" : 40, + "address" : 62, + "name" : "Speech 13: \"Be ready for the Game Time Bonus.\"" + }, + { + "id" : 41, + "address" : 63, + "name" : "Speech 14: \"That's naughty!\"" + }, + { + "id" : 42, + "address" : 64, + "name" : "Speech 15: \"Another coin please.\"" + }, + { + "id" : 43, + "address" : 65, + "name" : "Speech 16: \"Sorry. The time is over.\"" + }, + { + "id" : 44, + "address" : 66, + "name" : "Speech 17: \"I am the champ! Challenge me!\"" + }, + { + "id" : 45, + "address" : 67, + "name" : "Speech 18: \"Time is short.\"" + }, + { + "id" : 46, + "address" : 68, + "name" : "Speech 19: \"Once again for the special.\"" + }, + { + "id" : 47, + "address" : 69, + "name" : "Speech 20: \"Go for the high level board.\"" + }, + { + "id" : 48, + "address" : 70, + "name" : "Speech 21: \"Play gently to beat me.\"" + }, + { + "id" : 49, + "address" : 71, + "name" : "Speech 22: \"Quick! Hit the special.\"" + }, + { + "id" : 50, + "address" : 72, + "name" : "Speech 23: \"Shoot the special.\"" + }, + { + "id" : 51, + "address" : 73, + "name" : "Speech 24: \"Thirty\"" + }, + { + "id" : 52, + "address" : 74, + "name" : "Speech 25: \"Red\"" + }, + { + "id" : 53, + "address" : 75, + "name" : "Speech 27: \"Yellow\"" + }, + { + "id" : 54, + "address" : 76, + "name" : "Speech 28: \"Go for the Special.\"" + } + ] +} diff --git a/FlippR-Driver/contrib/json_example/output_socket_solenoid.json b/FlippR-Driver/contrib/json_example/output_socket_solenoid.json new file mode 100644 index 0000000..bd4aa12 --- /dev/null +++ b/FlippR-Driver/contrib/json_example/output_socket_solenoid.json @@ -0,0 +1,10 @@ +{ + "type" : "Solenoid", + "name" : "Right flap", + "functions" : + { + "trigger" : false + } +} +string function; +lamp \ No newline at end of file diff --git a/FlippR-Driver/contrib/json_example/server_config.json b/FlippR-Driver/contrib/json_example/server_config.json new file mode 100644 index 0000000..d8109d3 --- /dev/null +++ b/FlippR-Driver/contrib/json_example/server_config.json @@ -0,0 +1,8 @@ +{ + "input-config" :"../../contrib/json_example/input/Input_Pin_Config.json", + "matrix-config" :"../../contrib/json_example/input/Input_Matrix_Config.json", + "lamp-config" :"../../contrib/json_example/output/Lamp_Config.json", + "solenoid-config" :"../../contrib/json_example/output/Solenoid_Config.json", + "sound-config" :"../../contrib/json_example/output/Sound_Config.json", + "display-config" :"../../contrib/json_example/output/Display_Config.json" +} diff --git a/FlippR-Driver/contrib/pre-commit b/FlippR-Driver/contrib/pre-commit new file mode 100755 index 0000000..e2b0d22 --- /dev/null +++ b/FlippR-Driver/contrib/pre-commit @@ -0,0 +1,14 @@ +#!/bin/sh + +echo "Making sure the code compiles!!!" + +if [ ! -d 'FlippR-Driver/build' ]; then + echo "Make sure you have the build folder!" + exit 1 +fi + +cd FlippR-Driver/build +cmake .. +make + +exit $rc diff --git a/FlippR-Driver/contrib/uml/OutputItem_SequenceDiagram.puml b/FlippR-Driver/contrib/uml/OutputItem_SequenceDiagram.puml new file mode 100644 index 0000000..5d4ce05 --- /dev/null +++ b/FlippR-Driver/contrib/uml/OutputItem_SequenceDiagram.puml @@ -0,0 +1,13 @@ +@startuml +Sound -> GPIOInterface:activate() +GPIOInterface --> GPIOInterface:setAddress() +GPIOInterface --> GPIOInterface:setDataPin(1) +GPIOInterface -> Sound:done +Sound --> Sound:sleep_for() +Sound -> GPIOInterface:deactivate() +GPIOInterface --> GPIOInterface:setAddress() +GPIOInterface --> GPIOInterface:setDataPin(0) +GPIOInterface -> Sound:done + + +@enduml \ No newline at end of file diff --git a/FlippR-Driver/contrib/uml/output_umldiagramm.puml b/FlippR-Driver/contrib/uml/output_umldiagramm.puml new file mode 100644 index 0000000..0e00168 --- /dev/null +++ b/FlippR-Driver/contrib/uml/output_umldiagramm.puml @@ -0,0 +1,373 @@ +@startuml + + + + + +/' Objects '/ + +namespace flippR_driver::output::items { + class Display > { + +Display(int address, int id) + +~Display() + -address : int + +content : std::array + -fit_string(std::string& score_string) : std::string + +get_content() : std::vector + +write_content(std::array content) : void + +write_score(int score) : void + } +} + + +namespace flippR_driver::output { + class DisplayController { + +DisplayController(std::vector > displays, std::shared_ptr pin_controller) + +~DisplayController() + -is_running : bool + -pin_controller : std::shared_ptr + -display_cycle_thread : std::thread + -displays : std::vector > + -cycle_displays() : void + } +} + + +namespace flippR_driver::utility { + class DisplayGPIOInterface { + +DisplayGPIOInterface() + +~DisplayGPIOInterface() + } +} + + +namespace flippR_driver::utility { + class GPIOInterface { + +GPIOInterface() + +~GPIOInterface() + #{static} read_pin(char address) : bool + +{static} GPIO_LIB_INITIALIZED : static std::once_flag + -pin_base : unsigned int + #{static} initialize_input_pin(char address) : void + #{static} initialize_output_pin(char address) : void + #{static} write_pin(char address, char data) : void + } +} + + +namespace flippR_driver::utility { + abstract class IBlockingQueue > { + +~IBlockingQueue() + +{abstract} pop() : T + +{abstract} push(T const& value) : void + } +} + + +namespace flippR_driver::output::items { + abstract class IDisplay { + +IDisplay() + +~IDisplay() + +{abstract} get_content() : std::vector + } +} + + +namespace flippR_driver::output { + class IDisplayController { + +IDisplayController() + +~IDisplayController() + } +} + + +namespace flippR_driver::output::items { + class IDriverBoardItem { + +~IDriverBoardItem() + } +} + + +namespace flippR_driver::utility { + abstract class IInputGPIOInterface { + +~IInputGPIOInterface() + +{abstract} read_data(char pin) : bool + } +} + + +namespace flippR_driver::output::items { + abstract class IItem { + +~IItem() + +{abstract} get_address() : uint8_t + } +} + + +namespace flippR_driver::utility { + abstract class IOutputGPIOInterface { + +~IOutputGPIOInterface() + +{abstract} activate(output::items::IDriverBoardItem* driver_board_item) : void + +{abstract} activate(output::items::ISoundItem* sound) : void + +{abstract} deactivate(output::items::IDriverBoardItem* driver_board_item) : void + +{abstract} deactivate(output::items::ISoundItem* sound) : void + +{abstract} write_display(std::shared_ptr display) : void + } +} + + +namespace flippR_driver::output::items { + class ISoundItem { + } +} + + +namespace flippR_driver::utility { + class InputGPIOInterface { + +InputGPIOInterface(std::istream& input_config) + +read_data(char pin) : bool + -col_address_A : char + -col_address_B : char + -col_address_C : char + -data_address : char + -row_address_A : char + -row_address_B : char + -row_address_C : char + -init_members(std::istream& input_config_stream) : void + -init_pins() : void + -write_col(char data) : void + -write_row(char data) : void + } +} + + +namespace flippR_driver::utility { + class InputSocketHandler { + +InputSocketHandler(boost::asio::io_service& service, std::string socket_file) + -serialize_event(input::Event& event) : nlohmann::json + +handle(input::Event& event) : void + } +} + + +namespace flippR_driver::output::items { + class Item { + +Item(std::shared_ptr pin_controller, uint8_t address, std::string name) + +~Item() + #gpio_interface : const std::shared_ptr + #name : const std::string + #address : const uint8_t + +get_address() : uint8_t + } +} + + +namespace flippR_driver::output::items { + class Lamp { + +Lamp(std::shared_ptr pin_controller, uint8_t address, std::string name) + +~Lamp() + -activated : bool + +is_activated() : bool + +activate() : void + +deactivate() : void + } +} + + +namespace flippR_driver::output { + class OutputDriver { + +OutputDriver(std::map > solenoids, std::map > lamps, std::map > displays, std::map > sounds) + +~OutputDriver() + -displays : std::map > + -lamps : std::map > + -solenoids : std::map > + -sounds : std::map > + +get_display(char number) : std::shared_ptr + +get_lamp(std::string name) : std::shared_ptr + +get_solenoid(std::string name) : std::shared_ptr + +get_sound(std::string name) : std::shared_ptr + +get_displays() : std::vector > + +get_lamps() : std::vector > + +get_solenoids() : std::vector > + +get_sounds() : std::vector > + } +} + + +namespace flippR_driver::output { + class OutputDriverFactory { + +{static} getOutputDriver(std::ifstream& output_gpio_config, std::ifstream& output_config) : std::shared_ptr + } +} + + +namespace flippR_driver::utility { + class OutputGPIOInterface { + +OutputGPIOInterface(std::istream& output_config_stream) + +~OutputGPIOInterface() + -pins_display : std::map + -pins_driver_board : std::map + -pins_sound : std::map + -output_item_mutex : std::mutex + +activate(output::items::IDriverBoardItem* driver_board_item) : void + +activate(output::items::ISoundItem* sound) : void + +deactivate(output::items::IDriverBoardItem* driver_board_item) : void + +deactivate(output::items::ISoundItem* sound) : void + -fire_sound(bool fire) : void + -initialize_all_pins(uint8_t pin_base) : void + -initialize_i2c_addresses() : void + -initialize_pins() : void + -parse_output_config(nlohmann::json& output_config) : void + -parse_pins_display(nlohmann::json& display_board_config) : void + -parse_pins_driver_board(nlohmann::json& driver_board_config) : void + -parse_pins_sound(nlohmann::json& sound_board_config) : void + -select_latch(uint8_t latch) : void + -select_mux(uint8_t latch) : void + -select_pin(uint8_t pin) : void + -write_data(bool data) : void + +write_display(output::items::IDisplay* display) : void + -write_driver_board_address(uint8_t address) : void + -write_sound_address(uint8_t address) : void + } +} + + +namespace flippR_driver::utility { + class SocketHandler { + +SocketHandler(boost::asio::io_service& service, std::string socket_file) + #socket : boost::asio::local::stream_protocol::socket + #write_to_socket(nlohmann::json& data) : void + } +} + + +namespace flippR_driver::output::items { + class Solenoid { + +Solenoid(std::shared_ptr pin_controller, u_int8_t address, std::string name, std::chrono::milliseconds deactivation_time) + +~Solenoid() + -deactivation_time : std::chrono::milliseconds + -trigger_task : std::future + +trigger() : void + -triggerTask() : void + } +} + + +namespace flippR_driver::output::items { + class Sound { + +Sound(std::shared_ptr pin_controller, uint8_t address, std::string name, std::chrono::milliseconds deactivation_time, u_int id) + +~Sound() + -deactivation_time : std::chrono::milliseconds + -play_task : std::future + +id : u_int + +play() : void + -playTask() : void + } +} + + + + + +/' Inheritance relationships '/ + +namespace flippR_driver::utility { + GPIOInterface <|-- InputGPIOInterface +} + + +namespace flippR_driver::utility { + GPIOInterface <|-- OutputGPIOInterface +} + + +namespace flippR_driver::output::items { + IDisplay <|-- Display +} + + +namespace flippR_driver::output { + IDisplayController <|-- DisplayController +} + + +namespace flippR_driver::output::items { + IDriverBoardItem <|-- Lamp +} + + +namespace flippR_driver::output::items { + IDriverBoardItem <|-- Solenoid +} + + +namespace flippR_driver::utility { + IInputGPIOInterface <|-- InputGPIOInterface +} + + +namespace flippR_driver::output::items { + IItem <|-- IDriverBoardItem +} + + +namespace flippR_driver::output::items { + IItem <|-- ISoundItem +} + + +namespace flippR_driver::output::items { + IItem <|-- Item +} + + +namespace flippR_driver::utility { + IOutputGPIOInterface <|-- OutputGPIOInterface +} + + +namespace flippR_driver::output::items { + ISoundItem <|-- Sound +} + + +namespace flippR_driver::output::items { + Item <|-- Lamp +} + + +namespace flippR_driver::output::items { + Item <|-- Solenoid +} + + +namespace flippR_driver::output::items { + Item <|-- Sound +} + + +namespace flippR_driver::utility { + SocketHandler <|-- InputSocketHandler +} + + + + + +/' Aggregation relationships '/ + +flippR_driver::output.DisplayController o-- flippR_driver::output::items.IDisplay + + +flippR_driver::output.DisplayController o-- flippR_driver::utility.IOutputGPIOInterface + + +flippR_driver::output::items.Item o-- flippR_driver::utility.IOutputGPIOInterface + + +flippR_driver::output.OutputDriver o-- flippR_driver::output::items.IDisplay + + + + +@enduml diff --git a/FlippR-Driver/contrib/uml/uml.puml b/FlippR-Driver/contrib/uml/uml.puml new file mode 100644 index 0000000..07be795 --- /dev/null +++ b/FlippR-Driver/contrib/uml/uml.puml @@ -0,0 +1,256 @@ +@startuml + + + + + +/' Objects '/ + +namespace flippR_driver::output::items { + class Display > { + +Display(int address, int id) + +~Display() + -address : int + +content : std::array + -fit_string(std::string& score_string) : std::string + +get_content() : std::vector + +write_content(std::array content) : void + +write_score(int score) : void + } +} + + +namespace flippR_driver::output { + class DisplayController { + +DisplayController(std::vector > displays, std::shared_ptr pin_controller) + +~DisplayController() + -is_running : bool + -pin_controller : std::shared_ptr + -display_cycle_thread : std::thread + -displays : std::vector > + -cycle_displays() : void + } +} + + +namespace flippR_driver::output::items { + class DriverBoardItem { + +DriverBoardItem(std::shared_ptr pin_controller, uint8_t address, std::string name) + +~DriverBoardItem() + } +} + + +namespace flippR_driver::output::items { + abstract class IDisplay { + +~IDisplay() + +{abstract} get_content() : std::vector + } +} + + +namespace flippR_driver::output { + class IDisplayController { + +~IDisplayController() + } +} + + +namespace flippR_driver::output::items { + abstract class IItem { + +~IItem() + +{abstract} get_name() : std::string + +{abstract} get_address() : uint8_t + } +} + + +namespace flippR_driver::output { + abstract class IOutputGPIOInterface { + +~IOutputGPIOInterface() + +{abstract} activate(items::DriverBoardItem* driver_board_item) : void + +{abstract} activate(items::SoundItem* sound) : void + +{abstract} deactivate(items::DriverBoardItem* driver_board_item) : void + +{abstract} deactivate(items::SoundItem* sound) : void + +{abstract} write_display(std::shared_ptr display) : void + } +} + + +namespace flippR_driver::output::items { + class Item { + +Item(std::shared_ptr pin_controller, uint8_t address, std::string name) + +~Item() + #gpio_interface : const std::shared_ptr + #name : const std::string + #address : const uint8_t + +get_name() : std::string + +get_address() : uint8_t + } +} + + +namespace flippR_driver::output::items { + class Lamp { + +Lamp(std::shared_ptr pin_controller, uint8_t address, std::string name) + +~Lamp() + -activated : bool + +is_activated() : bool + +activate() : void + +deactivate() : void + } +} + + +namespace flippR_driver::output { + class OutputDriver { + +OutputDriver(std::map > solenoids, std::map > lamps, std::map > sounds, std::map > displays) + +~OutputDriver() + +get_display(char number) : boost::optional > + +get_lamp(std::string name) : boost::optional > + +get_solenoid(std::string name) : boost::optional > + +get_sound(std::string name) : boost::optional > + -displays : const std::map > + -lamps : const std::map > + -solenoids : const std::map > + -sounds : const std::map > + +get_displays() : std::vector > + +get_lamps() : std::vector > + +get_solenoids() : std::vector > + +get_sounds() : std::vector > + } +} + + +namespace flippR_driver::output { + class OutputGPIOInterface { + +OutputGPIOInterface(std::map pins_driver_board, std::map pins_sound, std::map pins_display) + +~OutputGPIOInterface() + -pins_display : const std::map + -pins_driver_board : const std::map + -pins_sound : const std::map + -output_item_mutex : std::mutex + +activate(items::DriverBoardItem* driver_board_item) : void + +activate(items::SoundItem* sound) : void + +deactivate(items::DriverBoardItem* driver_board_item) : void + +deactivate(items::SoundItem* sound) : void + -fire_sound(bool fire) : void + -initialize_all_pins(uint8_t pin_base) : void + -initialize_i2c_addresses() : void + -initialize_pins() : void + -select_latch(uint8_t latch) : void + -select_mux(uint8_t latch) : void + -select_pin(uint8_t pin) : void + -write_data(bool data) : void + +write_display(std::shared_ptr display) : void + -write_driver_board_address(uint8_t address) : void + -write_sound_address(uint8_t address) : void + } +} + + +namespace flippR_driver::output::items { + class Solenoid { + +Solenoid(std::shared_ptr pin_controller, u_int8_t address, std::string name, std::chrono::milliseconds deactivation_time) + +~Solenoid() + -deactivation_time : std::chrono::milliseconds + -trigger_task : std::future + +trigger() : void + -triggerTask() : void + } +} + + +namespace flippR_driver::output::items { + class Sound { + +Sound(std::shared_ptr pin_controller, uint8_t address, std::string name, std::chrono::milliseconds deactivation_time, u_int id) + +~Sound() + -deactivation_time : std::chrono::milliseconds + -play_task : std::future + +id : u_int + +play() : void + -playTask() : void + } +} + + +namespace flippR_driver::output::items { + class SoundItem { + +SoundItem(std::shared_ptr pin_controller, uint8_t address, std::string name) + +~SoundItem() + } +} + + + + + +/' Inheritance relationships '/ + +namespace flippR_driver::output::items { + DriverBoardItem <|-- Lamp +} + + +namespace flippR_driver::output::items { + DriverBoardItem <|-- Solenoid +} + + +namespace flippR_driver::output::items { + IDisplay <|-- Display +} + + +namespace flippR_driver::output { + IDisplayController <|-- DisplayController +} + + +namespace flippR_driver::output::items { + IItem <|-- Item +} + + +namespace flippR_driver::output { + IOutputGPIOInterface <|-- OutputGPIOInterface +} + + +namespace flippR_driver::output::items { + Item <|-- DriverBoardItem +} + + +namespace flippR_driver::output::items { + Item <|-- SoundItem +} + + +namespace flippR_driver::output::items { + SoundItem <|-- Sound +} + + + + + +/' Aggregation relationships '/ + +flippR_driver::output.DisplayController o-- flippR_driver::output::items.IDisplay + + +namespace flippR_driver::output { + DisplayController o-- IOutputGPIOInterface +} + + +flippR_driver::output::items.Item o-- flippR_driver::output.IOutputGPIOInterface + + +flippR_driver::output.OutputDriver o-- flippR_driver::output::items.IDisplay + + + + +@enduml diff --git a/FlippR-Driver/etc/Input_Config.json b/FlippR-Driver/etc/Input_Config.json deleted file mode 100644 index 8d1c8b6..0000000 --- a/FlippR-Driver/etc/Input_Config.json +++ /dev/null @@ -1 +0,0 @@ - diff --git a/FlippR-Driver/etc/Input_Matrix_Config.json b/FlippR-Driver/etc/Input_Matrix_Config.json deleted file mode 100644 index de13801..0000000 --- a/FlippR-Driver/etc/Input_Matrix_Config.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "input_matrix" : - [ - { - "name" : "event_01", - "address" : 123, - "priority" : 1 - }, - - { - "name" : "event_02", - "address" : 2, - "priority" : 2 - }, - ] -} diff --git a/FlippR-Driver/include/DriverFactory.h b/FlippR-Driver/include/DriverFactory.h new file mode 100644 index 0000000..3cebc57 --- /dev/null +++ b/FlippR-Driver/include/DriverFactory.h @@ -0,0 +1,23 @@ +// +// Created by rhetenor on 13.09.18. +// + +#ifndef flippR_driver_DRIVERFACTORY_H +#define flippR_driver_DRIVERFACTORY_H + +#include +#include + +#include "input/InputDriver.h" +#include "output/OutputDriver.h" + +namespace flippR_driver +{ + std::shared_ptr get_InputDriver(std::istream& input_config_stream, std::istream& matrix_config_stream); + std::shared_ptr get_OutputDriver(std::string & lamp_config_path, + std::string & solenoid_config_path, + std::string & sound_config_path, + std::string & display_config_path); +} + +#endif //flippR_driver_DRIVERFACTORY_H diff --git a/FlippR-Driver/include/input/Event.h b/FlippR-Driver/include/input/Event.h new file mode 100644 index 0000000..61ff4dd --- /dev/null +++ b/FlippR-Driver/include/input/Event.h @@ -0,0 +1,44 @@ +/* + * InputEvent.h + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef INPUTEVENT_H_ +#define INPUTEVENT_H_ + +#include +#include +#include + +namespace flippR_driver { +namespace input { + +class Event { +public: + Event(uint8_t address, int priority, std::string name); + + std::string getJsonString(); + + friend bool operator==(const Event &left, const Event &right); + + friend bool operator<(const Event &left, const Event &right) { + return left.priority < right.priority; + } + + +public: + std::string name; + uint8_t address; + int priority; + std::chrono::time_point last_activation; + +}; + +bool operator==(const Event &left, const Event &right); + +} + +} +#endif /* INPUTEVENT_H_ */ diff --git a/FlippR-Driver/include/input/EventHandler.h b/FlippR-Driver/include/input/EventHandler.h new file mode 100644 index 0000000..289e319 --- /dev/null +++ b/FlippR-Driver/include/input/EventHandler.h @@ -0,0 +1,43 @@ +/* + * EventHandler.h + * + * Created on: Jun 13, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_IEVENTHANDLER_H_ +#define SRC_IEVENTHANDLER_H_ + +#include "input/Event.h" +#include "InputDriver.h" + +#include + +namespace flippR_driver +{ +namespace input +{ + +class EventHandler +{ +public: + explicit EventHandler(std::shared_ptr input_driver) : + input_driver(std::move(input_driver)) + { + this->input_driver->register_event_handler(std::shared_ptr(this)); + } + + virtual ~EventHandler() + { + this->input_driver->unregister_event_handler(std::shared_ptr(this)); + }; + + virtual void handle(flippR_driver::input::Event &event) = 0; + +private: + const std::shared_ptr input_driver; +}; + +} +} +#endif /* SRC_IEVENTHANDLER_H_ */ diff --git a/FlippR-Driver/include/input/InputDriver.h b/FlippR-Driver/include/input/InputDriver.h new file mode 100644 index 0000000..067e462 --- /dev/null +++ b/FlippR-Driver/include/input/InputDriver.h @@ -0,0 +1,37 @@ +/* + * InputDriver.h + * + * Created on: Jun 14, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_INPUT_IINPUTDRIVER_H_ +#define SRC_INPUT_IINPUTDRIVER_H_ + +#include "Event.h" + +#include + +#include + +namespace flippR_driver +{ +namespace input +{ + +class EventHandler; + +class InputDriver { + public: + virtual ~InputDriver() = default; + + virtual void register_event_handler(std::shared_ptr handler) = 0; + + virtual void unregister_event_handler(std::shared_ptr handler) = 0; + + virtual boost::optional> get_event(std::string name) = 0; +}; + +} +} +#endif /* SRC_INPUT_IINPUTDRIVER_H_ */ diff --git a/FlippR-Driver/include/output/OutputDriver.h b/FlippR-Driver/include/output/OutputDriver.h new file mode 100644 index 0000000..3a76137 --- /dev/null +++ b/FlippR-Driver/include/output/OutputDriver.h @@ -0,0 +1,78 @@ +/* + * OutputDriver.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_IOUTPUTDRIVER_H_ +#define _SRC_OUTPUT_IOUTPUTDRIVER_H_ + +#include +#include +#include + +#include + +#include "output/DisplayController.h" + +#include "output/items/Solenoid.h" +#include "output/items/Lamp.h" +#include "output/items/Sound.h" +#include "output/items/Display.h" +#include "output/items/Flipper.h" + + +namespace flippR_driver +{ +namespace output +{ + +class OutputDriver +{ +public: + OutputDriver(std::shared_ptr display_controller, std::map> solenoids, + std::map> lamps, std::map> sounds, + std::map> flippers, std::map> displays); + + ~OutputDriver() = default; + + void activate_displays() const; + void deactivate_displays() const; + + void activate_all_lamps() const; + void deactivate_all_lamps() const; + void rotate_all_lamps() const; + + void activate_all_flipper_relays() const; + void deactivate_all_flipper_relays() const; + + void shut_down_driver() const; + + // todo driver board run for activate/deactivate? + // todo what is flipper_relay ? + std::vector> get_lamps() const; + std::vector> get_solenoids() const; + std::vector> get_sounds() const; + std::vector> get_flippers() const; + std::vector> get_displays() const; + + boost::optional> get_lamp(const std::string &name) const; + boost::optional> get_solenoid(const std::string &name) const; + boost::optional> get_sound(const std::string &name) const; + boost::optional> get_flipper(const std::string &name) const; + boost::optional> get_display(const std::string &name) const; + +private: + std::shared_ptr display_controller; + + const std::map> lamps; + const std::map> solenoids; + const std::map> sounds; + const std::map> flippers; + const std::map> displays; +}; + +} /* namespace output */ +} +#endif \ No newline at end of file diff --git a/FlippR-Driver/include/output/items/Display.h b/FlippR-Driver/include/output/items/Display.h new file mode 100644 index 0000000..db082b7 --- /dev/null +++ b/FlippR-Driver/include/output/items/Display.h @@ -0,0 +1,34 @@ +/* + * IOutputDisplay.h + * + * Created on: Nov 20, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_OUTPUT_ITEMS_DISPLAY_H_ +#define FLIPPR_DRIVER_OUTPUT_ITEMS_DISPLAY_H_ + +#include "Item.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class Display : public virtual items::Item +{ + +public: + virtual ~Display() = default; + + virtual void write_score(unsigned int score) = 0; +}; + +} +} +} + + +#endif /* SRC_OUTPUT_IOUTPUTDISPLAY_H_ */ diff --git a/FlippR-Driver/include/output/items/EightDigitDisplay.h b/FlippR-Driver/include/output/items/EightDigitDisplay.h new file mode 100644 index 0000000..74cb1b2 --- /dev/null +++ b/FlippR-Driver/include/output/items/EightDigitDisplay.h @@ -0,0 +1,30 @@ +// +// Created by rhetenor on 20.11.18. +// + +#ifndef FLIPPR_DRIVER_OUTPUT_ITEMS_EIGHTDIGITDISPLAY_H +#define FLIPPR_DRIVER_OUTPUT_ITEMS_EIGHTDIGITDISPLAY_H + +#include + +#include "output/items/Display.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class EightDigitDisplay : public virtual Display +{ +public: + virtual ~EightDigitDisplay() = default; + + virtual void write_content(std::string content) = 0; +}; + +} +} +} +#endif //FLIPPR_DRIVER_IEIGHTDIGITDISPLAY_H diff --git a/FlippR-Driver/include/output/items/Flipper.h b/FlippR-Driver/include/output/items/Flipper.h new file mode 100644 index 0000000..98e76db --- /dev/null +++ b/FlippR-Driver/include/output/items/Flipper.h @@ -0,0 +1,35 @@ +/* + * Flipper.h + * + * Created on: May 5, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _INCLUDE_FLIPPR_CODE_FLIPPER_H +#define _INCLUDE_FLIPPR_CODE_FLIPPER_H + +#include "Item.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class Flipper : public virtual Item +{ +public: + virtual ~Flipper() = default; + + virtual void activate() = 0; + virtual void deactivate() = 0; + virtual bool is_activated() = 0; +}; + +} +} +} + + +#endif //FLIPPR_CODE_FLIPPER_H diff --git a/FlippR-Driver/include/output/items/Item.h b/FlippR-Driver/include/output/items/Item.h new file mode 100644 index 0000000..7b34fe7 --- /dev/null +++ b/FlippR-Driver/include/output/items/Item.h @@ -0,0 +1,34 @@ +/* + * ICabinetItem.h + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_ICABINETITEM_H_ +#define _SRC_OUTPUT_ICABINETITEM_H_ + +#include +#include +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class Item +{ +public: + virtual ~Item() = default; + + virtual std::string get_name() const = 0; +}; + +} +} +} + +#endif diff --git a/FlippR-Driver/include/output/items/Lamp.h b/FlippR-Driver/include/output/items/Lamp.h new file mode 100644 index 0000000..5457106 --- /dev/null +++ b/FlippR-Driver/include/output/items/Lamp.h @@ -0,0 +1,37 @@ +/* + * Lamp.h + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_ILAMP_H_ +#define _SRC_OUTPUT_ILAMP_H_ + +#include "Item.h" + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class Lamp : public virtual Item +{ +public: + virtual ~Lamp() = default; + + virtual void activate() = 0; + virtual void deactivate() = 0; + virtual bool is_activated() = 0; + virtual std::chrono::milliseconds get_activation_time() const = 0; +}; + +} +} +} + +#endif \ No newline at end of file diff --git a/FlippR-Driver/include/output/items/SevenDigitDisplay.h b/FlippR-Driver/include/output/items/SevenDigitDisplay.h new file mode 100644 index 0000000..d6146b3 --- /dev/null +++ b/FlippR-Driver/include/output/items/SevenDigitDisplay.h @@ -0,0 +1,30 @@ +// +// Created by rhetenor on 20.11.18. +// + +#ifndef FLIPPR_DRIVER_ISEVENDIGITDISPLAY_H +#define FLIPPR_DRIVER_ISEVENDIGITDISPLAY_H + +#include + +#include "Display.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class SevenDigitDisplay : public virtual Display +{ +public: + virtual ~SevenDigitDisplay() = default; + + virtual void write_content(std::string & content) = 0; +}; + +} +} +} +#endif //FLIPPR_DRIVER_ISEVENDIGITDISPLAY_H diff --git a/FlippR-Driver/include/output/items/Solenoid.h b/FlippR-Driver/include/output/items/Solenoid.h new file mode 100644 index 0000000..8a98261 --- /dev/null +++ b/FlippR-Driver/include/output/items/Solenoid.h @@ -0,0 +1,33 @@ +/* + * Solenoid.h + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_ISOLENOID_H_ +#define _SRC_OUTPUT_ISOLENOID_H_ + + +#include "Item.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +// todo get name? parent calss output_item? +class Solenoid : public virtual Item +{ +public: + virtual ~Solenoid() = default; + + virtual void trigger() = 0; +}; + +} +} +} + +#endif \ No newline at end of file diff --git a/FlippR-Driver/include/output/items/Sound.h b/FlippR-Driver/include/output/items/Sound.h new file mode 100644 index 0000000..c2ddcee --- /dev/null +++ b/FlippR-Driver/include/output/items/Sound.h @@ -0,0 +1,31 @@ +/* + * Sound.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_ISOUND_H_ +#define _SRC_OUTPUT_ISOUND_H_ + +#include "Item.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class Sound : public virtual Item +{ +public: + virtual ~Sound() = default; + + virtual void play() = 0; +}; + +} +} /* namespace output */ +} +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/lib/easylogging/easylogging++.cc b/FlippR-Driver/lib/easylogging/easylogging++.cc similarity index 100% rename from FlippR-Driver/src/lib/easylogging/easylogging++.cc rename to FlippR-Driver/lib/easylogging/easylogging++.cc diff --git a/FlippR-Driver/src/lib/easylogging/easylogging++.h b/FlippR-Driver/lib/easylogging/easylogging++.h similarity index 100% rename from FlippR-Driver/src/lib/easylogging/easylogging++.h rename to FlippR-Driver/lib/easylogging/easylogging++.h diff --git a/FlippR-Driver/src/lib/json/json.hpp b/FlippR-Driver/lib/json/json.hpp similarity index 99% rename from FlippR-Driver/src/lib/json/json.hpp rename to FlippR-Driver/lib/json/json.hpp index c9ef758..13384dc 100644 --- a/FlippR-Driver/src/lib/json/json.hpp +++ b/FlippR-Driver/lib/json/json.hpp @@ -270,7 +270,7 @@ using enable_if_t = typename std::enable_if::type; template using uncvref_t = typename std::remove_cv::type>::type; -// implementation of C++14 index_sequence and affiliates +// impl of C++14 index_sequence and affiliates // source: https://stackoverflow.com/a/32223343 template struct index_sequence @@ -7369,7 +7369,7 @@ boundaries compute_boundaries(FloatType value) // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) static_assert(std::numeric_limits::is_iec559, - "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + "internal error: dtoa_short requires an IEEE-754 floating-point impl"); constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); diff --git a/FlippR-Driver/networking/CMakeLists.txt b/FlippR-Driver/networking/CMakeLists.txt new file mode 100644 index 0000000..6e1fcc0 --- /dev/null +++ b/FlippR-Driver/networking/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.6.2) +project(flippR_driver_networking) + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/bin/networking) +set(SOURCES + input/InputSocketHandler.cpp + output/OutputRequestHandler.cpp + output/OutputRequestHandlerFactory.cpp + FlippRServer.cpp + input/InputSocketHandlerFactory.cpp + ) + +add_executable(${PROJECT_NAME} ${SOURCES}) + +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) + +target_link_libraries(${PROJECT_NAME} PRIVATE FlippR-Driver) + +####################### POCO ############################## +find_package(Poco REQUIRED COMPONENTS Foundation Net JSON Util) + +if(NOT Poco_FOUND) + message(FATAL_ERROR, "Could not find libPoco") +endif() + +target_link_libraries(${PROJECT_NAME} PUBLIC Poco::Foundation Poco::Net Poco::JSON Poco::Util) diff --git a/FlippR-Driver/networking/FlippRServer.cpp b/FlippR-Driver/networking/FlippRServer.cpp new file mode 100644 index 0000000..6f3880d --- /dev/null +++ b/FlippR-Driver/networking/FlippRServer.cpp @@ -0,0 +1,298 @@ +// +// Created by rhetenor on 5/21/19. +// + +#include "FlippRServer.h" +#include "output/OutputRequestHandlerFactory.h" +#include "input/InputSocketHandlerFactory.h" +#include "DriverFactory.h" +#include "utility/Colors.h" +#include "utility/LoggerFactory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +int main(int argc, char** argv) +{ + std::cout << FGRN("Starting FlippR-Server ... ") << std::endl; + + flippR_driver::networking::FlippRServer app; + return app.run(argc, argv); +} + +namespace flippR_driver +{ +namespace networking +{ +using namespace Poco::Net; +using namespace Poco::Util; +using namespace Poco::JSON; +using namespace Poco; + +namespace fs = boost::filesystem; + +FlippRServer::FlippRServer() : + help_requested(false), + input_port(9980), + output_port(9981) +{} + +void FlippRServer::parse_server_config_file() +{ + std::ifstream config; + + Parser parser; + Object::Ptr json; + + try + { + config.open(this->server_config); + } + catch(const std::exception e) + { + logger().error(FCYN("server_config.json not specified!")); + exit(Application::EXIT_USAGE); + } + + try + { + auto parse = parser.parse(config); + json = parse.extract(); + } + catch(const std::exception e) + { + logger().error(e.what()); + exit(Application::EXIT_IOERR); + } + + logger().information(FCYN("Parsing server_config.json...")); + + Object::NameList keys = json->getNames(); + std::sort(keys.begin(), keys.end()); + + if(!std::includes(keys.begin(), keys.end(), REQUIRED_CONFIG_KEYS.begin(), REQUIRED_CONFIG_KEYS.end())) + { + std::string config_keys; + config_keys = std::accumulate(REQUIRED_CONFIG_KEYS.begin(), REQUIRED_CONFIG_KEYS.end(), config_keys); + logger().error("Need all of the following keys to be specified in server_config json" + config_keys); + Application::EXIT_USAGE; + } + + this->configs = *json; + + config.close(); +} + +void FlippRServer::uninitialize() +{ + this->output_driver->shut_down_driver(); + this->output_server->stop(); + + ServerApplication::uninitialize(); + + Poco::File socket_file(this->output_socket_file_path); + if (socket_file.exists()) + socket_file.remove(); + + Poco::File input_socket_file(this->input_socket_file_path); + if (input_socket_file.exists()) + input_socket_file.remove(); +} + +/** + * Initially called before main. + */ +void FlippRServer::initialize(Application &self) +{ + this->parse_server_config_file(); + //Todo May restructure with subsystems + //make this one application and subsystems ServerApplications + + this->initialize_output_driver(); + //this->initialize_input_driver(); + + this->output_server = std::unique_ptr(this->build_output_server()); + this->output_server->start(); + + this->input_server = std::unique_ptr(this->build_input_server()); + //this->input_server->start(); + logger().warning(FRED("Input server not started!")); + + ServerApplication::initialize(self); +} + +void FlippRServer::initialize_output_driver() +{ + std::string lamp_config_path; + std::string solenoid_config_path; + std::string sound_config_path; + std::string display_config_path; + + try + { + lamp_config_path = this->configs["lamp-config"].toString(); + solenoid_config_path = this->configs["solenoid-config"].toString(); + sound_config_path = this->configs["sound-config"].toString(); + display_config_path = this->configs["display-config"].toString(); + } + catch(const std::exception& e) + { + logger().error(e.what()); + exit(EXIT_FAILURE); + } + + this->output_driver = flippR_driver::get_OutputDriver(solenoid_config_path, + lamp_config_path, + sound_config_path, + display_config_path); +} + +void FlippRServer::initialize_input_driver() +{ + std::ifstream input_config_stream; + std::ifstream matrix_config_stream; + + try + { + input_config_stream.open(this->configs["input-config"].toString()); + matrix_config_stream.open(this->configs["matrix-config"].toString()); + } + catch(const std::exception& e) + { + logger().error(e.what()); + exit(EXIT_FAILURE); + } + + this->input_driver = flippR_driver::get_InputDriver(input_config_stream, matrix_config_stream); +} + +int FlippRServer::main(const std::vector& args) +{ + if(!help_requested) + { + logger().information(FGRN("Server running!")); + waitForTerminationRequest(); + } + return Application::EXIT_OK; + +} + +HTTPServer* FlippRServer::build_output_server() +{ + unsigned short port = (unsigned short) config().getInt("FlippRServer.port", this->output_port); + + this->output_socket_file_path = this->get_runtime_dir() + OUTPUT_SOCKET_NAME; + Poco::File socket_file(output_socket_file_path); + if (socket_file.exists()) + socket_file.remove(); + + SocketAddress address(SocketAddress::UNIX_LOCAL, socket_file.path()); + ServerSocket server_socket(address); + + return new HTTPServer(new OutputRequestHandlerFactory(this->output_driver), server_socket, new HTTPServerParams); +} + +TCPServer* FlippRServer::build_input_server() +{ + unsigned short port = (unsigned short) config().getInt("FlippRServer.port", this->input_port); + + this->input_socket_file_path = this->get_runtime_dir() + INPUT_SOCKET_NAME; + Poco::File socket_file(input_socket_file_path); + if (socket_file.exists()) + { + socket_file.remove(); + logger().information(FRED("Seems that server is already running. Make sure that only one instance of server is running.")); + } + + + SocketAddress address(SocketAddress::UNIX_LOCAL, socket_file.path()); + ServerSocket server_socket(address); + + return new TCPServer(new input::InputSocketHandlerFactory(this->input_driver), server_socket); +} + +void FlippRServer::defineOptions(OptionSet& options) +{ + ServerApplication::defineOptions(options); + + options.addOption( + Option("help", "h", "display this help") + .required(false) + .repeatable(false) + .callback(OptionCallback( + this, &FlippRServer::handle_help))); + + options.addOption(Option("input-port", "i", "Define the port for the TCP-Input-Server, which represents the flipper inputs. Default 9980") + .required(false) + .repeatable(false) + .callback(OptionCallback(this, &FlippRServer::handle_config_file)) + .argument("input-port", true)); + + options.addOption(Option("output-port", "o", "Define the port for the HTTP-Output-Server, which represents the flipper outputs. Default 9981") + .required(false) + .repeatable(false) + .callback(OptionCallback(this, &FlippRServer::handle_config_file)) + .argument("output-port", true)); + + options.addOption(Option("server-config", "s", "Specify where the server-config file with paths to the other configs is located. Only needed when not in this folder.") + .required(true) + .repeatable(false) + .callback(OptionCallback(this, &FlippRServer::handle_config_file)) + .argument("server-config", true)); + + options.addOption(Option("debug", "d", "Switch debug messages on.") + .required(false) + .repeatable(true) + .callback(OptionCallback(this, &FlippRServer::create_debug_logger))); +} + +void FlippRServer::handle_config_file(const std::string &name, const std::string &value) +{ + if(name == "input-port") + this->input_port = std::stoi(value); + else if(name == "output-port") + this->output_port = std::stoi(value); + else if(name == "server-config") + this->server_config = value; + else + { + logger().information("Configuration \"" + name + "\" is not known."); + return; + } + logger().information(KMAG "Set " + name + " to " + value + RST); +} + +void FlippRServer::handle_help(const std::string& name, const std::string& value) +{ + Poco::Util::HelpFormatter helpFormatter(options()); + helpFormatter.setCommand(commandName()); + helpFormatter.setUsage("OPTIONS"); + helpFormatter.setHeader( + "The FlippR-Server, one must specify a json with all needed config files."); + helpFormatter.format(std::cout); + stopOptionsProcessing(); + help_requested = true; +} + +std::string FlippRServer::get_runtime_dir() +{ + return std::getenv("XDG_RUNTIME_DIR") ? std::string(std::getenv("XDG_RUNTIME_DIR")) + "/" : DEFAULT_RUNTIME_DIR; +} + +void FlippRServer::create_debug_logger(const std::string &name, const std::string &value) +{ + utility::LoggerFactory::ActivateDebugLog(); + logger().information(FCYN("Activated debug logging.")); +} + +} +} diff --git a/FlippR-Driver/networking/FlippRServer.h b/FlippR-Driver/networking/FlippRServer.h new file mode 100644 index 0000000..78f0361 --- /dev/null +++ b/FlippR-Driver/networking/FlippRServer.h @@ -0,0 +1,74 @@ +// +// Created by rhetenor on 5/21/19. +// + +#ifndef FLIPPR_DRIVER_FLIPPRSERVER_H +#define FLIPPR_DRIVER_FLIPPRSERVER_H + +#include "output/OutputDriver.h" +#include "input/InputDriver.h" + +#include +#include +#include +#include + +namespace flippR_driver +{ +namespace networking +{ + +class FlippRServer : public Poco::Util::ServerApplication +{ +public: + FlippRServer(); + + int main(const std::vector& args); + + void initialize(Poco::Util::Application& self); + void uninitialize(); + + void defineOptions(Poco::Util::OptionSet& options); + void handle_help(const std::string &name, const std::string &port); + void handle_config_file(const std::string &name, const std::string &value); + +private: + void initialize_output_driver(); + void initialize_input_driver(); + + void parse_server_config_file(); + + std::string get_runtime_dir(); + Poco::Net::HTTPServer* build_output_server(); + Poco::Net::TCPServer* build_input_server(); + + void create_debug_logger(const std::string &name, const std::string &value); + +private: + const char * DEFAULT_RUNTIME_DIR = "/tmp/"; + const char * INPUT_SOCKET_NAME = "S.flippR_driver.in"; + const char * OUTPUT_SOCKET_NAME = "S.flippR_driver.out"; + const std::vector REQUIRED_CONFIG_KEYS = {"display-config", "input-config", "lamp-config", + "matrix-config", "solenoid-config", "sound-config"}; + std::string output_socket_file_path, input_socket_file_path; + int input_port; + int output_port; + + bool help_requested; + + Poco::DynamicStruct configs; + + std::string server_config; + + std::shared_ptr input_driver; + std::shared_ptr output_driver; + + std::unique_ptr output_server; + std::unique_ptr input_server; +}; + +}; +} + + +#endif //FLIPPR_DRIVER_FLIPPRSERVER_H diff --git a/FlippR-Driver/networking/input/InputSocketHandler.cpp b/FlippR-Driver/networking/input/InputSocketHandler.cpp new file mode 100644 index 0000000..baa69ee --- /dev/null +++ b/FlippR-Driver/networking/input/InputSocketHandler.cpp @@ -0,0 +1,58 @@ +/* + * SocketConnection.cpp + * + * Created on: Jun 13, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "InputSocketHandler.h" + + +using Poco::Net::StreamSocket; +using Poco::Net::TCPServerConnection; +using flippR_driver::input::InputDriver; +using flippR_driver::input::EventHandler; +using flippR_driver::input::Event; + +namespace flippR_driver +{ +namespace networking +{ +namespace input +{ + +InputSocketHandler::InputSocketHandler(StreamSocket streamSocket, std::shared_ptr inputDriver) : + TCPServerConnection(streamSocket), + EventHandler(inputDriver) +{ +} + +void InputSocketHandler::run() +{ + //todo should ne closed when connection is closed + // while(this->socket().poll(100, Poco::Net::Socket::SelectMode::SELECT_ERROR)) + while(true) + { + Event event = this->queue.pop(); + + if(event.name == "END") + { + return; + } + + std::string str = event.getJsonString() + std::string(1, 0x02 ) ; + + + this->socket().sendBytes(str.c_str(), str.size()); + } +} + +void InputSocketHandler::handle(Event &event) +{ + this->queue.push(event); +} + + +} +} +} diff --git a/FlippR-Driver/networking/input/InputSocketHandler.h b/FlippR-Driver/networking/input/InputSocketHandler.h new file mode 100644 index 0000000..3dcbe42 --- /dev/null +++ b/FlippR-Driver/networking/input/InputSocketHandler.h @@ -0,0 +1,42 @@ +/* + * SocketConnection.h + * + * Created on: Jun 13, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_CODE_INPUTSOCKETCONNECTION_H +#define FLIPPR_CODE_INPUTSOCKETCONNECTION_H + + +#include + +#include "input/InputDriver.h" +#include "input/EventHandler.h" +#include "input/Event.h" +#include "utility/BlockingQueue.hpp" + +namespace flippR_driver +{ +namespace networking +{ +namespace input +{ + +class InputSocketHandler : public Poco::Net::TCPServerConnection, flippR_driver::input::EventHandler +{ +public: + InputSocketHandler(Poco::Net::StreamSocket streamSocket, std::shared_ptr input_driver); + + void run() override; + void handle(flippR_driver::input::Event &event) override; + +private: + utility::BlockingQueue queue; +}; + +} +} +} + +#endif //FLIPPR_CODE_INPUTSOCKETCONNECTION_H diff --git a/FlippR-Driver/networking/input/InputSocketHandlerFactory.cpp b/FlippR-Driver/networking/input/InputSocketHandlerFactory.cpp new file mode 100644 index 0000000..cadede1 --- /dev/null +++ b/FlippR-Driver/networking/input/InputSocketHandlerFactory.cpp @@ -0,0 +1,31 @@ +// +// Created by johannes on 15.06.19. +// + +#include "InputSocketHandlerFactory.h" + +#include "InputSocketHandler.h" + +namespace flippR_driver +{ +namespace networking +{ +namespace input +{ +using namespace Poco::Net; + +InputSocketHandlerFactory::InputSocketHandlerFactory(std::shared_ptr inputDriver) : + input_driver(inputDriver) +{ + +} + +TCPServerConnection *InputSocketHandlerFactory::createConnection(const Poco::Net::StreamSocket &socket) +{ + return new InputSocketHandler(socket, this->input_driver); +} + +} +} +} + diff --git a/FlippR-Driver/networking/input/InputSocketHandlerFactory.h b/FlippR-Driver/networking/input/InputSocketHandlerFactory.h new file mode 100644 index 0000000..c45beed --- /dev/null +++ b/FlippR-Driver/networking/input/InputSocketHandlerFactory.h @@ -0,0 +1,33 @@ +// +// Created by johannes on 15.06.19. +// + +#ifndef FLIPPR_DRIVER_INPUTSOCKETHANDLERFACTORY_H +#define FLIPPR_DRIVER_INPUTSOCKETHANDLERFACTORY_H + +#include +#include + +namespace flippR_driver +{ +namespace networking +{ +namespace input +{ + +class InputSocketHandlerFactory : public Poco::Net::TCPServerConnectionFactory +{ +public: + explicit InputSocketHandlerFactory(std::shared_ptr inputDriver); + + Poco::Net::TCPServerConnection* createConnection(const Poco::Net::StreamSocket &socket) override; + +private: + std::shared_ptr input_driver; +}; + +} +} +} + +#endif //FLIPPR_DRIVER_INPUTSOCKETHANDLERFACTORY_H diff --git a/FlippR-Driver/networking/main.cpp b/FlippR-Driver/networking/main.cpp new file mode 100644 index 0000000..d8a9e7b --- /dev/null +++ b/FlippR-Driver/networking/main.cpp @@ -0,0 +1,9 @@ +// +// Created by rhetenor on 5/21/19. +// + +int main(int argc, const char* argv[]) +{ + + +} diff --git a/FlippR-Driver/networking/output/OutputHTTPServer.cpp b/FlippR-Driver/networking/output/OutputHTTPServer.cpp new file mode 100644 index 0000000..207102b --- /dev/null +++ b/FlippR-Driver/networking/output/OutputHTTPServer.cpp @@ -0,0 +1,21 @@ +// +// Created by rhetenor on 4/15/19. +// + +#include + +#include "OutputHTTPServer.h" +#include "OutputRequestHandlerFactory.h" + +namespace flippR_driver +{ +namespace networking +{ +using namespace Poco::Net; + +OutputHTTPServer::OutputHTTPServer(std::shared_ptr output_driver, Socket &socket) : + HTTPServer(new OutputRequestHandlerFactory(output_driver), socket, new HTTPServerParams()) +{} + +} +} diff --git a/FlippR-Driver/networking/output/OutputHTTPServer.h b/FlippR-Driver/networking/output/OutputHTTPServer.h new file mode 100644 index 0000000..513e6e5 --- /dev/null +++ b/FlippR-Driver/networking/output/OutputHTTPServer.h @@ -0,0 +1,28 @@ +// +// Created by rhetenor on 4/15/19. +// + +#ifndef FLIPPR_CODE_OUTPUTHTTPSERVER_H +#define FLIPPR_CODE_OUTPUTHTTPSERVER_H + +#include +#include + +#include "output/OutputDriver.h" + +namespace flippR_driver +{ +namespace networking +{ + +class OutputHTTPServer : public Poco::Net::HTTPServer +{ +public: + explicit OutputHTTPServer(std::shared_ptr output_driver, Poco::Net::Socket &socket); + +}; + +} +} + +#endif //FLIPPR_CODE_OUTPUTHTTPSERVER_H diff --git a/FlippR-Driver/networking/output/OutputRequestHandler.cpp b/FlippR-Driver/networking/output/OutputRequestHandler.cpp new file mode 100644 index 0000000..537210d --- /dev/null +++ b/FlippR-Driver/networking/output/OutputRequestHandler.cpp @@ -0,0 +1,319 @@ +// +// Created by rhetenor on 3/6/19. +// + + +#include +#include +#include + +#include + +#include "OutputRequestHandler.h" + +namespace flippR_driver +{ +namespace networking +{ + +using namespace Poco; +using namespace Poco::Net; + +OutputRequestHandler::OutputRequestHandler(std::shared_ptr output_driver) : + output_driver(output_driver) + {} + + /** + * Handles a REST request with a URI form of: + * + * address/{item_type}/[item_name]/[action]/[score] + * + * Where + * {item_type} is either solenoids, lamps, sounds, displays, or one of the two special events: activate and deactivate + * [item_name] is the string name of an item (optional if you want to get the list of all available items) + * [action] is the particular action for the item: + * Solenoids: trigger + * lamps: activate, deactivate, status + * sounds: play + * displays: write_score (for this is the additional optional attribute [score] + * + * @param request + * @param response + */ +void OutputRequestHandler::handleRequest(HTTPServerRequest &request, + HTTPServerResponse &response) +{ + auto path_segments = getPathSegments(URI(request.getURI())); + + // fill up vector + for(int i = path_segments.size(); i < 4; i++) + { + path_segments.emplace_back(""); + } + + std::string item_type = path_segments.at(0); + std::string item_name = path_segments.at(1); + std::string action = path_segments.at(2); + std::string score = path_segments.at(3); + + if(item_type == "deactivate") + { + this->output_driver->deactivate_displays(); + this->output_driver->deactivate_all_lamps(); + this->output_driver->deactivate_all_flipper_relays(); + return; + } + + if(item_type == "activate") + { + this->output_driver->activate_displays(); + this->output_driver->activate_all_flipper_relays(); + return; + } + + response.setContentType("text/json"); + + try + { + boost::optional json_response = parseRequest(item_type, item_name, action, score); + + if(json_response) + { + response.setStatus(HTTPServerResponse::HTTP_OK); + std::ostream& ostr = response.send(); + json_response->stringify(ostr); + } + } + catch(const NotFoundException &e) + { + response.setStatusAndReason(HTTPServerResponse::HTTP_NOT_FOUND, e.displayText()); + } + catch(const Poco::InvalidArgumentException &e) + { + response.setStatusAndReason(HTTPServerResponse::HTTP_BAD_REQUEST, e.displayText()); + } +} + +boost::optional OutputRequestHandler::parseRequest(const std::string& item_type, const std::string& item_name, const std::string& action, const std::string& score) +{ + + std::string log_msg = "Got request from client to " + action + " " + item_type + " with name " + item_name + " (" + score + ")"; + + Poco::Logger::root().information(log_msg); + + if(item_type == "solenoids") + { + return parseSolenoid(item_name, action); + } + else if(item_type == "lamps") + { + return parseLamp(item_name, action); + } + else if(item_type == "sounds") + { + return parseSound(item_name, action); + } + else if(item_type == "displays") + { + return parseDisplay(item_name, action, score); + } + else if(item_type == "flippers") + { + return parseFlipper(item_name, action); + } + else + { + throw new Poco::NotFoundException("No item type called " + item_type); + } +} + +boost::optional OutputRequestHandler::parseSolenoid(const std::string& item_name, const std::string& action) +{ + Poco::JSON::Object response; + if(item_name == "") + { + response.set("solenoids", getItemArray(this->output_driver->get_solenoids()) ); + return response; + } + + auto opt_solenoid = this->output_driver->get_solenoid(item_name); + + if(!opt_solenoid) + { + throw new Poco::NotFoundException("No solenoid with name \"" + item_name + "\"!"); + } + + auto solenoid = opt_solenoid->get(); + + if(action == "trigger") + { + solenoid->trigger(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on solenoids!"); + } + + return response; +} + +boost::optional OutputRequestHandler::parseLamp(const std::string& item_name, const std::string& action) +{ + Poco::JSON::Object response; + if(item_name == "") + { + response.set("lamps", getItemArray(this->output_driver->get_lamps()) ); + return response; + } + + auto opt_lamp = this->output_driver->get_lamp(item_name); + + if(!opt_lamp) + { + throw new Poco::NotFoundException("No lamp with name \"" + item_name + "\"!"); + } + + auto lamp = opt_lamp->get(); + + if(action == "activate") + { + lamp->activate(); + } + else if(action == "deactivate") + { + lamp->deactivate(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on lamps!"); + } + + return response; +} + +boost::optional OutputRequestHandler::parseSound(const std::string& item_name, const std::string& action) +{ + Poco::JSON::Object response; + if(item_name == "") + { + response.set("sounds", getItemArray(this->output_driver->get_sounds()) ); + return response; + } + + auto opt_sound = this->output_driver->get_sound(item_name); + + if(!opt_sound) + { + throw new Poco::NotFoundException("No sound with name \"" + item_name + "\"!"); + } + + auto sound = opt_sound->get(); + + if(action == "play") + { + sound->play(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on sounds!"); + } + + return response; +} + +boost::optional OutputRequestHandler::parseDisplay(const std::string& display_name, const std::string& action, const std::string& score) +{ + Poco::JSON::Object response; + if(display_name == "") + { + response.set("displays", getItemArray(this->output_driver->get_displays())); + return response; + } + + auto opt_display = this->output_driver->get_display(display_name); + + if(!opt_display) + { + throw new Poco::NotFoundException("No display with name \"" + display_name + "\"!"); + } + + auto display = opt_display->get(); + + + if(action == "write_score") + { + try + { + unsigned int numerical_score = std::stoi(score); + display->write_score(numerical_score); + } + catch(std::invalid_argument &e) + { + throw new Poco::InvalidArgumentException("Could not convert " + score + " to a number!\n" + e.what()); + } + } + else + { + throw new Poco::NotFoundException("No Action with name \"" + action + "\" on sounds!"); + } + + return response; +} + +boost::optional OutputRequestHandler::parseFlipper(const std::string& item_name, const std::string& action) +{ + Poco::JSON::Object response; + if(item_name == "") + { + response.set("flippers", getItemArray(this->output_driver->get_flippers()) ); + return response; + } + + auto opt_flipper = this->output_driver->get_flipper(item_name); + + if(!opt_flipper) + { + throw new Poco::NotFoundException("No flipper with name \"" + item_name + "\"!"); + } + + auto flipper = opt_flipper->get(); + + if(action == "activate") + { + flipper->activate(); + } + else if(action == "deactivate") + { + flipper->deactivate(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on flippers!"); + } + + return response; +} + +std::vector OutputRequestHandler::getPathSegments(Poco::URI uri) +{ + std::vector path_segments; + uri.getPathSegments(path_segments); + return path_segments; +} + +template +Poco::JSON::Array getItemArray(const std::vector> & items) +{ + Poco::JSON::Array array; + for ( auto & item : items ) + { + Poco::JSON::Object var; + var.set("name", item->get_name()); + array.add(var); + } + return array; +} + +} +} + diff --git a/FlippR-Driver/networking/output/OutputRequestHandler.cpp.autosave b/FlippR-Driver/networking/output/OutputRequestHandler.cpp.autosave new file mode 100644 index 0000000..06bd662 --- /dev/null +++ b/FlippR-Driver/networking/output/OutputRequestHandler.cpp.autosave @@ -0,0 +1,261 @@ +// +// Created by rhetenor on 3/6/19. +// + + +#include +#include +#include + +#include + +#include "OutputRequestHandler.h" + +namespace flippR_driver +{ +namespace networking +{ + +using namespace Poco; +using namespace Poco::Net; + +OutputRequestHandler::OutputRequestHandler(std::shared_ptr output_driver) : + output_driver(output_driver) + {} + + /** + * Handles a REST request with a URI form of: + * + * address/{item_type}/[item_name]/[action]/[score] + * + * Where + * {item_type} is either solenoids, lamps, sounds, displays, or one of the two special events: activate and deactivate + * [item_name] is the string name of an item (optional if you want to get the list of all available items) + * [action] is the particular action for the item: + * solenoids: trigger + * lamps: activate, deactivate, status + * sounds: play + * displays: write_score (for this is the additional optional attribute [score] + * + * @param request + * @param response + */ +void OutputRequestHandler::handleRequest(HTTPServerRequest &request, + HTTPServerResponse &response) +{ + auto path_segments = getPathSegments(URI(request.getURI())); + + // fill up vector + for(int i = path_segments.size(); i < 4; i++) + { + path_segments.emplace_back(""); + } + + std::string item_type = path_segments.at(0); + std::string item_name = path_segments.at(1); + std::string action = path_segments.at(2); + std::string score = path_segments.at(3); + + if(item_type == "deactivate") + { + this->output_driver->deactivate_displays(); + this->output_driver->deactivate_all_lamps(); + return; + } + + if(item_type == "activate") + { + this->output_driver->activate_displays(); + return; + } + + response.setContentType("text/json"); + response.setStatus(HTTPServerResponse::HTTP_OK); + + try + { + boost::optional json_response = parseRequest(item_type, item_name, action, score); + if(json_response) + { + std::ostream& ostr = response.send(); + json_response->stringify(ostr); + } + } + catch(const NotFoundException &e) + { + response.setStatusAndReason(HTTPServerResponse::HTTP_NOT_FOUND, e.displayText()); + } + catch(const Poco::InvalidArgumentException &e) + { + response.setStatusAndReason(HTTPServerResponse::HTTP_BAD_REQUEST, e.displayText()); + } +} + +boost::optional OutputRequestHandler::parseRequest(const std::string& item_type, const std::string& item_name, const std::string& action, const std::string& score) +{ + if(item_type == "solenoids") + { + return parseSolenoid(item_name, action); + } + else if(item_type == "lamps") + { + return parseLamp(item_name, action); + } + else if(item_type == "sounds") + { + return parseSound(item_name, action); + } + else if(item_type == "displays") + { + return parseDisplay(item_name, action, score); + } + else + { + throw new Poco::NotFoundException("No item type called " + item_type); + } +} + +boost::optional OutputRequestHandler::parseSolenoid(const std::string& item_name, const std::string& action) +{ + if(item_name == "") + { + Poco::JSON::Object response; + response.set("solenoids", this->output_driver->get_solenoids()); + return response; + } + + auto opt_solenoid = this->output_driver->get_solenoid(item_name); + + if(!opt_solenoid) + { + throw new Poco::NotFoundException("No solenoid with name \"" + item_name + "\"!"); + } + + auto solenoid = opt_solenoid->get(); + + if(action == "trigger") + { + solenoid->trigger(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on solenoids!"); + } + + return {}; +} + +boost::optional OutputRequestHandler::parseLamp(const std::string& item_name, const std::string& action) +{ + if(item_name == "") + { + Poco::JSON::Object response; + response.set("lamps", this->output_driver->get_lamps()); + return response; + } + + auto opt_lamp = this->output_driver->get_lamp(item_name); + + if(!opt_lamp) + { + throw new Poco::NotFoundException("No lamp with name \"" + item_name + "\"!"); + } + + auto lamp = opt_lamp->get(); + + if(action == "activate") + { + lamp->activate(); + } + else if(action == "deactivate") + { + lamp->deactivate(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on lamps!"); + } + + return {}; +} + +boost::optional OutputRequestHandler::parseSound(const std::string& item_name, const std::string& action) +{ + if(item_name == "") + { + Poco::JSON::Object response; + response.set("sounds", this->output_driver->get_sounds()); + return response; + } + + auto opt_sound = this->output_driver->get_sound(item_name); + + if(!opt_sound) + { + throw new Poco::NotFoundException("No sound with name \"" + item_name + "\"!"); + } + + auto sound = opt_sound->get(); + + if(action == "play") + { + sound->play(); + } + else + { + throw new Poco::NotFoundException("No action with name \"" + action + "\" on sounds!"); + } + + return {}; +} + +boost::optional OutputRequestHandler::parseDisplay(const std::string& item_name, const std::string& action, const std::string& score) +{ + if(item_name == "") + { + Poco::JSON::Object response; + response.set("displays", this->output_driver->get_displays()); + return response; + } + + uint8_t display_number = std::stoi(item_name); + auto opt_display = this->output_driver->get_display(display_number); + + if(!opt_display) + { + throw new Poco::NotFoundException("No display with number \"" + item_name + "\"!"); + } + + auto display = opt_display->get(); + + + if(action == "write_score") + { + try + { + unsigned int numerical_score = std::stoi(score); + display->write_score(numerical_score); + } + catch(std::invalid_argument &e) + { + throw new Poco::InvalidArgumentException("Could not convert " + score + " to a number!\n" + e.what()); + } + } + else + { + throw new Poco::NotFoundException("No Action with name \"" + action + "\" on sounds!"); + } + + return {}; +} + +std::vector OutputRequestHandler::getPathSegments(Poco::URI uri) +{ + std::vector path_segments; + uri.getPathSegments(path_segments); + return path_segments; +} + +} +} + diff --git a/FlippR-Driver/networking/output/OutputRequestHandler.h b/FlippR-Driver/networking/output/OutputRequestHandler.h new file mode 100644 index 0000000..e413d0a --- /dev/null +++ b/FlippR-Driver/networking/output/OutputRequestHandler.h @@ -0,0 +1,53 @@ +// +// Created by rhetenor on 3/6/19. +// + +#ifndef FLIPPR_CODE_OUTPUTREQUESTHANDLER_H +#define FLIPPR_CODE_OUTPUTREQUESTHANDLER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "output/OutputDriver.h" + +namespace flippR_driver +{ +namespace networking +{ + +class OutputRequestHandler : public Poco::Net::HTTPRequestHandler +{ +public: + OutputRequestHandler(std::shared_ptr output_driver); + + void handleRequest(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response) override; + +private: + boost::optional parseRequest(const std::string& item_type, const std::string& item_name, const std::string& action, const std::string& score = 0); + + boost::optional parseSolenoid(const std::string& item_name, const std::string& action); + boost::optional parseLamp(const std::string& item_name, const std::string& action); + boost::optional parseSound(const std::string& item_name, const std::string& action); + boost::optional parseDisplay(const std::string& display_name, const std::string& action, const std::string& score); + boost::optional parseFlipper(const std::string& item_name, const std::string& action); + + std::vector getPathSegments(Poco::URI uri); + +private: + std::shared_ptr output_driver; + +}; + +template +Poco::JSON::Array getItemArray(const std::vector> & items); + +} +} + + +#endif //FLIPPR_CODE_OUTPUTREQUESTHANDLER_H diff --git a/FlippR-Driver/networking/output/OutputRequestHandlerFactory.cpp b/FlippR-Driver/networking/output/OutputRequestHandlerFactory.cpp new file mode 100644 index 0000000..4192b31 --- /dev/null +++ b/FlippR-Driver/networking/output/OutputRequestHandlerFactory.cpp @@ -0,0 +1,24 @@ +// +// Created by rhetenor on 4/15/19. +// + +#include "OutputRequestHandlerFactory.h" +#include "OutputRequestHandler.h" + +namespace flippR_driver +{ +namespace networking +{ +using namespace Poco::Net; + +OutputRequestHandlerFactory::OutputRequestHandlerFactory(std::shared_ptr output_driver) : + output_driver(output_driver) +{} + +HTTPRequestHandler *OutputRequestHandlerFactory::createRequestHandler(const HTTPServerRequest &request) +{ + return new OutputRequestHandler(this->output_driver); +} + +} +} diff --git a/FlippR-Driver/networking/output/OutputRequestHandlerFactory.h b/FlippR-Driver/networking/output/OutputRequestHandlerFactory.h new file mode 100644 index 0000000..dee1a17 --- /dev/null +++ b/FlippR-Driver/networking/output/OutputRequestHandlerFactory.h @@ -0,0 +1,31 @@ +// +// Created by rhetenor on 4/15/19. +// + +#ifndef FLIPPR_CODE_OUTPUTREQUESTHANDLERFACTORY_H +#define FLIPPR_CODE_OUTPUTREQUESTHANDLERFACTORY_H + +#include +#include + +#include "output/OutputDriver.h" + +namespace flippR_driver +{ +namespace networking +{ + +class OutputRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory +{ +public: + explicit OutputRequestHandlerFactory(std::shared_ptr output_driver); + Poco::Net::HTTPRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request) override; + +private: + std::shared_ptr output_driver; +}; + +} +} + +#endif //FLIPPR_CODE_OUTPUTREQUESTHANDLERFACTORY_H diff --git a/FlippR-Driver/src/.directory b/FlippR-Driver/src/.directory new file mode 100644 index 0000000..0aa6c94 --- /dev/null +++ b/FlippR-Driver/src/.directory @@ -0,0 +1,6 @@ +[Dolphin] +Timestamp=2019,5,6,20,16,26 +Version=4 + +[Settings] +HiddenFilesShown=true diff --git a/FlippR-Driver/src/CMakeLists.txt b/FlippR-Driver/src/CMakeLists.txt deleted file mode 100644 index a856a3d..0000000 --- a/FlippR-Driver/src/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -project(flippr-driver) - -subdirs(bin input lib tests utilities) diff --git a/FlippR-Driver/src/DriverFactory.cpp b/FlippR-Driver/src/DriverFactory.cpp new file mode 100644 index 0000000..add9479 --- /dev/null +++ b/FlippR-Driver/src/DriverFactory.cpp @@ -0,0 +1,26 @@ +// +// Created by rhetenor on 13.09.18. +// + +#include "DriverFactory.h" + +#include "utility/LoggerFactory.h" + +#include "input/InputDriverFactory.h" +#include "output/OutputDriverFactory.h" + +namespace flippR_driver +{ + std::shared_ptr get_InputDriver(std::istream& input_config_stream, std::istream& matrix_config_stream) + { + return input::InputDriverFactory::get_InputDriver(input_config_stream, matrix_config_stream); + } + + std::shared_ptr get_OutputDriver(std::string & lamp_config_path, + std::string & solenoid_config_path, + std::string & sound_config_path, + std::string & display_config_path) + { + return output::OutputDriverFactory::get_OutputDriver(lamp_config_path, solenoid_config_path, sound_config_path, display_config_path); + } +} diff --git a/FlippR-Driver/src/PinController.cpp b/FlippR-Driver/src/PinController.cpp new file mode 100644 index 0000000..2f5fc67 --- /dev/null +++ b/FlippR-Driver/src/PinController.cpp @@ -0,0 +1,72 @@ +/* + * PinController.cpp + * + * Created on: Jun 15, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "PinController.h" +#include "utility/config.h" +#include "utility/LoggerFactory.h" + +#ifndef NO_WIRING_PI +#include +#include +#else +#warning "Include testing wiringPi library" +#include "utility/wiringPiTesting.hpp" +#endif + +namespace flippR_driver +{ + +std::once_flag PinController::GPIO_LIB_INITIALIZED; + +PinController::PinController() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created PinController"; + std::call_once(GPIO_LIB_INITIALIZED, wiringPiSetup); +} + +void PinController::initialize_input_pin(uint8_t address) +{ + pinMode(address, INPUT); +} + +void PinController::initialize_output_pin(const uint8_t address) +{ + pinMode(address, OUTPUT); +} + +void PinController::write_pin(uint8_t address, bool value) +{ + digitalWrite(address, value); +} + +bool PinController::read_pin(uint8_t address) +{ + return PULLDOWN == digitalRead(address); +} + +void PinController::initialize_port_expander(const uint8_t i2c_address, const uint8_t pin_base) +{ + auto initialized_port_extender = this->initialized_port_extenders.insert(std::pair(i2c_address, pin_base)); + if(not initialized_port_extender.second) + { + if(initialized_port_extender.first->second != pin_base) + { + char hex_string[4]; + sprintf(hex_string, "%X", i2c_address); + CLOG(WARNING, OUTPUT_LOGGER) << "Port extender with address 0x" << hex_string + << " is already initialized with pin base " << int(pin_base) << ". Check config files!"; + } + return; + } + + mcp23017Setup(pin_base, i2c_address); + char hex_string[4]; + sprintf(hex_string, "%X", i2c_address); + CLOG(INFO, OUTPUT_LOGGER) << "MCP23017 initialized with i2c-address 0x" << hex_string << " and pin-base " << int(pin_base) << "."; +} + +} diff --git a/FlippR-Driver/src/PinController.h b/FlippR-Driver/src/PinController.h new file mode 100644 index 0000000..6a3e7d3 --- /dev/null +++ b/FlippR-Driver/src/PinController.h @@ -0,0 +1,47 @@ +/* + * PinController.hpp + * + * Responsible for communicating with the actual GPIO hardware. + * + * Created on: May 6, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_UTILITIES_GPIOINTERFACE_H_ +#define SRC_UTILITIES_GPIOINTERFACE_H_ + +#include +#include +#include + +namespace flippR_driver +{ + +class PinController +{ +public: + PinController(); + virtual ~PinController() = default; + + void initialize_port_expander(const uint8_t i2c_address, const uint8_t pin_base); + +protected: + static void initialize_output_pin(const uint8_t address); + static void initialize_input_pin(uint8_t address); + + static void write_pin(uint8_t address, bool value); + + static bool read_pin(uint8_t address); + +public: + static std::once_flag GPIO_LIB_INITIALIZED; + + static std::mutex lock; + + std::map initialized_port_extenders; +}; + +} + + +#endif diff --git a/FlippR-Driver/src/input/CMakeLists.txt b/FlippR-Driver/src/input/CMakeLists.txt deleted file mode 100644 index e69de29..0000000 diff --git a/FlippR-Driver/src/input/Detector.cpp b/FlippR-Driver/src/input/Detector.cpp deleted file mode 100644 index a147a70..0000000 --- a/FlippR-Driver/src/input/Detector.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Detector.cpp - * - * Created on: Apr 5, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#include "Detector.h" - -#include -#include - -#include "../utilities/config.h" - -namespace Input -{ - -Detector::Detector(InputGPIOInterface* input_gpio_interface, std::map events, IEventNotifier* event_notifier) : - input_gpio_interface(input_gpio_interface), events(events), is_running(true), event_notifier(event_notifier) -{ - detect_thread = std::thread(&Detector::detect, this); - - CLOG(WARNING, INPUT_LOGGER) << "Created Detector"; -} - -Detector::~Detector() -{ - is_running = false; - - detect_thread.join(); - - delete this->input_gpio_interface; - this->input_gpio_interface = NULL; - - delete this->event_notifier; - this->event_notifier = NULL; -} - -// Cycles over all s and enqueues an event if detected. -void Detector::detect() -{ - while(is_running) - { - char address; - if(check_inputs(address)) - { - try - { - Event& event = events.at(address); - event_notifier->distribute_event(event); - } - catch(std::out_of_range& e) - { - CLOG(WARNING, INPUT_LOGGER) << "Did not found event for address: " << address << " check config-file"; - } - } - } -} - -bool Detector::check_inputs(char& address) -{ - for(int pin = 0; pin < (INPUT_MATRIX_SIZE * INPUT_MATRIX_SIZE); pin++) - { - if(input_gpio_interface->read_input_data(pin)) - { - address = pin; - return true; - } - } - return false; -} - -} diff --git a/FlippR-Driver/src/input/Detector.h b/FlippR-Driver/src/input/Detector.h index 1ee5d4e..dbb0da2 100644 --- a/FlippR-Driver/src/input/Detector.h +++ b/FlippR-Driver/src/input/Detector.h @@ -1,48 +1,27 @@ /* * Detector.h * - * Responsible for detecting InputEvents. - * - * Creates two Threads; - * One cycles over the inputs gpios and pushes detected input events to a queue. - * The other cycles over the queue and notifies input event handlers. - * - * Created on: Apr 5, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + * Created on: Jun 13, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert */ -#ifndef DETECTOR_H_ -#define DETECTOR_H_ +#ifndef SRC_INPUT_DETECTOR_H_ +#define SRC_INPUT_DETECTOR_H_ -#include "IDetector.h" -namespace Input +namespace flippR_driver +{ +namespace input { -class Detector : public IDetector +class Detector { public: - Detector(InputGPIOInterface* input_gpio_interface, std::map events, IEventNotifier* event_notifier); - ~Detector(); - -private: - void detect(); - bool check_inputs(char& address); - -private: - InputGPIOInterface* input_gpio_interface; - - std::map events; - - IEventNotifier* event_notifier; - - bool is_running; - std::thread detect_thread; + virtual ~Detector() = default; }; } - - -#endif /* DETECTOR_H_ */ +} +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/input/DistributingEvent.cpp b/FlippR-Driver/src/input/DistributingEvent.cpp new file mode 100644 index 0000000..82301b6 --- /dev/null +++ b/FlippR-Driver/src/input/DistributingEvent.cpp @@ -0,0 +1,62 @@ +// +// Created by rhetenor on 21.09.18. +// + +#include "DistributingEvent.h" + +namespace flippR_driver +{ +namespace input +{ + +DistributingEvent::DistributingEvent(uint8_t address, int priority, std::string name, + std::chrono::milliseconds bounce_time, std::shared_ptr event_notifier) +: + Event(address, priority, std::move(name)), + bounce_time(bounce_time), + event_notifier(std::move(event_notifier)), + activation_state(NOT_ACTIVATED) +{} + +void DistributingEvent::distribute() +{ + event_notifier->distribute_event(*this); +} + +void DistributingEvent::active() +{ + if(!is_bouncing()) + { + if(activation_state != ACTIVATED) + { + activation_state = activation_state == NOT_ACTIVATED ? FIRST_ACTIVATED : ACTIVATED; + } + + last_activation = std::chrono::high_resolution_clock::now(); + + if(activation_state == FIRST_ACTIVATED) + { + this->distribute(); + } + } +} + +bool DistributingEvent::is_bouncing() +{ + std::chrono::time_point now = std::chrono::high_resolution_clock::now(); + std::chrono::milliseconds elapsed_time = std::chrono::duration_cast(now - last_activation); + + return elapsed_time < bounce_time; +} + +void DistributingEvent::inactive() +{ + if(activation_state == ACTIVATED) + { + this->last_activation = std::chrono::high_resolution_clock::now(); + activation_state = NOT_ACTIVATED; + } +} + +} +} \ No newline at end of file diff --git a/FlippR-Driver/src/input/DistributingEvent.h b/FlippR-Driver/src/input/DistributingEvent.h new file mode 100644 index 0000000..44ede56 --- /dev/null +++ b/FlippR-Driver/src/input/DistributingEvent.h @@ -0,0 +1,50 @@ +// +// Created by rhetenor on 21.09.18. +// + +#ifndef flippR_driver_DISTRIBUTINGEVENT_H +#define flippR_driver_DISTRIBUTINGEVENT_H + +#include "input/Event.h" +#include "input/EventNotifier.h" + +namespace flippR_driver +{ +namespace input +{ + +class DistributingEvent : public Event +{ +public: + DistributingEvent(uint8_t address, int priority, std::string name, + std::chrono::milliseconds bounce_time, std::shared_ptr event_notifier); + + void active(); + void inactive(); + +private: + bool is_bouncing(); + + void distribute(); + +public: + const std::chrono::milliseconds bounce_time; + +private: + enum ActivationState + { + NOT_ACTIVATED, + FIRST_ACTIVATED, + ACTIVATED + }; + + const std::shared_ptr event_notifier; + + ActivationState activation_state; + +}; + +} +} + +#endif //flippR_driver_DISTRIBUTINGEVENT_H diff --git a/FlippR-Driver/src/input/Event.cpp b/FlippR-Driver/src/input/Event.cpp new file mode 100644 index 0000000..b95cd15 --- /dev/null +++ b/FlippR-Driver/src/input/Event.cpp @@ -0,0 +1,41 @@ +/* + * Event.cpp + * + * Created on: Jun 15, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ +#include "input/Event.h" + +#include "json/json.hpp" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace input +{ + +Event::Event(uint8_t address, int priority, std::string name) : + address(address), priority(priority), name(name) +{ + CLOG_IF(VLOG_IS_ON(0), DEBUG, INPUT_LOGGER) << "Created event: " << name << ", address: " << address; +} + +std::string Event::getJsonString() +{ + nlohmann::json json; + + json["name"] = this->name; + json["address"] = this->address; + json["priority"] = this->priority; + + return json.dump(); +} + +bool operator==(const Event& left, const Event& right) +{ + return left.name == right.name; +} + +} +} diff --git a/FlippR-Driver/src/input/Event.hpp b/FlippR-Driver/src/input/Event.hpp deleted file mode 100644 index ce55f6f..0000000 --- a/FlippR-Driver/src/input/Event.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * InputEvent.h - * - * Created on: Apr 5, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef INPUTEVENT_H_ -#define INPUTEVENT_H_ - -#include -#include - -#include "../utilities/config.h" - -namespace Input -{ - -class Event -{ - -public: - Event(char address, char priority, std::string name) : - address(address), priority(priority), name(name) - { - CLOG_IF(VLOG_IS_ON(HIGH_VERBOSITY), INFO, INPUT_LOGGER) << "Created event: " << name << ", address: " << address; - } - - bool operator==(const Event& other) - { - return this->name == other.name; - } - - friend bool operator<(const Event& left, const Event& right) - { - return left.priority < right.priority; - } -private: - char address; - char priority; - std::string name; - - -}; - -} - - -#endif /* INPUTEVENT_H_ */ diff --git a/FlippR-Driver/src/input/EventHandler.hpp b/FlippR-Driver/src/input/EventHandler.hpp deleted file mode 100644 index e915545..0000000 --- a/FlippR-Driver/src/input/EventHandler.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * InputEventHandler.h - * - * This interface must be implemented to be informed about input events. - * - * Please be aware that handle must be implemented thread safe! - * - * Created on: Apr 5, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef INPUTEVENTHANDLER_H_ -#define INPUTEVENTHANDLER_H_ - -#include "Event.hpp" -#include "IInputDriver.h" - -#include "../utilities/IEventHandler.h" -#include "../utilities/config.h" - -namespace Input -{ -class EventHandler; - -class EventHandler : public IEventHandler -{ -public: - EventHandler(std::shared_ptr input_driver) : - input_driver(input_driver) - { - this->input_driver->register_event_handler(this); - - CLOG(INFO, INPUT_LOGGER) << "Created EventHandler"; - } - - virtual ~EventHandler() - { - this->input_driver->unregister_event_handler(this); - this->input_driver = NULL; - } - - // This function is intended to be non pure, if it is called when the derived class doesn't exist anymore - virtual void handle(Event& event) - { - CLOG(WARNING, INPUT_LOGGER) << "Called EventHandler parent class"; - } - -private: - std::shared_ptr input_driver; -}; - -} - -#endif /* INPUTEVENTHANDLER_H_ */ diff --git a/FlippR-Driver/src/input/EventNotifier.cpp b/FlippR-Driver/src/input/EventNotifier.cpp deleted file mode 100644 index 8fb99cb..0000000 --- a/FlippR-Driver/src/input/EventNotifier.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * EventNotifier.cpp - * - * Created on: May 17, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#include - -#include "../utilities/config.h" - -#include "EventNotifier.h" - -namespace Input -{ - -EventNotifier::EventNotifier() -: is_running(true) -{ - notify_thread = std::thread(&EventNotifier::notify, this); - - CLOG(INFO, INPUT_LOGGER) << "Created EventNotifier and started thread"; -} - -EventNotifier::~EventNotifier() -{ - is_running = false; - - notify_thread.join(); -} - -void EventNotifier::register_event_handler(IEventHandler* handler) -{ - std::lock_guard event_handler_guard(event_handler_mutex); - event_handler.insert(handler); -} - -void EventNotifier::unregister_event_handler(IEventHandler* handler) -{ - std::lock_guard event_handler_guard(event_handler_mutex); - event_handler.erase(handler); -} - -void EventNotifier::distribute_event(Event& event) -{ - event_queue.push(event); -} - -void EventNotifier::notify() -{ - while(is_running) - { - Event event = event_queue.pop(); - - // getting a guard and calling all registered handlers - std::lock_guard event_handler_guard(event_handler_mutex); - for(auto handler : event_handler) - { - boost::thread handler_caller(boost::bind(&IEventHandler::handle, handler, event)); - - if(!handler_caller.timed_join(boost::posix_time::milliseconds(HANDLER_TIMEOUT))) - { - CLOG(WARNING, INPUT_LOGGER) << "Handler " << typeid(handler).name() << " didn't finish in " - << HANDLER_TIMEOUT << " milliseconds. Aborting Execution!"; - } - } - } -} - -} diff --git a/FlippR-Driver/src/input/EventNotifier.h b/FlippR-Driver/src/input/EventNotifier.h index 9f4431d..4848bfe 100644 --- a/FlippR-Driver/src/input/EventNotifier.h +++ b/FlippR-Driver/src/input/EventNotifier.h @@ -1,53 +1,33 @@ /* - * InputEventNotifier.h + * EventNotifier.h * - * Created on: May 17, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + * Created on: Jun 13, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert */ -#ifndef SRC_INPUT_EVENTNOTIFIER_H_ -#define SRC_INPUT_EVENTNOTIFIER_H_ +#ifndef SRC_INPUT_IEVENTNOTIFIER_H_ +#define SRC_INPUT_IEVENTNOTIFIER_H_ -#include "IEventNotifier.h" +#include "input/Event.h" +#include "input/EventHandler.h" +#include -#include -#include -#include - -#include "../utilities/BlockingQueue.hpp" -#include "Event.hpp" -#include "EventHandler.hpp" - -#define HANDLER_TIMEOUT 2000 - -namespace Input +namespace flippR_driver +{ +namespace input { -class EventNotifier : public IEventNotifier +class EventNotifier { - public: - EventNotifier(); - ~EventNotifier(); + virtual ~EventNotifier() = default; - void register_event_handler(IEventHandler* handler); - void unregister_event_handler(IEventHandler* handler); + virtual void register_event_handler(std::shared_ptr handler) = 0; + virtual void unregister_event_handler(std::shared_ptr handler) = 0; - void distribute_event(Event& event); - -private: - void notify(); - -private: - BlockingQueue event_queue; - std::set event_handler; - - bool is_running; - std::thread notify_thread; - std::mutex event_handler_mutex; + virtual void distribute_event(const Event &event) = 0; }; + } - - - -#endif /* SRC_INPUT_EVENTNOTIFIER_H_ */ +} +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/input/IDetector.h b/FlippR-Driver/src/input/IDetector.h deleted file mode 100644 index dba89d9..0000000 --- a/FlippR-Driver/src/input/IDetector.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * IDetector.h - * - * Created on: Jun 13, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_INPUT_IDETECTOR_H_ -#define SRC_INPUT_IDETECTOR_H_ - -#include -#include - -#include "../utilities/InputGPIOInterface.h" -#include "Event.hpp" -#include "EventNotifier.h" - -namespace Input -{ - -class IDetector -{ - -public: - virtual ~IDetector() = 0; -}; - -} - -#endif /* SRC_INPUT_IDETECTOR_H_ */ diff --git a/FlippR-Driver/src/input/IEventNotifier.h b/FlippR-Driver/src/input/IEventNotifier.h deleted file mode 100644 index 35b0827..0000000 --- a/FlippR-Driver/src/input/IEventNotifier.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * IEventNotifier.h - * - * Created on: Jun 13, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_INPUT_IEVENTNOTIFIER_H_ -#define SRC_INPUT_IEVENTNOTIFIER_H_ - -#include "IEventHandler.h" -#include "Event.hpp" - -namespace Input -{ - -class IEventNotifier -{ -public: - virtual ~IEventNotifier() = 0; - - virtual void register_event_handler(IEventHandler* handler) = 0; - virtual void unregister_event_handler(IEventHandler* handler) = 0; - - virtual void distribute_event(Event& event) = 0; -}; - -} -#endif /* SRC_INPUT_IEVENTNOTIFIER_H_ */ diff --git a/FlippR-Driver/src/input/IInputDriver.h b/FlippR-Driver/src/input/IInputDriver.h deleted file mode 100644 index 3d2940c..0000000 --- a/FlippR-Driver/src/input/IInputDriver.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * IInputDriver.h - * - * Created on: Jun 14, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_INPUT_IINPUTDRIVER_H_ -#define SRC_INPUT_IINPUTDRIVER_H_ - -#include "IEventHandler.h" -#include "IEventNotifier.h" - -namespace Input { - -class IInputDriver -{ -public: - virtual ~IInputDriver() = 0; - virtual void register_event_handler(IEventHandler* handler) = 0; - virtual void unregister_event_handler(IEventHandler* handler) = 0; -}; -} - -#endif /* SRC_INPUT_IINPUTDRIVER_H_ */ diff --git a/FlippR-Driver/src/input/IInputDriverFactory.h b/FlippR-Driver/src/input/IInputDriverFactory.h deleted file mode 100644 index 49ee81d..0000000 --- a/FlippR-Driver/src/input/IInputDriverFactory.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * IInputDriverFactory.h - * - * Created on: Jun 13, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_INPUT_IINPUTDRIVERFACTORY_H_ -#define SRC_INPUT_IINPUTDRIVERFACTORY_H_ - -namespace Input { - -class IInputDriverFactory -{ - -}; -} - -#endif /* SRC_INPUT_IINPUTDRIVERFACTORY_H_ */ diff --git a/FlippR-Driver/src/input/InputDriver.hpp b/FlippR-Driver/src/input/InputDriver.hpp deleted file mode 100644 index ed87623..0000000 --- a/FlippR-Driver/src/input/InputDriver.hpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * InputDriver.hpp - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ -#ifndef SRC_INPUT_INPUTDRIVER_HPP_ -#define SRC_INPUT_INPUTDRIVER_HPP_ - -#include "../utilities/config.h" - -#include "IInputDriver.h" -#include "IDetector.h" - -namespace Input -{ - -class InputDriver : public IInputDriver -{ - -public: - InputDriver(IEventNotifier* event_notifier, IDetector* detector) : - event_notifier(event_notifier), detector(detector) - { - CLOG(INFO, INPUT_LOGGER) << "Created InputDriver"; - } - - ~InputDriver() - { - delete event_notifier; - event_notifier = NULL; - - delete detector; - detector = NULL; - } - - void register_event_handler(IEventHandler* handler) - { - event_notifier->register_event_handler(handler); - } - - void unregister_event_handler(IEventHandler* handler) - { - event_notifier->unregister_event_handler(handler); - } - -private: - IEventNotifier* event_notifier; - IDetector* detector; -}; - -} - -#endif /* SRC_INPUT_INPUTDRIVER_HPP_ */ diff --git a/FlippR-Driver/src/input/InputDriverFactory.cpp b/FlippR-Driver/src/input/InputDriverFactory.cpp new file mode 100644 index 0000000..273892e --- /dev/null +++ b/FlippR-Driver/src/input/InputDriverFactory.cpp @@ -0,0 +1,130 @@ +/* + * InputDriverFactory.cpp + * + * Created on: Jun 14, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + + +#include "InputDriverFactory.h" + +#include "utility/config.h" + +#include "utility/LoggerFactory.h" + +#include "input/detail/InputDriver.h" +#include "input/detail/EventNotifier.h" +#include "input/detail/Detector.h" + +namespace flippR_driver +{ +namespace input +{ +namespace InputDriverFactory +{ + +using namespace nlohmann; +using namespace flippR_driver::utility; + +std::shared_ptr get_InputDriver(std::istream &input_pin_stream, std::istream &matrix_config_stream) +{ + LoggerFactory::CreateInputLogger(); + + IBlockingQueue *event_queue = new BlockingQueue; + std::shared_ptr event_notifier(new detail::EventNotifier(event_queue)); + + std::vector> events; + std::map> name_event_map; + + create_events(matrix_config_stream, events, name_event_map, event_notifier); + + std::unique_ptr input_gpio_interface(new detail::InputPinController(create_pin_map(input_pin_stream))); + std::unique_ptr detector(new detail::Detector(std::move(input_gpio_interface), events)); + + return std::make_shared(event_notifier, std::move(detector), name_event_map); +} + +namespace +{ + void create_events(std::istream &matrix_config_stream, std::vector> &events, + std::map> &name_event_map, + std::shared_ptr event_notifier) + { + json matrix_config; + matrix_config_stream >> matrix_config; + + try + { + int global_bounce_time = matrix_config.at("global_bounce_time").get(); + auto &json_events = matrix_config.at("input_matrix"); + + for(auto &json_event : json_events) + { + std::shared_ptr event = create_event(json_event, event_notifier, global_bounce_time); + + events.push_back(event); + name_event_map.emplace(event->name, event); + } + } + catch(json::exception &e) + { + CLOG(ERROR, INPUT_LOGGER) << "Event matrix config file corrupted: " << e.what(); + exit(EXIT_FAILURE); + } + } + + std::shared_ptr create_event(json &json_event, std::shared_ptr event_notifier, int bounce_time) + { + std::string name = json_event.at("name"); + uint8_t address = json_event.at("address").get(); + int priority = json_event.at("priority").get(); + + set_individual_bounce_time(json_event, bounce_time); + + return std::make_shared(address, priority, name, std::chrono::milliseconds(bounce_time), event_notifier); + } + + void set_individual_bounce_time(json &json_event, int &bounce_time) + { + auto it_bounce_time = json_event.find("bounce_time"); + + if(it_bounce_time != json_event.end()) + { + bounce_time = it_bounce_time->get(); + } + } + + std::map create_pin_map(std::istream &input_pin_stream) + { + std::map input_pin_map; + + json pin_config; + input_pin_stream >> pin_config; + + try + { + json row_json = pin_config.at("row"); + input_pin_map["row_address_A"] = row_json.at("A").get(); + input_pin_map["row_address_B"] = row_json.at("B").get(); + input_pin_map["row_address_C"] = row_json.at("C").get(); + + json col_json = pin_config.at("col"); + input_pin_map["col_address_A"] = col_json.at("A").get(); + input_pin_map["col_address_B"] = col_json.at("B").get(); + input_pin_map["col_address_C"] = col_json.at("C").get(); + + input_pin_map["data_address"] = pin_config.at("data").get(); + } + catch(json::exception &e) + { + CLOG(ERROR, INPUT_LOGGER) << "Input pin config file corrupted! " << e.what(); + exit(EXIT_FAILURE); + } + + return input_pin_map; + } + +} +} +} +} diff --git a/FlippR-Driver/src/input/InputDriverFactory.h b/FlippR-Driver/src/input/InputDriverFactory.h new file mode 100644 index 0000000..a2f2e33 --- /dev/null +++ b/FlippR-Driver/src/input/InputDriverFactory.h @@ -0,0 +1,42 @@ +/* + * InputFactory.h + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef INPUTFACTORY_H_ +#define INPUTFACTORY_H_ + +#include +#include "json/json.hpp" + +#include "input/InputDriver.h" +#include "DistributingEvent.h" +#include "input/detail/InputPinController.h" +#include "input/EventNotifier.h" + +namespace flippR_driver +{ +namespace input +{ +namespace InputDriverFactory +{ + std::shared_ptr get_InputDriver(std::istream &input_pin_stream, std::istream &matrix_config_stream); + + namespace + { + static void create_events(std::istream &matrix_config, + std::vector> &events, + std::map> &name_event_map, + std::shared_ptr event_notifier); + + static std::shared_ptr create_event(nlohmann::json &json_event, std::shared_ptr event_notifier, int bounce_time); + static void set_individual_bounce_time(nlohmann::json &json_event, int &bounce_time); + + static std::map create_pin_map(std::istream &input_pin_stream); + } +}; +} +} +#endif diff --git a/FlippR-Driver/src/input/InputDriverFactory.hpp b/FlippR-Driver/src/input/InputDriverFactory.hpp deleted file mode 100644 index 8f8e465..0000000 --- a/FlippR-Driver/src/input/InputDriverFactory.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * InputFactory.h - * - * Created on: Apr 5, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef INPUTFACTORY_H_ -#define INPUTFACTORY_H_ - -#include - -#include "IDetector.h" - -#include "../utilities/InputGPIOInterface.h" -#include "../utilities/config.h" -#include "../lib/json/json.hpp" -#include "../lib/easylogging/easylogging++.h" -#include "IEventNotifier.h" - -using namespace nlohmann; - - -INITIALIZE_EASYLOGGINGPP - -namespace Input -{ -class InputFactory -{ - -public: - static shared_ptr get_InputDriver(std::string& input_config_path, std::string& matrix_config_path) - { - this->ConfigureLogger(); - auto event_notifier = new EventNotifier(); - - auto detector = this->get_detector(input_config_path, matrix_config_path); - - return shared_ptr(new InputDriver(event_notifier, detector)); - } - -private: - static IDetector* get_detector(std::string& input_config_path, std::string& matrix_config_path) - { - std::ifstream input_config_stream(input_config_path); - json input_config; - input_config << input_config_stream; - - std::ifstream matrix_config_stream(matrix_config_path); - json matrix_config; - matrix_config << matrix_config_stream; - - auto input_gpio_interface = new InputGPIOInterface(input_config); - auto input_notifier = new InputEventNotifier(); - - std::map input_events = this->create_input_events(matrix_config); - - return new Detector(input_gpio_interface, input_events, input_notifier); - } - - static std::map create_input_events(json matrix_config) - { - std::map events; - - for(auto& json_event : matrix_config) - { - try - { - std::string name = json_event.at("name"); - char address = json_event.at("address"); - int priority = json_event.at("priority"); - - Event event(address, priority, name); - - events.emplace(address, event); - } - catch(json::exception& e) - { - CLOG(ERROR, INPUT_LOGGER) << "Matrix config-file corrupted: " << e.what(); - exit(EXIT_FAILURE); - } - } - - return events; - } - - static void ConfigureLogger() - { - el::Loggers::getLogger(INPUT_LOGGER); - - //TODO may configure? - el::Configurations conf; - conf.setToDefault(); - conf.set(el::Level::Global, el::ConfigurationType::Filename, DRIVER_LOG_FILE); - conf.set(el::Level::Global, el::ConfigurationType::Format, "%datetime [%level] [%func] : %msg"); - - el::Loggers::reconfigureLogger(INPUT_LOGGER, conf); - } - -}; -} - -#endif /* INPUTFACTORY_H_ */ diff --git a/FlippR-Driver/src/input/InputPinController.h b/FlippR-Driver/src/input/InputPinController.h new file mode 100644 index 0000000..eba88a8 --- /dev/null +++ b/FlippR-Driver/src/input/InputPinController.h @@ -0,0 +1,29 @@ +/* + * InputPinController.h + * + * Created on: May 31, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_UTILITIES_IINPUTGPIOINTERFACE_H_ +#define SRC_UTILITIES_IINPUTGPIOINTERFACE_H_ + +#include + +namespace flippR_driver +{ +namespace input +{ + +class InputPinController +{ +public: + virtual ~InputPinController() = default; + + virtual bool read_data(uint8_t pin) const = 0; +}; + +} +} + +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/input/detail/Detector.cpp b/FlippR-Driver/src/input/detail/Detector.cpp new file mode 100644 index 0000000..cae9a35 --- /dev/null +++ b/FlippR-Driver/src/input/detail/Detector.cpp @@ -0,0 +1,55 @@ +/* + * Detector.cpp + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "Detector.h" + +#include + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +Detector::Detector(std::unique_ptr input_pin_controller, std::vector> events) : + input_pin_controller(std::move(input_pin_controller)), events(std::move(events)), is_running(true) +{ + this->detect_thread = std::thread(&Detector::detect, this); + + CLOG(DEBUG, INPUT_LOGGER) << "Created Detector"; + CLOG(INFO, INPUT_LOGGER) << "Detector thread running. Occuring input-events should get detected now!"; +} + +Detector::~Detector() +{ + this->is_running = false; + + this->detect_thread.join(); +} + +void Detector::detect() const +{ + while(this->is_running) + { + check_inputs(); + } +} + +void Detector::check_inputs() const +{ + for(auto &event : events) + { + input_pin_controller->read_data(event->address) ? event->active() : event->inactive(); + } +} + +} +} +} diff --git a/FlippR-Driver/src/input/detail/Detector.h b/FlippR-Driver/src/input/detail/Detector.h new file mode 100644 index 0000000..1642c05 --- /dev/null +++ b/FlippR-Driver/src/input/detail/Detector.h @@ -0,0 +1,58 @@ +/* + * Detector.h + * + * Responsible for detecting InputEvents. + * + * Creates two Threads; + * One cycles over the inputs gpios and pushes detected input events to a queue. + * The other cycles over the queue and notifies input event handlers. + * + * Created on: Apr 5, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef INPUT_IMPL_DETECTOR_H_ +#define INPUT_IMPL_DETECTOR_H_ + + +#include +#include +#include + +#include "input/InputPinController.h" + +#include "input/Detector.h" +#include "input/DistributingEvent.h" +#include "input/EventNotifier.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +class Detector : public input::Detector +{ + +public: + Detector(std::unique_ptr input_pin_controller, std::vector> events); + ~Detector() override; + +private: + void detect() const; + void check_inputs() const; + +private: + const std::unique_ptr input_pin_controller; + + const std::vector> events; + + bool is_running; + std::thread detect_thread; +}; + +} +} +} +#endif diff --git a/FlippR-Driver/src/input/detail/EventNotifier.cpp b/FlippR-Driver/src/input/detail/EventNotifier.cpp new file mode 100644 index 0000000..229aab9 --- /dev/null +++ b/FlippR-Driver/src/input/detail/EventNotifier.cpp @@ -0,0 +1,90 @@ +/* + * EventNotifier.cpp + * + * Created on: May 17, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include +#include "utility/config.h" +#include "EventNotifier.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +EventNotifier::EventNotifier(utility::IBlockingQueue *queue) : +is_running(true), +event_queue(queue) +{ + this->notify_thread = std::thread(&EventNotifier::notify, this); + + CLOG(DEBUG, INPUT_LOGGER) << "Created EventNotifier and started thread"; +} + +EventNotifier::~EventNotifier() +{ + this->is_running = false; + + Event end_event(0, 0, "END"); + this->event_queue->push(end_event); + + this->notify_thread.join(); + + delete this->event_queue; +} + +void EventNotifier::register_event_handler(std::shared_ptr handler) +{ + std::lock_guard event_handler_guard(event_handler_mutex); + this->event_handlers.insert(handler); + CLOG(INFO, INPUT_LOGGER) << "New Eventhandler at adress " << handler << " was registered."; +} + +void EventNotifier::unregister_event_handler(std::shared_ptr handler) +{ + std::lock_guard event_handler_guard(event_handler_mutex); + this->event_handlers.erase(handler); + CLOG(INFO, INPUT_LOGGER) << "Eventhandler at adress " << handler << " was unregistered."; +} + +void EventNotifier::distribute_event(const Event &event) +{ + this->event_queue->push(event); +} + +void EventNotifier::notify() +{ + while(this->is_running) + { + Event event = this->event_queue->pop(); + + // TODO schoener machen + if(event.name == "END") + { + return; + } + + // getting a guard and calling all registered handlers + std::lock_guard event_handler_guard(this->event_handler_mutex); + //CLOG(INFO, INPUT_LOGGER) << "Notified " << this->event_handlers.size() << " EventHandlers"; + for(auto handler : this->event_handlers) + { + //CLOG(INFO, INPUT_LOGGER) << "Notify " << handler; + boost::thread handler_caller(boost::bind(&EventHandler::handle, handler, event)); + + if(!handler_caller.timed_join(boost::posix_time::milliseconds(INPUT_HANDLER_TIMEOUT_MILLI))) + { + CLOG(WARNING, INPUT_LOGGER) << "Handler " << typeid(handler).name() << " didn't finish in " + << INPUT_HANDLER_TIMEOUT_MILLI << " milliseconds. Aborting Execution!"; + } + } + } +} + +} +} +} diff --git a/FlippR-Driver/src/input/detail/EventNotifier.h b/FlippR-Driver/src/input/detail/EventNotifier.h new file mode 100644 index 0000000..53beb89 --- /dev/null +++ b/FlippR-Driver/src/input/detail/EventNotifier.h @@ -0,0 +1,58 @@ +/* + * InputEventNotifier.h + * + * Created on: May 17, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef INPUT_IMPL_EVENTNOTIFIER_H_ +#define INPUT_IMPL_EVENTNOTIFIER_H_ + +#include +#include +#include + +#include "input/EventNotifier.h" + +#include "input/Event.h" +#include "input/EventHandler.h" + +#include "utility/BlockingQueue.hpp" +#include "utility/IBlockingQueue.h" + + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +class EventNotifier : public input::EventNotifier +{ + +public: + explicit EventNotifier(utility::IBlockingQueue *queue); + ~EventNotifier() override; + + void register_event_handler(std::shared_ptr handler) override; + void unregister_event_handler(std::shared_ptr handler) override; + + void distribute_event(const Event &event) override; + +private: + void notify(); + +private: + utility::IBlockingQueue *event_queue; + std::set> event_handlers; + + bool is_running; + std::thread notify_thread; + std::mutex event_handler_mutex; +}; + +} +} +} +#endif diff --git a/FlippR-Driver/src/input/detail/InputDriver.cpp b/FlippR-Driver/src/input/detail/InputDriver.cpp new file mode 100644 index 0000000..22e8f2d --- /dev/null +++ b/FlippR-Driver/src/input/detail/InputDriver.cpp @@ -0,0 +1,51 @@ +/* + * InputDriver.cpp + * + * Created on: Jun 15, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ +#include "InputDriver.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +InputDriver::InputDriver(std::shared_ptr event_notifier, std::unique_ptr detector, + std::map> events) : +event_notifier(std::move(event_notifier)), detector(std::move(detector)), events(std::move(events)) +{ + CLOG(INFO, INPUT_LOGGER) << "InputDriver created and running."; +} + +void InputDriver::register_event_handler(std::shared_ptr handler) +{ + this->event_notifier->register_event_handler(handler); +} + +void InputDriver::unregister_event_handler(std::shared_ptr handler) +{ + this->event_notifier->unregister_event_handler(handler); +} + +boost::optional> InputDriver::get_event(std::string name) +{ + try + { + return this->events.at(name); + } + catch(std::out_of_range &e) + { + CLOG_N_TIMES(1, WARNING, OUTPUT_LOGGER) << "Did not found event " << name << " please check config file!"; + } + return boost::optional> {}; +} + +} +} +} + diff --git a/FlippR-Driver/src/input/detail/InputDriver.h b/FlippR-Driver/src/input/detail/InputDriver.h new file mode 100644 index 0000000..abd2419 --- /dev/null +++ b/FlippR-Driver/src/input/detail/InputDriver.h @@ -0,0 +1,45 @@ +/* + * InputDriver.hpp + * + * Created on: May 31, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ +#ifndef INPUT_IMPL_INPUTDRIVER_H_ +#define INPUT_IMPL_INPUTDRIVER_H_ + +#include "input/InputDriver.h" + +#include + +#include "input/EventNotifier.h" +#include "input/Detector.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +class InputDriver : public input::InputDriver +{ + +public: + + InputDriver(std::shared_ptr event_notifier, std::unique_ptr detector, std::map> events); + void register_event_handler(std::shared_ptr handler) override; + void unregister_event_handler(std::shared_ptr handler) override; + + boost::optional> get_event(std::string name) override; + +private: + const std::shared_ptr event_notifier; + const std::unique_ptr detector; + + const std::map> events; +}; + +} +} +} +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/input/detail/InputPinController.cpp b/FlippR-Driver/src/input/detail/InputPinController.cpp new file mode 100644 index 0000000..4b6ae5e --- /dev/null +++ b/FlippR-Driver/src/input/detail/InputPinController.cpp @@ -0,0 +1,72 @@ +/* + * InputPinController.cpp + * + * Created on: May 31, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "InputPinController.h" + +#include + +#include "json/json.hpp" +#include "easylogging/easylogging++.h" +#include "utility/config.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +using namespace nlohmann; + +InputPinController::InputPinController(std::map pins) +: pins(std::move(pins)) +{ + init_pins(); +} + +bool InputPinController::read_data(uint8_t pin) const +{ + // setting address to read + write_row(pin / INPUT_MATRIX_SIZE); + write_col(pin % INPUT_MATRIX_SIZE); + + // wait for mux to set address + std::this_thread::sleep_for(std::chrono::nanoseconds(INPUT_SLEEP_DURATION_NANO)); + + return read_pin(this->pins.at("data_address")); +} + +void InputPinController::write_row(uint8_t data) const +{ + write_pin(this->pins.at("row_address_A"), data & 0b001u); + write_pin(this->pins.at("row_address_B"), data & 0b010u); + write_pin(this->pins.at("row_address_C"), data & 0b100u); +} + +void InputPinController::write_col(uint8_t data) const +{ + write_pin(this->pins.at("col_address_A"), data & 0b001u); + write_pin(this->pins.at("col_address_B"), data & 0b010u); + write_pin(this->pins.at("col_address_C"), data & 0b100u); +} + +void InputPinController::init_pins() const +{ + initialize_output_pin(this->pins.at("col_address_A")); + initialize_output_pin(this->pins.at("col_address_B")); + initialize_output_pin(this->pins.at("col_address_C")); + + initialize_output_pin(this->pins.at("row_address_A")); + initialize_output_pin(this->pins.at("row_address_B")); + initialize_output_pin(this->pins.at("row_address_C")); + + initialize_input_pin(this->pins.at("data_address")); +} + +} +} +} diff --git a/FlippR-Driver/src/input/detail/InputPinController.h b/FlippR-Driver/src/input/detail/InputPinController.h new file mode 100644 index 0000000..a31613c --- /dev/null +++ b/FlippR-Driver/src/input/detail/InputPinController.h @@ -0,0 +1,44 @@ +/* + * InputPinController.h + * + * Created on: May 31, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_UTILITIES_INPUTGPIOINTERFACE_H_ +#define SRC_UTILITIES_INPUTGPIOINTERFACE_H_ + +#include "input/InputPinController.h" + +#include +#include + +#include "PinController.h" + +namespace flippR_driver +{ +namespace input +{ +namespace detail +{ + +class InputPinController : public input::InputPinController, public PinController +{ +public: + explicit InputPinController(std::map pins); + bool read_data(uint8_t pin) const override; + +private: + void init_pins() const; + void write_row(uint8_t data) const; + void write_col(uint8_t data) const; + +private: + const std::map pins; + +}; + +} +} +} +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/input/main.cpp b/FlippR-Driver/src/input/main.cpp deleted file mode 100644 index 308ff5b..0000000 --- a/FlippR-Driver/src/input/main.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include "Detector.h" -#include - -#include "Event.hpp" -int main() -{ - return 0; -} diff --git a/FlippR-Driver/src/lib/libwiringPi.so.2.44 b/FlippR-Driver/src/lib/libwiringPi.so.2.44 deleted file mode 100755 index 92f7d4d..0000000 Binary files a/FlippR-Driver/src/lib/libwiringPi.so.2.44 and /dev/null differ diff --git a/FlippR-Driver/src/lib/wiringPi/COPYING.LESSER b/FlippR-Driver/src/lib/wiringPi/COPYING.LESSER deleted file mode 100644 index 65c5ca8..0000000 --- a/FlippR-Driver/src/lib/wiringPi/COPYING.LESSER +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/FlippR-Driver/src/lib/wiringPi/Makefile b/FlippR-Driver/src/lib/wiringPi/Makefile deleted file mode 100644 index e1868b9..0000000 --- a/FlippR-Driver/src/lib/wiringPi/Makefile +++ /dev/null @@ -1,177 +0,0 @@ -# -# Makefile: -# wiringPi - Wiring Compatable library for the Raspberry Pi -# -# Copyright (c) 2012-2015 Gordon Henderson -################################################################################# -# This file is part of wiringPi: -# https://projects.drogon.net/raspberry-pi/wiringpi/ -# -# wiringPi is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# wiringPi is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with wiringPi. If not, see . -################################################################################# - -VERSION=$(shell cat ../VERSION) -DESTDIR?=/usr -PREFIX?=/local - -LDCONFIG?=ldconfig - -ifneq ($V,1) -Q ?= @ -endif - -STATIC=libwiringPi.a -DYNAMIC=libwiringPi.so.$(VERSION) - -#DEBUG = -g -O0 -DEBUG = -O2 -CC = gcc -INCLUDE = -I. -DEFS = -D_GNU_SOURCE -CFLAGS = $(DEBUG) $(DEFS) -Wformat=2 -Wall -Wextra -Winline $(INCLUDE) -pipe -fPIC - -LIBS = -lm -lpthread -lrt -lcrypt - -############################################################################### - -SRC = wiringPi.c \ - wiringSerial.c wiringShift.c \ - piHiPri.c piThread.c \ - wiringPiSPI.c wiringPiI2C.c \ - softPwm.c softTone.c \ - mcp23008.c mcp23016.c mcp23017.c \ - mcp23s08.c mcp23s17.c \ - sr595.c \ - pcf8574.c pcf8591.c \ - mcp3002.c mcp3004.c mcp4802.c mcp3422.c \ - max31855.c max5322.c ads1115.c \ - sn3218.c \ - bmp180.c htu21d.c ds18b20.c rht03.c \ - drcSerial.c drcNet.c \ - pseudoPins.c \ - wpiExtensions.c - -HEADERS = $(shell ls *.h) - -OBJ = $(SRC:.c=.o) - -all: $(DYNAMIC) - -static: $(STATIC) - -$(STATIC): $(OBJ) - $Q echo "[Link (Static)]" - $Q ar rcs $(STATIC) $(OBJ) - $Q ranlib $(STATIC) -# @size $(STATIC) - -$(DYNAMIC): $(OBJ) - $Q echo "[Link (Dynamic)]" - $Q $(CC) -shared -Wl,-soname,libwiringPi.so$(WIRINGPI_SONAME_SUFFIX) -o libwiringPi.so.$(VERSION) $(LIBS) $(OBJ) - -.c.o: - $Q echo [Compile] $< - $Q $(CC) -c $(CFLAGS) $< -o $@ - - -.PHONY: clean -clean: - $Q echo "[Clean]" - $Q rm -f $(OBJ) $(OBJ_I2C) *~ core tags Makefile.bak libwiringPi.* - -.PHONY: tags -tags: $(SRC) - $Q echo [ctags] - $Q ctags $(SRC) - - -.PHONY: install -install: $(DYNAMIC) - $Q echo "[Install Headers]" - $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/include - $Q install -m 0644 $(HEADERS) $(DESTDIR)$(PREFIX)/include - $Q echo "[Install Dynamic Lib]" - $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/lib - $Q install -m 0755 libwiringPi.so.$(VERSION) $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) - $Q ln -sf $(DESTDIR)$(PREFIX)/lib/libwiringPi.so.$(VERSION) $(DESTDIR)/lib/libwiringPi.so - $Q $(LDCONFIG) - -.PHONY: install-static -install-static: $(STATIC) - $Q echo "[Install Headers]" - $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/include - $Q install -m 0644 $(HEADERS) $(DESTDIR)$(PREFIX)/include - $Q echo "[Install Static Lib]" - $Q install -m 0755 -d $(DESTDIR)$(PREFIX)/lib - $Q install -m 0755 libwiringPi.a $(DESTDIR)$(PREFIX)/lib - -.PHONY: install-deb -install-deb: $(DYNAMIC) - $Q echo "[Install Headers: deb]" - $Q install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/include - $Q install -m 0644 $(HEADERS) ~/wiringPi/debian-template/wiringPi/usr/include - $Q echo "[Install Dynamic Lib: deb]" - install -m 0755 -d ~/wiringPi/debian-template/wiringPi/usr/lib - install -m 0755 libwiringPi.so.$(VERSION) ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPi.so.$(VERSION) - ln -sf ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPi.so.$(VERSION) ~/wiringPi/debian-template/wiringPi/usr/lib/libwiringPi.so - -.PHONY: uninstall -uninstall: - $Q echo "[UnInstall]" - $Q cd $(DESTDIR)$(PREFIX)/include/ && rm -f $(HEADERS) - $Q cd $(DESTDIR)$(PREFIX)/lib/ && rm -f libwiringPi.* - $Q $(LDCONFIG) - - -.PHONY: depend -depend: - makedepend -Y $(SRC) $(SRC_I2C) - -# DO NOT DELETE - -wiringPi.o: softPwm.h softTone.h wiringPi.h ../version.h -wiringSerial.o: wiringSerial.h -wiringShift.o: wiringPi.h wiringShift.h -piHiPri.o: wiringPi.h -piThread.o: wiringPi.h -wiringPiSPI.o: wiringPi.h wiringPiSPI.h -wiringPiI2C.o: wiringPi.h wiringPiI2C.h -softPwm.o: wiringPi.h softPwm.h -softTone.o: wiringPi.h softTone.h -mcp23008.o: wiringPi.h wiringPiI2C.h mcp23x0817.h mcp23008.h -mcp23016.o: wiringPi.h wiringPiI2C.h mcp23016.h mcp23016reg.h -mcp23017.o: wiringPi.h wiringPiI2C.h mcp23x0817.h mcp23017.h -mcp23s08.o: wiringPi.h wiringPiSPI.h mcp23x0817.h mcp23s08.h -mcp23s17.o: wiringPi.h wiringPiSPI.h mcp23x0817.h mcp23s17.h -sr595.o: wiringPi.h sr595.h -pcf8574.o: wiringPi.h wiringPiI2C.h pcf8574.h -pcf8591.o: wiringPi.h wiringPiI2C.h pcf8591.h -mcp3002.o: wiringPi.h wiringPiSPI.h mcp3002.h -mcp3004.o: wiringPi.h wiringPiSPI.h mcp3004.h -mcp4802.o: wiringPi.h wiringPiSPI.h mcp4802.h -mcp3422.o: wiringPi.h wiringPiI2C.h mcp3422.h -max31855.o: wiringPi.h wiringPiSPI.h max31855.h -max5322.o: wiringPi.h wiringPiSPI.h max5322.h -ads1115.o: wiringPi.h wiringPiI2C.h ads1115.h -sn3218.o: wiringPi.h wiringPiI2C.h sn3218.h -bmp180.o: wiringPi.h wiringPiI2C.h bmp180.h -htu21d.o: wiringPi.h wiringPiI2C.h htu21d.h -ds18b20.o: wiringPi.h ds18b20.h -drcSerial.o: wiringPi.h wiringSerial.h drcSerial.h -pseudoPins.o: wiringPi.h pseudoPins.h -wpiExtensions.o: wiringPi.h mcp23008.h mcp23016.h mcp23017.h mcp23s08.h -wpiExtensions.o: mcp23s17.h sr595.h pcf8574.h pcf8591.h mcp3002.h mcp3004.h -wpiExtensions.o: mcp4802.h mcp3422.h max31855.h max5322.h ads1115.h sn3218.h -wpiExtensions.o: drcSerial.h pseudoPins.h bmp180.h htu21d.h ds18b20.h -wpiExtensions.o: wpiExtensions.h diff --git a/FlippR-Driver/src/lib/wiringPi/ads1115.c b/FlippR-Driver/src/lib/wiringPi/ads1115.c deleted file mode 100644 index 648e612..0000000 --- a/FlippR-Driver/src/lib/wiringPi/ads1115.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * ads1115.c: - * Extend wiringPi with the ADS1115 I2C 16-bit ADC - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -/* - ********************************************************************************* - * We're going to work in a hybrid mode to fit in with the wiringPi way of - * doing things, so there will be 4 analog pin which read the 4 single-ended - * channels as usual, also some fake digitalOutputs - these are the control - * registers that allow the user to put it into single/diff mode, set the - * gain and data rates. - ********************************************************************************* - */ - -#include -#include -#include - -#include -#include - -#include "ads1115.h" - -// Bits in the config register (it's a 16-bit register) - -#define CONFIG_OS_MASK (0x8000) // Operational Status Register -#define CONFIG_OS_SINGLE (0x8000) // Write - Starts a single-conversion - // Read 1 = Conversion complete - -// The multiplexor - -#define CONFIG_MUX_MASK (0x7000) - -// Differential modes - -#define CONFIG_MUX_DIFF_0_1 (0x0000) // Pos = AIN0, Neg = AIN1 (default) -#define CONFIG_MUX_DIFF_0_3 (0x1000) // Pos = AIN0, Neg = AIN3 -#define CONFIG_MUX_DIFF_1_3 (0x2000) // Pos = AIN1, Neg = AIN3 -#define CONFIG_MUX_DIFF_2_3 (0x3000) // Pos = AIN2, Neg = AIN3 (2nd differential channel) - -// Single-ended modes - -#define CONFIG_MUX_SINGLE_0 (0x4000) // AIN0 -#define CONFIG_MUX_SINGLE_1 (0x5000) // AIN1 -#define CONFIG_MUX_SINGLE_2 (0x6000) // AIN2 -#define CONFIG_MUX_SINGLE_3 (0x7000) // AIN3 - -// Programmable Gain Amplifier - -#define CONFIG_PGA_MASK (0x0E00) -#define CONFIG_PGA_6_144V (0x0000) // +/-6.144V range = Gain 2/3 -#define CONFIG_PGA_4_096V (0x0200) // +/-4.096V range = Gain 1 -#define CONFIG_PGA_2_048V (0x0400) // +/-2.048V range = Gain 2 (default) -#define CONFIG_PGA_1_024V (0x0600) // +/-1.024V range = Gain 4 -#define CONFIG_PGA_0_512V (0x0800) // +/-0.512V range = Gain 8 -#define CONFIG_PGA_0_256V (0x0A00) // +/-0.256V range = Gain 16 - -#define CONFIG_MODE (0x0100) // 0 is continuous, 1 is single-shot (default) - -// Data Rate - -#define CONFIG_DR_MASK (0x00E0) -#define CONFIG_DR_8SPS (0x0000) // 8 samples per second -#define CONFIG_DR_16SPS (0x0020) // 16 samples per second -#define CONFIG_DR_32SPS (0x0040) // 32 samples per second -#define CONFIG_DR_64SPS (0x0060) // 64 samples per second -#define CONFIG_DR_128SPS (0x0080) // 128 samples per second (default) -#define CONFIG_DR_475SPS (0x00A0) // 475 samples per second -#define CONFIG_DR_860SPS (0x00C0) // 860 samples per second - -// Comparator mode - -#define CONFIG_CMODE_MASK (0x0010) -#define CONFIG_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default) -#define CONFIG_CMODE_WINDOW (0x0010) // Window comparator - -// Comparator polarity - the polarity of the output alert/rdy pin - -#define CONFIG_CPOL_MASK (0x0008) -#define CONFIG_CPOL_ACTVLOW (0x0000) // Active low (default) -#define CONFIG_CPOL_ACTVHI (0x0008) // Active high - -// Latching comparator - does the alert/rdy pin latch - -#define CONFIG_CLAT_MASK (0x0004) -#define CONFIG_CLAT_NONLAT (0x0000) // Non-latching comparator (default) -#define CONFIG_CLAT_LATCH (0x0004) // Latching comparator - -// Comparitor queue - -#define CONFIG_CQUE_MASK (0x0003) -#define CONFIG_CQUE_1CONV (0x0000) // Assert after one conversions -#define CONFIG_CQUE_2CONV (0x0001) // Assert after two conversions -#define CONFIG_CQUE_4CONV (0x0002) // Assert after four conversions -#define CONFIG_CQUE_NONE (0x0003) // Disable the comparator (default) - -#define CONFIG_DEFAULT (0x8583) // From the datasheet - - -static const uint16_t dataRates [8] = -{ - CONFIG_DR_8SPS, CONFIG_DR_16SPS, CONFIG_DR_32SPS, CONFIG_DR_64SPS, CONFIG_DR_128SPS, CONFIG_DR_475SPS, CONFIG_DR_860SPS -} ; - -static const uint16_t gains [6] = -{ - CONFIG_PGA_6_144V, CONFIG_PGA_4_096V, CONFIG_PGA_2_048V, CONFIG_PGA_1_024V, CONFIG_PGA_0_512V, CONFIG_PGA_0_256V -} ; - - -/* - * analogRead: - * Pin is the channel to sample on the device. - * Channels 0-3 are single ended inputs, - * channels 4-7 are the various differential combinations. - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int chan = pin - node->pinBase ; - int16_t result ; - uint16_t config = CONFIG_DEFAULT ; - - chan &= 7 ; - -// Setup the configuration register - -// Set PGA/voltage range - - config &= ~CONFIG_PGA_MASK ; - config |= node->data0 ; - -// Set sample speed - - config &= ~CONFIG_DR_MASK ; - config |= node->data1 ; - -// Set single-ended channel or differential mode - - config &= ~CONFIG_MUX_MASK ; - - switch (chan) - { - case 0: config |= CONFIG_MUX_SINGLE_0 ; break ; - case 1: config |= CONFIG_MUX_SINGLE_1 ; break ; - case 2: config |= CONFIG_MUX_SINGLE_2 ; break ; - case 3: config |= CONFIG_MUX_SINGLE_3 ; break ; - - case 4: config |= CONFIG_MUX_DIFF_0_1 ; break ; - case 5: config |= CONFIG_MUX_DIFF_2_3 ; break ; - case 6: config |= CONFIG_MUX_DIFF_0_3 ; break ; - case 7: config |= CONFIG_MUX_DIFF_1_3 ; break ; - } - -// Start a single conversion - - config |= CONFIG_OS_SINGLE ; - config = __bswap_16 (config) ; - wiringPiI2CWriteReg16 (node->fd, 1, config) ; - -// Wait for the conversion to complete - - for (;;) - { - result = wiringPiI2CReadReg16 (node->fd, 1) ; - result = __bswap_16 (result) ; - if ((result & CONFIG_OS_MASK) != 0) - break ; - delayMicroseconds (100) ; - } - - result = wiringPiI2CReadReg16 (node->fd, 0) ; - result = __bswap_16 (result) ; - -// Sometimes with a 0v input on a single-ended channel the internal 0v reference -// can be higher than the input, so you get a negative result... - - if ( (chan < 4) && (result < 0) ) - return 0 ; - else - return (int)result ; -} - - -/* - * digitalWrite: - * It may seem odd to have a digital write here, but it's the best way - * to pass paramters into the chip in the wiringPi way of things. - * We have 2 digital registers: - * 0 is the gain control - * 1 is the data rate control - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int data) -{ - int chan = pin - node->pinBase ; - chan &= 3 ; - - if (chan == 0) // Gain Control - { - if ( (data < 0) || (data > 6) ) // Use default if out of range - data = 2 ; - node->data0 = gains [data] ; - } - else // Data rate control - { - if ( (data < 0) || (data > 7) ) // Use default if out of range - data = 4 ; - node->data1 = dataRates [data] ; // Bugfix 0-1 by "Eric de jong (gm)" - Thanks. - } - -} - - -/* - * analogWrite: - * We're using this to write to the 2 comparitor threshold registers. - * We could use a digitalWrite here but as it's an analog comparison - * then it feels better to do it this way. - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int data) -{ - int chan = pin - node->pinBase ; - int reg ; - int16_t ndata ; - - chan &= 3 ; - - reg = chan + 2 ; - - /**/ if (data < -32767) - ndata = -32767 ; - else if (data > 32767) - ndata = 32767 ; - else - ndata = (int16_t)data ; - - ndata = __bswap_16 (ndata) ; - wiringPiI2CWriteReg16 (node->fd, reg, data) ; -} - - - -/* - * ads1115Setup: - * Create a new wiringPi device node for an ads1115 on the Pi's - * I2C interface. - ********************************************************************************* - */ - -int ads1115Setup (const int pinBase, int i2cAddr) -{ - struct wiringPiNodeStruct *node ; - int fd ; - - if ((fd = wiringPiI2CSetup (i2cAddr)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 8) ; - - node->fd = fd ; - node->data0 = CONFIG_PGA_4_096V ; // Gain in data0 - node->data1 = CONFIG_DR_128SPS ; // Samples/sec in data1 - node->analogRead = myAnalogRead ; - node->analogWrite = myAnalogWrite ; - node->digitalWrite = myDigitalWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/ads1115.h b/FlippR-Driver/src/lib/wiringPi/ads1115.h deleted file mode 100644 index 5c91735..0000000 --- a/FlippR-Driver/src/lib/wiringPi/ads1115.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ads1115.c: - * Extend wiringPi with the ADS1115 I2C 16-bit ADC - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -// Constants for some of the internal functions - -// Gain - -#define ADS1115_GAIN_6 0 -#define ADS1115_GAIN_4 1 -#define ADS1115_GAIN_2 2 -#define ADS1115_GAIN_1 3 -#define ADS1115_GAIN_HALF 4 -#define ADS1115_GAIN_QUARTER 5 - -// Data rate - -#define ADS1115_DR_8 0 -#define ADS1115_DR_16 1 -#define ADS1115_DR_32 2 -#define ADS1115_DR_64 3 -#define ADS1115_DR_128 4 -#define ADS1115_DR_250 5 -#define ADS1115_DR_475 6 -#define ADS1115_DR_860 7 - -#ifdef __cplusplus -extern "C" { -#endif - -extern int ads1115Setup (int pinBase, int i2cAddress) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/bmp180.c b/FlippR-Driver/src/lib/wiringPi/bmp180.c deleted file mode 100644 index bad4bb3..0000000 --- a/FlippR-Driver/src/lib/wiringPi/bmp180.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * bmp180.c: - * Extend wiringPi with the BMP180 I2C Pressure and Temperature - * sensor. This is used in the Pi Weather Station - * Copyright (c) 2016 Gordon Henderson - * - * Information from the document held at: - * http://wmrx00.sourceforge.net/Arduino/BMP085-Calcs.pdf - * was very useful when building this code. - * - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" - -#include "bmp180.h" - -#undef DEBUG - -#define I2C_ADDRESS 0x77 -#define BMP180_OSS 0 - - -// Static calibration data -// The down-side of this is that there can only be one BMP180 in -// a system - which is practice isn't an issue as it's I2C -// address is fixed. - -static int16_t AC1, AC2, AC3 ; -static uint16_t AC4, AC5, AC6 ; -static int16_t VB1, VB2 ; -static int16_t MB, MC, MD ; - -static double c5, c6, mc, md, x0, x1, x2, yy0, yy1, yy2, p0, p1, p2 ; - -// Pressure & Temp variables - -uint32_t cPress, cTemp ; - -static int altitude ; - -/* - * read16: - * Quick hack to read the 16-bit data with the correct endian - ********************************************************************************* - */ - -uint16_t read16 (int fd, int reg) -{ - return (wiringPiI2CReadReg8 (fd, reg) << 8) | wiringPiI2CReadReg8 (fd, reg + 1) ; - -} - - -/* - * bmp180ReadTempPress: - * Does the hard work of reading the sensor - ********************************************************************************* - */ - -static void bmp180ReadTempPress (int fd) -{ - double fTemp, fPress ; - double tu, a ; - double pu, s, x, y, z ; - - uint8_t data [4] ; - -// Start a temperature sensor reading - - wiringPiI2CWriteReg8 (fd, 0xF4, 0x2E) ; - delay (5) ; - -// Read the raw data - - data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ; - data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ; - -// And calculate... - - tu = (data [0] * 256.0) + data [1] ; - - a = c5 * (tu - c6) ; - fTemp = a + (mc / (a + md)) ; - cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ; - -#ifdef DEBUG - printf ("fTemp: %f, cTemp: %6d\n", fTemp, cTemp) ; -#endif - -// Start a pressure snsor reading - - wiringPiI2CWriteReg8 (fd, 0xF4, 0x34 | (BMP180_OSS << 6)) ; - delay (5) ; - -// Read the raw data - - data [0] = wiringPiI2CReadReg8 (fd, 0xF6) ; - data [1] = wiringPiI2CReadReg8 (fd, 0xF7) ; - data [2] = wiringPiI2CReadReg8 (fd, 0xF8) ; - -// And calculate... - - pu = ((double)data [0] * 256.0) + (double)data [1] + ((double)data [2] / 256.0) ; - s = fTemp - 25.0 ; - x = (x2 * pow (s, 2.0)) + (x1 * s) + x0 ; - y = (yy2 * pow (s, 2.0)) + (yy1 * s) + yy0 ; - z = (pu - x) / y ; - fPress = (p2 * pow (z, 2.0)) + (p1 * z) + p0 ; - cPress = (int)rint (((100.0 * fPress) + 0.5) / 10.0) ; - -#ifdef DEBUG - printf ("fPress: %f, cPress: %6d\n", fPress, cPress) ; -#endif -} - - -/* - * myAnalogWrite: - * Write to a fake register to represent the height above sea level - * so that the peudo millibar register can read the pressure in mB - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int chan = pin - node->pinBase ; - - if (chan == 0) - altitude = value ; -} - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int chan = pin - node->pinBase ; - - bmp180ReadTempPress (node->fd) ; - - /**/ if (chan == 0) // Read Temperature - return cTemp ; - else if (chan == 1) // Pressure - return cPress ; - else if (chan == 2) // Pressure in mB - return cPress / pow (1 - ((double)altitude / 44330.0), 5.255) ; - else - return -9999 ; - -} - - -/* - * bmp180Setup: - * Create a new instance of a PCF8591 I2C GPIO interface. We know it - * has 4 pins, (4 analog inputs and 1 analog output which we'll shadow - * input 0) so all we need to know here is the I2C address and the - * user-defined pin base. - ********************************************************************************* - */ - -int bmp180Setup (const int pinBase) -{ - double c3, c4, b1 ; - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 4) ; - - node->fd = fd ; - node->analogRead = myAnalogRead ; - node->analogWrite = myAnalogWrite ; - -// Read calibration data - - AC1 = read16 (fd, 0xAA) ; - AC2 = read16 (fd, 0xAC) ; - AC3 = read16 (fd, 0xAE) ; - AC4 = read16 (fd, 0xB0) ; - AC5 = read16 (fd, 0xB2) ; - AC6 = read16 (fd, 0xB4) ; - VB1 = read16 (fd, 0xB6) ; - VB2 = read16 (fd, 0xB8) ; - MB = read16 (fd, 0xBA) ; - MC = read16 (fd, 0xBC) ; - MD = read16 (fd, 0xBE) ; - -// Calculate coefficients - - c3 = 160.0 * pow (2.0, -15.0) * AC3 ; - c4 = pow (10.0, -3.0) * pow(2.0,-15.0) * AC4 ; - b1 = pow (160.0, 2.0) * pow(2.0,-30.0) * VB1 ; - c5 = (pow (2.0, -15.0) / 160.0) * AC5 ; - c6 = AC6 ; - mc = (pow (2.0, 11.0) / pow(160.0,2.0)) * MC ; - md = MD / 160.0 ; - x0 = AC1 ; - x1 = 160.0 * pow (2.0, -13.0) * AC2 ; - x2 = pow (160.0, 2.0) * pow(2.0,-25.0) * VB2 ; - yy0 = c4 * pow (2.0, 15.0) ; - yy1 = c4 * c3 ; - yy2 = c4 * b1 ; - p0 = (3791.0 - 8.0) / 1600.0 ; - p1 = 1.0 - 7357.0 * pow (2.0, -20.0) ; - p2 = 3038.0 * 100.0 * pow (2.0, -36.0) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/bmp180.h b/FlippR-Driver/src/lib/wiringPi/bmp180.h deleted file mode 100644 index 4a6d13a..0000000 --- a/FlippR-Driver/src/lib/wiringPi/bmp180.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bmp180.h: - * Extend wiringPi with the BMP180 I2C Pressure and Temperature - * sensor. - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int bmp180Setup (const int pinBase) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/drcNet.c b/FlippR-Driver/src/lib/wiringPi/drcNet.c deleted file mode 100644 index 0964ff7..0000000 --- a/FlippR-Driver/src/lib/wiringPi/drcNet.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * drcNet.h: - * Extend wiringPi with the DRC Network protocol (e.g. to another Pi) - * Copyright (c) 2016-2017 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "wiringPi.h" -#include "drcNet.h" -#include "../wiringPiD/drcNetCmd.h" - - -/* - * remoteReadline: - * Read in a line of data from the remote server, ending with a newline - * character which is not stored. Returns the length or < 0 on - * any sort of failure. - ********************************************************************************* - */ - -static int remoteReadline (int fd, char *buf, int max) -{ - int len = 0 ; - char c ; - - for (;;) - { - if (read (fd, &c, 1) < 1) - return -1 ; - - if (c == '\n') - return len ; - - *buf++ = c ; - if (++len == max) - return len ; - } -} - - -/* - * getChallenge: - * Read in lines from the remote site until we get one identified - * as the challenge. This line contains the password salt. - ********************************************************************************* - */ - -static char *getChallenge (int fd) -{ - static char buf [1024] ; - int num ; - - for (;;) - { - if ((num = remoteReadline (fd, buf, 1023)) < 0) - return NULL ; - buf [num] = 0 ; - - if (strncmp (buf, "Challenge ", 10) == 0) - return &buf [10] ; - } -} - - -/* - * authenticate: - * Read in the challenge from the server, use it to encrypt our password - * and send it back to the server. Wait for a reply back from the server - * to say that we're good to go. - * The server will simply disconnect on a bad response. No 3 chances here. - ********************************************************************************* - */ - -static int authenticate (int fd, const char *pass) -{ - char *challenge ; - char *encrypted ; - char salted [1024] ; - - if ((challenge = getChallenge (fd)) == NULL) - return -1 ; - - sprintf (salted, "$6$%s$", challenge) ; - encrypted = crypt (pass, salted) ; - -// This is an assertion, or sanity check on my part... -// The '20' comes from the $6$ then the 16 characters of the salt, -// then the terminating $. - - if (strncmp (encrypted, salted, 20) != 0) - { - errno = EBADE ; - return -1 ; - } - -// 86 characters is the length of the SHA-256 hash - - if (write (fd, encrypted + 20, 86) == 86) - return 0 ; - else - return -1 ; -} - - -/* - * _drcSetupNet: - * Do the hard work of establishing a network connection and authenticating - * the password. - ********************************************************************************* - */ - -int _drcSetupNet (const char *ipAddress, const char *port, const char *password) -{ - struct addrinfo hints; - struct addrinfo *result, *rp ; - struct in6_addr serveraddr ; - int remoteFd ; - -// Start by seeing if we've been given a (textual) numeric IP address -// which will save lookups in getaddrinfo() - - memset (&hints, 0, sizeof (hints)) ; - hints.ai_flags = AI_NUMERICSERV ; - hints.ai_family = AF_UNSPEC ; - hints.ai_socktype = SOCK_STREAM ; - hints.ai_protocol = 0 ; - - if (inet_pton (AF_INET, ipAddress, &serveraddr) == 1) // Valid IPv4 - { - hints.ai_family = AF_INET ; - hints.ai_flags |= AI_NUMERICHOST ; - } - else - { - if (inet_pton (AF_INET6, ipAddress, &serveraddr) == 1) // Valid IPv6 - { - hints.ai_family = AF_INET6 ; - hints.ai_flags |= AI_NUMERICHOST ; - } - } - -// Now use getaddrinfo() with the newly supplied hints - - if (getaddrinfo (ipAddress, port, &hints, &result) != 0) - return -1 ; - -// Now try each address in-turn until we get one that connects... - - for (rp = result; rp != NULL; rp = rp->ai_next) - { - if ((remoteFd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) - continue ; - - if (connect (remoteFd, rp->ai_addr, rp->ai_addrlen) < 0) - continue ; - - if (authenticate (remoteFd, password) < 0) - { - close (remoteFd) ; - errno = EACCES ; // Permission denied - return -1 ; - } - else - return remoteFd ; - } - - errno = EHOSTUNREACH ; // Host unreachable - may not be right, but good enough - return -1 ; // Nothing connected -} - - -/* - * myPinMode: - * Change the pin mode on the remote DRC device - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_PIN_MODE ; - cmd.data = mode ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - - -/* - * myPullUpDnControl: - ********************************************************************************* - */ - -static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_PULL_UP_DN ; - cmd.data = mode ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_DIGITAL_WRITE ; - cmd.data = value ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - - -/* - * myDigitalWrite8: - ********************************************************************************* - -static void myDigitalWrite8 (struct wiringPiNodeStruct *node, int pin, int value) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_DIGITAL_WRITE8 ; - cmd.data = value ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - */ - - -/* - * myAnalogWrite: - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_ANALOG_WRITE ; - cmd.data = value ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - - -/* - * myPwmWrite: - ********************************************************************************* - */ - -static void myPwmWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_PWM_WRITE ; - cmd.data = value ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; -} - - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_ANALOG_READ ; - cmd.data = 0 ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; - - return cmd.data ; -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_DIGITAL_READ ; - cmd.data = 0 ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; - - return cmd.data ; -} - - -/* - * myDigitalRead8: - ********************************************************************************* - -static unsigned int myDigitalRead8 (struct wiringPiNodeStruct *node, int pin) -{ - struct drcNetComStruct cmd ; - - cmd.pin = pin - node->pinBase ; - cmd.cmd = DRCN_DIGITAL_READ8 ; - cmd.data = 0 ; - - (void)send (node->fd, &cmd, sizeof (cmd), 0) ; - (void)recv (node->fd, &cmd, sizeof (cmd), 0) ; - - return cmd.data ; -} - */ - - -/* - * drcNet: - * Create a new instance of an DRC GPIO interface. - * Could be a variable nunber of pins here - we might not know in advance. - ********************************************************************************* - */ - -int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password) -{ - int fd, len ; - struct wiringPiNodeStruct *node ; - - if ((fd = _drcSetupNet (ipAddress, port, password)) < 0) - return FALSE ; - - len = sizeof (struct drcNetComStruct) ; - - if (setsockopt (fd, SOL_SOCKET, SO_RCVLOWAT, (void *)&len, sizeof (len)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, numPins) ; - - node->fd = fd ; - node->pinMode = myPinMode ; - node->pullUpDnControl = myPullUpDnControl ; - node->analogRead = myAnalogRead ; - node->analogRead = myAnalogRead ; - node->analogWrite = myAnalogWrite ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; -//node->digitalRead8 = myDigitalRead8 ; -//node->digitalWrite8 = myDigitalWrite8 ; - node->pwmWrite = myPwmWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/drcNet.h b/FlippR-Driver/src/lib/wiringPi/drcNet.h deleted file mode 100644 index 00f9b05..0000000 --- a/FlippR-Driver/src/lib/wiringPi/drcNet.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * drcNet.h: - * Extend wiringPi with the DRC Network protocol (e.g. to another Pi) - * Copyright (c) 2016-2017 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -/********* -struct drcNetStruct -{ - uint32_t pin ; - uint32_t cmd ; - uint32_t data ; -} ; -**************/ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int drcSetupNet (const int pinBase, const int numPins, const char *ipAddress, const char *port, const char *password) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/drcSerial.c b/FlippR-Driver/src/lib/wiringPi/drcSerial.c deleted file mode 100644 index db7cc09..0000000 --- a/FlippR-Driver/src/lib/wiringPi/drcSerial.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * drcSerial.c: - * Extend wiringPi with the DRC Serial protocol (e.g. to Arduino) - * Copyright (c) 2013-2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include -#include - -#include "wiringPi.h" -#include "wiringSerial.h" - -#include "drcSerial.h" - - -/* - * myPinMode: - * Change the pin mode on the remote DRC device - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - /**/ if (mode == OUTPUT) - serialPutchar (node->fd, 'o') ; // Input - else if (mode == PWM_OUTPUT) - serialPutchar (node->fd, 'p') ; // PWM - else - serialPutchar (node->fd, 'i') ; // Default to input - - serialPutchar (node->fd, pin - node->pinBase) ; -} - - -/* - * myPullUpDnControl: - * ATmegas only have pull-up's on of off. No pull-downs. - ********************************************************************************* - */ - -static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) -{ - -// Force pin into input mode - - serialPutchar (node->fd, 'i' ) ; - serialPutchar (node->fd, pin - node->pinBase) ; - - /**/ if (mode == PUD_UP) - { - serialPutchar (node->fd, '1') ; - serialPutchar (node->fd, pin - node->pinBase) ; - } - else if (mode == PUD_OFF) - { - serialPutchar (node->fd, '0') ; - serialPutchar (node->fd, pin - node->pinBase) ; - } -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - serialPutchar (node->fd, value == 0 ? '0' : '1') ; - serialPutchar (node->fd, pin - node->pinBase) ; -} - - -/* - * myPwmWrite: - ********************************************************************************* - */ - -static void myPwmWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - serialPutchar (node->fd, 'v') ; - serialPutchar (node->fd, pin - node->pinBase) ; - serialPutchar (node->fd, value & 0xFF) ; -} - - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int vHi, vLo ; - - serialPutchar (node->fd, 'a') ; - serialPutchar (node->fd, pin - node->pinBase) ; - vHi = serialGetchar (node->fd) ; - vLo = serialGetchar (node->fd) ; - - return (vHi << 8) | vLo ; -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - serialPutchar (node->fd, 'r') ; // Send read command - serialPutchar (node->fd, pin - node->pinBase) ; - return (serialGetchar (node->fd) == '0') ? 0 : 1 ; -} - - -/* - * drcSetup: - * Create a new instance of an DRC GPIO interface. - * Could be a variable nunber of pins here - we might not know in advance - * if it's an ATmega with 14 pins, or something with less or more! - ********************************************************************************* - */ - -int drcSetupSerial (const int pinBase, const int numPins, const char *device, const int baud) -{ - int fd ; - int ok, tries ; - time_t then ; - struct wiringPiNodeStruct *node ; - - if ((fd = serialOpen (device, baud)) < 0) - return FALSE ; - - delay (10) ; // May need longer if it's an Uno that reboots on the open... - -// Flush any pending input - - while (serialDataAvail (fd)) - (void)serialGetchar (fd) ; - - ok = FALSE ; - for (tries = 1 ; (tries < 5) && (!ok) ; ++tries) - { - serialPutchar (fd, '@') ; // Ping - then = time (NULL) + 2 ; - while (time (NULL) < then) - if (serialDataAvail (fd)) - { - if (serialGetchar (fd) == '@') - { - ok = TRUE ; - break ; - } - } - } - - if (!ok) - { - serialClose (fd) ; - return FALSE ; - } - - node = wiringPiNewNode (pinBase, numPins) ; - - node->fd = fd ; - node->pinMode = myPinMode ; - node->pullUpDnControl = myPullUpDnControl ; - node->analogRead = myAnalogRead ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->pwmWrite = myPwmWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/drcSerial.h b/FlippR-Driver/src/lib/wiringPi/drcSerial.h deleted file mode 100644 index 29e988e..0000000 --- a/FlippR-Driver/src/lib/wiringPi/drcSerial.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * drcSerial.h: - * Extend wiringPi with the DRC Serial protocol (e.g. to Arduino) - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int drcSetupSerial (const int pinBase, const int numPins, const char *device, const int baud) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/ds18b20.c b/FlippR-Driver/src/lib/wiringPi/ds18b20.c deleted file mode 100644 index 533398e..0000000 --- a/FlippR-Driver/src/lib/wiringPi/ds18b20.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * ds18b20.c: - * Extend wiringPi with the DS18B20 1-Wire temperature sensor. - * This is used in the Pi Weather Station and many other places. - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "wiringPi.h" - -#include "ds18b20.h" - -#define W1_PREFIX "/sys/bus/w1/devices/28-" -#define W1_POSTFIX "/w1_slave" - - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int chan = pin - node->pinBase ; - int fd = node->fd ; - char buffer [4096] ; - char *p ; - int temp, sign ; - - if (chan != 0) - return -9999 ; - -// Rewind the file - we're keeping it open to keep things going -// smoothly - - lseek (fd, 0, SEEK_SET) ; - -// Read the file - we know it's only a couple of lines, so this ought to be -// more than enough - - if (read (fd, buffer, 4096) <= 0) // Read nothing, or it failed in some odd way - return -9998 ; - -// Look for YES, then t= - - if (strstr (buffer, "YES") == NULL) - return -9997 ; - - if ((p = strstr (buffer, "t=")) == NULL) - return -9996 ; - -// p points to the 't', so we skip over it... - - p += 2 ; - -// and extract the number -// (without caring about overflow) - - - if (*p == '-') // Negative number? - { - sign = -1 ; - ++p ; - } - else - sign = 1 ; - - temp = 0 ; - while (isdigit (*p)) - { - temp = temp * 10 + (*p - '0') ; - ++p ; - } - -// We know it returns temp * 1000, but we only really want temp * 10, so -// do a bit of rounding... - - temp = (temp + 50) / 100 ; - return temp * sign ; -} - - -/* - * ds18b20Setup: - * Create a new instance of a DS18B20 temperature sensor. - ********************************************************************************* - */ - -int ds18b20Setup (const int pinBase, const char *deviceId) -{ - int fd ; - struct wiringPiNodeStruct *node ; - char *fileName ; - -// Allocate space for the filename - - if ((fileName = malloc (strlen (W1_PREFIX) + strlen (W1_POSTFIX) + strlen (deviceId) + 1)) == NULL) - return FALSE ; - - sprintf (fileName, "%s%s%s", W1_PREFIX, deviceId, W1_POSTFIX) ; - - fd = open (fileName, O_RDONLY) ; - - free (fileName) ; - - if (fd < 0) - return FALSE ; - -// We'll keep the file open, to make access a little faster -// although it's very slow reading these things anyway )-: - - node = wiringPiNewNode (pinBase, 1) ; - - node->fd = fd ; - node->analogRead = myAnalogRead ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/ds18b20.h b/FlippR-Driver/src/lib/wiringPi/ds18b20.h deleted file mode 100644 index a9ea291..0000000 --- a/FlippR-Driver/src/lib/wiringPi/ds18b20.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * bmp180.h: - * Extend wiringPi with the BMP180 I2C Pressure and Temperature - * sensor. - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int ds18b20Setup (const int pinBase, const char *serialNum) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/htu21d.c b/FlippR-Driver/src/lib/wiringPi/htu21d.c deleted file mode 100644 index 46c0fcb..0000000 --- a/FlippR-Driver/src/lib/wiringPi/htu21d.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * htu21d.c: - * Extend wiringPi with the HTU21D I2C humidity and Temperature - * sensor. This is used in the Pi Weather station. - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" - -#include "htu21d.h" - -#define DEBUG -#undef FAKE_SENSOR - -#define I2C_ADDRESS 0x40 - -int checksum (UNU uint8_t data [4]) -{ - return TRUE ; -} - - - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int chan = pin - node->pinBase ; - int fd = node->fd ; - uint8_t data [4] ; - uint32_t sTemp, sHumid ; - double fTemp, fHumid ; - int cTemp, cHumid ; - - /**/ if (chan == 0) // Read Temperature - { - -// Send read temperature command: - - data [0] = 0xF3 ; - if (write (fd, data, 1) != 1) - return -9999 ; - -// Wait then read the data - - delay (50) ; - if (read (fd, data, 3) != 3) - return -9998 ; - - if (!checksum (data)) - return -9997 ; - -// Do the calculation - - sTemp = (data [0] << 8) | data [1] ; - fTemp = -48.85 + 175.72 * (double)sTemp / 63356.0 ; - cTemp = (int)rint (((100.0 * fTemp) + 0.5) / 10.0) ; - return cTemp ; - } - else if (chan == 1) // humidity - { -// Send read humidity command: - - data [0] = 0xF5 ; - if (write (fd, data, 1) != 1) - return -9999 ; - -// Wait then read the data - - delay (50) ; - if (read (fd, data, 3) != 3) - return -9998 ; - - if (!checksum (data)) - return -9997 ; - - sHumid = (data [0] << 8) | data [1] ; - fHumid = -6.0 + 125.0 * (double)sHumid / 65536.0 ; - cHumid = (int)rint (((100.0 * fHumid) + 0.5) / 10.0) ; - return cHumid ; - } - else - return -9999 ; -} - - -/* - * htu21dSetup: - * Create a new instance of a HTU21D I2C GPIO interface. - * This chip has a fixed I2C address, so we are not providing any - * allowance to change this. - ********************************************************************************* - */ - -int htu21dSetup (const int pinBase) -{ - int fd ; - struct wiringPiNodeStruct *node ; - uint8_t data ; - int status ; - - if ((fd = wiringPiI2CSetup (I2C_ADDRESS)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 2) ; - - node->fd = fd ; - node->analogRead = myAnalogRead ; - -// Send a reset code to it: - - data = 0xFE ; - if (write (fd, &data, 1) != 1) - return FALSE ; - - delay (15) ; - -// Read the status register to check it's really there - - status = wiringPiI2CReadReg8 (fd, 0xE7) ; - - return (status == 0x02) ? TRUE : FALSE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/htu21d.h b/FlippR-Driver/src/lib/wiringPi/htu21d.h deleted file mode 100644 index 3965c54..0000000 --- a/FlippR-Driver/src/lib/wiringPi/htu21d.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * htu21d.h: - * Extend wiringPi with the HTU21D I2C Humidity and Temperature - * sensor. - * Copyright (c) 2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int htu21dSetup (const int pinBase) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/max31855.c b/FlippR-Driver/src/lib/wiringPi/max31855.c deleted file mode 100644 index d86cabd..0000000 --- a/FlippR-Driver/src/lib/wiringPi/max31855.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * max31855.c: - * Extend wiringPi with the max31855 SPI Analog to Digital convertor - * Copyright (c) 2012-2015 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include -#include - -#include "max31855.h" - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - uint32_t spiData ; - int temp ; - int chan = pin - node->pinBase ; - - wiringPiSPIDataRW (node->fd, (unsigned char *)&spiData, 4) ; - - spiData = __bswap_32(spiData) ; - - switch (chan) - { - case 0: // Existing read - return raw value * 4 - spiData >>= 18 ; - temp = spiData & 0x1FFF ; // Bottom 13 bits - if ((spiData & 0x2000) != 0) // Negative - temp = -temp ; - - return temp ; - - case 1: // Return error bits - return spiData & 0x7 ; - - case 2: // Return temp in C * 10 - spiData >>= 18 ; - temp = spiData & 0x1FFF ; // Bottom 13 bits - if ((spiData & 0x2000) != 0) // Negative - temp = -temp ; - - return (int)((((double)temp * 25) + 0.5) / 10.0) ; - - case 3: // Return temp in F * 10 - spiData >>= 18 ; - temp = spiData & 0x1FFF ; // Bottom 13 bits - if ((spiData & 0x2000) != 0) // Negative - temp = -temp ; - - return (int)((((((double)temp * 0.25 * 9.0 / 5.0) + 32.0) * 100.0) + 0.5) / 10.0) ; - - default: // Who knows... - return 0 ; - - } -} - - -/* - * max31855Setup: - * Create a new wiringPi device node for an max31855 on the Pi's - * SPI interface. - ********************************************************************************* - */ - -int max31855Setup (const int pinBase, int spiChannel) -{ - struct wiringPiNodeStruct *node ; - - if (wiringPiSPISetup (spiChannel, 5000000) < 0) // 5MHz - prob 4 on the Pi - return FALSE ; - - node = wiringPiNewNode (pinBase, 4) ; - - node->fd = spiChannel ; - node->analogRead = myAnalogRead ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/max31855.h b/FlippR-Driver/src/lib/wiringPi/max31855.h deleted file mode 100644 index 385c4bd..0000000 --- a/FlippR-Driver/src/lib/wiringPi/max31855.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * max31855.c: - * Extend wiringPi with the MAX31855 SPI Thermocouple driver - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int max31855Setup (int pinBase, int spiChannel) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/max5322.c b/FlippR-Driver/src/lib/wiringPi/max5322.c deleted file mode 100644 index e56b085..0000000 --- a/FlippR-Driver/src/lib/wiringPi/max5322.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * max5322.c: - * Extend wiringPi with the MAX5322 SPI Digital to Analog convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "max5322.h" - -/* - * myAnalogWrite: - * Write analog value on the given pin - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - unsigned char spiData [2] ; - unsigned char chanBits, dataBits ; - int chan = pin - node->pinBase ; - - if (chan == 0) - chanBits = 0b01000000 ; - else - chanBits = 0b01010000 ; - - chanBits |= ((value >> 12) & 0x0F) ; - dataBits = ((value ) & 0xFF) ; - - spiData [0] = chanBits ; - spiData [1] = dataBits ; - - wiringPiSPIDataRW (node->fd, spiData, 2) ; -} - -/* - * max5322Setup: - * Create a new wiringPi device node for an max5322 on the Pi's - * SPI interface. - ********************************************************************************* - */ - -int max5322Setup (const int pinBase, int spiChannel) -{ - struct wiringPiNodeStruct *node ; - unsigned char spiData [2] ; - - if (wiringPiSPISetup (spiChannel, 8000000) < 0) // 10MHz Max - return FALSE ; - - node = wiringPiNewNode (pinBase, 2) ; - - node->fd = spiChannel ; - node->analogWrite = myAnalogWrite ; - -// Enable both DACs - - spiData [0] = 0b11100000 ; - spiData [1] = 0 ; - - wiringPiSPIDataRW (node->fd, spiData, 2) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/max5322.h b/FlippR-Driver/src/lib/wiringPi/max5322.h deleted file mode 100644 index a217cf8..0000000 --- a/FlippR-Driver/src/lib/wiringPi/max5322.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * max5322.h: - * Extend wiringPi with the MAX5322 SPI Digital to Analog convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int max5322Setup (int pinBase, int spiChannel) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23008.c b/FlippR-Driver/src/lib/wiringPi/mcp23008.c deleted file mode 100644 index 71757a8..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23008.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * mcp23008.c: - * Extend wiringPi with the MCP 23008 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" -#include "mcp23x0817.h" - -#include "mcp23008.h" - - -/* - * myPinMode: - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - reg = MCP23x08_IODIR ; - mask = 1 << (pin - node->pinBase) ; - old = wiringPiI2CReadReg8 (node->fd, reg) ; - - if (mode == OUTPUT) - old &= (~mask) ; - else - old |= mask ; - - wiringPiI2CWriteReg8 (node->fd, reg, old) ; -} - - -/* - * myPullUpDnControl: - ********************************************************************************* - */ - -static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - reg = MCP23x08_GPPU ; - mask = 1 << (pin - node->pinBase) ; - - old = wiringPiI2CReadReg8 (node->fd, reg) ; - - if (mode == PUD_UP) - old |= mask ; - else - old &= (~mask) ; - - wiringPiI2CWriteReg8 (node->fd, reg, old) ; -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int bit, old ; - - bit = 1 << ((pin - node->pinBase) & 7) ; - - old = node->data2 ; - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - wiringPiI2CWriteReg8 (node->fd, MCP23x08_GPIO, old) ; - node->data2 = old ; -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - int mask, value ; - - mask = 1 << ((pin - node->pinBase) & 7) ; - value = wiringPiI2CReadReg8 (node->fd, MCP23x08_GPIO) ; - - if ((value & mask) == 0) - return LOW ; - else - return HIGH ; -} - - -/* - * mcp23008Setup: - * Create a new instance of an MCP23008 I2C GPIO interface. We know it - * has 8 pins, so all we need to know here is the I2C address and the - * user-defined pin base. - ********************************************************************************* - */ - -int mcp23008Setup (const int pinBase, const int i2cAddress) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) - return FALSE ; - - wiringPiI2CWriteReg8 (fd, MCP23x08_IOCON, IOCON_INIT) ; - - node = wiringPiNewNode (pinBase, 8) ; - - node->fd = fd ; - node->pinMode = myPinMode ; - node->pullUpDnControl = myPullUpDnControl ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->data2 = wiringPiI2CReadReg8 (fd, MCP23x08_OLAT) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23008.h b/FlippR-Driver/src/lib/wiringPi/mcp23008.h deleted file mode 100644 index e9299a8..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23008.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 23008.h: - * Extend wiringPi with the MCP 23008 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp23008Setup (const int pinBase, const int i2cAddress) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23016.c b/FlippR-Driver/src/lib/wiringPi/mcp23016.c deleted file mode 100644 index 928d9e5..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23016.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * mcp23016.c: - * Extend wiringPi with the MCP 23016 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" -#include "mcp23016.h" - -#include "mcp23016reg.h" - - -/* - * myPinMode: - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - reg = MCP23016_IODIR0 ; - else - { - reg = MCP23016_IODIR1 ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - old = wiringPiI2CReadReg8 (node->fd, reg) ; - - if (mode == OUTPUT) - old &= (~mask) ; - else - old |= mask ; - - wiringPiI2CWriteReg8 (node->fd, reg, old) ; -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int bit, old ; - - pin -= node->pinBase ; // Pin now 0-15 - - bit = 1 << (pin & 7) ; - - if (pin < 8) // Bank A - { - old = node->data2 ; - - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - wiringPiI2CWriteReg8 (node->fd, MCP23016_GP0, old) ; - node->data2 = old ; - } - else // Bank B - { - old = node->data3 ; - - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - wiringPiI2CWriteReg8 (node->fd, MCP23016_GP1, old) ; - node->data3 = old ; - } -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - int mask, value, gpio ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - gpio = MCP23016_GP0 ; - else - { - gpio = MCP23016_GP1 ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - value = wiringPiI2CReadReg8 (node->fd, gpio) ; - - if ((value & mask) == 0) - return LOW ; - else - return HIGH ; -} - - -/* - * mcp23016Setup: - * Create a new instance of an MCP23016 I2C GPIO interface. We know it - * has 16 pins, so all we need to know here is the I2C address and the - * user-defined pin base. - ********************************************************************************* - */ - -int mcp23016Setup (const int pinBase, const int i2cAddress) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) - return FALSE ; - - wiringPiI2CWriteReg8 (fd, MCP23016_IOCON0, IOCON_INIT) ; - wiringPiI2CWriteReg8 (fd, MCP23016_IOCON1, IOCON_INIT) ; - - node = wiringPiNewNode (pinBase, 16) ; - - node->fd = fd ; - node->pinMode = myPinMode ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->data2 = wiringPiI2CReadReg8 (fd, MCP23016_OLAT0) ; - node->data3 = wiringPiI2CReadReg8 (fd, MCP23016_OLAT1) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23016.h b/FlippR-Driver/src/lib/wiringPi/mcp23016.h deleted file mode 100644 index f9b5cc5..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23016.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * mcp23016.h: - * Extend wiringPi with the MCP 23016 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp23016Setup (const int pinBase, const int i2cAddress) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23016reg.h b/FlippR-Driver/src/lib/wiringPi/mcp23016reg.h deleted file mode 100644 index 9aea92d..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23016reg.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * mcp23016: - * Copyright (c) 2012-2013 Gordon Henderson - * - * Header file for code using the MCP23016 GPIO expander - * chip. - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -// MCP23016 Registers - -#define MCP23016_GP0 0x00 -#define MCP23016_GP1 0x01 -#define MCP23016_OLAT0 0x02 -#define MCP23016_OLAT1 0x03 -#define MCP23016_IPOL0 0x04 -#define MCP23016_IPOL1 0x05 -#define MCP23016_IODIR0 0x06 -#define MCP23016_IODIR1 0x07 -#define MCP23016_INTCAP0 0x08 -#define MCP23016_INTCAP1 0x09 -#define MCP23016_IOCON0 0x0A -#define MCP23016_IOCON1 0x0B - -// Bits in the IOCON register - -#define IOCON_IARES 0x01 - -// Default initialisation mode - -#define IOCON_INIT 0 diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23017.c b/FlippR-Driver/src/lib/wiringPi/mcp23017.c deleted file mode 100644 index 4c3952d..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23017.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * mcp23017.c: - * Extend wiringPi with the MCP 23017 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" -#include "mcp23x0817.h" - -#include "mcp23017.h" - - -/* - * myPinMode: - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - reg = MCP23x17_IODIRA ; - else - { - reg = MCP23x17_IODIRB ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - old = wiringPiI2CReadReg8 (node->fd, reg) ; - - if (mode == OUTPUT) - old &= (~mask) ; - else - old |= mask ; - - wiringPiI2CWriteReg8 (node->fd, reg, old) ; -} - - -/* - * myPullUpDnControl: - ********************************************************************************* - */ - -static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - reg = MCP23x17_GPPUA ; - else - { - reg = MCP23x17_GPPUB ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - old = wiringPiI2CReadReg8 (node->fd, reg) ; - - if (mode == PUD_UP) - old |= mask ; - else - old &= (~mask) ; - - wiringPiI2CWriteReg8 (node->fd, reg, old) ; -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int bit, old ; - - pin -= node->pinBase ; // Pin now 0-15 - - bit = 1 << (pin & 7) ; - - if (pin < 8) // Bank A - { - old = node->data2 ; - - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - wiringPiI2CWriteReg8 (node->fd, MCP23x17_GPIOA, old) ; - node->data2 = old ; - } - else // Bank B - { - old = node->data3 ; - - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - wiringPiI2CWriteReg8 (node->fd, MCP23x17_GPIOB, old) ; - node->data3 = old ; - } -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - int mask, value, gpio ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - gpio = MCP23x17_GPIOA ; - else - { - gpio = MCP23x17_GPIOB ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - value = wiringPiI2CReadReg8 (node->fd, gpio) ; - - if ((value & mask) == 0) - return LOW ; - else - return HIGH ; -} - - -/* - * mcp23017Setup: - * Create a new instance of an MCP23017 I2C GPIO interface. We know it - * has 16 pins, so all we need to know here is the I2C address and the - * user-defined pin base. - ********************************************************************************* - */ - -int mcp23017Setup (const int pinBase, const int i2cAddress) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) - return FALSE ; - - wiringPiI2CWriteReg8 (fd, MCP23x17_IOCON, IOCON_INIT) ; - - node = wiringPiNewNode (pinBase, 16) ; - - node->fd = fd ; - node->pinMode = myPinMode ; - node->pullUpDnControl = myPullUpDnControl ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->data2 = wiringPiI2CReadReg8 (fd, MCP23x17_OLATA) ; - node->data3 = wiringPiI2CReadReg8 (fd, MCP23x17_OLATB) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23017.h b/FlippR-Driver/src/lib/wiringPi/mcp23017.h deleted file mode 100644 index 79b4d7b..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23017.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 23017.h: - * Extend wiringPi with the MCP 23017 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp23017Setup (const int pinBase, const int i2cAddress) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s08.c b/FlippR-Driver/src/lib/wiringPi/mcp23s08.c deleted file mode 100644 index f293f3a..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23s08.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * mcp23s08.c: - * Extend wiringPi with the MCP 23s08 SPI GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "wiringPiSPI.h" -#include "mcp23x0817.h" - -#include "mcp23s08.h" - -#define MCP_SPEED 4000000 - - - -/* - * writeByte: - * Write a byte to a register on the MCP23s08 on the SPI bus. - ********************************************************************************* - */ - -static void writeByte (uint8_t spiPort, uint8_t devId, uint8_t reg, uint8_t data) -{ - uint8_t spiData [4] ; - - spiData [0] = CMD_WRITE | ((devId & 7) << 1) ; - spiData [1] = reg ; - spiData [2] = data ; - - wiringPiSPIDataRW (spiPort, spiData, 3) ; -} - -/* - * readByte: - * Read a byte from a register on the MCP23s08 on the SPI bus. - ********************************************************************************* - */ - -static uint8_t readByte (uint8_t spiPort, uint8_t devId, uint8_t reg) -{ - uint8_t spiData [4] ; - - spiData [0] = CMD_READ | ((devId & 7) << 1) ; - spiData [1] = reg ; - - wiringPiSPIDataRW (spiPort, spiData, 3) ; - - return spiData [2] ; -} - - -/* - * myPinMode: - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - reg = MCP23x08_IODIR ; - mask = 1 << (pin - node->pinBase) ; - old = readByte (node->data0, node->data1, reg) ; - - if (mode == OUTPUT) - old &= (~mask) ; - else - old |= mask ; - - writeByte (node->data0, node->data1, reg, old) ; -} - - -/* - * myPullUpDnControl: - ********************************************************************************* - */ - -static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - reg = MCP23x08_GPPU ; - mask = 1 << (pin - node->pinBase) ; - - old = readByte (node->data0, node->data1, reg) ; - - if (mode == PUD_UP) - old |= mask ; - else - old &= (~mask) ; - - writeByte (node->data0, node->data1, reg, old) ; -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int bit, old ; - - bit = 1 << ((pin - node->pinBase) & 7) ; - - old = node->data2 ; - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - writeByte (node->data0, node->data1, MCP23x08_GPIO, old) ; - node->data2 = old ; -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - int mask, value ; - - mask = 1 << ((pin - node->pinBase) & 7) ; - value = readByte (node->data0, node->data1, MCP23x08_GPIO) ; - - if ((value & mask) == 0) - return LOW ; - else - return HIGH ; -} - - -/* - * mcp23s08Setup: - * Create a new instance of an MCP23s08 SPI GPIO interface. We know it - * has 8 pins, so all we need to know here is the SPI address and the - * user-defined pin base. - ********************************************************************************* - */ - -int mcp23s08Setup (const int pinBase, const int spiPort, const int devId) -{ - struct wiringPiNodeStruct *node ; - - if (wiringPiSPISetup (spiPort, MCP_SPEED) < 0) - return FALSE ; - - writeByte (spiPort, devId, MCP23x08_IOCON, IOCON_INIT) ; - - node = wiringPiNewNode (pinBase, 8) ; - - node->data0 = spiPort ; - node->data1 = devId ; - node->pinMode = myPinMode ; - node->pullUpDnControl = myPullUpDnControl ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->data2 = readByte (spiPort, devId, MCP23x08_OLAT) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s08.h b/FlippR-Driver/src/lib/wiringPi/mcp23s08.h deleted file mode 100644 index ebf93d1..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23s08.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 23s08.h: - * Extend wiringPi with the MCP 23s08 SPI GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp23s08Setup (const int pinBase, const int spiPort, const int devId) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s17.c b/FlippR-Driver/src/lib/wiringPi/mcp23s17.c deleted file mode 100644 index 42b0358..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23s17.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * mcp23s17.c: - * Extend wiringPi with the MCP 23s17 SPI GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "wiringPiSPI.h" -#include "mcp23x0817.h" - -#include "mcp23s17.h" - -#define MCP_SPEED 4000000 - - - -/* - * writeByte: - * Write a byte to a register on the MCP23s17 on the SPI bus. - ********************************************************************************* - */ - -static void writeByte (uint8_t spiPort, uint8_t devId, uint8_t reg, uint8_t data) -{ - uint8_t spiData [4] ; - - spiData [0] = CMD_WRITE | ((devId & 7) << 1) ; - spiData [1] = reg ; - spiData [2] = data ; - - wiringPiSPIDataRW (spiPort, spiData, 3) ; -} - -/* - * readByte: - * Read a byte from a register on the MCP23s17 on the SPI bus. - ********************************************************************************* - */ - -static uint8_t readByte (uint8_t spiPort, uint8_t devId, uint8_t reg) -{ - uint8_t spiData [4] ; - - spiData [0] = CMD_READ | ((devId & 7) << 1) ; - spiData [1] = reg ; - - wiringPiSPIDataRW (spiPort, spiData, 3) ; - - return spiData [2] ; -} - - -/* - * myPinMode: - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - reg = MCP23x17_IODIRA ; - else - { - reg = MCP23x17_IODIRB ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - old = readByte (node->data0, node->data1, reg) ; - - if (mode == OUTPUT) - old &= (~mask) ; - else - old |= mask ; - - writeByte (node->data0, node->data1, reg, old) ; -} - - -/* - * myPullUpDnControl: - ********************************************************************************* - */ - -static void myPullUpDnControl (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int mask, old, reg ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - reg = MCP23x17_GPPUA ; - else - { - reg = MCP23x17_GPPUB ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - old = readByte (node->data0, node->data1, reg) ; - - if (mode == PUD_UP) - old |= mask ; - else - old &= (~mask) ; - - writeByte (node->data0, node->data1, reg, old) ; -} - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int bit, old ; - - pin -= node->pinBase ; // Pin now 0-15 - - bit = 1 << (pin & 7) ; - - if (pin < 8) // Bank A - { - old = node->data2 ; - - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - writeByte (node->data0, node->data1, MCP23x17_GPIOA, old) ; - node->data2 = old ; - } - else // Bank B - { - old = node->data3 ; - - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - writeByte (node->data0, node->data1, MCP23x17_GPIOB, old) ; - node->data3 = old ; - } -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - int mask, value, gpio ; - - pin -= node->pinBase ; - - if (pin < 8) // Bank A - gpio = MCP23x17_GPIOA ; - else - { - gpio = MCP23x17_GPIOB ; - pin &= 0x07 ; - } - - mask = 1 << pin ; - value = readByte (node->data0, node->data1, gpio) ; - - if ((value & mask) == 0) - return LOW ; - else - return HIGH ; -} - - -/* - * mcp23s17Setup: - * Create a new instance of an MCP23s17 SPI GPIO interface. We know it - * has 16 pins, so all we need to know here is the SPI address and the - * user-defined pin base. - ********************************************************************************* - */ - -int mcp23s17Setup (const int pinBase, const int spiPort, const int devId) -{ - struct wiringPiNodeStruct *node ; - - if (wiringPiSPISetup (spiPort, MCP_SPEED) < 0) - return FALSE ; - - writeByte (spiPort, devId, MCP23x17_IOCON, IOCON_INIT | IOCON_HAEN) ; - writeByte (spiPort, devId, MCP23x17_IOCONB, IOCON_INIT | IOCON_HAEN) ; - - node = wiringPiNewNode (pinBase, 16) ; - - node->data0 = spiPort ; - node->data1 = devId ; - node->pinMode = myPinMode ; - node->pullUpDnControl = myPullUpDnControl ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->data2 = readByte (spiPort, devId, MCP23x17_OLATA) ; - node->data3 = readByte (spiPort, devId, MCP23x17_OLATB) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23s17.h b/FlippR-Driver/src/lib/wiringPi/mcp23s17.h deleted file mode 100644 index 3b2a808..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23s17.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 23s17.h: - * Extend wiringPi with the MCP 23s17 SPI GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp23s17Setup (int pinBase, int spiPort, int devId) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23x08.h b/FlippR-Driver/src/lib/wiringPi/mcp23x08.h deleted file mode 100644 index c4e6b27..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23x08.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * mcp23x17: - * Copyright (c) 2012-2013 Gordon Henderson - * - * Header file for code using the MCP23x17 GPIO expander chip. - * This comes in 2 flavours: MCP23017 which has an I2C interface, - * an the MXP23S17 which has an SPI interface. - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - - -// MCP23x17 Registers - -#define IODIRA 0x00 -#define IPOLA 0x02 -#define GPINTENA 0x04 -#define DEFVALA 0x06 -#define INTCONA 0x08 -#define IOCON 0x0A -#define GPPUA 0x0C -#define INTFA 0x0E -#define INTCAPA 0x10 -#define GPIOA 0x12 -#define OLATA 0x14 - -#define IODIRB 0x01 -#define IPOLB 0x03 -#define GPINTENB 0x05 -#define DEFVALB 0x07 -#define INTCONB 0x09 -#define IOCONB 0x0B -#define GPPUB 0x0D -#define INTFB 0x0F -#define INTCAPB 0x11 -#define GPIOB 0x13 -#define OLATB 0x15 - -// Bits in the IOCON register - -#define IOCON_UNUSED 0x01 -#define IOCON_INTPOL 0x02 -#define IOCON_ODR 0x04 -#define IOCON_HAEN 0x08 -#define IOCON_DISSLW 0x10 -#define IOCON_SEQOP 0x20 -#define IOCON_MIRROR 0x40 -#define IOCON_BANK_MODE 0x80 - -// Default initialisation mode - -#define IOCON_INIT (IOCON_SEQOP) - -// SPI Command codes - -#define CMD_WRITE 0x40 -#define CMD_READ 0x41 diff --git a/FlippR-Driver/src/lib/wiringPi/mcp23x0817.h b/FlippR-Driver/src/lib/wiringPi/mcp23x0817.h deleted file mode 100644 index 58bc038..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp23x0817.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * mcp23xxx: - * Copyright (c) 2012-2013 Gordon Henderson - * - * Header file for code using the MCP23x08 and 17 GPIO expander - * chips. - * This comes in 2 flavours: MCP230xx (08/17) which has an I2C - * interface, and the MXP23Sxx (08/17) which has an SPI interface. - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -// MCP23x08 Registers - -#define MCP23x08_IODIR 0x00 -#define MCP23x08_IPOL 0x01 -#define MCP23x08_GPINTEN 0x02 -#define MCP23x08_DEFVAL 0x03 -#define MCP23x08_INTCON 0x04 -#define MCP23x08_IOCON 0x05 -#define MCP23x08_GPPU 0x06 -#define MCP23x08_INTF 0x07 -#define MCP23x08_INTCAP 0x08 -#define MCP23x08_GPIO 0x09 -#define MCP23x08_OLAT 0x0A - -// MCP23x17 Registers - -#define MCP23x17_IODIRA 0x00 -#define MCP23x17_IPOLA 0x02 -#define MCP23x17_GPINTENA 0x04 -#define MCP23x17_DEFVALA 0x06 -#define MCP23x17_INTCONA 0x08 -#define MCP23x17_IOCON 0x0A -#define MCP23x17_GPPUA 0x0C -#define MCP23x17_INTFA 0x0E -#define MCP23x17_INTCAPA 0x10 -#define MCP23x17_GPIOA 0x12 -#define MCP23x17_OLATA 0x14 - -#define MCP23x17_IODIRB 0x01 -#define MCP23x17_IPOLB 0x03 -#define MCP23x17_GPINTENB 0x05 -#define MCP23x17_DEFVALB 0x07 -#define MCP23x17_INTCONB 0x09 -#define MCP23x17_IOCONB 0x0B -#define MCP23x17_GPPUB 0x0D -#define MCP23x17_INTFB 0x0F -#define MCP23x17_INTCAPB 0x11 -#define MCP23x17_GPIOB 0x13 -#define MCP23x17_OLATB 0x15 - -// Bits in the IOCON register - -#define IOCON_UNUSED 0x01 -#define IOCON_INTPOL 0x02 -#define IOCON_ODR 0x04 -#define IOCON_HAEN 0x08 -#define IOCON_DISSLW 0x10 -#define IOCON_SEQOP 0x20 -#define IOCON_MIRROR 0x40 -#define IOCON_BANK_MODE 0x80 - -// Default initialisation mode - -#define IOCON_INIT (IOCON_SEQOP) - -// SPI Command codes - -#define CMD_WRITE 0x40 -#define CMD_READ 0x41 diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3002.c b/FlippR-Driver/src/lib/wiringPi/mcp3002.c deleted file mode 100644 index 9ebf3e4..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp3002.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * mcp3002.c: - * Extend wiringPi with the MCP3002 SPI Analog to Digital convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "mcp3002.h" - -/* - * myAnalogRead: - * Return the analog value of the given pin - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - unsigned char spiData [2] ; - unsigned char chanBits ; - int chan = pin - node->pinBase ; - - if (chan == 0) - chanBits = 0b11010000 ; - else - chanBits = 0b11110000 ; - - spiData [0] = chanBits ; - spiData [1] = 0 ; - - wiringPiSPIDataRW (node->fd, spiData, 2) ; - - return ((spiData [0] << 8) | (spiData [1] >> 1)) & 0x3FF ; -} - - -/* - * mcp3002Setup: - * Create a new wiringPi device node for an mcp3002 on the Pi's - * SPI interface. - ********************************************************************************* - */ - -int mcp3002Setup (const int pinBase, int spiChannel) -{ - struct wiringPiNodeStruct *node ; - - if (wiringPiSPISetup (spiChannel, 1000000) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 2) ; - - node->fd = spiChannel ; - node->analogRead = myAnalogRead ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3002.h b/FlippR-Driver/src/lib/wiringPi/mcp3002.h deleted file mode 100644 index 0cd727f..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp3002.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * mcp3002.c: - * Extend wiringPi with the MCP3002 SPI Analog to Digital convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp3002Setup (int pinBase, int spiChannel) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3004.c b/FlippR-Driver/src/lib/wiringPi/mcp3004.c deleted file mode 100644 index be8383e..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp3004.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * mcp3004.c: - * Extend wiringPi with the MCP3004 SPI Analog to Digital convertor - * Copyright (c) 2012-2013 Gordon Henderson - * - * Thanks also to "ShorTie" on IRC for some remote debugging help! - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "mcp3004.h" - -/* - * myAnalogRead: - * Return the analog value of the given pin - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - unsigned char spiData [3] ; - unsigned char chanBits ; - int chan = pin - node->pinBase ; - - chanBits = 0b10000000 | (chan << 4) ; - - spiData [0] = 1 ; // Start bit - spiData [1] = chanBits ; - spiData [2] = 0 ; - - wiringPiSPIDataRW (node->fd, spiData, 3) ; - - return ((spiData [1] << 8) | spiData [2]) & 0x3FF ; -} - - -/* - * mcp3004Setup: - * Create a new wiringPi device node for an mcp3004 on the Pi's - * SPI interface. - ********************************************************************************* - */ - -int mcp3004Setup (const int pinBase, int spiChannel) -{ - struct wiringPiNodeStruct *node ; - - if (wiringPiSPISetup (spiChannel, 1000000) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 8) ; - - node->fd = spiChannel ; - node->analogRead = myAnalogRead ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3004.h b/FlippR-Driver/src/lib/wiringPi/mcp3004.h deleted file mode 100644 index a07c0bf..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp3004.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * mcp3004.c: - * Extend wiringPi with the MCP3004 SPI Analog to Digital convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp3004Setup (int pinBase, int spiChannel) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3422.c b/FlippR-Driver/src/lib/wiringPi/mcp3422.c deleted file mode 100644 index be14db6..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp3422.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * mcp3422.c: - * Extend wiringPi with the MCP3422/3/4 I2C ADC chip - * This code assumes single-ended mode only. - * Tested on actual hardware: 20th Feb 2016. - * Copyright (c) 2013-2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - - -#include -#include -#include -#include -#include - -#include -#include - -#include "mcp3422.h" - - -/* - * waitForConversion: - * Common code to wait for the ADC to finish conversion - ********************************************************************************* - */ - -void waitForConversion (int fd, unsigned char *buffer, int n) -{ - for (;;) - { - read (fd, buffer, n) ; - if ((buffer [n-1] & 0x80) == 0) - break ; - delay (1) ; - } -} - -/* - * myAnalogRead: - * Read a channel from the device - ********************************************************************************* - */ - -int myAnalogRead (struct wiringPiNodeStruct *node, int chan) -{ - unsigned char config ; - unsigned char buffer [4] ; - int value = 0 ; - int realChan = (chan & 3) - node->pinBase ; - -// One-shot mode, trigger plus the other configs. - - config = 0x80 | (realChan << 5) | (node->data0 << 2) | (node->data1) ; - - wiringPiI2CWrite (node->fd, config) ; - - switch (node->data0) // Sample rate - { - case MCP3422_SR_3_75: // 18 bits - waitForConversion (node->fd, &buffer [0], 4) ; - value = ((buffer [0] & 3) << 16) | (buffer [1] << 8) | buffer [2] ; - break ; - - case MCP3422_SR_15: // 16 bits - waitForConversion (node->fd, buffer, 3) ; - value = (buffer [0] << 8) | buffer [1] ; - break ; - - case MCP3422_SR_60: // 14 bits - waitForConversion (node->fd, buffer, 3) ; - value = ((buffer [0] & 0x3F) << 8) | buffer [1] ; - break ; - - case MCP3422_SR_240: // 12 bits - default - waitForConversion (node->fd, buffer, 3) ; - value = ((buffer [0] & 0x0F) << 8) | buffer [1] ; - break ; - } - - return value ; -} - - -/* - * mcp3422Setup: - * Create a new wiringPi device node for the mcp3422 - ********************************************************************************* - */ - -int mcp3422Setup (int pinBase, int i2cAddress, int sampleRate, int gain) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 4) ; - - node->fd = fd ; - node->data0 = sampleRate ; - node->data1 = gain ; - node->analogRead = myAnalogRead ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp3422.h b/FlippR-Driver/src/lib/wiringPi/mcp3422.h deleted file mode 100644 index 72647d4..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp3422.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * mcp3422.h: - * Extend wiringPi with the MCP3422/3/4 I2C ADC chip - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#define MCP3422_SR_240 0 -#define MCP3422_SR_60 1 -#define MCP3422_SR_15 2 -#define MCP3422_SR_3_75 3 - -#define MCP3422_GAIN_1 0 -#define MCP3422_GAIN_2 1 -#define MCP3422_GAIN_4 2 -#define MCP3422_GAIN_8 3 - - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp3422Setup (int pinBase, int i2cAddress, int sampleRate, int gain) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/mcp4802.c b/FlippR-Driver/src/lib/wiringPi/mcp4802.c deleted file mode 100644 index ef104ed..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp4802.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * mcp4802.c: - * Extend wiringPi with the MCP4802 SPI Digital to Analog convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "mcp4802.h" - -/* - * myAnalogWrite: - * Write analog value on the given pin - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - unsigned char spiData [2] ; - unsigned char chanBits, dataBits ; - int chan = pin - node->pinBase ; - - if (chan == 0) - chanBits = 0x30 ; - else - chanBits = 0xB0 ; - - chanBits |= ((value >> 4) & 0x0F) ; - dataBits = ((value << 4) & 0xF0) ; - - spiData [0] = chanBits ; - spiData [1] = dataBits ; - - wiringPiSPIDataRW (node->fd, spiData, 2) ; -} - -/* - * mcp4802Setup: - * Create a new wiringPi device node for an mcp4802 on the Pi's - * SPI interface. - ********************************************************************************* - */ - -int mcp4802Setup (const int pinBase, int spiChannel) -{ - struct wiringPiNodeStruct *node ; - - if (wiringPiSPISetup (spiChannel, 1000000) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 2) ; - - node->fd = spiChannel ; - node->analogWrite = myAnalogWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/mcp4802.h b/FlippR-Driver/src/lib/wiringPi/mcp4802.h deleted file mode 100644 index effa024..0000000 --- a/FlippR-Driver/src/lib/wiringPi/mcp4802.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * mcp4802.c: - * Extend wiringPi with the MCP4802 SPI Digital to Analog convertor - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int mcp4802Setup (int pinBase, int spiChannel) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8574.c b/FlippR-Driver/src/lib/wiringPi/pcf8574.c deleted file mode 100644 index e0b686a..0000000 --- a/FlippR-Driver/src/lib/wiringPi/pcf8574.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * pcf8574.c: - * Extend wiringPi with the PCF8574 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" - -#include "pcf8574.h" - - -/* - * myPinMode: - * The PCF8574 is an odd chip - the pins are effectively bi-directional, - * however the pins should be drven high when used as an input pin... - * So, we're effectively copying digitalWrite... - ********************************************************************************* - */ - -static void myPinMode (struct wiringPiNodeStruct *node, int pin, int mode) -{ - int bit, old ; - - bit = 1 << ((pin - node->pinBase) & 7) ; - - old = node->data2 ; - if (mode == OUTPUT) - old &= (~bit) ; // Write bit to 0 - else - old |= bit ; // Write bit to 1 - - wiringPiI2CWrite (node->fd, old) ; - node->data2 = old ; -} - - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int bit, old ; - - bit = 1 << ((pin - node->pinBase) & 7) ; - - old = node->data2 ; - if (value == LOW) - old &= (~bit) ; - else - old |= bit ; - - wiringPiI2CWrite (node->fd, old) ; - node->data2 = old ; -} - - -/* - * myDigitalRead: - ********************************************************************************* - */ - -static int myDigitalRead (struct wiringPiNodeStruct *node, int pin) -{ - int mask, value ; - - mask = 1 << ((pin - node->pinBase) & 7) ; - value = wiringPiI2CRead (node->fd) ; - - if ((value & mask) == 0) - return LOW ; - else - return HIGH ; -} - - -/* - * pcf8574Setup: - * Create a new instance of a PCF8574 I2C GPIO interface. We know it - * has 8 pins, so all we need to know here is the I2C address and the - * user-defined pin base. - ********************************************************************************* - */ - -int pcf8574Setup (const int pinBase, const int i2cAddress) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 8) ; - - node->fd = fd ; - node->pinMode = myPinMode ; - node->digitalRead = myDigitalRead ; - node->digitalWrite = myDigitalWrite ; - node->data2 = wiringPiI2CRead (fd) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8574.h b/FlippR-Driver/src/lib/wiringPi/pcf8574.h deleted file mode 100644 index 8e2d818..0000000 --- a/FlippR-Driver/src/lib/wiringPi/pcf8574.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * pcf8574.h: - * Extend wiringPi with the PCF8574 I2C GPIO expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int pcf8574Setup (const int pinBase, const int i2cAddress) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8591.c b/FlippR-Driver/src/lib/wiringPi/pcf8591.c deleted file mode 100644 index 66c6255..0000000 --- a/FlippR-Driver/src/lib/wiringPi/pcf8591.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * pcf8591.c: - * Extend wiringPi with the PCF8591 I2C GPIO Analog expander chip - * The chip has 1 8-bit DAC and 4 x 8-bit ADCs - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" - -#include "pcf8591.h" - - -/* - * myAnalogWrite: - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, UNU int pin, int value) -{ - unsigned char b [2] ; - b [0] = 0x40 ; - b [1] = value & 0xFF ; - write (node->fd, b, 2) ; -} - - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int x ; - - wiringPiI2CWrite (node->fd, 0x40 | ((pin - node->pinBase) & 3)) ; - - x = wiringPiI2CRead (node->fd) ; // Throw away the first read - x = wiringPiI2CRead (node->fd) ; - - return x ; -} - - -/* - * pcf8591Setup: - * Create a new instance of a PCF8591 I2C GPIO interface. We know it - * has 4 pins, (4 analog inputs and 1 analog output which we'll shadow - * input 0) so all we need to know here is the I2C address and the - * user-defined pin base. - ********************************************************************************* - */ - -int pcf8591Setup (const int pinBase, const int i2cAddress) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (i2cAddress)) < 0) - return FALSE ; - - node = wiringPiNewNode (pinBase, 4) ; - - node->fd = fd ; - node->analogRead = myAnalogRead ; - node->analogWrite = myAnalogWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/pcf8591.h b/FlippR-Driver/src/lib/wiringPi/pcf8591.h deleted file mode 100644 index 6b44ccf..0000000 --- a/FlippR-Driver/src/lib/wiringPi/pcf8591.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * pcf8591.h: - * Extend wiringPi with the PCF8591 I2C GPIO Analog expander chip - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int pcf8591Setup (const int pinBase, const int i2cAddress) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/piHiPri.c b/FlippR-Driver/src/lib/wiringPi/piHiPri.c deleted file mode 100644 index d2f3b4e..0000000 --- a/FlippR-Driver/src/lib/wiringPi/piHiPri.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * piHiPri: - * Simple way to get your program running at high priority - * with realtime schedulling. - * - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" - - -/* - * piHiPri: - * Attempt to set a high priority schedulling for the running program - ********************************************************************************* - */ - -int piHiPri (const int pri) -{ - struct sched_param sched ; - - memset (&sched, 0, sizeof(sched)) ; - - if (pri > sched_get_priority_max (SCHED_RR)) - sched.sched_priority = sched_get_priority_max (SCHED_RR) ; - else - sched.sched_priority = pri ; - - return sched_setscheduler (0, SCHED_RR, &sched) ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/piThread.c b/FlippR-Driver/src/lib/wiringPi/piThread.c deleted file mode 100644 index b0499be..0000000 --- a/FlippR-Driver/src/lib/wiringPi/piThread.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * piThread.c: - * Provide a simplified interface to pthreads - * - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include "wiringPi.h" - -static pthread_mutex_t piMutexes [4] ; - - - -/* - * piThreadCreate: - * Create and start a thread - ********************************************************************************* - */ - -int piThreadCreate (void *(*fn)(void *)) -{ - pthread_t myThread ; - - return pthread_create (&myThread, NULL, fn, NULL) ; -} - -/* - * piLock: piUnlock: - * Activate/Deactivate a mutex. - * We're keeping things simple here and only tracking 4 mutexes which - * is more than enough for out entry-level pthread programming - ********************************************************************************* - */ - -void piLock (int key) -{ - pthread_mutex_lock (&piMutexes [key]) ; -} - -void piUnlock (int key) -{ - pthread_mutex_unlock (&piMutexes [key]) ; -} - diff --git a/FlippR-Driver/src/lib/wiringPi/pseudoPins.c b/FlippR-Driver/src/lib/wiringPi/pseudoPins.c deleted file mode 100644 index c2bf5e0..0000000 --- a/FlippR-Driver/src/lib/wiringPi/pseudoPins.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * pseudoPins.c: - * Extend wiringPi with a number of pseudo pins which can be - * digitally or analog written/read. - * - * Note: - * Just one set of pseudo pins can exist per Raspberry Pi. - * These pins are shared between all programs running on - * that Raspberry Pi. The values are also persistant as - * they live in shared RAM. This gives you a means for - * temporary variable storing/sharing between programs, - * or for other cunning things I've not thought of yet.. - * - * Copyright (c) 2012-2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#define SHARED_NAME "wiringPiPseudoPins" -#define PSEUDO_PINS 64 - -#include -#include -#include -#include -#include - -#include - -#include "pseudoPins.h" - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int *ptr = (int *)node->data0 ; - int myPin = pin - node->pinBase ; - - return *(ptr + myPin) ; -} - - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int *ptr = (int *)node->data0 ; - int myPin = pin - node->pinBase ; - - *(ptr + myPin) = value ; -} - - -/* - * pseudoPinsSetup: - * Create a new wiringPi device node for the pseudoPins driver - ********************************************************************************* - */ - -int pseudoPinsSetup (const int pinBase) -{ - struct wiringPiNodeStruct *node ; - void *ptr ; - - node = wiringPiNewNode (pinBase, PSEUDO_PINS) ; - - node->fd = shm_open (SHARED_NAME, O_CREAT | O_RDWR, 0666) ; - - if (node->fd < 0) - return FALSE ; - - if (ftruncate (node->fd, PSEUDO_PINS * sizeof (int)) < 0) - return FALSE ; - - ptr = mmap (NULL, PSEUDO_PINS * sizeof (int), PROT_READ | PROT_WRITE, MAP_SHARED, node->fd, 0) ; - - node->data0 = (unsigned int)ptr ; - - node->analogRead = myAnalogRead ; - node->analogWrite = myAnalogWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/pseudoPins.h b/FlippR-Driver/src/lib/wiringPi/pseudoPins.h deleted file mode 100644 index bef4660..0000000 --- a/FlippR-Driver/src/lib/wiringPi/pseudoPins.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * pseudoPins.h: - * Extend wiringPi with a number of pseudo pins which can be - * digitally or analog written/read. - * Copyright (c) 2012-2016 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -extern int pseudoPinsSetup (const int pinBase) ; diff --git a/FlippR-Driver/src/lib/wiringPi/rht03.c b/FlippR-Driver/src/lib/wiringPi/rht03.c deleted file mode 100644 index 1129cfd..0000000 --- a/FlippR-Driver/src/lib/wiringPi/rht03.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * rht03.c: - * Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. - * Copyright (c) 2016-2017 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include -#include - -#include "wiringPi.h" -#include "rht03.h" - -/* - * maxDetectLowHighWait: - * Wait for a transition from low to high on the bus - ********************************************************************************* - */ - -static int maxDetectLowHighWait (const int pin) -{ - struct timeval now, timeOut, timeUp ; - -// If already high then wait for pin to go low - - gettimeofday (&now, NULL) ; - timerclear (&timeOut) ; - timeOut.tv_usec = 1000 ; - timeradd (&now, &timeOut, &timeUp) ; - - while (digitalRead (pin) == HIGH) - { - gettimeofday (&now, NULL) ; - if (timercmp (&now, &timeUp, >)) - return FALSE ; - } - -// Wait for it to go HIGH - - gettimeofday (&now, NULL) ; - timerclear (&timeOut) ; - timeOut.tv_usec = 1000 ; - timeradd (&now, &timeOut, &timeUp) ; - - while (digitalRead (pin) == LOW) - { - gettimeofday (&now, NULL) ; - if (timercmp (&now, &timeUp, >)) - return FALSE ; - } - - return TRUE ; -} - - -/* - * maxDetectClockByte: - * Read in a single byte from the MaxDetect bus - ********************************************************************************* - */ - -static unsigned int maxDetectClockByte (const int pin) -{ - unsigned int byte = 0 ; - int bit ; - - for (bit = 0 ; bit < 8 ; ++bit) - { - if (!maxDetectLowHighWait (pin)) - return 0 ; - -// bit starting now - we need to time it. - - delayMicroseconds (30) ; - byte <<= 1 ; - if (digitalRead (pin) == HIGH) // It's a 1 - byte |= 1 ; - } - - return byte ; -} - - -/* - * maxDetectRead: - * Read in and return the 4 data bytes from the MaxDetect sensor. - * Return TRUE/FALSE depending on the checksum validity - ********************************************************************************* - */ - -static int maxDetectRead (const int pin, unsigned char buffer [4]) -{ - int i ; - unsigned int checksum ; - unsigned char localBuf [5] ; - struct timeval now, then, took ; - -// See how long we took - - gettimeofday (&then, NULL) ; - -// Wake up the RHT03 by pulling the data line low, then high -// Low for 10mS, high for 40uS. - - pinMode (pin, OUTPUT) ; - digitalWrite (pin, 0) ; delay (10) ; - digitalWrite (pin, 1) ; delayMicroseconds (40) ; - pinMode (pin, INPUT) ; - -// Now wait for sensor to pull pin low - - if (!maxDetectLowHighWait (pin)) - return FALSE ; - -// and read in 5 bytes (40 bits) - - for (i = 0 ; i < 5 ; ++i) - localBuf [i] = maxDetectClockByte (pin) ; - - checksum = 0 ; - for (i = 0 ; i < 4 ; ++i) - { - buffer [i] = localBuf [i] ; - checksum += localBuf [i] ; - } - checksum &= 0xFF ; - -// See how long we took - - gettimeofday (&now, NULL) ; - timersub (&now, &then, &took) ; - -// Total time to do this should be: -// 10mS + 40µS - reset -// + 80µS + 80µS - sensor doing its low -> high thing -// + 40 * (50µS + 27µS (0) or 70µS (1) ) -// = 15010µS -// so if we take more than that, we've had a scheduling interruption and the -// reading is probably bogus. - - if ((took.tv_sec != 0) || (took.tv_usec > 16000)) - return FALSE ; - - return checksum == localBuf [4] ; -} - - -/* - * myReadRHT03: - * Read the Temperature & Humidity from an RHT03 sensor - * Values returned are *10, so 123 is 12.3. - ********************************************************************************* - */ - -static int myReadRHT03 (const int pin, int *temp, int *rh) -{ - int result ; - unsigned char buffer [4] ; - -// Read ... - - result = maxDetectRead (pin, buffer) ; - - if (!result) - return FALSE ; - - *rh = (buffer [0] * 256 + buffer [1]) ; - *temp = (buffer [2] * 256 + buffer [3]) ; - - if ((*temp & 0x8000) != 0) // Negative - { - *temp &= 0x7FFF ; - *temp = -*temp ; - } - -// Discard obviously bogus readings - the checksum can't detect a 2-bit error -// (which does seem to happen - no realtime here) - - if ((*rh > 999) || (*temp > 800) || (*temp < -400)) - return FALSE ; - - return TRUE ; -} - - -/* - * myAnalogRead: - ********************************************************************************* - */ - -static int myAnalogRead (struct wiringPiNodeStruct *node, int pin) -{ - int piPin = node->fd ; - int chan = pin - node->pinBase ; - int temp = -9997 ; - int rh = -9997 ; - int try ; - - if (chan > 1) - return -9999 ; // Bad parameters - - for (try = 0 ; try < 10 ; ++try) - { - if (myReadRHT03 (piPin, &temp, &rh)) - return chan == 0 ? temp : rh ; - } - - return -9998 ; -} - - -/* - * rht03Setup: - * Create a new instance of an RHT03 temperature sensor. - ********************************************************************************* - */ - -int rht03Setup (const int pinBase, const int piPin) -{ - struct wiringPiNodeStruct *node ; - - if ((piPin & PI_GPIO_MASK) != 0) // Must be an on-board pin - return FALSE ; - -// 2 pins - temperature and humidity - - node = wiringPiNewNode (pinBase, 2) ; - - node->fd = piPin ; - node->analogRead = myAnalogRead ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/rht03.h b/FlippR-Driver/src/lib/wiringPi/rht03.h deleted file mode 100644 index 9523fbf..0000000 --- a/FlippR-Driver/src/lib/wiringPi/rht03.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * rht03.h: - * Extend wiringPi with the rht03 Maxdetect 1-Wire sensor. - * Copyright (c) 2016-2017 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -extern int rht03Setup (const int pinBase, const int devicePin) ; diff --git a/FlippR-Driver/src/lib/wiringPi/sn3218.c b/FlippR-Driver/src/lib/wiringPi/sn3218.c deleted file mode 100644 index d9b9113..0000000 --- a/FlippR-Driver/src/lib/wiringPi/sn3218.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * sn3218.c: - * Extend wiringPi with the SN3218 I2C LEd Driver - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "sn3218.h" - -/* - * myAnalogWrite: - * Write analog value on the given pin - ********************************************************************************* - */ - -static void myAnalogWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - int fd = node->fd ; - int chan = 0x01 + (pin - node->pinBase) ; - - wiringPiI2CWriteReg8 (fd, chan, value & 0xFF) ; // Value - wiringPiI2CWriteReg8 (fd, 0x16, 0x00) ; // Update -} - -/* - * sn3218Setup: - * Create a new wiringPi device node for an sn3218 on the Pi's - * SPI interface. - ********************************************************************************* - */ - -int sn3218Setup (const int pinBase) -{ - int fd ; - struct wiringPiNodeStruct *node ; - - if ((fd = wiringPiI2CSetup (0x54)) < 0) - return FALSE ; - -// Setup the chip - initialise all 18 LEDs to off - -//wiringPiI2CWriteReg8 (fd, 0x17, 0) ; // Reset - wiringPiI2CWriteReg8 (fd, 0x00, 1) ; // Not Shutdown - wiringPiI2CWriteReg8 (fd, 0x13, 0x3F) ; // Enable LEDs 0- 5 - wiringPiI2CWriteReg8 (fd, 0x14, 0x3F) ; // Enable LEDs 6-11 - wiringPiI2CWriteReg8 (fd, 0x15, 0x3F) ; // Enable LEDs 12-17 - wiringPiI2CWriteReg8 (fd, 0x16, 0x00) ; // Update - - node = wiringPiNewNode (pinBase, 18) ; - - node->fd = fd ; - node->analogWrite = myAnalogWrite ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/sn3218.h b/FlippR-Driver/src/lib/wiringPi/sn3218.h deleted file mode 100644 index 580d5f9..0000000 --- a/FlippR-Driver/src/lib/wiringPi/sn3218.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * sn3218.c: - * Extend wiringPi with the SN3218 I2C LED driver board. - * Copyright (c) 2012-2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int sn3218Setup (int pinBase) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/softPwm.c b/FlippR-Driver/src/lib/wiringPi/softPwm.c deleted file mode 100644 index d99fa00..0000000 --- a/FlippR-Driver/src/lib/wiringPi/softPwm.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * softPwm.c: - * Provide many channels of software driven PWM. - * Copyright (c) 2012-2017 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include -#include - -#include "wiringPi.h" -#include "softPwm.h" - -// MAX_PINS: -// This is more than the number of Pi pins because we can actually softPwm. -// Once upon a time I let pins on gpio expanders be softPwm'd, but it's really -// really not a good thing. - -#define MAX_PINS 64 - -// The PWM Frequency is derived from the "pulse time" below. Essentially, -// the frequency is a function of the range and this pulse time. -// The total period will be range * pulse time in µS, so a pulse time -// of 100 and a range of 100 gives a period of 100 * 100 = 10,000 µS -// which is a frequency of 100Hz. -// -// It's possible to get a higher frequency by lowering the pulse time, -// however CPU uage will skyrocket as wiringPi uses a hard-loop to time -// periods under 100µS - this is because the Linux timer calls are just -// not accurate at all, and have an overhead. -// -// Another way to increase the frequency is to reduce the range - however -// that reduces the overall output accuracy... - -#define PULSE_TIME 100 - -static volatile int marks [MAX_PINS] ; -static volatile int range [MAX_PINS] ; -static volatile pthread_t threads [MAX_PINS] ; -static volatile int newPin = -1 ; - - -/* - * softPwmThread: - * Thread to do the actual PWM output - ********************************************************************************* - */ - -static void *softPwmThread (void *arg) -{ - int pin, mark, space ; - struct sched_param param ; - - param.sched_priority = sched_get_priority_max (SCHED_RR) ; - pthread_setschedparam (pthread_self (), SCHED_RR, ¶m) ; - - pin = *((int *)arg) ; - free (arg) ; - - pin = newPin ; - newPin = -1 ; - - piHiPri (90) ; - - for (;;) - { - mark = marks [pin] ; - space = range [pin] - mark ; - - if (mark != 0) - digitalWrite (pin, HIGH) ; - delayMicroseconds (mark * 100) ; - - if (space != 0) - digitalWrite (pin, LOW) ; - delayMicroseconds (space * 100) ; - } - - return NULL ; -} - - -/* - * softPwmWrite: - * Write a PWM value to the given pin - ********************************************************************************* - */ - -void softPwmWrite (int pin, int value) -{ - if (pin < MAX_PINS) - { - /**/ if (value < 0) - value = 0 ; - else if (value > range [pin]) - value = range [pin] ; - - marks [pin] = value ; - } -} - - -/* - * softPwmCreate: - * Create a new softPWM thread. - ********************************************************************************* - */ - -int softPwmCreate (int pin, int initialValue, int pwmRange) -{ - int res ; - pthread_t myThread ; - int *passPin ; - - if (pin >= MAX_PINS) - return -1 ; - - if (range [pin] != 0) // Already running on this pin - return -1 ; - - if (pwmRange <= 0) - return -1 ; - - passPin = malloc (sizeof (*passPin)) ; - if (passPin == NULL) - return -1 ; - - digitalWrite (pin, LOW) ; - pinMode (pin, OUTPUT) ; - - marks [pin] = initialValue ; - range [pin] = pwmRange ; - - *passPin = pin ; - newPin = pin ; - res = pthread_create (&myThread, NULL, softPwmThread, (void *)passPin) ; - - while (newPin != -1) - delay (1) ; - - threads [pin] = myThread ; - - return res ; -} - - -/* - * softPwmStop: - * Stop an existing softPWM thread - ********************************************************************************* - */ - -void softPwmStop (int pin) -{ - if (pin < MAX_PINS) - { - if (range [pin] != 0) - { - pthread_cancel (threads [pin]) ; - pthread_join (threads [pin], NULL) ; - range [pin] = 0 ; - digitalWrite (pin, LOW) ; - } - } -} diff --git a/FlippR-Driver/src/lib/wiringPi/softPwm.h b/FlippR-Driver/src/lib/wiringPi/softPwm.h deleted file mode 100644 index 0351da5..0000000 --- a/FlippR-Driver/src/lib/wiringPi/softPwm.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * softPwm.h: - * Provide 2 channels of software driven PWM. - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int softPwmCreate (int pin, int value, int range) ; -extern void softPwmWrite (int pin, int value) ; -extern void softPwmStop (int pin) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/softServo.c b/FlippR-Driver/src/lib/wiringPi/softServo.c deleted file mode 100644 index 9de9f4f..0000000 --- a/FlippR-Driver/src/lib/wiringPi/softServo.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * softServo.c: - * Provide N channels of software driven PWM suitable for RC - * servo motors. - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -//#include -#include -#include -#include -#include - -#include "wiringPi.h" -#include "softServo.h" - -// RC Servo motors are a bit of an oddity - designed in the days when -// radio control was experimental and people were tryin to make -// things as simple as possible as it was all very expensive... -// -// So... To drive an RC Servo motor, you need to send it a modified PWM -// signal - it needs anything from 1ms to 2ms - with 1ms meaning -// to move the server fully left, and 2ms meaning to move it fully -// right. Then you need a long gap before sending the next pulse. -// The reason for this is that you send a multiplexed stream of these -// pulses up the radio signal into the reciever which de-multiplexes -// them into the signals for each individual servo. Typically there -// might be 8 channels, so you need at least 8 "slots" of 2mS pulses -// meaning the entire frame must fit into a 16mS slot - which would -// then be repeated... -// -// In practice we have a total slot width of about 20mS - so we're sending 50 -// updates per second to each servo. -// -// In this code, we don't need to be too fussy about the gap as we're not doing -// the multipexing, but it does need to be at least 10mS, and preferably 16 -// from what I've been able to determine. - -// WARNING: -// This code is really experimental. It was written in response to some people -// asking for a servo driver, however while it works, there is too much -// jitter to successfully drive a small servo - I have tried it with a micro -// servo and it worked, but the servo ran hot due to the jitter in the signal -// being sent to it. -// -// If you want servo control for the Pi, then use the servoblaster kernel -// module. - -#define MAX_SERVOS 8 - -static int pinMap [MAX_SERVOS] ; // Keep track of our pins -static int pulseWidth [MAX_SERVOS] ; // microseconds - - -/* - * softServoThread: - * Thread to do the actual Servo PWM output - ********************************************************************************* - */ - -static PI_THREAD (softServoThread) -{ - register int i, j, k, m, tmp ; - int lastDelay, pin, servo ; - - int myDelays [MAX_SERVOS] ; - int myPins [MAX_SERVOS] ; - - struct timeval tNow, tStart, tPeriod, tGap, tTotal ; - struct timespec tNs ; - - tTotal.tv_sec = 0 ; - tTotal.tv_usec = 8000 ; - - piHiPri (50) ; - - for (;;) - { - gettimeofday (&tStart, NULL) ; - - memcpy (myDelays, pulseWidth, sizeof (myDelays)) ; - memcpy (myPins, pinMap, sizeof (myPins)) ; - -// Sort the delays (& pins), shortest first - - for (m = MAX_SERVOS / 2 ; m > 0 ; m /= 2 ) - for (j = m ; j < MAX_SERVOS ; ++j) - for (i = j - m ; i >= 0 ; i -= m) - { - k = i + m ; - if (myDelays [k] >= myDelays [i]) - break ; - else // Swap - { - tmp = myDelays [i] ; myDelays [i] = myDelays [k] ; myDelays [k] = tmp ; - tmp = myPins [i] ; myPins [i] = myPins [k] ; myPins [k] = tmp ; - } - } - -// All on - - lastDelay = 0 ; - for (servo = 0 ; servo < MAX_SERVOS ; ++servo) - { - if ((pin = myPins [servo]) == -1) - continue ; - - digitalWrite (pin, HIGH) ; - myDelays [servo] = myDelays [servo] - lastDelay ; - lastDelay += myDelays [servo] ; - } - -// Now loop, turning them all off as required - - for (servo = 0 ; servo < MAX_SERVOS ; ++servo) - { - if ((pin = myPins [servo]) == -1) - continue ; - - delayMicroseconds (myDelays [servo]) ; - digitalWrite (pin, LOW) ; - } - -// Wait until the end of an 8mS time-slot - - gettimeofday (&tNow, NULL) ; - timersub (&tNow, &tStart, &tPeriod) ; - timersub (&tTotal, &tPeriod, &tGap) ; - tNs.tv_sec = tGap.tv_sec ; - tNs.tv_nsec = tGap.tv_usec * 1000 ; - nanosleep (&tNs, NULL) ; - } - - return NULL ; -} - - -/* - * softServoWrite: - * Write a Servo value to the given pin - ********************************************************************************* - */ - -void softServoWrite (int servoPin, int value) -{ - int servo ; - - servoPin &= 63 ; - - /**/ if (value < -250) - value = -250 ; - else if (value > 1250) - value = 1250 ; - - for (servo = 0 ; servo < MAX_SERVOS ; ++servo) - if (pinMap [servo] == servoPin) - pulseWidth [servo] = value + 1000 ; // uS -} - - -/* - * softServoSetup: - * Setup the software servo system - ********************************************************************************* - */ - -int softServoSetup (int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7) -{ - int servo ; - - if (p0 != -1) { pinMode (p0, OUTPUT) ; digitalWrite (p0, LOW) ; } - if (p1 != -1) { pinMode (p1, OUTPUT) ; digitalWrite (p1, LOW) ; } - if (p2 != -1) { pinMode (p2, OUTPUT) ; digitalWrite (p2, LOW) ; } - if (p3 != -1) { pinMode (p3, OUTPUT) ; digitalWrite (p3, LOW) ; } - if (p4 != -1) { pinMode (p4, OUTPUT) ; digitalWrite (p4, LOW) ; } - if (p5 != -1) { pinMode (p5, OUTPUT) ; digitalWrite (p5, LOW) ; } - if (p6 != -1) { pinMode (p6, OUTPUT) ; digitalWrite (p6, LOW) ; } - if (p7 != -1) { pinMode (p7, OUTPUT) ; digitalWrite (p7, LOW) ; } - - pinMap [0] = p0 ; - pinMap [1] = p1 ; - pinMap [2] = p2 ; - pinMap [3] = p3 ; - pinMap [4] = p4 ; - pinMap [5] = p5 ; - pinMap [6] = p6 ; - pinMap [7] = p7 ; - - for (servo = 0 ; servo < MAX_SERVOS ; ++servo) - pulseWidth [servo] = 1500 ; // Mid point - - return piThreadCreate (softServoThread) ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/softServo.h b/FlippR-Driver/src/lib/wiringPi/softServo.h deleted file mode 100644 index 794cf55..0000000 --- a/FlippR-Driver/src/lib/wiringPi/softServo.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * softServo.h: - * Provide N channels of software driven PWM suitable for RC - * servo motors. - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern void softServoWrite (int pin, int value) ; -extern int softServoSetup (int p0, int p1, int p2, int p3, int p4, int p5, int p6, int p7) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/softTone.c b/FlippR-Driver/src/lib/wiringPi/softTone.c deleted file mode 100644 index e2fb737..0000000 --- a/FlippR-Driver/src/lib/wiringPi/softTone.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * softTone.c: - * For that authentic retro sound... - * Er... A little experiment to produce tones out of a Pi using - * one (or 2) GPIO pins and a piezeo "speaker" element. - * (Or a high impedance speaker, but don'y blame me if you blow-up - * the GPIO pins!) - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" -#include "softTone.h" - -#define MAX_PINS 64 - -#define PULSE_TIME 100 - -static int freqs [MAX_PINS] ; -static pthread_t threads [MAX_PINS] ; - -static int newPin = -1 ; - - -/* - * softToneThread: - * Thread to do the actual PWM output - ********************************************************************************* - */ - -static PI_THREAD (softToneThread) -{ - int pin, freq, halfPeriod ; - struct sched_param param ; - - param.sched_priority = sched_get_priority_max (SCHED_RR) ; - pthread_setschedparam (pthread_self (), SCHED_RR, ¶m) ; - - pin = newPin ; - newPin = -1 ; - - piHiPri (50) ; - - for (;;) - { - freq = freqs [pin] ; - if (freq == 0) - delay (1) ; - else - { - halfPeriod = 500000 / freq ; - - digitalWrite (pin, HIGH) ; - delayMicroseconds (halfPeriod) ; - - digitalWrite (pin, LOW) ; - delayMicroseconds (halfPeriod) ; - } - } - - return NULL ; -} - - -/* - * softToneWrite: - * Write a frequency value to the given pin - ********************************************************************************* - */ - -void softToneWrite (int pin, int freq) -{ - pin &= 63 ; - - /**/ if (freq < 0) - freq = 0 ; - else if (freq > 5000) // Max 5KHz - freq = 5000 ; - - freqs [pin] = freq ; -} - - -/* - * softToneCreate: - * Create a new tone thread. - ********************************************************************************* - */ - -int softToneCreate (int pin) -{ - int res ; - pthread_t myThread ; - - pinMode (pin, OUTPUT) ; - digitalWrite (pin, LOW) ; - - if (threads [pin] != 0) - return -1 ; - - freqs [pin] = 0 ; - - newPin = pin ; - res = pthread_create (&myThread, NULL, softToneThread, NULL) ; - - while (newPin != -1) - delay (1) ; - - threads [pin] = myThread ; - - return res ; -} - - -/* - * softToneStop: - * Stop an existing softTone thread - ********************************************************************************* - */ - -void softToneStop (int pin) -{ - if (threads [pin] != 0) - { - pthread_cancel (threads [pin]) ; - pthread_join (threads [pin], NULL) ; - threads [pin] = 0 ; - digitalWrite (pin, LOW) ; - } -} diff --git a/FlippR-Driver/src/lib/wiringPi/softTone.h b/FlippR-Driver/src/lib/wiringPi/softTone.h deleted file mode 100644 index a93c5af..0000000 --- a/FlippR-Driver/src/lib/wiringPi/softTone.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * softTone.c: - * For that authentic retro sound... - * Er... A little experiment to produce tones out of a Pi using - * one (or 2) GPIO pins and a piezeo "speaker" element. - * (Or a high impedance speaker, but don'y blame me if you blow-up - * the GPIO pins!) - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int softToneCreate (int pin) ; -extern void softToneStop (int pin) ; -extern void softToneWrite (int pin, int freq) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/sr595.c b/FlippR-Driver/src/lib/wiringPi/sr595.c deleted file mode 100644 index 8280618..0000000 --- a/FlippR-Driver/src/lib/wiringPi/sr595.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * sr595.c: - * Extend wiringPi with the 74x595 shift register as a GPIO - * expander chip. - * Note that the code can cope with a number of 595's - * daisy-chained together - up to 4 for now as we're storing - * the output "register" in a single unsigned int. - * - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -#include "wiringPi.h" - -#include "sr595.h" - - -/* - * myDigitalWrite: - ********************************************************************************* - */ - -static void myDigitalWrite (struct wiringPiNodeStruct *node, int pin, int value) -{ - unsigned int mask ; - int dataPin, clockPin, latchPin ; - int bit, bits, output ; - - pin -= node->pinBase ; // Normalise pin number - bits = node->pinMax - node->pinBase + 1 ; // ie. number of clock pulses - dataPin = node->data0 ; - clockPin = node->data1 ; - latchPin = node->data2 ; - output = node->data3 ; - - mask = 1 << pin ; - - if (value == LOW) - output &= (~mask) ; - else - output |= mask ; - - node->data3 = output ; - -// A low -> high latch transition copies the latch to the output pins - - digitalWrite (latchPin, LOW) ; delayMicroseconds (1) ; - for (bit = bits - 1 ; bit >= 0 ; --bit) - { - digitalWrite (dataPin, output & (1 << bit)) ; - - digitalWrite (clockPin, HIGH) ; delayMicroseconds (1) ; - digitalWrite (clockPin, LOW) ; delayMicroseconds (1) ; - } - digitalWrite (latchPin, HIGH) ; delayMicroseconds (1) ; -} - - -/* - * sr595Setup: - * Create a new instance of a 74x595 shift register GPIO expander. - ********************************************************************************* - */ - -int sr595Setup (const int pinBase, const int numPins, - const int dataPin, const int clockPin, const int latchPin) -{ - struct wiringPiNodeStruct *node ; - - node = wiringPiNewNode (pinBase, numPins) ; - - node->data0 = dataPin ; - node->data1 = clockPin ; - node->data2 = latchPin ; - node->data3 = 0 ; // Output register - node->digitalWrite = myDigitalWrite ; - -// Initialise the underlying hardware - - digitalWrite (dataPin, LOW) ; - digitalWrite (clockPin, LOW) ; - digitalWrite (latchPin, HIGH) ; - - pinMode (dataPin, OUTPUT) ; - pinMode (clockPin, OUTPUT) ; - pinMode (latchPin, OUTPUT) ; - - return TRUE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/sr595.h b/FlippR-Driver/src/lib/wiringPi/sr595.h deleted file mode 100644 index 4a26dc7..0000000 --- a/FlippR-Driver/src/lib/wiringPi/sr595.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * sr595.h: - * Extend wiringPi with the 74x595 shift registers. - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int sr595Setup (const int pinBase, const int numPins, - const int dataPin, const int clockPin, const int latchPin) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPi.c b/FlippR-Driver/src/lib/wiringPi/wiringPi.c deleted file mode 100644 index bd1a369..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringPi.c +++ /dev/null @@ -1,2373 +0,0 @@ -/* - * wiringPi: - * Arduino look-a-like Wiring library for the Raspberry Pi - * Copyright (c) 2012-2017 Gordon Henderson - * Additional code for pwmSetClock by Chris Hall - * - * Thanks to code samples from Gert Jan van Loo and the - * BCM2835 ARM Peripherals manual, however it's missing - * the clock section /grr/mutter/ - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -// Revisions: -// 19 Jul 2012: -// Moved to the LGPL -// Added an abstraction layer to the main routines to save a tiny -// bit of run-time and make the clode a little cleaner (if a little -// larger) -// Added waitForInterrupt code -// Added piHiPri code -// -// 9 Jul 2012: -// Added in support to use the /sys/class/gpio interface. -// 2 Jul 2012: -// Fixed a few more bugs to do with range-checking when in GPIO mode. -// 11 Jun 2012: -// Fixed some typos. -// Added c++ support for the .h file -// Added a new function to allow for using my "pin" numbers, or native -// GPIO pin numbers. -// Removed my busy-loop delay and replaced it with a call to delayMicroseconds -// -// 02 May 2012: -// Added in the 2 UART pins -// Change maxPins to numPins to more accurately reflect purpose - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "softPwm.h" -#include "softTone.h" - -#include "wiringPi.h" -#include "../version.h" - -// Environment Variables - -#define ENV_DEBUG "WIRINGPI_DEBUG" -#define ENV_CODES "WIRINGPI_CODES" -#define ENV_GPIOMEM "WIRINGPI_GPIOMEM" - - -// Extend wiringPi with other pin-based devices and keep track of -// them in this structure - -struct wiringPiNodeStruct *wiringPiNodes = NULL ; - -// BCM Magic - -#define BCM_PASSWORD 0x5A000000 - - -// The BCM2835 has 54 GPIO pins. -// BCM2835 data sheet, Page 90 onwards. -// There are 6 control registers, each control the functions of a block -// of 10 pins. -// Each control register has 10 sets of 3 bits per GPIO pin - the ALT values -// -// 000 = GPIO Pin X is an input -// 001 = GPIO Pin X is an output -// 100 = GPIO Pin X takes alternate function 0 -// 101 = GPIO Pin X takes alternate function 1 -// 110 = GPIO Pin X takes alternate function 2 -// 111 = GPIO Pin X takes alternate function 3 -// 011 = GPIO Pin X takes alternate function 4 -// 010 = GPIO Pin X takes alternate function 5 -// -// So the 3 bits for port X are: -// X / 10 + ((X % 10) * 3) - -// Port function select bits - -#define FSEL_INPT 0b000 -#define FSEL_OUTP 0b001 -#define FSEL_ALT0 0b100 -#define FSEL_ALT1 0b101 -#define FSEL_ALT2 0b110 -#define FSEL_ALT3 0b111 -#define FSEL_ALT4 0b011 -#define FSEL_ALT5 0b010 - -// Access from ARM Running Linux -// Taken from Gert/Doms code. Some of this is not in the manual -// that I can find )-: -// -// Updates in September 2015 - all now static variables (and apologies for the caps) -// due to the Pi v2, v3, etc. and the new /dev/gpiomem interface - -static volatile unsigned int GPIO_PADS ; -static volatile unsigned int GPIO_CLOCK_BASE ; -static volatile unsigned int GPIO_BASE ; -static volatile unsigned int GPIO_TIMER ; -static volatile unsigned int GPIO_PWM ; - -#define PAGE_SIZE (4*1024) -#define BLOCK_SIZE (4*1024) - -// PWM -// Word offsets into the PWM control region - -#define PWM_CONTROL 0 -#define PWM_STATUS 1 -#define PWM0_RANGE 4 -#define PWM0_DATA 5 -#define PWM1_RANGE 8 -#define PWM1_DATA 9 - -// Clock regsiter offsets - -#define PWMCLK_CNTL 40 -#define PWMCLK_DIV 41 - -#define PWM0_MS_MODE 0x0080 // Run in MS mode -#define PWM0_USEFIFO 0x0020 // Data from FIFO -#define PWM0_REVPOLAR 0x0010 // Reverse polarity -#define PWM0_OFFSTATE 0x0008 // Ouput Off state -#define PWM0_REPEATFF 0x0004 // Repeat last value if FIFO empty -#define PWM0_SERIAL 0x0002 // Run in serial mode -#define PWM0_ENABLE 0x0001 // Channel Enable - -#define PWM1_MS_MODE 0x8000 // Run in MS mode -#define PWM1_USEFIFO 0x2000 // Data from FIFO -#define PWM1_REVPOLAR 0x1000 // Reverse polarity -#define PWM1_OFFSTATE 0x0800 // Ouput Off state -#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty -#define PWM1_SERIAL 0x0200 // Run in serial mode -#define PWM1_ENABLE 0x0100 // Channel Enable - -// Timer -// Word offsets - -#define TIMER_LOAD (0x400 >> 2) -#define TIMER_VALUE (0x404 >> 2) -#define TIMER_CONTROL (0x408 >> 2) -#define TIMER_IRQ_CLR (0x40C >> 2) -#define TIMER_IRQ_RAW (0x410 >> 2) -#define TIMER_IRQ_MASK (0x414 >> 2) -#define TIMER_RELOAD (0x418 >> 2) -#define TIMER_PRE_DIV (0x41C >> 2) -#define TIMER_COUNTER (0x420 >> 2) - -// Locals to hold pointers to the hardware - -static volatile uint32_t *gpio ; -static volatile uint32_t *pwm ; -static volatile uint32_t *clk ; -static volatile uint32_t *pads ; - -#ifdef USE_TIMER -static volatile uint32_t *timer ; -static volatile uint32_t *timerIrqRaw ; -#endif - -// Data for use with the boardId functions. -// The order of entries here to correspond with the PI_MODEL_X -// and PI_VERSION_X defines in wiringPi.h -// Only intended for the gpio command - use at your own risk! - -// piGpioBase: -// The base address of the GPIO memory mapped hardware IO - -#define GPIO_PERI_BASE_OLD 0x20000000 -#define GPIO_PERI_BASE_NEW 0x3F000000 - -static volatile unsigned int piGpioBase = 0 ; - -const char *piModelNames [16] = -{ - "Model A", // 0 - "Model B", // 1 - "Model A+", // 2 - "Model B+", // 3 - "Pi 2", // 4 - "Alpha", // 5 - "CM", // 6 - "Unknown07", // 07 - "Pi 3", // 08 - "Pi Zero", // 09 - "CM3", // 10 - "Unknown11", // 11 - "Pi Zero-W", // 12 - "Unknown13", // 13 - "Unknown14", // 14 - "Unknown15", // 15 -} ; - -const char *piRevisionNames [16] = -{ - "00", - "01", - "02", - "03", - "04", - "05", - "06", - "07", - "08", - "09", - "10", - "11", - "12", - "13", - "14", - "15", -} ; - -const char *piMakerNames [16] = -{ - "Sony", // 0 - "Egoman", // 1 - "Embest", // 2 - "Unknown", // 3 - "Embest", // 4 - "Unknown05", // 5 - "Unknown06", // 6 - "Unknown07", // 7 - "Unknown08", // 8 - "Unknown09", // 9 - "Unknown10", // 10 - "Unknown11", // 11 - "Unknown12", // 12 - "Unknown13", // 13 - "Unknown14", // 14 - "Unknown15", // 15 -} ; - -const int piMemorySize [8] = -{ - 256, // 0 - 512, // 1 - 1024, // 2 - 0, // 3 - 0, // 4 - 0, // 5 - 0, // 6 - 0, // 7 -} ; - -// Time for easy calculations - -static uint64_t epochMilli, epochMicro ; - -// Misc - -static int wiringPiMode = WPI_MODE_UNINITIALISED ; -static volatile int pinPass = -1 ; -static pthread_mutex_t pinMutex ; - -// Debugging & Return codes - -int wiringPiDebug = FALSE ; -int wiringPiReturnCodes = FALSE ; - -// Use /dev/gpiomem ? - -int wiringPiTryGpioMem = FALSE ; - -// sysFds: -// Map a file descriptor from the /sys/class/gpio/gpioX/value - -static int sysFds [64] = -{ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -} ; - -// ISR Data - -static void (*isrFunctions [64])(void) ; - - -// Doing it the Arduino way with lookup tables... -// Yes, it's probably more innefficient than all the bit-twidling, but it -// does tend to make it all a bit clearer. At least to me! - -// pinToGpio: -// Take a Wiring pin (0 through X) and re-map it to the BCM_GPIO pin -// Cope for 3 different board revisions here. - -static int *pinToGpio ; - -// Revision 1, 1.1: - -static int pinToGpioR1 [64] = -{ - 17, 18, 21, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7 - 0, 1, // I2C - SDA1, SCL1 wpi 8 - 9 - 8, 7, // SPI - CE1, CE0 wpi 10 - 11 - 10, 9, 11, // SPI - MOSI, MISO, SCLK wpi 12 - 14 - 14, 15, // UART - Tx, Rx wpi 15 - 16 - -// Padding: - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 31 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 -} ; - -// Revision 2: - -static int pinToGpioR2 [64] = -{ - 17, 18, 27, 22, 23, 24, 25, 4, // From the Original Wiki - GPIO 0 through 7: wpi 0 - 7 - 2, 3, // I2C - SDA0, SCL0 wpi 8 - 9 - 8, 7, // SPI - CE1, CE0 wpi 10 - 11 - 10, 9, 11, // SPI - MOSI, MISO, SCLK wpi 12 - 14 - 14, 15, // UART - Tx, Rx wpi 15 - 16 - 28, 29, 30, 31, // Rev 2: New GPIOs 8 though 11 wpi 17 - 20 - 5, 6, 13, 19, 26, // B+ wpi 21, 22, 23, 24, 25 - 12, 16, 20, 21, // B+ wpi 26, 27, 28, 29 - 0, 1, // B+ wpi 30, 31 - -// Padding: - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 -} ; - - -// physToGpio: -// Take a physical pin (1 through 26) and re-map it to the BCM_GPIO pin -// Cope for 2 different board revisions here. -// Also add in the P5 connector, so the P5 pins are 3,4,5,6, so 53,54,55,56 - -static int *physToGpio ; - -static int physToGpioR1 [64] = -{ - -1, // 0 - -1, -1, // 1, 2 - 0, -1, - 1, -1, - 4, 14, - -1, 15, - 17, 18, - 21, -1, - 22, 23, - -1, 24, - 10, -1, - 9, 25, - 11, 8, - -1, 7, // 25, 26 - - -1, -1, -1, -1, -1, // ... 31 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63 -} ; - -static int physToGpioR2 [64] = -{ - -1, // 0 - -1, -1, // 1, 2 - 2, -1, - 3, -1, - 4, 14, - -1, 15, - 17, 18, - 27, -1, - 22, 23, - -1, 24, - 10, -1, - 9, 25, - 11, 8, - -1, 7, // 25, 26 - -// B+ - - 0, 1, - 5, -1, - 6, 12, - 13, -1, - 19, 16, - 26, 20, - -1, 21, - -// the P5 connector on the Rev 2 boards: - - -1, -1, - -1, -1, - -1, -1, - -1, -1, - -1, -1, - 28, 29, - 30, 31, - -1, -1, - -1, -1, - -1, -1, - -1, -1, -} ; - -// gpioToGPFSEL: -// Map a BCM_GPIO pin to it's Function Selection -// control port. (GPFSEL 0-5) -// Groups of 10 - 3 bits per Function - 30 bits per port - -static uint8_t gpioToGPFSEL [] = -{ - 0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5, -} ; - - -// gpioToShift -// Define the shift up for the 3 bits per pin in each GPFSEL port - -static uint8_t gpioToShift [] = -{ - 0,3,6,9,12,15,18,21,24,27, - 0,3,6,9,12,15,18,21,24,27, - 0,3,6,9,12,15,18,21,24,27, - 0,3,6,9,12,15,18,21,24,27, - 0,3,6,9,12,15,18,21,24,27, - 0,3,6,9,12,15,18,21,24,27, -} ; - - -// gpioToGPSET: -// (Word) offset to the GPIO Set registers for each GPIO pin - -static uint8_t gpioToGPSET [] = -{ - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, -} ; - -// gpioToGPCLR: -// (Word) offset to the GPIO Clear registers for each GPIO pin - -static uint8_t gpioToGPCLR [] = -{ - 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, - 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, -} ; - - -// gpioToGPLEV: -// (Word) offset to the GPIO Input level registers for each GPIO pin - -static uint8_t gpioToGPLEV [] = -{ - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, -} ; - - -#ifdef notYetReady -// gpioToEDS -// (Word) offset to the Event Detect Status - -static uint8_t gpioToEDS [] = -{ - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, -} ; - -// gpioToREN -// (Word) offset to the Rising edge ENable register - -static uint8_t gpioToREN [] = -{ - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, -} ; - -// gpioToFEN -// (Word) offset to the Falling edgde ENable register - -static uint8_t gpioToFEN [] = -{ - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, -} ; -#endif - - -// GPPUD: -// GPIO Pin pull up/down register - -#define GPPUD 37 - -// gpioToPUDCLK -// (Word) offset to the Pull Up Down Clock regsiter - -static uint8_t gpioToPUDCLK [] = -{ - 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, - 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, -} ; - - -// gpioToPwmALT -// the ALT value to put a GPIO pin into PWM mode - -static uint8_t gpioToPwmALT [] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7 - 0, 0, 0, 0, FSEL_ALT0, FSEL_ALT0, 0, 0, // 8 -> 15 - 0, 0, FSEL_ALT5, FSEL_ALT5, 0, 0, 0, 0, // 16 -> 23 - 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 - 0, 0, 0, 0, 0, 0, 0, 0, // 32 -> 39 - FSEL_ALT0, FSEL_ALT0, 0, 0, 0, FSEL_ALT0, 0, 0, // 40 -> 47 - 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 - 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 -} ; - - -// gpioToPwmPort -// The port value to put a GPIO pin into PWM mode - -static uint8_t gpioToPwmPort [] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, // 0 -> 7 - 0, 0, 0, 0, PWM0_DATA, PWM1_DATA, 0, 0, // 8 -> 15 - 0, 0, PWM0_DATA, PWM1_DATA, 0, 0, 0, 0, // 16 -> 23 - 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 - 0, 0, 0, 0, 0, 0, 0, 0, // 32 -> 39 - PWM0_DATA, PWM1_DATA, 0, 0, 0, PWM1_DATA, 0, 0, // 40 -> 47 - 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 - 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 - -} ; - -// gpioToGpClkALT: -// ALT value to put a GPIO pin into GP Clock mode. -// On the Pi we can really only use BCM_GPIO_4 and BCM_GPIO_21 -// for clocks 0 and 1 respectively, however I'll include the full -// list for completeness - maybe one day... - -#define GPIO_CLOCK_SOURCE 1 - -// gpioToGpClkALT0: - -static uint8_t gpioToGpClkALT0 [] = -{ - 0, 0, 0, 0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0, 0, // 0 -> 7 - 0, 0, 0, 0, 0, 0, 0, 0, // 8 -> 15 - 0, 0, 0, 0, FSEL_ALT5, FSEL_ALT5, 0, 0, // 16 -> 23 - 0, 0, 0, 0, 0, 0, 0, 0, // 24 -> 31 - FSEL_ALT0, 0, FSEL_ALT0, 0, 0, 0, 0, 0, // 32 -> 39 - 0, 0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0, 0, 0, 0, // 40 -> 47 - 0, 0, 0, 0, 0, 0, 0, 0, // 48 -> 55 - 0, 0, 0, 0, 0, 0, 0, 0, // 56 -> 63 -} ; - -// gpioToClk: -// (word) Offsets to the clock Control and Divisor register - -static uint8_t gpioToClkCon [] = -{ - -1, -1, -1, -1, 28, 30, 32, -1, // 0 -> 7 - -1, -1, -1, -1, -1, -1, -1, -1, // 8 -> 15 - -1, -1, -1, -1, 28, 30, -1, -1, // 16 -> 23 - -1, -1, -1, -1, -1, -1, -1, -1, // 24 -> 31 - 28, -1, 28, -1, -1, -1, -1, -1, // 32 -> 39 - -1, -1, 28, 30, 28, -1, -1, -1, // 40 -> 47 - -1, -1, -1, -1, -1, -1, -1, -1, // 48 -> 55 - -1, -1, -1, -1, -1, -1, -1, -1, // 56 -> 63 -} ; - -static uint8_t gpioToClkDiv [] = -{ - -1, -1, -1, -1, 29, 31, 33, -1, // 0 -> 7 - -1, -1, -1, -1, -1, -1, -1, -1, // 8 -> 15 - -1, -1, -1, -1, 29, 31, -1, -1, // 16 -> 23 - -1, -1, -1, -1, -1, -1, -1, -1, // 24 -> 31 - 29, -1, 29, -1, -1, -1, -1, -1, // 32 -> 39 - -1, -1, 29, 31, 29, -1, -1, -1, // 40 -> 47 - -1, -1, -1, -1, -1, -1, -1, -1, // 48 -> 55 - -1, -1, -1, -1, -1, -1, -1, -1, // 56 -> 63 -} ; - - -/* - * Functions - ********************************************************************************* - */ - - -/* - * wiringPiFailure: - * Fail. Or not. - ********************************************************************************* - */ - -int wiringPiFailure (int fatal, const char *message, ...) -{ - va_list argp ; - char buffer [1024] ; - - if (!fatal && wiringPiReturnCodes) - return -1 ; - - va_start (argp, message) ; - vsnprintf (buffer, 1023, message, argp) ; - va_end (argp) ; - - fprintf (stderr, "%s", buffer) ; - exit (EXIT_FAILURE) ; - - return 0 ; -} - - -/* - * piGpioLayout: - * Return a number representing the hardware revision of the board. - * This is not strictly the board revision but is used to check the - * layout of the GPIO connector - and there are 2 types that we are - * really interested in here. The very earliest Pi's and the - * ones that came after that which switched some pins .... - * - * Revision 1 really means the early Model A and B's. - * Revision 2 is everything else - it covers the B, B+ and CM. - * ... and the Pi 2 - which is a B+ ++ ... - * ... and the Pi 0 - which is an A+ ... - * - * The main difference between the revision 1 and 2 system that I use here - * is the mapping of the GPIO pins. From revision 2, the Pi Foundation changed - * 3 GPIO pins on the (original) 26-way header - BCM_GPIO 22 was dropped and - * replaced with 27, and 0 + 1 - I2C bus 0 was changed to 2 + 3; I2C bus 1. - * - * Additionally, here we set the piModel2 flag too. This is again, nothing to - * do with the actual model, but the major version numbers - the GPIO base - * hardware address changed at model 2 and above (not the Zero though) - * - ********************************************************************************* - */ - -static void piGpioLayoutOops (const char *why) -{ - fprintf (stderr, "Oops: Unable to determine board revision from /proc/cpuinfo\n") ; - fprintf (stderr, " -> %s\n", why) ; - fprintf (stderr, " -> You'd best google the error to find out why.\n") ; -//fprintf (stderr, " -> http://www.raspberrypi.org/phpBB3/viewtopic.php?p=184410#p184410\n") ; - exit (EXIT_FAILURE) ; -} - -int piGpioLayout (void) -{ - FILE *cpuFd ; - char line [120] ; - char *c ; - static int gpioLayout = -1 ; - - if (gpioLayout != -1) // No point checking twice - return gpioLayout ; - - if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) - piGpioLayoutOops ("Unable to open /proc/cpuinfo") ; - -// Start by looking for the Architecture to make sure we're really running -// on a Pi. I'm getting fed-up with people whinging at me because -// they can't get it to work on weirdFruitPi boards... - - while (fgets (line, 120, cpuFd) != NULL) - if (strncmp (line, "Hardware", 8) == 0) - break ; - - if (strncmp (line, "Hardware", 8) != 0) - piGpioLayoutOops ("No \"Hardware\" line") ; - - if (wiringPiDebug) - printf ("piGpioLayout: Hardware: %s\n", line) ; - -// See if it's BCM2708 or BCM2709 or the new BCM2835. - -// OK. As of Kernel 4.8, we have BCM2835 only, regardless of model. -// However I still want to check because it will trap the cheapskates and rip- -// off merchants who want to use wiringPi on non-Raspberry Pi platforms - which -// I do not support so don't email me your bleating whinges about anything -// other than a genuine Raspberry Pi. - - if (! (strstr (line, "BCM2708") || strstr (line, "BCM2709") || strstr (line, "BCM2835"))) - { - fprintf (stderr, "Unable to determine hardware version. I see: %s,\n", line) ; - fprintf (stderr, " - expecting BCM2708, BCM2709 or BCM2835.\n") ; - fprintf (stderr, "If this is a genuine Raspberry Pi then please report this\n") ; - fprintf (stderr, "to projects@drogon.net. If this is not a Raspberry Pi then you\n") ; - fprintf (stderr, "are on your own as wiringPi is designed to support the\n") ; - fprintf (stderr, "Raspberry Pi ONLY.\n") ; - exit (EXIT_FAILURE) ; - } - -// Right - we're Probably on a Raspberry Pi. Check the revision field for the real -// hardware type -// In-future, I ought to use the device tree as there are now Pi entries in -// /proc/device-tree/ ... -// but I'll leave that for the next revision. - -// Isolate the Revision line - - rewind (cpuFd) ; - while (fgets (line, 120, cpuFd) != NULL) - if (strncmp (line, "Revision", 8) == 0) - break ; - - fclose (cpuFd) ; - - if (strncmp (line, "Revision", 8) != 0) - piGpioLayoutOops ("No \"Revision\" line") ; - -// Chomp trailing CR/NL - - for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c) - *c = 0 ; - - if (wiringPiDebug) - printf ("piGpioLayout: Revision string: %s\n", line) ; - -// Scan to the first character of the revision number - - for (c = line ; *c ; ++c) - if (*c == ':') - break ; - - if (*c != ':') - piGpioLayoutOops ("Bogus \"Revision\" line (no colon)") ; - -// Chomp spaces - - ++c ; - while (isspace (*c)) - ++c ; - - if (!isxdigit (*c)) - piGpioLayoutOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; - -// Make sure its long enough - - if (strlen (c) < 4) - piGpioLayoutOops ("Bogus revision line (too small)") ; - -// Isolate last 4 characters: (in-case of overvolting or new encoding scheme) - - c = c + strlen (c) - 4 ; - - if (wiringPiDebug) - printf ("piGpioLayout: last4Chars are: \"%s\"\n", c) ; - - if ( (strcmp (c, "0002") == 0) || (strcmp (c, "0003") == 0)) - gpioLayout = 1 ; - else - gpioLayout = 2 ; // Covers everything else from the B revision 2 to the B+, the Pi v2, v3, zero and CM's. - - if (wiringPiDebug) - printf ("piGpioLayoutOops: Returning revision: %d\n", gpioLayout) ; - - return gpioLayout ; -} - -/* - * piBoardRev: - * Deprecated, but does the same as piGpioLayout - ********************************************************************************* - */ - -int piBoardRev (void) -{ - return piGpioLayout () ; -} - - - -/* - * piBoardId: - * Return the real details of the board we have. - * - * This is undocumented and really only intended for the GPIO command. - * Use at your own risk! - * - * Seems there are some boards with 0000 in them (mistake in manufacture) - * So the distinction between boards that I can see is: - * - * 0000 - Error - * 0001 - Not used - * - * Original Pi boards: - * 0002 - Model B, Rev 1, 256MB, Egoman - * 0003 - Model B, Rev 1.1, 256MB, Egoman, Fuses/D14 removed. - * - * Newer Pi's with remapped GPIO: - * 0004 - Model B, Rev 1.2, 256MB, Sony - * 0005 - Model B, Rev 1.2, 256MB, Egoman - * 0006 - Model B, Rev 1.2, 256MB, Egoman - * - * 0007 - Model A, Rev 1.2, 256MB, Egoman - * 0008 - Model A, Rev 1.2, 256MB, Sony - * 0009 - Model A, Rev 1.2, 256MB, Egoman - * - * 000d - Model B, Rev 1.2, 512MB, Egoman (Red Pi, Blue Pi?) - * 000e - Model B, Rev 1.2, 512MB, Sony - * 000f - Model B, Rev 1.2, 512MB, Egoman - * - * 0010 - Model B+, Rev 1.2, 512MB, Sony - * 0013 - Model B+ Rev 1.2, 512MB, Embest - * 0016 - Model B+ Rev 1.2, 512MB, Sony - * 0019 - Model B+ Rev 1.2, 512MB, Egoman - * - * 0011 - Pi CM, Rev 1.1, 512MB, Sony - * 0014 - Pi CM, Rev 1.1, 512MB, Embest - * 0017 - Pi CM, Rev 1.1, 512MB, Sony - * 001a - Pi CM, Rev 1.1, 512MB, Egoman - * - * 0012 - Model A+ Rev 1.1, 256MB, Sony - * 0015 - Model A+ Rev 1.1, 512MB, Embest - * 0018 - Model A+ Rev 1.1, 256MB, Sony - * 001b - Model A+ Rev 1.1, 256MB, Egoman - * - * A small thorn is the olde style overvolting - that will add in - * 1000000 - * - * The Pi compute module has an revision of 0011 or 0014 - since we only - * check the last digit, then it's 1, therefore it'll default to not 2 or - * 3 for a Rev 1, so will appear as a Rev 2. This is fine for the most part, but - * we'll properly detect the Compute Module later and adjust accordingly. - * - * And then things changed with the introduction of the v2... - * - * For Pi v2 and subsequent models - e.g. the Zero: - * - * [USER:8] [NEW:1] [MEMSIZE:3] [MANUFACTURER:4] [PROCESSOR:4] [TYPE:8] [REV:4] - * NEW 23: will be 1 for the new scheme, 0 for the old scheme - * MEMSIZE 20: 0=256M 1=512M 2=1G - * MANUFACTURER 16: 0=SONY 1=EGOMAN 2=EMBEST - * PROCESSOR 12: 0=2835 1=2836 - * TYPE 04: 0=MODELA 1=MODELB 2=MODELA+ 3=MODELB+ 4=Pi2 MODEL B 5=ALPHA 6=CM - * REV 00: 0=REV0 1=REV1 2=REV2 - ********************************************************************************* - */ - -void piBoardId (int *model, int *rev, int *mem, int *maker, int *warranty) -{ - FILE *cpuFd ; - char line [120] ; - char *c ; - unsigned int revision ; - int bRev, bType, bProc, bMfg, bMem, bWarranty ; - -// Will deal with the properly later on - for now, lets just get it going... -// unsigned int modelNum ; - - (void)piGpioLayout () ; // Call this first to make sure all's OK. Don't care about the result. - - if ((cpuFd = fopen ("/proc/cpuinfo", "r")) == NULL) - piGpioLayoutOops ("Unable to open /proc/cpuinfo") ; - - while (fgets (line, 120, cpuFd) != NULL) - if (strncmp (line, "Revision", 8) == 0) - break ; - - fclose (cpuFd) ; - - if (strncmp (line, "Revision", 8) != 0) - piGpioLayoutOops ("No \"Revision\" line") ; - -// Chomp trailing CR/NL - - for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c) - *c = 0 ; - - if (wiringPiDebug) - printf ("piBoardId: Revision string: %s\n", line) ; - -// Need to work out if it's using the new or old encoding scheme: - -// Scan to the first character of the revision number - - for (c = line ; *c ; ++c) - if (*c == ':') - break ; - - if (*c != ':') - piGpioLayoutOops ("Bogus \"Revision\" line (no colon)") ; - -// Chomp spaces - - ++c ; - while (isspace (*c)) - ++c ; - - if (!isxdigit (*c)) - piGpioLayoutOops ("Bogus \"Revision\" line (no hex digit at start of revision)") ; - - revision = (unsigned int)strtol (c, NULL, 16) ; // Hex number with no leading 0x - -// Check for new way: - - if ((revision & (1 << 23)) != 0) // New way - { - if (wiringPiDebug) - printf ("piBoardId: New Way: revision is: 0x%08X\n", revision) ; - - bRev = (revision & (0x0F << 0)) >> 0 ; - bType = (revision & (0xFF << 4)) >> 4 ; - bProc = (revision & (0x0F << 12)) >> 12 ; // Not used for now. - bMfg = (revision & (0x0F << 16)) >> 16 ; - bMem = (revision & (0x07 << 20)) >> 20 ; - bWarranty = (revision & (0x03 << 24)) != 0 ; - - *model = bType ; - *rev = bRev ; - *mem = bMem ; - *maker = bMfg ; - *warranty = bWarranty ; - - if (wiringPiDebug) - printf ("piBoardId: rev: %d, type: %d, proc: %d, mfg: %d, mem: %d, warranty: %d\n", - bRev, bType, bProc, bMfg, bMem, bWarranty) ; - } - else // Old way - { - if (wiringPiDebug) - printf ("piBoardId: Old Way: revision is: %s\n", c) ; - - if (!isdigit (*c)) - piGpioLayoutOops ("Bogus \"Revision\" line (no digit at start of revision)") ; - -// Make sure its long enough - - if (strlen (c) < 4) - piGpioLayoutOops ("Bogus \"Revision\" line (not long enough)") ; - -// If longer than 4, we'll assume it's been overvolted - - *warranty = strlen (c) > 4 ; - -// Extract last 4 characters: - - c = c + strlen (c) - 4 ; - -// Fill out the replys as appropriate - - /**/ if (strcmp (c, "0002") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0003") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - - else if (strcmp (c, "0004") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0005") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0006") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - - else if (strcmp (c, "0007") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "0008") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_SONY ; ; } - else if (strcmp (c, "0009") == 0) { *model = PI_MODEL_A ; *rev = PI_VERSION_1_2 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - - else if (strcmp (c, "000d") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - else if (strcmp (c, "000e") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "000f") == 0) { *model = PI_MODEL_B ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - - else if (strcmp (c, "0010") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0013") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } - else if (strcmp (c, "0016") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0019") == 0) { *model = PI_MODEL_BP ; *rev = PI_VERSION_1_2 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - - else if (strcmp (c, "0011") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0014") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } - else if (strcmp (c, "0017") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "001a") == 0) { *model = PI_MODEL_CM ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EGOMAN ; } - - else if (strcmp (c, "0012") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "0015") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 1 ; *maker = PI_MAKER_EMBEST ; } - else if (strcmp (c, "0018") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_SONY ; } - else if (strcmp (c, "001b") == 0) { *model = PI_MODEL_AP ; *rev = PI_VERSION_1_1 ; *mem = 0 ; *maker = PI_MAKER_EGOMAN ; } - - else { *model = 0 ; *rev = 0 ; *mem = 0 ; *maker = 0 ; } - } -} - - - -/* - * wpiPinToGpio: - * Translate a wiringPi Pin number to native GPIO pin number. - * Provided for external support. - ********************************************************************************* - */ - -int wpiPinToGpio (int wpiPin) -{ - return pinToGpio [wpiPin & 63] ; -} - - -/* - * physPinToGpio: - * Translate a physical Pin number to native GPIO pin number. - * Provided for external support. - ********************************************************************************* - */ - -int physPinToGpio (int physPin) -{ - return physToGpio [physPin & 63] ; -} - - -/* - * setPadDrive: - * Set the PAD driver value - ********************************************************************************* - */ - -void setPadDrive (int group, int value) -{ - uint32_t wrVal ; - - if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) - { - if ((group < 0) || (group > 2)) - return ; - - wrVal = BCM_PASSWORD | 0x18 | (value & 7) ; - *(pads + group + 11) = wrVal ; - - if (wiringPiDebug) - { - printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ; - printf ("Read : %08X\n", *(pads + group + 11)) ; - } - } -} - - -/* - * getAlt: - * Returns the ALT bits for a given port. Only really of-use - * for the gpio readall command (I think) - ********************************************************************************* - */ - -int getAlt (int pin) -{ - int fSel, shift, alt ; - - pin &= 63 ; - - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return 0 ; - - fSel = gpioToGPFSEL [pin] ; - shift = gpioToShift [pin] ; - - alt = (*(gpio + fSel) >> shift) & 7 ; - - return alt ; -} - - -/* - * pwmSetMode: - * Select the native "balanced" mode, or standard mark:space mode - ********************************************************************************* - */ - -void pwmSetMode (int mode) -{ - if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) - { - if (mode == PWM_MODE_MS) - *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ; - else - *(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ; - } -} - - -/* - * pwmSetRange: - * Set the PWM range register. We set both range registers to the same - * value. If you want different in your own code, then write your own. - ********************************************************************************* - */ - -void pwmSetRange (unsigned int range) -{ - if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) - { - *(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ; - *(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ; - } -} - - -/* - * pwmSetClock: - * Set/Change the PWM clock. Originally my code, but changed - * (for the better!) by Chris Hall, - * after further study of the manual and testing with a 'scope - ********************************************************************************* - */ - -void pwmSetClock (int divisor) -{ - uint32_t pwm_control ; - divisor &= 4095 ; - - if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO)) - { - if (wiringPiDebug) - printf ("Setting to: %d. Current: 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; - - pwm_control = *(pwm + PWM_CONTROL) ; // preserve PWM_CONTROL - -// We need to stop PWM prior to stopping PWM clock in MS mode otherwise BUSY -// stays high. - - *(pwm + PWM_CONTROL) = 0 ; // Stop PWM - -// Stop PWM clock before changing divisor. The delay after this does need to -// this big (95uS occasionally fails, 100uS OK), it's almost as though the BUSY -// flag is not working properly in balanced mode. Without the delay when DIV is -// adjusted the clock sometimes switches to very slow, once slow further DIV -// adjustments do nothing and it's difficult to get out of this mode. - - *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01 ; // Stop PWM Clock - delayMicroseconds (110) ; // prevents clock going sloooow - - while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY - delayMicroseconds (1) ; - - *(clk + PWMCLK_DIV) = BCM_PASSWORD | (divisor << 12) ; - - *(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Start PWM clock - *(pwm + PWM_CONTROL) = pwm_control ; // restore PWM_CONTROL - - if (wiringPiDebug) - printf ("Set to: %d. Now : 0x%08X\n", divisor, *(clk + PWMCLK_DIV)) ; - } -} - - -/* - * gpioClockSet: - * Set the freuency on a GPIO clock pin - ********************************************************************************* - */ - -void gpioClockSet (int pin, int freq) -{ - int divi, divr, divf ; - - pin &= 63 ; - - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - divi = 19200000 / freq ; - divr = 19200000 % freq ; - divf = (int)((double)divr * 4096.0 / 19200000.0) ; - - if (divi > 4095) - divi = 4095 ; - - *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | GPIO_CLOCK_SOURCE ; // Stop GPIO Clock - while ((*(clk + gpioToClkCon [pin]) & 0x80) != 0) // ... and wait - ; - - *(clk + gpioToClkDiv [pin]) = BCM_PASSWORD | (divi << 12) | divf ; // Set dividers - *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | 0x10 | GPIO_CLOCK_SOURCE ; // Start Clock -} - - -/* - * wiringPiFindNode: - * Locate our device node - ********************************************************************************* - */ - -struct wiringPiNodeStruct *wiringPiFindNode (int pin) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - while (node != NULL) - if ((pin >= node->pinBase) && (pin <= node->pinMax)) - return node ; - else - node = node->next ; - - return NULL ; -} - - -/* - * wiringPiNewNode: - * Create a new GPIO node into the wiringPi handling system - ********************************************************************************* - */ - -static void pinModeDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode) { return ; } -static void pullUpDnControlDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud) { return ; } -static unsigned int digitalRead8Dummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return 0 ; } -static void digitalWrite8Dummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } -static int digitalReadDummy (UNU struct wiringPiNodeStruct *node, UNU int UNU pin) { return LOW ; } -static void digitalWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } -static void pwmWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } -static int analogReadDummy (UNU struct wiringPiNodeStruct *node, UNU int pin) { return 0 ; } -static void analogWriteDummy (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; } - -struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) -{ - int pin ; - struct wiringPiNodeStruct *node ; - -// Minimum pin base is 64 - - if (pinBase < 64) - (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: pinBase of %d is < 64\n", pinBase) ; - -// Check all pins in-case there is overlap: - - for (pin = pinBase ; pin < (pinBase + numPins) ; ++pin) - if (wiringPiFindNode (pin) != NULL) - (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Pin %d overlaps with existing definition\n", pin) ; - - node = (struct wiringPiNodeStruct *)calloc (sizeof (struct wiringPiNodeStruct), 1) ; // calloc zeros - if (node == NULL) - (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ; - - node->pinBase = pinBase ; - node->pinMax = pinBase + numPins - 1 ; - node->pinMode = pinModeDummy ; - node->pullUpDnControl = pullUpDnControlDummy ; - node->digitalRead = digitalReadDummy ; -//node->digitalRead8 = digitalRead8Dummy ; - node->digitalWrite = digitalWriteDummy ; -//node->digitalWrite8 = digitalWrite8Dummy ; - node->pwmWrite = pwmWriteDummy ; - node->analogRead = analogReadDummy ; - node->analogWrite = analogWriteDummy ; - node->next = wiringPiNodes ; - wiringPiNodes = node ; - - return node ; -} - - -#ifdef notYetReady -/* - * pinED01: - * pinED10: - * Enables edge-detect mode on a pin - from a 0 to a 1 or 1 to 0 - * Pin must already be in input mode with appropriate pull up/downs set. - ********************************************************************************* - */ - -void pinEnableED01Pi (int pin) -{ - pin = pinToGpio [pin & 63] ; -} -#endif - - -/* - ********************************************************************************* - * Core Functions - ********************************************************************************* - */ - -/* - * pinModeAlt: - * This is an un-documented special to let you set any pin to any mode - ********************************************************************************* - */ - -void pinModeAlt (int pin, int mode) -{ - int fSel, shift ; - - if ((pin & PI_GPIO_MASK) == 0) // On-board pin - { - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - fSel = gpioToGPFSEL [pin] ; - shift = gpioToShift [pin] ; - - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | ((mode & 0x7) << shift) ; - } -} - - -/* - * pinMode: - * Sets the mode of a pin to be input, output or PWM output - ********************************************************************************* - */ - -void pinMode (int pin, int mode) -{ - int fSel, shift, alt ; - struct wiringPiNodeStruct *node = wiringPiNodes ; - int origPin = pin ; - - if ((pin & PI_GPIO_MASK) == 0) // On-board pin - { - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - softPwmStop (origPin) ; - softToneStop (origPin) ; - - fSel = gpioToGPFSEL [pin] ; - shift = gpioToShift [pin] ; - - /**/ if (mode == INPUT) - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input - else if (mode == OUTPUT) - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ; - else if (mode == SOFT_PWM_OUTPUT) - softPwmCreate (origPin, 0, 100) ; - else if (mode == SOFT_TONE_OUTPUT) - softToneCreate (origPin) ; - else if (mode == PWM_TONE_OUTPUT) - { - pinMode (origPin, PWM_OUTPUT) ; // Call myself to enable PWM mode - pwmSetMode (PWM_MODE_MS) ; - } - else if (mode == PWM_OUTPUT) - { - if ((alt = gpioToPwmALT [pin]) == 0) // Not a hardware capable PWM pin - return ; - -// Set pin to PWM mode - - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; - delayMicroseconds (110) ; // See comments in pwmSetClockWPi - - pwmSetMode (PWM_MODE_BAL) ; // Pi default mode - pwmSetRange (1024) ; // Default range of 1024 - pwmSetClock (32) ; // 19.2 / 32 = 600KHz - Also starts the PWM - } - else if (mode == GPIO_CLOCK) - { - if ((alt = gpioToGpClkALT0 [pin]) == 0) // Not a GPIO_CLOCK pin - return ; - -// Set pin to GPIO_CLOCK mode and set the clock frequency to 100KHz - - *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (alt << shift) ; - delayMicroseconds (110) ; - gpioClockSet (pin, 100000) ; - } - } - else - { - if ((node = wiringPiFindNode (pin)) != NULL) - node->pinMode (node, pin, mode) ; - return ; - } -} - - -/* - * pullUpDownCtrl: - * Control the internal pull-up/down resistors on a GPIO pin - * The Arduino only has pull-ups and these are enabled by writing 1 - * to a port when in input mode - this paradigm doesn't quite apply - * here though. - ********************************************************************************* - */ - -void pullUpDnControl (int pin, int pud) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - { - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - *(gpio + GPPUD) = pud & 3 ; delayMicroseconds (5) ; - *(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ; - - *(gpio + GPPUD) = 0 ; delayMicroseconds (5) ; - *(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ; - } - else // Extension module - { - if ((node = wiringPiFindNode (pin)) != NULL) - node->pullUpDnControl (node, pin, pud) ; - return ; - } -} - - -/* - * digitalRead: - * Read the value of a given Pin, returning HIGH or LOW - ********************************************************************************* - */ - -int digitalRead (int pin) -{ - char c ; - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - { - /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode - { - if (sysFds [pin] == -1) - return LOW ; - - lseek (sysFds [pin], 0L, SEEK_SET) ; - read (sysFds [pin], &c, 1) ; - return (c == '0') ? LOW : HIGH ; - } - else if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return LOW ; - - if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0) - return HIGH ; - else - return LOW ; - } - else - { - if ((node = wiringPiFindNode (pin)) == NULL) - return LOW ; - return node->digitalRead (node, pin) ; - } -} - - -/* - * digitalRead8: - * Read 8-bits (a byte) from given start pin. - ********************************************************************************* - -unsigned int digitalRead8 (int pin) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - return 0 ; - else - { - if ((node = wiringPiFindNode (pin)) == NULL) - return LOW ; - return node->digitalRead8 (node, pin) ; - } -} - */ - - -/* - * digitalWrite: - * Set an output bit - ********************************************************************************* - */ - -void digitalWrite (int pin, int value) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - { - /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) // Sys mode - { - if (sysFds [pin] != -1) - { - if (value == LOW) - write (sysFds [pin], "0\n", 2) ; - else - write (sysFds [pin], "1\n", 2) ; - } - return ; - } - else if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - if (value == LOW) - *(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ; - else - *(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ; - } - else - { - if ((node = wiringPiFindNode (pin)) != NULL) - node->digitalWrite (node, pin, value) ; - } -} - - -/* - * digitalWrite8: - * Set an output 8-bit byte on the device from the given pin number - ********************************************************************************* - -void digitalWrite8 (int pin, int value) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - return ; - else - { - if ((node = wiringPiFindNode (pin)) != NULL) - node->digitalWrite8 (node, pin, value) ; - } -} - */ - - -/* - * pwmWrite: - * Set an output PWM value - ********************************************************************************* - */ - -void pwmWrite (int pin, int value) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((pin & PI_GPIO_MASK) == 0) // On-Board Pin - { - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - else if (wiringPiMode != WPI_MODE_GPIO) - return ; - - *(pwm + gpioToPwmPort [pin]) = value ; - } - else - { - if ((node = wiringPiFindNode (pin)) != NULL) - node->pwmWrite (node, pin, value) ; - } -} - - -/* - * analogRead: - * Read the analog value of a given Pin. - * There is no on-board Pi analog hardware, - * so this needs to go to a new node. - ********************************************************************************* - */ - -int analogRead (int pin) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((node = wiringPiFindNode (pin)) == NULL) - return 0 ; - else - return node->analogRead (node, pin) ; -} - - -/* - * analogWrite: - * Write the analog value to the given Pin. - * There is no on-board Pi analog hardware, - * so this needs to go to a new node. - ********************************************************************************* - */ - -void analogWrite (int pin, int value) -{ - struct wiringPiNodeStruct *node = wiringPiNodes ; - - if ((node = wiringPiFindNode (pin)) == NULL) - return ; - - node->analogWrite (node, pin, value) ; -} - - -/* - * pwmToneWrite: - * Pi Specific. - * Output the given frequency on the Pi's PWM pin - ********************************************************************************* - */ - -void pwmToneWrite (int pin, int freq) -{ - int range ; - - if (freq == 0) - pwmWrite (pin, 0) ; // Off - else - { - range = 600000 / freq ; - pwmSetRange (range) ; - pwmWrite (pin, freq / 2) ; - } -} - - - -/* - * digitalWriteByte: - * digitalReadByte: - * Pi Specific - * Write an 8-bit byte to the first 8 GPIO pins - try to do it as - * fast as possible. - * However it still needs 2 operations to set the bits, so any external - * hardware must not rely on seeing a change as there will be a change - * to set the outputs bits to zero, then another change to set the 1's - * Reading is just bit fiddling. - * These are wiringPi pin numbers 0..7, or BCM_GPIO pin numbers - * 17, 18, 22, 23, 24, 24, 4 on a Pi v1 rev 0-3 - * 17, 18, 27, 23, 24, 24, 4 on a Pi v1 rev 3 onwards or B+, 2, 3, zero - ********************************************************************************* - */ - -void digitalWriteByte (const int value) -{ - uint32_t pinSet = 0 ; - uint32_t pinClr = 0 ; - int mask = 1 ; - int pin ; - - /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) - { - for (pin = 0 ; pin < 8 ; ++pin) - { - digitalWrite (pinToGpio [pin], value & mask) ; - mask <<= 1 ; - } - return ; - } - else - { - for (pin = 0 ; pin < 8 ; ++pin) - { - if ((value & mask) == 0) - pinClr |= (1 << pinToGpio [pin]) ; - else - pinSet |= (1 << pinToGpio [pin]) ; - - mask <<= 1 ; - } - - *(gpio + gpioToGPCLR [0]) = pinClr ; - *(gpio + gpioToGPSET [0]) = pinSet ; - } -} - -unsigned int digitalReadByte (void) -{ - int pin, x ; - uint32_t raw ; - uint32_t data = 0 ; - - /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) - { - for (pin = 0 ; pin < 8 ; ++pin) - { - x = digitalRead (pinToGpio [pin]) ; - data = (data << 1) | x ; - } - } - else - { - raw = *(gpio + gpioToGPLEV [0]) ; // First bank for these pins - for (pin = 0 ; pin < 8 ; ++pin) - { - x = pinToGpio [pin] ; - data = (data << 1) | (((raw & (1 << x)) == 0) ? 0 : 1) ; - } - } - return data ; -} - - -/* - * digitalWriteByte2: - * digitalReadByte2: - * Pi Specific - * Write an 8-bit byte to the second set of 8 GPIO pins. This is marginally - * faster than the first lot as these are consecutive BCM_GPIO pin numbers. - * However they overlap with the original read/write bytes. - ********************************************************************************* - */ - -void digitalWriteByte2 (const int value) -{ - register int mask = 1 ; - register int pin ; - - /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) - { - for (pin = 20 ; pin < 28 ; ++pin) - { - digitalWrite (pin, value & mask) ; - mask <<= 1 ; - } - return ; - } - else - { - *(gpio + gpioToGPCLR [0]) = (~value & 0xFF) << 20 ; // 0x0FF00000; ILJ > CHANGE: Old causes glitch - *(gpio + gpioToGPSET [0]) = ( value & 0xFF) << 20 ; - } -} - -unsigned int digitalReadByte2 (void) -{ - int pin, x ; - uint32_t data = 0 ; - - /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS) - { - for (pin = 20 ; pin < 28 ; ++pin) - { - x = digitalRead (pin) ; - data = (data << 1) | x ; - } - } - else - data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins - - return data ; -} - - -/* - * waitForInterrupt: - * Pi Specific. - * Wait for Interrupt on a GPIO pin. - * This is actually done via the /sys/class/gpio interface regardless of - * the wiringPi access mode in-use. Maybe sometime it might get a better - * way for a bit more efficiency. - ********************************************************************************* - */ - -int waitForInterrupt (int pin, int mS) -{ - int fd, x ; - uint8_t c ; - struct pollfd polls ; - - /**/ if (wiringPiMode == WPI_MODE_PINS) - pin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - pin = physToGpio [pin] ; - - if ((fd = sysFds [pin]) == -1) - return -2 ; - -// Setup poll structure - - polls.fd = fd ; - polls.events = POLLPRI | POLLERR ; - -// Wait for it ... - - x = poll (&polls, 1, mS) ; - -// If no error, do a dummy read to clear the interrupt -// A one character read appars to be enough. - - if (x > 0) - { - lseek (fd, 0, SEEK_SET) ; // Rewind - (void)read (fd, &c, 1) ; // Read & clear - } - - return x ; -} - - -/* - * interruptHandler: - * This is a thread and gets started to wait for the interrupt we're - * hoping to catch. It will call the user-function when the interrupt - * fires. - ********************************************************************************* - */ - -static void *interruptHandler (UNU void *arg) -{ - int myPin ; - - (void)piHiPri (55) ; // Only effective if we run as root - - myPin = pinPass ; - pinPass = -1 ; - - for (;;) - if (waitForInterrupt (myPin, -1) > 0) - isrFunctions [myPin] () ; - - return NULL ; -} - - -/* - * wiringPiISR: - * Pi Specific. - * Take the details and create an interrupt handler that will do a call- - * back to the user supplied function. - ********************************************************************************* - */ - -int wiringPiISR (int pin, int mode, void (*function)(void)) -{ - pthread_t threadId ; - const char *modeS ; - char fName [64] ; - char pinS [8] ; - pid_t pid ; - int count, i ; - char c ; - int bcmGpioPin ; - - if ((pin < 0) || (pin > 63)) - return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-63 (%d)\n", pin) ; - - /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED) - return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ; - else if (wiringPiMode == WPI_MODE_PINS) - bcmGpioPin = pinToGpio [pin] ; - else if (wiringPiMode == WPI_MODE_PHYS) - bcmGpioPin = physToGpio [pin] ; - else - bcmGpioPin = pin ; - -// Now export the pin and set the right edge -// We're going to use the gpio program to do this, so it assumes -// a full installation of wiringPi. It's a bit 'clunky', but it -// is a way that will work when we're running in "Sys" mode, as -// a non-root user. (without sudo) - - if (mode != INT_EDGE_SETUP) - { - /**/ if (mode == INT_EDGE_FALLING) - modeS = "falling" ; - else if (mode == INT_EDGE_RISING) - modeS = "rising" ; - else - modeS = "both" ; - - sprintf (pinS, "%d", bcmGpioPin) ; - - if ((pid = fork ()) < 0) // Fail - return wiringPiFailure (WPI_FATAL, "wiringPiISR: fork failed: %s\n", strerror (errno)) ; - - if (pid == 0) // Child, exec - { - /**/ if (access ("/usr/local/bin/gpio", X_OK) == 0) - { - execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; - return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; - } - else if (access ("/usr/bin/gpio", X_OK) == 0) - { - execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ; - return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ; - } - else - return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ; - } - else // Parent, wait - wait (NULL) ; - } - -// Now pre-open the /sys/class node - but it may already be open if -// we are in Sys mode... - - if (sysFds [bcmGpioPin] == -1) - { - sprintf (fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin) ; - if ((sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0) - return wiringPiFailure (WPI_FATAL, "wiringPiISR: unable to open %s: %s\n", fName, strerror (errno)) ; - } - -// Clear any initial pending interrupt - - ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ; - for (i = 0 ; i < count ; ++i) - read (sysFds [bcmGpioPin], &c, 1) ; - - isrFunctions [pin] = function ; - - pthread_mutex_lock (&pinMutex) ; - pinPass = pin ; - pthread_create (&threadId, NULL, interruptHandler, NULL) ; - while (pinPass != -1) - delay (1) ; - pthread_mutex_unlock (&pinMutex) ; - - return 0 ; -} - - -/* - * initialiseEpoch: - * Initialise our start-of-time variable to be the current unix - * time in milliseconds and microseconds. - ********************************************************************************* - */ - -static void initialiseEpoch (void) -{ -#ifdef OLD_WAY - struct timeval tv ; - - gettimeofday (&tv, NULL) ; - epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ; - epochMicro = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)(tv.tv_usec) ; -#else - struct timespec ts ; - - clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ; - epochMilli = (uint64_t)ts.tv_sec * (uint64_t)1000 + (uint64_t)(ts.tv_nsec / 1000000L) ; - epochMicro = (uint64_t)ts.tv_sec * (uint64_t)1000000 + (uint64_t)(ts.tv_nsec / 1000L) ; -#endif -} - - -/* - * delay: - * Wait for some number of milliseconds - ********************************************************************************* - */ - -void delay (unsigned int howLong) -{ - struct timespec sleeper, dummy ; - - sleeper.tv_sec = (time_t)(howLong / 1000) ; - sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ; - - nanosleep (&sleeper, &dummy) ; -} - - -/* - * delayMicroseconds: - * This is somewhat intersting. It seems that on the Pi, a single call - * to nanosleep takes some 80 to 130 microseconds anyway, so while - * obeying the standards (may take longer), it's not always what we - * want! - * - * So what I'll do now is if the delay is less than 100uS we'll do it - * in a hard loop, watching a built-in counter on the ARM chip. This is - * somewhat sub-optimal in that it uses 100% CPU, something not an issue - * in a microcontroller, but under a multi-tasking, multi-user OS, it's - * wastefull, however we've no real choice )-: - * - * Plan B: It seems all might not be well with that plan, so changing it - * to use gettimeofday () and poll on that instead... - ********************************************************************************* - */ - -void delayMicrosecondsHard (unsigned int howLong) -{ - struct timeval tNow, tLong, tEnd ; - - gettimeofday (&tNow, NULL) ; - tLong.tv_sec = howLong / 1000000 ; - tLong.tv_usec = howLong % 1000000 ; - timeradd (&tNow, &tLong, &tEnd) ; - - while (timercmp (&tNow, &tEnd, <)) - gettimeofday (&tNow, NULL) ; -} - -void delayMicroseconds (unsigned int howLong) -{ - struct timespec sleeper ; - unsigned int uSecs = howLong % 1000000 ; - unsigned int wSecs = howLong / 1000000 ; - - /**/ if (howLong == 0) - return ; - else if (howLong < 100) - delayMicrosecondsHard (howLong) ; - else - { - sleeper.tv_sec = wSecs ; - sleeper.tv_nsec = (long)(uSecs * 1000L) ; - nanosleep (&sleeper, NULL) ; - } -} - - -/* - * millis: - * Return a number of milliseconds as an unsigned int. - * Wraps at 49 days. - ********************************************************************************* - */ - -unsigned int millis (void) -{ - uint64_t now ; - -#ifdef OLD_WAY - struct timeval tv ; - - gettimeofday (&tv, NULL) ; - now = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ; - -#else - struct timespec ts ; - - clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ; - now = (uint64_t)ts.tv_sec * (uint64_t)1000 + (uint64_t)(ts.tv_nsec / 1000000L) ; -#endif - - return (uint32_t)(now - epochMilli) ; -} - - -/* - * micros: - * Return a number of microseconds as an unsigned int. - * Wraps after 71 minutes. - ********************************************************************************* - */ - -unsigned int micros (void) -{ - uint64_t now ; -#ifdef OLD_WAY - struct timeval tv ; - - gettimeofday (&tv, NULL) ; - now = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)tv.tv_usec ; -#else - struct timespec ts ; - - clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ; - now = (uint64_t)ts.tv_sec * (uint64_t)1000000 + (uint64_t)(ts.tv_nsec / 1000) ; -#endif - - - return (uint32_t)(now - epochMicro) ; -} - -/* - * wiringPiVersion: - * Return our current version number - ********************************************************************************* - */ - -void wiringPiVersion (int *major, int *minor) -{ - *major = VERSION_MAJOR ; - *minor = VERSION_MINOR ; -} - - -/* - * wiringPiSetup: - * Must be called once at the start of your program execution. - * - * Default setup: Initialises the system into wiringPi Pin mode and uses the - * memory mapped hardware directly. - * - * Changed now to revert to "gpio" mode if we're running on a Compute Module. - ********************************************************************************* - */ - -int wiringPiSetup (void) -{ - int fd ; - int model, rev, mem, maker, overVolted ; - static int alreadyDoneThis = FALSE ; - -// It's actually a fatal error to call any of the wiringPiSetup routines more than once, -// (you run out of file handles!) but I'm fed-up with the useless twats who email -// me bleating that there is a bug in my code, so screw-em. - - if (alreadyDoneThis) - return 0 ; - - alreadyDoneThis = TRUE ; - - if (getenv (ENV_DEBUG) != NULL) - wiringPiDebug = TRUE ; - - if (getenv (ENV_CODES) != NULL) - wiringPiReturnCodes = TRUE ; - - if (wiringPiDebug) - printf ("wiringPi: wiringPiSetup called\n") ; - -// Get the board ID information. We're not really using the information here, -// but it will give us information like the GPIO layout scheme (2 variants -// on the older 26-pin Pi's) and the GPIO peripheral base address. -// and if we're running on a compute module, then wiringPi pin numbers -// don't really many anything, so force native BCM mode anyway. - - piBoardId (&model, &rev, &mem, &maker, &overVolted) ; - - if ((model == PI_MODEL_CM) || (model == PI_MODEL_CM3)) - wiringPiMode = WPI_MODE_GPIO ; - else - wiringPiMode = WPI_MODE_PINS ; - - /**/ if (piGpioLayout () == 1) // A, B, Rev 1, 1.1 - { - pinToGpio = pinToGpioR1 ; - physToGpio = physToGpioR1 ; - } - else // A2, B2, A+, B+, CM, Pi2, Pi3, Zero - { - pinToGpio = pinToGpioR2 ; - physToGpio = physToGpioR2 ; - } - -// ... - - switch (model) - { - case PI_MODEL_A: case PI_MODEL_B: - case PI_MODEL_AP: case PI_MODEL_BP: - case PI_ALPHA: case PI_MODEL_CM: - case PI_MODEL_ZERO: case PI_MODEL_ZERO_W: - piGpioBase = GPIO_PERI_BASE_OLD ; - break ; - - default: - piGpioBase = GPIO_PERI_BASE_NEW ; - break ; - } - -// Open the master /dev/ memory control device -// Device strategy: December 2016: -// Try /dev/mem. If that fails, then -// try /dev/gpiomem. If that fails then game over. - - if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) - { - if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) < 0) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/mem or /dev/gpiomem: %s.\n Try running with sudo?\n", strerror (errno)) ; - piGpioBase = 0 ; - } - -// Set the offsets into the memory interface. - - GPIO_PADS = piGpioBase + 0x00100000 ; - GPIO_CLOCK_BASE = piGpioBase + 0x00101000 ; - GPIO_BASE = piGpioBase + 0x00200000 ; - GPIO_TIMER = piGpioBase + 0x0000B000 ; - GPIO_PWM = piGpioBase + 0x0020C000 ; - -// Map the individual hardware components - -// GPIO: - - gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_BASE) ; - if (gpio == MAP_FAILED) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (GPIO) failed: %s\n", strerror (errno)) ; - -// PWM - - pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PWM) ; - if (pwm == MAP_FAILED) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PWM) failed: %s\n", strerror (errno)) ; - -// Clock control (needed for PWM) - - clk = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_CLOCK_BASE) ; - if (clk == MAP_FAILED) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (CLOCK) failed: %s\n", strerror (errno)) ; - -// The drive pads - - pads = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_PADS) ; - if (pads == MAP_FAILED) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (PADS) failed: %s\n", strerror (errno)) ; - -#ifdef USE_TIMER -// The system timer - - timer = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO_TIMER) ; - if (timer == MAP_FAILED) - return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: mmap (TIMER) failed: %s\n", strerror (errno)) ; - -// Set the timer to free-running, 1MHz. -// 0xF9 is 249, the timer divide is base clock / (divide+1) -// so base clock is 250MHz / 250 = 1MHz. - - *(timer + TIMER_CONTROL) = 0x0000280 ; - *(timer + TIMER_PRE_DIV) = 0x00000F9 ; - timerIrqRaw = timer + TIMER_IRQ_RAW ; -#endif - - initialiseEpoch () ; - - return 0 ; -} - - -/* - * wiringPiSetupGpio: - * Must be called once at the start of your program execution. - * - * GPIO setup: Initialises the system into GPIO Pin mode and uses the - * memory mapped hardware directly. - ********************************************************************************* - */ - -int wiringPiSetupGpio (void) -{ - (void)wiringPiSetup () ; - - if (wiringPiDebug) - printf ("wiringPi: wiringPiSetupGpio called\n") ; - - wiringPiMode = WPI_MODE_GPIO ; - - return 0 ; -} - - -/* - * wiringPiSetupPhys: - * Must be called once at the start of your program execution. - * - * Phys setup: Initialises the system into Physical Pin mode and uses the - * memory mapped hardware directly. - ********************************************************************************* - */ - -int wiringPiSetupPhys (void) -{ - (void)wiringPiSetup () ; - - if (wiringPiDebug) - printf ("wiringPi: wiringPiSetupPhys called\n") ; - - wiringPiMode = WPI_MODE_PHYS ; - - return 0 ; -} - - -/* - * wiringPiSetupSys: - * Must be called once at the start of your program execution. - * - * Initialisation (again), however this time we are using the /sys/class/gpio - * interface to the GPIO systems - slightly slower, but always usable as - * a non-root user, assuming the devices are already exported and setup correctly. - */ - -int wiringPiSetupSys (void) -{ - int pin ; - char fName [128] ; - - static int alreadyDoneThis = FALSE ; - -// It's actually a fatal error to call any of the wiringPiSetup routines more than once, -// (you run out of file handles!) but I'm fed-up with the useless twats who email -// me bleating that there is a bug in my code, so screw-em. - - if (alreadyDoneThis) - return 0 ; - - alreadyDoneThis = TRUE ; - - if (getenv (ENV_DEBUG) != NULL) - wiringPiDebug = TRUE ; - - if (getenv (ENV_CODES) != NULL) - wiringPiReturnCodes = TRUE ; - - if (wiringPiDebug) - printf ("wiringPi: wiringPiSetupSys called\n") ; - - if (piGpioLayout () == 1) - { - pinToGpio = pinToGpioR1 ; - physToGpio = physToGpioR1 ; - } - else - { - pinToGpio = pinToGpioR2 ; - physToGpio = physToGpioR2 ; - } - -// Open and scan the directory, looking for exported GPIOs, and pre-open -// the 'value' interface to speed things up for later - - for (pin = 0 ; pin < 64 ; ++pin) - { - sprintf (fName, "/sys/class/gpio/gpio%d/value", pin) ; - sysFds [pin] = open (fName, O_RDWR) ; - } - - initialiseEpoch () ; - - wiringPiMode = WPI_MODE_GPIO_SYS ; - - return 0 ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPi.h b/FlippR-Driver/src/lib/wiringPi/wiringPi.h deleted file mode 100644 index f601f13..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringPi.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * wiringPi.h: - * Arduino like Wiring library for the Raspberry Pi. - * Copyright (c) 2012-2017 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - -#ifndef __WIRING_PI_H__ -#define __WIRING_PI_H__ - -// C doesn't have true/false by default and I can never remember which -// way round they are, so ... -// (and yes, I know about stdbool.h but I like capitals for these and I'm old) - -#ifndef TRUE -# define TRUE (1==1) -# define FALSE (!TRUE) -#endif - -// GCC warning suppressor - -#define UNU __attribute__((unused)) - -// Mask for the bottom 64 pins which belong to the Raspberry Pi -// The others are available for the other devices - -#define PI_GPIO_MASK (0xFFFFFFC0) - -// Handy defines - -// wiringPi modes - -#define WPI_MODE_PINS 0 -#define WPI_MODE_GPIO 1 -#define WPI_MODE_GPIO_SYS 2 -#define WPI_MODE_PHYS 3 -#define WPI_MODE_PIFACE 4 -#define WPI_MODE_UNINITIALISED -1 - -// Pin modes - -#define INPUT 0 -#define OUTPUT 1 -#define PWM_OUTPUT 2 -#define GPIO_CLOCK 3 -#define SOFT_PWM_OUTPUT 4 -#define SOFT_TONE_OUTPUT 5 -#define PWM_TONE_OUTPUT 6 - -#define LOW 0 -#define HIGH 1 - -// Pull up/down/none - -#define PUD_OFF 0 -#define PUD_DOWN 1 -#define PUD_UP 2 - -// PWM - -#define PWM_MODE_MS 0 -#define PWM_MODE_BAL 1 - -// Interrupt levels - -#define INT_EDGE_SETUP 0 -#define INT_EDGE_FALLING 1 -#define INT_EDGE_RISING 2 -#define INT_EDGE_BOTH 3 - -// Pi model types and version numbers -// Intended for the GPIO program Use at your own risk. - -#define PI_MODEL_A 0 -#define PI_MODEL_B 1 -#define PI_MODEL_AP 2 -#define PI_MODEL_BP 3 -#define PI_MODEL_2 4 -#define PI_ALPHA 5 -#define PI_MODEL_CM 6 -#define PI_MODEL_07 7 -#define PI_MODEL_3 8 -#define PI_MODEL_ZERO 9 -#define PI_MODEL_CM3 10 -#define PI_MODEL_ZERO_W 12 - -#define PI_VERSION_1 0 -#define PI_VERSION_1_1 1 -#define PI_VERSION_1_2 2 -#define PI_VERSION_2 3 - -#define PI_MAKER_SONY 0 -#define PI_MAKER_EGOMAN 1 -#define PI_MAKER_EMBEST 2 -#define PI_MAKER_UNKNOWN 3 - -extern const char *piModelNames [16] ; -extern const char *piRevisionNames [16] ; -extern const char *piMakerNames [16] ; -extern const int piMemorySize [ 8] ; - - -// Intended for the GPIO program Use at your own risk. - -// Threads - -#define PI_THREAD(X) void *X (UNU void *dummy) - -// Failure modes - -#define WPI_FATAL (1==1) -#define WPI_ALMOST (1==2) - - -// wiringPiNodeStruct: -// This describes additional device nodes in the extended wiringPi -// 2.0 scheme of things. -// It's a simple linked list for now, but will hopefully migrate to -// a binary tree for efficiency reasons - but then again, the chances -// of more than 1 or 2 devices being added are fairly slim, so who -// knows.... - -struct wiringPiNodeStruct -{ - int pinBase ; - int pinMax ; - - int fd ; // Node specific - unsigned int data0 ; // ditto - unsigned int data1 ; // ditto - unsigned int data2 ; // ditto - unsigned int data3 ; // ditto - - void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; - void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; - int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; -//unsigned int (*digitalRead8) (struct wiringPiNodeStruct *node, int pin) ; - void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; -// void (*digitalWrite8) (struct wiringPiNodeStruct *node, int pin, int value) ; - void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; - int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; - void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; - - struct wiringPiNodeStruct *next ; -} ; - -extern struct wiringPiNodeStruct *wiringPiNodes ; - - -// Function prototypes -// c++ wrappers thanks to a comment by Nick Lott -// (and others on the Raspberry Pi forums) - -#ifdef __cplusplus -extern "C" { -#endif - -// Data - -// Internal - -extern int wiringPiFailure (int fatal, const char *message, ...) ; - -// Core wiringPi functions - -extern struct wiringPiNodeStruct *wiringPiFindNode (int pin) ; -extern struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) ; - -extern void wiringPiVersion (int *major, int *minor) ; -extern int wiringPiSetup (void) ; -extern int wiringPiSetupSys (void) ; -extern int wiringPiSetupGpio (void) ; -extern int wiringPiSetupPhys (void) ; - -extern void pinModeAlt (int pin, int mode) ; -extern void pinMode (int pin, int mode) ; -extern void pullUpDnControl (int pin, int pud) ; -extern int digitalRead (int pin) ; -extern void digitalWrite (int pin, int value) ; -extern unsigned int digitalRead8 (int pin) ; -extern void digitalWrite8 (int pin, int value) ; -extern void pwmWrite (int pin, int value) ; -extern int analogRead (int pin) ; -extern void analogWrite (int pin, int value) ; - -// PiFace specifics -// (Deprecated) - -extern int wiringPiSetupPiFace (void) ; -extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only - -// On-Board Raspberry Pi hardware specific stuff - -extern int piGpioLayout (void) ; -extern int piBoardRev (void) ; // Deprecated -extern void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) ; -extern int wpiPinToGpio (int wpiPin) ; -extern int physPinToGpio (int physPin) ; -extern void setPadDrive (int group, int value) ; -extern int getAlt (int pin) ; -extern void pwmToneWrite (int pin, int freq) ; -extern void pwmSetMode (int mode) ; -extern void pwmSetRange (unsigned int range) ; -extern void pwmSetClock (int divisor) ; -extern void gpioClockSet (int pin, int freq) ; -extern unsigned int digitalReadByte (void) ; -extern unsigned int digitalReadByte2 (void) ; -extern void digitalWriteByte (int value) ; -extern void digitalWriteByte2 (int value) ; - -// Interrupts -// (Also Pi hardware specific) - -extern int waitForInterrupt (int pin, int mS) ; -extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; - -// Threads - -extern int piThreadCreate (void *(*fn)(void *)) ; -extern void piLock (int key) ; -extern void piUnlock (int key) ; - -// Schedulling priority - -extern int piHiPri (const int pri) ; - -// Extras from arduino land - -extern void delay (unsigned int howLong) ; -extern void delayMicroseconds (unsigned int howLong) ; -extern unsigned int millis (void) ; -extern unsigned int micros (void) ; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.c b/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.c deleted file mode 100644 index b0ee5d3..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * wiringPiI2C.c: - * Simplified I2C access routines - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -/* - * Notes: - * The Linux I2C code is actually the same (almost) as the SMBus code. - * SMBus is System Management Bus - and in essentially I2C with some - * additional functionality added, and stricter controls on the electrical - * specifications, etc. however I2C does work well with it and the - * protocols work over both. - * - * I'm directly including the SMBus functions here as some Linux distros - * lack the correct header files, and also some header files are GPLv2 - * rather than the LGPL that wiringPi is released under - presumably because - * originally no-one expected I2C/SMBus to be used outside the kernel - - * however enter the Raspberry Pi with people now taking directly to I2C - * devices without going via the kernel... - * - * This may ultimately reduce the flexibility of this code, but it won't be - * hard to maintain it and keep it current, should things change. - * - * Information here gained from: kernel/Documentation/i2c/dev-interface - * as well as other online resources. - ********************************************************************************* - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wiringPi.h" -#include "wiringPiI2C.h" - -// I2C definitions - -#define I2C_SLAVE 0x0703 -#define I2C_SMBUS 0x0720 /* SMBus-level access */ - -#define I2C_SMBUS_READ 1 -#define I2C_SMBUS_WRITE 0 - -// SMBus transaction types - -#define I2C_SMBUS_QUICK 0 -#define I2C_SMBUS_BYTE 1 -#define I2C_SMBUS_BYTE_DATA 2 -#define I2C_SMBUS_WORD_DATA 3 -#define I2C_SMBUS_PROC_CALL 4 -#define I2C_SMBUS_BLOCK_DATA 5 -#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 -#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ -#define I2C_SMBUS_I2C_BLOCK_DATA 8 - -// SMBus messages - -#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ -#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ - -// Structures used in the ioctl() calls - -union i2c_smbus_data -{ - uint8_t byte ; - uint16_t word ; - uint8_t block [I2C_SMBUS_BLOCK_MAX + 2] ; // block [0] is used for length + one more for PEC -} ; - -struct i2c_smbus_ioctl_data -{ - char read_write ; - uint8_t command ; - int size ; - union i2c_smbus_data *data ; -} ; - -static inline int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data) -{ - struct i2c_smbus_ioctl_data args ; - - args.read_write = rw ; - args.command = command ; - args.size = size ; - args.data = data ; - return ioctl (fd, I2C_SMBUS, &args) ; -} - - -/* - * wiringPiI2CRead: - * Simple device read - ********************************************************************************* - */ - -int wiringPiI2CRead (int fd) -{ - union i2c_smbus_data data ; - - if (i2c_smbus_access (fd, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data)) - return -1 ; - else - return data.byte & 0xFF ; -} - - -/* - * wiringPiI2CReadReg8: wiringPiI2CReadReg16: - * Read an 8 or 16-bit value from a regsiter on the device - ********************************************************************************* - */ - -int wiringPiI2CReadReg8 (int fd, int reg) -{ - union i2c_smbus_data data; - - if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data)) - return -1 ; - else - return data.byte & 0xFF ; -} - -int wiringPiI2CReadReg16 (int fd, int reg) -{ - union i2c_smbus_data data; - - if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_WORD_DATA, &data)) - return -1 ; - else - return data.word & 0xFFFF ; -} - - -/* - * wiringPiI2CWrite: - * Simple device write - ********************************************************************************* - */ - -int wiringPiI2CWrite (int fd, int data) -{ - return i2c_smbus_access (fd, I2C_SMBUS_WRITE, data, I2C_SMBUS_BYTE, NULL) ; -} - - -/* - * wiringPiI2CWriteReg8: wiringPiI2CWriteReg16: - * Write an 8 or 16-bit value to the given register - ********************************************************************************* - */ - -int wiringPiI2CWriteReg8 (int fd, int reg, int value) -{ - union i2c_smbus_data data ; - - data.byte = value ; - return i2c_smbus_access (fd, I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &data) ; -} - -int wiringPiI2CWriteReg16 (int fd, int reg, int value) -{ - union i2c_smbus_data data ; - - data.word = value ; - return i2c_smbus_access (fd, I2C_SMBUS_WRITE, reg, I2C_SMBUS_WORD_DATA, &data) ; -} - - -/* - * wiringPiI2CSetupInterface: - * Undocumented access to set the interface explicitly - might be used - * for the Pi's 2nd I2C interface... - ********************************************************************************* - */ - -int wiringPiI2CSetupInterface (const char *device, int devId) -{ - int fd ; - - if ((fd = open (device, O_RDWR)) < 0) - return wiringPiFailure (WPI_ALMOST, "Unable to open I2C device: %s\n", strerror (errno)) ; - - if (ioctl (fd, I2C_SLAVE, devId) < 0) - return wiringPiFailure (WPI_ALMOST, "Unable to select I2C device: %s\n", strerror (errno)) ; - - return fd ; -} - - -/* - * wiringPiI2CSetup: - * Open the I2C device, and regsiter the target device - ********************************************************************************* - */ - -int wiringPiI2CSetup (const int devId) -{ - int rev ; - const char *device ; - - rev = piGpioLayout () ; - - if (rev == 1) - device = "/dev/i2c-0" ; - else - device = "/dev/i2c-1" ; - - return wiringPiI2CSetupInterface (device, devId) ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.h b/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.h deleted file mode 100644 index 6db8c68..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringPiI2C.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * wiringPiI2C.h: - * Simplified I2C access routines - * Copyright (c) 2013 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int wiringPiI2CRead (int fd) ; -extern int wiringPiI2CReadReg8 (int fd, int reg) ; -extern int wiringPiI2CReadReg16 (int fd, int reg) ; - -extern int wiringPiI2CWrite (int fd, int data) ; -extern int wiringPiI2CWriteReg8 (int fd, int reg, int data) ; -extern int wiringPiI2CWriteReg16 (int fd, int reg, int data) ; - -extern int wiringPiI2CSetupInterface (const char *device, int devId) ; -extern int wiringPiI2CSetup (const int devId) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.c b/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.c deleted file mode 100644 index 022b99f..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * wiringPiSPI.c: - * Simplified SPI access routines - * Copyright (c) 2012-2015 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include "wiringPi.h" - -#include "wiringPiSPI.h" - - -// The SPI bus parameters -// Variables as they need to be passed as pointers later on - -static const char *spiDev0 = "/dev/spidev0.0" ; -static const char *spiDev1 = "/dev/spidev0.1" ; -static const uint8_t spiBPW = 8 ; -static const uint16_t spiDelay = 0 ; - -static uint32_t spiSpeeds [2] ; -static int spiFds [2] ; - - -/* - * wiringPiSPIGetFd: - * Return the file-descriptor for the given channel - ********************************************************************************* - */ - -int wiringPiSPIGetFd (int channel) -{ - return spiFds [channel & 1] ; -} - - -/* - * wiringPiSPIDataRW: - * Write and Read a block of data over the SPI bus. - * Note the data ia being read into the transmit buffer, so will - * overwrite it! - * This is also a full-duplex operation. - ********************************************************************************* - */ - -int wiringPiSPIDataRW (int channel, unsigned char *data, int len) -{ - struct spi_ioc_transfer spi ; - - channel &= 1 ; - -// Mentioned in spidev.h but not used in the original kernel documentation -// test program )-: - - memset (&spi, 0, sizeof (spi)) ; - - spi.tx_buf = (unsigned long)data ; - spi.rx_buf = (unsigned long)data ; - spi.len = len ; - spi.delay_usecs = spiDelay ; - spi.speed_hz = spiSpeeds [channel] ; - spi.bits_per_word = spiBPW ; - - return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ; -} - - -/* - * wiringPiSPISetupMode: - * Open the SPI device, and set it up, with the mode, etc. - ********************************************************************************* - */ - -int wiringPiSPISetupMode (int channel, int speed, int mode) -{ - int fd ; - - mode &= 3 ; // Mode is 0, 1, 2 or 3 - channel &= 1 ; // Channel is 0 or 1 - - if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0) - return wiringPiFailure (WPI_ALMOST, "Unable to open SPI device: %s\n", strerror (errno)) ; - - spiSpeeds [channel] = speed ; - spiFds [channel] = fd ; - -// Set SPI parameters. - - if (ioctl (fd, SPI_IOC_WR_MODE, &mode) < 0) - return wiringPiFailure (WPI_ALMOST, "SPI Mode Change failure: %s\n", strerror (errno)) ; - - if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) - return wiringPiFailure (WPI_ALMOST, "SPI BPW Change failure: %s\n", strerror (errno)) ; - - if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) - return wiringPiFailure (WPI_ALMOST, "SPI Speed Change failure: %s\n", strerror (errno)) ; - - return fd ; -} - - -/* - * wiringPiSPISetup: - * Open the SPI device, and set it up, etc. in the default MODE 0 - ********************************************************************************* - */ - -int wiringPiSPISetup (int channel, int speed) -{ - return wiringPiSPISetupMode (channel, speed, 0) ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.h b/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.h deleted file mode 100644 index 3980321..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringPiSPI.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * wiringPiSPI.h: - * Simplified SPI access routines - * Copyright (c) 2012-2015 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -int wiringPiSPIGetFd (int channel) ; -int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ; -int wiringPiSPISetupMode (int channel, int speed, int mode) ; -int wiringPiSPISetup (int channel, int speed) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringSerial.c b/FlippR-Driver/src/lib/wiringPi/wiringSerial.c deleted file mode 100644 index e1587ad..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringSerial.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * wiringSerial.c: - * Handle a serial port - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "wiringSerial.h" - -/* - * serialOpen: - * Open and initialise the serial port, setting all the right - * port parameters - or as many as are required - hopefully! - ********************************************************************************* - */ - -int serialOpen (const char *device, const int baud) -{ - struct termios options ; - speed_t myBaud ; - int status, fd ; - - switch (baud) - { - case 50: myBaud = B50 ; break ; - case 75: myBaud = B75 ; break ; - case 110: myBaud = B110 ; break ; - case 134: myBaud = B134 ; break ; - case 150: myBaud = B150 ; break ; - case 200: myBaud = B200 ; break ; - case 300: myBaud = B300 ; break ; - case 600: myBaud = B600 ; break ; - case 1200: myBaud = B1200 ; break ; - case 1800: myBaud = B1800 ; break ; - case 2400: myBaud = B2400 ; break ; - case 4800: myBaud = B4800 ; break ; - case 9600: myBaud = B9600 ; break ; - case 19200: myBaud = B19200 ; break ; - case 38400: myBaud = B38400 ; break ; - case 57600: myBaud = B57600 ; break ; - case 115200: myBaud = B115200 ; break ; - case 230400: myBaud = B230400 ; break ; - case 460800: myBaud = B460800 ; break ; - case 500000: myBaud = B500000 ; break ; - case 576000: myBaud = B576000 ; break ; - case 921600: myBaud = B921600 ; break ; - case 1000000: myBaud = B1000000 ; break ; - case 1152000: myBaud = B1152000 ; break ; - case 1500000: myBaud = B1500000 ; break ; - case 2000000: myBaud = B2000000 ; break ; - case 2500000: myBaud = B2500000 ; break ; - case 3000000: myBaud = B3000000 ; break ; - case 3500000: myBaud = B3500000 ; break ; - case 4000000: myBaud = B4000000 ; break ; - - default: - return -2 ; - } - - if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1) - return -1 ; - - fcntl (fd, F_SETFL, O_RDWR) ; - -// Get and modify current options: - - tcgetattr (fd, &options) ; - - cfmakeraw (&options) ; - cfsetispeed (&options, myBaud) ; - cfsetospeed (&options, myBaud) ; - - options.c_cflag |= (CLOCAL | CREAD) ; - options.c_cflag &= ~PARENB ; - options.c_cflag &= ~CSTOPB ; - options.c_cflag &= ~CSIZE ; - options.c_cflag |= CS8 ; - options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ; - options.c_oflag &= ~OPOST ; - - options.c_cc [VMIN] = 0 ; - options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds) - - tcsetattr (fd, TCSANOW, &options) ; - - ioctl (fd, TIOCMGET, &status); - - status |= TIOCM_DTR ; - status |= TIOCM_RTS ; - - ioctl (fd, TIOCMSET, &status); - - usleep (10000) ; // 10mS - - return fd ; -} - - -/* - * serialFlush: - * Flush the serial buffers (both tx & rx) - ********************************************************************************* - */ - -void serialFlush (const int fd) -{ - tcflush (fd, TCIOFLUSH) ; -} - - -/* - * serialClose: - * Release the serial port - ********************************************************************************* - */ - -void serialClose (const int fd) -{ - close (fd) ; -} - - -/* - * serialPutchar: - * Send a single character to the serial port - ********************************************************************************* - */ - -void serialPutchar (const int fd, const unsigned char c) -{ - write (fd, &c, 1) ; -} - - -/* - * serialPuts: - * Send a string to the serial port - ********************************************************************************* - */ - -void serialPuts (const int fd, const char *s) -{ - write (fd, s, strlen (s)) ; -} - -/* - * serialPrintf: - * Printf over Serial - ********************************************************************************* - */ - -void serialPrintf (const int fd, const char *message, ...) -{ - va_list argp ; - char buffer [1024] ; - - va_start (argp, message) ; - vsnprintf (buffer, 1023, message, argp) ; - va_end (argp) ; - - serialPuts (fd, buffer) ; -} - - -/* - * serialDataAvail: - * Return the number of bytes of data avalable to be read in the serial port - ********************************************************************************* - */ - -int serialDataAvail (const int fd) -{ - int result ; - - if (ioctl (fd, FIONREAD, &result) == -1) - return -1 ; - - return result ; -} - - -/* - * serialGetchar: - * Get a single character from the serial device. - * Note: Zero is a valid character and this function will time-out after - * 10 seconds. - ********************************************************************************* - */ - -int serialGetchar (const int fd) -{ - uint8_t x ; - - if (read (fd, &x, 1) != 1) - return -1 ; - - return ((int)x) & 0xFF ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringSerial.h b/FlippR-Driver/src/lib/wiringPi/wiringSerial.h deleted file mode 100644 index 430dc73..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringSerial.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * wiringSerial.h: - * Handle a serial port - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int serialOpen (const char *device, const int baud) ; -extern void serialClose (const int fd) ; -extern void serialFlush (const int fd) ; -extern void serialPutchar (const int fd, const unsigned char c) ; -extern void serialPuts (const int fd, const char *s) ; -extern void serialPrintf (const int fd, const char *message, ...) ; -extern int serialDataAvail (const int fd) ; -extern int serialGetchar (const int fd) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wiringShift.c b/FlippR-Driver/src/lib/wiringPi/wiringShift.c deleted file mode 100644 index 3df94e8..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringShift.c +++ /dev/null @@ -1,83 +0,0 @@ -/* - * wiringShift.c: - * Emulate some of the Arduino wiring functionality. - * - * Copyright (c) 2009-2012 Gordon Henderson. - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - -#include - -#include "wiringPi.h" -#include "wiringShift.h" - -/* - * shiftIn: - * Shift data in from a clocked source - ********************************************************************************* - */ - -uint8_t shiftIn (uint8_t dPin, uint8_t cPin, uint8_t order) -{ - uint8_t value = 0 ; - int8_t i ; - - if (order == MSBFIRST) - for (i = 7 ; i >= 0 ; --i) - { - digitalWrite (cPin, HIGH) ; - value |= digitalRead (dPin) << i ; - digitalWrite (cPin, LOW) ; - } - else - for (i = 0 ; i < 8 ; ++i) - { - digitalWrite (cPin, HIGH) ; - value |= digitalRead (dPin) << i ; - digitalWrite (cPin, LOW) ; - } - - return value; -} - -/* - * shiftOut: - * Shift data out to a clocked source - ********************************************************************************* - */ - -void shiftOut (uint8_t dPin, uint8_t cPin, uint8_t order, uint8_t val) -{ - int8_t i; - - if (order == MSBFIRST) - for (i = 7 ; i >= 0 ; --i) - { - digitalWrite (dPin, val & (1 << i)) ; - digitalWrite (cPin, HIGH) ; - digitalWrite (cPin, LOW) ; - } - else - for (i = 0 ; i < 8 ; ++i) - { - digitalWrite (dPin, val & (1 << i)) ; - digitalWrite (cPin, HIGH) ; - digitalWrite (cPin, LOW) ; - } -} diff --git a/FlippR-Driver/src/lib/wiringPi/wiringShift.h b/FlippR-Driver/src/lib/wiringPi/wiringShift.h deleted file mode 100644 index 419ade4..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wiringShift.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * wiringShift.h: - * Emulate some of the Arduino wiring functionality. - * - * Copyright (c) 2009-2012 Gordon Henderson. - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - -#define LSBFIRST 0 -#define MSBFIRST 1 - -#ifndef _STDINT_H -# include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -extern uint8_t shiftIn (uint8_t dPin, uint8_t cPin, uint8_t order) ; -extern void shiftOut (uint8_t dPin, uint8_t cPin, uint8_t order, uint8_t val) ; - -#ifdef __cplusplus -} -#endif diff --git a/FlippR-Driver/src/lib/wiringPi/wpiExtensions.c b/FlippR-Driver/src/lib/wiringPi/wpiExtensions.c deleted file mode 100644 index 53fafc0..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wpiExtensions.c +++ /dev/null @@ -1,928 +0,0 @@ -/* - * extensions.c: - * Originally part of the GPIO program to test, peek, poke and otherwise - * noodle with the GPIO hardware on the Raspberry Pi. - * Now used as a general purpose library to allow systems to dynamically - * add in new devices into wiringPi at program run-time. - * Copyright (c) 2012-2015 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "mcp23008.h" -#include "mcp23016.h" -#include "mcp23017.h" -#include "mcp23s08.h" -#include "mcp23s17.h" -#include "sr595.h" -#include "pcf8574.h" -#include "pcf8591.h" -#include "mcp3002.h" -#include "mcp3004.h" -#include "mcp4802.h" -#include "mcp3422.h" -#include "max31855.h" -#include "max5322.h" -#include "ads1115.h" -#include "sn3218.h" -#include "drcSerial.h" -#include "drcNet.h" -#include "../wiringPiD/drcNetCmd.h" -#include "pseudoPins.h" -#include "bmp180.h" -#include "htu21d.h" -#include "ds18b20.h" -#include "rht03.h" - -#include "wpiExtensions.h" - -extern int wiringPiDebug ; - -static int verbose ; -static char errorMessage [1024] ; - - -// Local structure to hold details - -struct extensionFunctionStruct -{ - const char *name ; - int (*function)(char *progName, int pinBase, char *params) ; -} ; - - -/* - * verbError: - * Convenient error handling - ********************************************************************************* - */ - -static void verbError (const char *message, ...) -{ - va_list argp ; - va_start (argp, message) ; - vsnprintf (errorMessage, 1023, message, argp) ; - va_end (argp) ; - - if (verbose) - fprintf (stderr, "%s\n", errorMessage) ; -} - - -/* - * extractInt: - * Check & return an integer at the given location (prefixed by a :) - ********************************************************************************* - */ - -static char *extractInt (char *progName, char *p, int *num) -{ - if (*p != ':') - { - verbError ("%s: colon expected", progName) ; - return NULL ; - } - - ++p ; - - if (!isdigit (*p)) - { - verbError ("%s: digit expected", progName) ; - return NULL ; - } - - *num = strtol (p, NULL, 0) ; - -// Increment p, but we need to check for hex 0x - - if ((*p == '0') && (*(p + 1) == 'x')) - p +=2 ; - - while (isxdigit (*p)) - ++p ; - - return p ; -} - - -/* - * extractStr: - * Check & return a string at the given location (prefixed by a :) - * Note: The string can be enclosed in []'s to escape colons. This is - * so we can handle IPv6 addresses which contain colons and the []'s is - * a common way to prepresent them. - ********************************************************************************* - */ - -static char *extractStr (char *progName, char *p, char **str) -{ - char *q, *r ; - int quoted = FALSE ; - - if (*p != ':') - { - verbError ("%s: colon expected", progName) ; - return NULL ; - } - - ++p ; - - if (*p == '[') - { - quoted = TRUE ; - ++p ; - } - - if (!isprint (*p)) // Is this needed? - { - verbError ("%s: character expected", progName) ; - return NULL ; - } - - q = p ; - if (quoted) - { - while ((*q != 0) && (*q != ']')) - ++q ; - } - else - { - while ((*q != 0) && (*q != ':')) - ++q ; - } - - *str = r = calloc (q - p + 2, 1) ; // Zeros it - - while (p != q) - *r++ = *p++ ; - - if (quoted) // Skip over the ] to the : - ++p ; - - return p ; -} - - - -/* - * doExtensionMcp23008: - * MCP23008 - 8-bit I2C GPIO expansion chip - * mcp23002:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionMcp23008 (char *progName, int pinBase, char *params) -{ - int i2c ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x01) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - mcp23008Setup (pinBase, i2c) ; - - return TRUE ; -} - - -/* - * doExtensionMcp23016: - * MCP230016- 16-bit I2C GPIO expansion chip - * mcp23016:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionMcp23016 (char *progName, int pinBase, char *params) -{ - int i2c ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x03) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - mcp23016Setup (pinBase, i2c) ; - - return TRUE ; -} - - -/* - * doExtensionMcp23017: - * MCP230017- 16-bit I2C GPIO expansion chip - * mcp23017:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionMcp23017 (char *progName, int pinBase, char *params) -{ - int i2c ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x03) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - mcp23017Setup (pinBase, i2c) ; - - return TRUE ; -} - - -/* - * doExtensionMcp23s08: - * MCP23s08 - 8-bit SPI GPIO expansion chip - * mcp23s08:base:spi:port - ********************************************************************************* - */ - -static int doExtensionMcp23s08 (char *progName, int pinBase, char *params) -{ - int spi, port ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI address (%d) out of range", progName, spi) ; - return FALSE ; - } - - if ((params = extractInt (progName, params, &port)) == NULL) - return FALSE ; - - if ((port < 0) || (port > 7)) - { - verbError ("%s: port address (%d) out of range", progName, port) ; - return FALSE ; - } - - mcp23s08Setup (pinBase, spi, port) ; - - return TRUE ; -} - - -/* - * doExtensionMcp23s17: - * MCP23s17 - 16-bit SPI GPIO expansion chip - * mcp23s17:base:spi:port - ********************************************************************************* - */ - -static int doExtensionMcp23s17 (char *progName, int pinBase, char *params) -{ - int spi, port ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI address (%d) out of range", progName, spi) ; - return FALSE ; - } - - if ((params = extractInt (progName, params, &port)) == NULL) - return FALSE ; - - if ((port < 0) || (port > 7)) - { - verbError ("%s: port address (%d) out of range", progName, port) ; - return FALSE ; - } - - mcp23s17Setup (pinBase, spi, port) ; - - return TRUE ; -} - - -/* - * doExtensionSr595: - * Shift Register 74x595 - * sr595:base:pins:data:clock:latch - ********************************************************************************* - */ - -static int doExtensionSr595 (char *progName, int pinBase, char *params) -{ - int pins, data, clock, latch ; - -// Extract pins - - if ((params = extractInt (progName, params, &pins)) == NULL) - return FALSE ; - - if ((pins < 8) || (pins > 32)) - { - verbError ("%s: pin count (%d) out of range - 8-32 expected.", progName, pins) ; - return FALSE ; - } - - if ((params = extractInt (progName, params, &data)) == NULL) - return FALSE ; - - if ((params = extractInt (progName, params, &clock)) == NULL) - return FALSE ; - - if ((params = extractInt (progName, params, &latch)) == NULL) - return FALSE ; - - sr595Setup (pinBase, pins, data, clock, latch) ; - - return TRUE ; -} - - -/* - * doExtensionPcf8574: - * Digital IO (Crude!) - * pcf8574:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionPcf8574 (char *progName, int pinBase, char *params) -{ - int i2c ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x03) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - pcf8574Setup (pinBase, i2c) ; - - return TRUE ; -} - - -/* - * doExtensionAds1115: - * Analog Input - * ads1115:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionAds1115 (char *progName, int pinBase, char *params) -{ - int i2c ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x03) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - ads1115Setup (pinBase, i2c) ; - - return TRUE ; -} - - -/* - * doExtensionPcf8591: - * Analog IO - * pcf8591:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionPcf8591 (char *progName, int pinBase, char *params) -{ - int i2c ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x03) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - pcf8591Setup (pinBase, i2c) ; - - return TRUE ; -} - - -/* - * doExtensionPseudoPins: - * 64 Memory resident pseudo pins - * pseudoPins:base - ********************************************************************************* - */ - -static int doExtensionPseudoPins (UNU char *progName, int pinBase, UNU char *params) -{ - pseudoPinsSetup (pinBase) ; - - return TRUE ; -} - - -/* - * doExtensionBmp180: - * Analog Temp + Pressure - * bmp180:base - ********************************************************************************* - */ - -static int doExtensionBmp180 (UNU char *progName, int pinBase, UNU char *params) -{ - bmp180Setup (pinBase) ; - - return TRUE ; -} - - -/* - * doExtensionHtu21d: - * Analog humidity + Pressure - * htu21d:base - ********************************************************************************* - */ - -static int doExtensionHtu21d (UNU char *progName, int pinBase, UNU char *params) -{ - htu21dSetup (pinBase) ; - - return TRUE ; -} - - -/* - * doExtensionDs18b20: - * 1-Wire Temperature - * htu21d:base:serialNum - ********************************************************************************* - */ - -static int doExtensionDs18b20 (char *progName, int pinBase, char *params) -{ - char *serialNum ; - - if ((params = extractStr (progName, params, &serialNum)) == NULL) - return FALSE ; - - return ds18b20Setup (pinBase, serialNum) ; -} - - -/* - * doExtensionRht03: - * Maxdetect 1-Wire Temperature & Humidity - * rht03:base:piPin - ********************************************************************************* - */ - -static int doExtensionRht03 (char *progName, int pinBase, char *params) -{ - int piPin ; - - if ((params = extractInt (progName, params, &piPin)) == NULL) - return FALSE ; - - return rht03Setup (pinBase, piPin) ; -} - - -/* - * doExtensionMax31855: - * Analog IO - * max31855:base:spiChan - ********************************************************************************* - */ - -static int doExtensionMax31855 (char *progName, int pinBase, char *params) -{ - int spi ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI channel (%d) out of range", progName, spi) ; - return FALSE ; - } - - max31855Setup (pinBase, spi) ; - - return TRUE ; -} - - -/* - * doExtensionMcp3002: - * Analog IO - * mcp3002:base:spiChan - ********************************************************************************* - */ - -static int doExtensionMcp3002 (char *progName, int pinBase, char *params) -{ - int spi ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI channel (%d) out of range", progName, spi) ; - return FALSE ; - } - - mcp3002Setup (pinBase, spi) ; - - return TRUE ; -} - - -/* - * doExtensionMcp3004: - * Analog IO - * mcp3004:base:spiChan - ********************************************************************************* - */ - -static int doExtensionMcp3004 (char *progName, int pinBase, char *params) -{ - int spi ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI channel (%d) out of range", progName, spi) ; - return FALSE ; - } - - mcp3004Setup (pinBase, spi) ; - - return TRUE ; -} - - -/* - * doExtensionMax5322: - * Analog O - * max5322:base:spiChan - ********************************************************************************* - */ - -static int doExtensionMax5322 (char *progName, int pinBase, char *params) -{ - int spi ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI channel (%d) out of range", progName, spi) ; - return FALSE ; - } - - max5322Setup (pinBase, spi) ; - - return TRUE ; -} - - -/* - * doExtensionMcp4802: - * Analog IO - * mcp4802:base:spiChan - ********************************************************************************* - */ - -static int doExtensionMcp4802 (char *progName, int pinBase, char *params) -{ - int spi ; - - if ((params = extractInt (progName, params, &spi)) == NULL) - return FALSE ; - - if ((spi < 0) || (spi > 1)) - { - verbError ("%s: SPI channel (%d) out of range", progName, spi) ; - return FALSE ; - } - - mcp4802Setup (pinBase, spi) ; - - return TRUE ; -} - - -/* - * doExtensionSn3218: - * Analog Output (LED Driver) - * sn3218:base - ********************************************************************************* - */ - -static int doExtensionSn3218 (UNU char *progName, int pinBase, UNU char *params) -{ - sn3218Setup (pinBase) ; - return TRUE ; -} - - -/* - * doExtensionMcp3422: - * Analog IO - * mcp3422:base:i2cAddr - ********************************************************************************* - */ - -static int doExtensionMcp3422 (char *progName, int pinBase, char *params) -{ - int i2c, sampleRate, gain ; - - if ((params = extractInt (progName, params, &i2c)) == NULL) - return FALSE ; - - if ((i2c < 0x03) || (i2c > 0x77)) - { - verbError ("%s: i2c address (0x%X) out of range", progName, i2c) ; - return FALSE ; - } - - if ((params = extractInt (progName, params, &sampleRate)) == NULL) - return FALSE ; - - if ((sampleRate < 0) || (sampleRate > 3)) - { - verbError ("%s: sample rate (%d) out of range", progName, sampleRate) ; - return FALSE ; - } - - if ((params = extractInt (progName, params, &gain)) == NULL) - return FALSE ; - - if ((gain < 0) || (gain > 3)) - { - verbError ("%s: gain (%d) out of range", progName, gain) ; - return FALSE ; - } - - mcp3422Setup (pinBase, i2c, sampleRate, gain) ; - - return TRUE ; -} - - -/* - * doExtensionDrcS: - * Interface to a DRC Serial system - * drcs:base:pins:serialPort:baud - ********************************************************************************* - */ - -static int doExtensionDrcS (char *progName, int pinBase, char *params) -{ - char *port ; - int pins, baud ; - - if ((params = extractInt (progName, params, &pins)) == NULL) - return FALSE ; - - if ((pins < 1) || (pins > 1000)) - { - verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ; - return FALSE ; - } - - if ((params = extractStr (progName, params, &port)) == NULL) - return FALSE ; - - if (strlen (port) == 0) - { - verbError ("%s: serial port device name required", progName) ; - return FALSE ; - } - - if ((params = extractInt (progName, params, &baud)) == NULL) - return FALSE ; - - if ((baud < 1) || (baud > 4000000)) - { - verbError ("%s: baud rate (%d) out of range", progName, baud) ; - return FALSE ; - } - - drcSetupSerial (pinBase, pins, port, baud) ; - - return TRUE ; -} - - -/* - * doExtensionDrcNet: - * Interface to a DRC Network system - * drcn:base:pins:ipAddress:port:password - ********************************************************************************* - */ - -static int doExtensionDrcNet (char *progName, int pinBase, char *params) -{ - int pins ; - char *ipAddress, *port, *password ; - char pPort [1024] ; - - if ((params = extractInt (progName, params, &pins)) == NULL) - return FALSE ; - - if ((pins < 1) || (pins > 1000)) - { - verbError ("%s: pins (%d) out of range (2-1000)", progName, pins) ; - return FALSE ; - } - - if ((params = extractStr (progName, params, &ipAddress)) == NULL) - return FALSE ; - - if (strlen (ipAddress) == 0) - { - verbError ("%s: ipAddress required", progName) ; - return FALSE ; - } - - if ((params = extractStr (progName, params, &port)) == NULL) - return FALSE ; - - if (strlen (port) == 0) - { - sprintf (pPort, "%d", DEFAULT_SERVER_PORT) ; - port = pPort ; - } - - if ((params = extractStr (progName, params, &password)) == NULL) - return FALSE ; - - if (strlen (password) == 0) - { - verbError ("%s: password required", progName) ; - return FALSE ; - } - - return drcSetupNet (pinBase, pins, ipAddress, port, password) ; -} - - - -/* - * Function list - ********************************************************************************* - */ - -static struct extensionFunctionStruct extensionFunctions [] = -{ - { "mcp23008", &doExtensionMcp23008 }, - { "mcp23016", &doExtensionMcp23016 }, - { "mcp23017", &doExtensionMcp23017 }, - { "mcp23s08", &doExtensionMcp23s08 }, - { "mcp23s17", &doExtensionMcp23s17 }, - { "sr595", &doExtensionSr595 }, - { "pcf8574", &doExtensionPcf8574 }, - { "pcf8591", &doExtensionPcf8591 }, - { "bmp180", &doExtensionBmp180 }, - { "pseudoPins", &doExtensionPseudoPins }, - { "htu21d", &doExtensionHtu21d }, - { "ds18b20", &doExtensionDs18b20 }, - { "rht03", &doExtensionRht03 }, - { "mcp3002", &doExtensionMcp3002 }, - { "mcp3004", &doExtensionMcp3004 }, - { "mcp4802", &doExtensionMcp4802 }, - { "mcp3422", &doExtensionMcp3422 }, - { "max31855", &doExtensionMax31855 }, - { "ads1115", &doExtensionAds1115 }, - { "max5322", &doExtensionMax5322 }, - { "sn3218", &doExtensionSn3218 }, - { "drcs", &doExtensionDrcS }, - { "drcn", &doExtensionDrcNet }, - { NULL, NULL }, -} ; - - -/* - * loadWPiExtension: - * Load in a wiringPi extension - * The extensionData always starts with the name, a colon then the pinBase - * number. Other parameters after that are decoded by the module in question. - ********************************************************************************* - */ - -int loadWPiExtension (char *progName, char *extensionData, int printErrors) -{ - char *p ; - char *extension = extensionData ; - struct extensionFunctionStruct *extensionFn ; - unsigned pinBase = 0 ; - - verbose = printErrors ; - -// Get the extension name by finding the first colon - - p = extension ; - while (*p != ':') - { - if (!*p) // ran out of characters - { - verbError ("%s: extension name not terminated by a colon", progName) ; - return FALSE ; - } - ++p ; - } - *p++ = 0 ; - -// Simple ATOI code - - if (!isdigit (*p)) - { - verbError ("%s: decimal pinBase number expected after extension name", progName) ; - return FALSE ; - } - - while (isdigit (*p)) - { - if (pinBase > 2147483647) // 2^31-1 ... Lets be realistic here... - { - verbError ("%s: pinBase too large", progName) ; - return FALSE ; - } - - pinBase = pinBase * 10 + (*p - '0') ; - ++p ; - } - - if (pinBase < 64) - { - verbError ("%s: pinBase (%d) too small. Minimum is 64.", progName, pinBase) ; - return FALSE ; - } - -// Search for extensions: - - for (extensionFn = extensionFunctions ; extensionFn->name != NULL ; ++extensionFn) - { - if (strcmp (extensionFn->name, extension) == 0) - return extensionFn->function (progName, pinBase, p) ; - } - - fprintf (stderr, "%s: extension %s not found", progName, extension) ; - return FALSE ; -} diff --git a/FlippR-Driver/src/lib/wiringPi/wpiExtensions.h b/FlippR-Driver/src/lib/wiringPi/wpiExtensions.h deleted file mode 100644 index fcaec96..0000000 --- a/FlippR-Driver/src/lib/wiringPi/wpiExtensions.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * extensions.h: - * Part of the GPIO program to test, peek, poke and otherwise - * noodle with the GPIO hardware on the Raspberry Pi. - * Copyright (c) 2012-2015 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * wiringPi is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with wiringPi. If not, see . - *********************************************************************** - */ - - -extern int loadWPiExtension (char *progName, char *extensionData, int verbose) ; diff --git a/FlippR-Driver/src/output/DisplayBoardPinController.h b/FlippR-Driver/src/output/DisplayBoardPinController.h new file mode 100644 index 0000000..1825636 --- /dev/null +++ b/FlippR-Driver/src/output/DisplayBoardPinController.h @@ -0,0 +1,33 @@ +// +// Created by rhetenor on 14.12.18. +// + +#ifndef FLIPPR_DRIVER_DISPLAYPINCONTROLLER_H +#define FLIPPR_DRIVER_DISPLAYPINCONTROLLER_H + +#include "output/items/OutputDisplay.h" +#include "PinController.h" + +namespace flippR_driver +{ +namespace output +{ + +class DisplayBoardPinController : public PinController +{ +public: + virtual ~DisplayBoardPinController() = default; + + virtual void activate_displays() const = 0; + virtual void deactivate_displays() const = 0; + + virtual void initDisplay(const items::OutputDisplay &display) const = 0; + + virtual void write_display(const items::OutputDisplay &display) const = 0; + + virtual void set_pin_map(std::map & pins_display) = 0; +}; + +} +} +#endif //FLIPPR_DRIVER_DISPLAYPINCONTROLLER_H diff --git a/FlippR-Driver/src/output/DisplayController.h b/FlippR-Driver/src/output/DisplayController.h new file mode 100644 index 0000000..fa675fd --- /dev/null +++ b/FlippR-Driver/src/output/DisplayController.h @@ -0,0 +1,28 @@ +/* + * DisplayController.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_IDISPLAYCONTROLLER_H_ +#define _SRC_OUTPUT_IDISPLAYCONTROLLER_H_ + +namespace flippR_driver +{ +namespace output +{ + +class DisplayController +{ + +public: + virtual ~DisplayController () = default; + + virtual void activate_displays() const = 0; + virtual void deactivate_displays() const = 0; +}; + +} /* namespace output */ +} +#endif diff --git a/FlippR-Driver/src/output/DriverBoardPinController.h b/FlippR-Driver/src/output/DriverBoardPinController.h new file mode 100644 index 0000000..5a0e45f --- /dev/null +++ b/FlippR-Driver/src/output/DriverBoardPinController.h @@ -0,0 +1,33 @@ +// +// Created by rhetenor on 13.12.18. +// + +#ifndef FLIPPR_DRIVER_DRIVERBOARDPINCONTROLLER_H +#define FLIPPR_DRIVER_DRIVERBOARDPINCONTROLLER_H + +#include "PinController.h" + +namespace flippR_driver +{ +namespace output +{ + +namespace items +{ + class DriverBoardItem; +} + +class DriverBoardPinController : public PinController +{ +public: + virtual ~DriverBoardPinController() = default; + + virtual void activate(items::DriverBoardItem &driver_board_item) = 0; + virtual void deactivate(items::DriverBoardItem &driver_board_item) = 0; + virtual void clear() = 0; + +}; + +} +} +#endif //FLIPPR_DRIVER_DRIVERBOARDPINCONTROLLER_H diff --git a/FlippR-Driver/src/output/EventHandler.cpp b/FlippR-Driver/src/output/EventHandler.cpp deleted file mode 100644 index 7464850..0000000 --- a/FlippR-Driver/src/output/EventHandler.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * EventHandler.cpp - * - * Created on: Jun 14, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#include "EventHandler.h" - -namespace output -{ - - EventHandler::EventHandler () - { - // TODO Auto-generated constructor stub - - } - - EventHandler::~EventHandler () - { - // TODO Auto-generated destructor stub - } - -} /* namespace output */ diff --git a/FlippR-Driver/src/output/EventHandler.h b/FlippR-Driver/src/output/EventHandler.h deleted file mode 100644 index 66ddadb..0000000 --- a/FlippR-Driver/src/output/EventHandler.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * EventHandler.h - * - * Created on: Jun 14, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - - -#include "../utilities/IEventHandler.h" - -#ifndef SRC_OUTPUT_EVENTHANDLER_H_ -#define SRC_OUTPUT_EVENTHANDLER_H_ - -namespace output -{ - -class EventHandler : public IEventHandler -{ -public: - EventHandler(); - virtual ~EventHandler(); - - virtual void handle() override; -}; - -} /* namespace output */ - -#endif /* SRC_OUTPUT_EVENTHANDLER_H_ */ diff --git a/FlippR-Driver/src/output/OutputDriverFactory.cpp b/FlippR-Driver/src/output/OutputDriverFactory.cpp new file mode 100644 index 0000000..7257795 --- /dev/null +++ b/FlippR-Driver/src/output/OutputDriverFactory.cpp @@ -0,0 +1,87 @@ +// +// Created by rhetenor on 04.10.18. +// + +#include +#include +#include +#include +#include +#include "OutputDriverFactory.h" + +#include "utility/LoggerFactory.h" + +#include "output/detail/DisplayController.h" +#include "output/detail/SoundBoardPinController.h" +#include "output/detail/DisplayBoardPinController.h" +#include "output/detail/DriverBoardPinController.h" + +#include "output/items/Flipper.h" + +namespace flippR_driver +{ +namespace output +{ +namespace OutputDriverFactory +{ + +using namespace nlohmann; + +std::shared_ptr get_OutputDriver(const std::string & solenoid_config_path, + const std::string & lamp_config_path, + const std::string & sound_config_path, + const std::string & display_config_path) +{ + utility::LoggerFactory::CreateOutputLogger(); + + auto output_pin_mutex = std::make_shared(); + std::shared_ptr driver_board_pin_controller(new detail::DriverBoardPinController(output_pin_mutex)); + + auto flippers = get_items(solenoid_config_path, driver_board_pin_controller); + auto solenoids = get_items(solenoid_config_path, driver_board_pin_controller); + auto lamps = get_items(lamp_config_path, driver_board_pin_controller); + + driver_board_pin_controller->clear(); + + auto sound_board_pin_controller = std::make_shared(output_pin_mutex); + auto sounds = get_items(sound_config_path, sound_board_pin_controller); + + auto display_board_pin_controller = std::make_shared(); + auto displays = get_items(display_config_path, display_board_pin_controller); + + auto display_controller = std::make_unique(displays, display_board_pin_controller, get_update_frequency(display_config_path)); + + return std::make_shared(std::move(display_controller), solenoids, lamps, sounds, flippers, displays); +} + +std::chrono::seconds get_update_frequency(const std::string & display_config_path) +{ + nlohmann::json display_config; + std::ifstream(display_config_path) >> display_config; + return std::chrono::seconds{1/display_config.at(config_path::display_update_frequency).get()}; +} + +template +std::map> get_items(const std::string &config_path, std::shared_ptr pin_controller) +{ + std::ifstream config_stream{config_path}; + nlohmann::json config_json; + config_stream >> config_json; + + std::map> map; + try{ + FactoryType factory{config_json, std::static_pointer_cast(pin_controller)}; + map = factory.getItemMap(); + } + catch(json::exception & e) + { + CLOG(ERROR, OUTPUT_LOGGER) << "File " << config_path << " seems to be corrupted: " << e.what(); + exit(EXIT_FAILURE); + } + + return map; +} + +} +} +} \ No newline at end of file diff --git a/FlippR-Driver/src/output/OutputDriverFactory.h b/FlippR-Driver/src/output/OutputDriverFactory.h new file mode 100644 index 0000000..adfb2a9 --- /dev/null +++ b/FlippR-Driver/src/output/OutputDriverFactory.h @@ -0,0 +1,40 @@ + +// Created by rhetenor on 04.10.18. +// + +#ifndef flippR_driver_OUTPUTDRIVERFACTORY_H +#define flippR_driver_OUTPUTDRIVERFACTORY_H + +#include "output/OutputDriver.h" +#include "output/items/detail/Solenoid.h" +#include "output/items/detail/Lamp.h" +#include "output/items/detail/Sound.h" +#include "output/items/Flipper.h" +#include "output/items/detail/Flipper.h" +#include "output/DisplayBoardPinController.h" + +#include "json/json.hpp" + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace OutputDriverFactory +{ +std::shared_ptr get_OutputDriver(const std::string & solenoid_config_path, + const std::string & lamp_config_path, + const std::string & sound_config_path, + const std::string & display_config_path); + +std::chrono::seconds get_update_frequency(const std::string & display_config_path); + +template +std::map> get_items(const std::string & config_path, std::shared_ptr pin_controller); + +} +} +} + +#endif //flippR_driver_OUTPUTDRIVERFACTORY_H \ No newline at end of file diff --git a/FlippR-Driver/src/output/SoundBoardPinController.h b/FlippR-Driver/src/output/SoundBoardPinController.h new file mode 100644 index 0000000..2589b83 --- /dev/null +++ b/FlippR-Driver/src/output/SoundBoardPinController.h @@ -0,0 +1,28 @@ +// +// Created by rhetenor on 14.12.18. +// + +#ifndef FLIPPR_DRIVER_OUTPUT_SOUNDBOARDPINCONTROLLER_H +#define FLIPPR_DRIVER_OUTPUT_SOUNDBOARDPINCONTROLLER_H + +#include "output/items/detail/Sound.h" +#include "PinController.h" + +namespace flippR_driver +{ +namespace output +{ + +class SoundBoardPinController : public PinController +{ +public: + virtual ~SoundBoardPinController() = default; + + virtual void activate(const items::detail::Sound &sound) = 0; + virtual void deactivate(const items::detail::Sound &sound) = 0; +}; + +} +} + +#endif //FLIPPR_DRIVER_SOUNDPINCONTROLLER_H diff --git a/FlippR-Driver/src/output/detail/DisplayBoardPinController.cpp b/FlippR-Driver/src/output/detail/DisplayBoardPinController.cpp new file mode 100644 index 0000000..9a6c9c9 --- /dev/null +++ b/FlippR-Driver/src/output/detail/DisplayBoardPinController.cpp @@ -0,0 +1,115 @@ +// +// Created by rhetenor on 14.12.18. +// + +#include "output/detail/DisplayBoardPinController.h" + +#include + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +DisplayBoardPinController::DisplayBoardPinController(std::map & pins_display) : + pins_display_board{std::move(pins_display)} +{ + initialize_pins_output(); + + clear(); + + CLOG(DEBUG, OUTPUT_LOGGER) << "Created DisplayBoardPinController"; +} + +DisplayBoardPinController::DisplayBoardPinController() : + pins_display_board{} +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created DisplayBoardPinController without pin map"; +} + +void DisplayBoardPinController::clear() +{ + std::for_each(this->pins_display_board.begin(), this->pins_display_board.end(), [](auto& pin) { write_pin(pin.second, 0); }); +} + +void DisplayBoardPinController::initDisplay(const items::OutputDisplay &display) const +{ + initialize_output_pin(display.get_address()); + + write_pin(display.get_address(), 0); +} + +void DisplayBoardPinController::activate_displays() const +{ + write_pin(pins_display_board.at("run"), 1); +} + +void DisplayBoardPinController::deactivate_displays() const +{ + write_pin(pins_display_board.at("run"), 0); +} + +void DisplayBoardPinController::write_display(const items::OutputDisplay &display) const +{ + std::string content = display.get_content(); + + for (uint8_t i = 0; i < content.size(); i++) + { + write_display_digit(display.get_address(), content.at(i), i); + } +} + +void DisplayBoardPinController::write_display_digit(uint8_t display_address, uint8_t content, uint8_t position) const +{ + select_display_segment(position); + + select_display_digit(content); + + run_display(display_address); + + std::this_thread::sleep_for(std::chrono::milliseconds(DISPLAY_SLEEP_TIME_MILLI)); +} + +void DisplayBoardPinController::select_display_segment(uint8_t segment) const +{ + write_pin(pins_display_board.at("segment_select_A"), segment & ~0b001u); + write_pin(pins_display_board.at("segment_select_B"), segment & ~0b010u); + write_pin(pins_display_board.at("segment_select_C"), segment & ~0b100u); +} + +void DisplayBoardPinController::select_display_digit(uint8_t content) const +{ + write_pin(pins_display_board.at("digit_select_A"), content & 0b0001u); + write_pin(pins_display_board.at("digit_select_B"), content & 0b0010u); + write_pin(pins_display_board.at("digit_select_C"), content & 0b0100u); + write_pin(pins_display_board.at("digit_select_D"), content & 0b1000u); +} + +void DisplayBoardPinController::run_display(uint8_t address) const +{ + write_pin(address, 1); + write_pin(address, 0); +} + +void DisplayBoardPinController::set_pin_map(std::map & pins_display) +{ + this->pins_display_board.insert(pins_display.begin(), pins_display.end()); + + this->initialize_pins_output(); + + clear(); +} +void DisplayBoardPinController::initialize_pins_output() +{ + for(auto& pin : this->pins_display_board) { + initialize_output_pin(pin.second); + } +} + +} +} +} \ No newline at end of file diff --git a/FlippR-Driver/src/output/detail/DisplayBoardPinController.h b/FlippR-Driver/src/output/detail/DisplayBoardPinController.h new file mode 100644 index 0000000..7dcaf84 --- /dev/null +++ b/FlippR-Driver/src/output/detail/DisplayBoardPinController.h @@ -0,0 +1,50 @@ +// +// Created by rhetenor on 14.12.18. +// + +#ifndef FLIPPR_DRIVER_OUTPUT_IMPL_DISPLAYPINCONTROLLER_H +#define FLIPPR_DRIVER_OUTPUT_IMPL_DISPLAYPINCONTROLLER_H + +#include "output/DisplayBoardPinController.h" + +#include +#include + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +class DisplayBoardPinController : public output::DisplayBoardPinController +{ +public: + explicit DisplayBoardPinController(std::map & pins_display); + explicit DisplayBoardPinController(); + ~DisplayBoardPinController() override = default; + + void initDisplay(const items::OutputDisplay &display) const; + void activate_displays() const; + void deactivate_displays() const; + + void write_display(const items::OutputDisplay &display) const; + + void set_pin_map(std::map & pins_display); + +private: + void initialize_pins_output(); + void clear(); + void write_display_digit(uint8_t display_address, uint8_t content, uint8_t position) const; + void select_display_segment(uint8_t digit) const; + void select_display_digit(uint8_t content) const; + void run_display(uint8_t address) const; + +private: + std::map pins_display_board; +}; + +} +} +} +#endif //FLIPPR_DRIVER_DISPLAYPINCONTROLLER_H diff --git a/FlippR-Driver/src/output/detail/DisplayController.cpp b/FlippR-Driver/src/output/detail/DisplayController.cpp new file mode 100644 index 0000000..c072697 --- /dev/null +++ b/FlippR-Driver/src/output/detail/DisplayController.cpp @@ -0,0 +1,75 @@ +/* + * DisplayController.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "output/detail/DisplayController.h" + +#include "output/DisplayController.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +DisplayController::DisplayController(std::map> & displays, + std::shared_ptr pin_controller, std::chrono::milliseconds update_frequency +) + : pin_controller{pin_controller}, update_frequency(update_frequency), is_running(true) +{ + for (auto display : displays) + { + this->displays.push_back(std::dynamic_pointer_cast(display.second)); + } + + for(auto &display : this->displays) { + pin_controller->initDisplay(*display); + } + + activate_displays(); + + //this->display_cycle_thread = std::thread(&DisplayController::cycle_displays, this); + + CLOG(DEBUG, OUTPUT_LOGGER) << "Created DisplayController and started cycling them."; +} + +DisplayController::~DisplayController() +{ + this->is_running = false; + + this->display_cycle_thread.join(); +} + +void DisplayController::cycle_displays() const +{ + while (is_running) + { + std::this_thread::sleep_for(update_frequency); + for (auto &display : this->displays) + { + pin_controller->write_display(*display); + } + } +} + +void DisplayController::activate_displays() const +{ + pin_controller->activate_displays(); + CLOG(DEBUG, OUTPUT_LOGGER) << "Activated all displays!"; +} + +void DisplayController::deactivate_displays() const +{ + pin_controller->deactivate_displays(); + CLOG(DEBUG, OUTPUT_LOGGER) << "Deactivated all displays!"; +} + +} +} +} diff --git a/FlippR-Driver/src/output/detail/DisplayController.h b/FlippR-Driver/src/output/detail/DisplayController.h new file mode 100644 index 0000000..a78b1f1 --- /dev/null +++ b/FlippR-Driver/src/output/detail/DisplayController.h @@ -0,0 +1,50 @@ +/* + * DisplayController.h + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_DISPLAYCONTROLLER_H_ +#define _SRC_OUTPUT_DISPLAYCONTROLLER_H_ + +#include +#include + +#include "output/DisplayController.h" +#include "output/items/OutputDisplay.h" +#include "output/DisplayBoardPinController.h" + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +class DisplayController : public output::DisplayController +{ +public: + DisplayController(std::map> &displays, std::shared_ptr pin_controller, std::chrono::milliseconds update_frequency); + ~DisplayController() override; + + void activate_displays() const override; + void deactivate_displays() const override; + +private: + void cycle_displays() const; + +private: + std::vector> displays; + + const std::shared_ptr pin_controller; + + std::thread display_cycle_thread; + std::chrono::milliseconds update_frequency; + bool is_running; +}; + +} +} +} +#endif diff --git a/FlippR-Driver/src/output/detail/DriverBoardPinController.cpp b/FlippR-Driver/src/output/detail/DriverBoardPinController.cpp new file mode 100644 index 0000000..0cf951d --- /dev/null +++ b/FlippR-Driver/src/output/detail/DriverBoardPinController.cpp @@ -0,0 +1,142 @@ +// +// Created by rhetenor on 14.12.18. +// + +#include +#include "output/detail/DriverBoardPinController.h" + +#include "output/items/DriverBoardItem.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +DriverBoardPinController::DriverBoardPinController(std::shared_ptr output_item_mutex) : + output_item_mutex(std::move(output_item_mutex)) +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created DriverBoardPinController."; +} + +void DriverBoardPinController::activate(items::DriverBoardItem &driver_board_item) +{ + std::lock_guard guard(*output_item_mutex); + + this->deselect_all_muxes(); + + uint8_t address = driver_board_item.get_address(); + + this->select_address(address); + write_pin(this->data_pin, true); + + this->select_mux(address/8); + + this->deselect_all_muxes(); +} + +void DriverBoardPinController::deactivate(items::DriverBoardItem &driver_board_item) +{ + std::lock_guard guard(*output_item_mutex); + + this->deselect_all_muxes(); + + uint8_t address = driver_board_item.get_address(); + + this->select_address(address); + write_pin(this->data_pin, false); + + this->select_mux(address/8); + + this->deselect_all_muxes(); +} + +void DriverBoardPinController::select_address(uint8_t address) +{ + address = address % 8; + write_pin(this->address_pins[0], address & 0b001); + write_pin(this->address_pins[1], address & 0b010); + write_pin(this->address_pins[2], address & 0b100); +} + +void DriverBoardPinController::select_mux(uint8_t mux) +{ + write_pin(this->mux_enable_pins[mux], 0); +} + +void DriverBoardPinController::deselect_all_muxes() +{ + for(auto pin : mux_enable_pins) + { + write_pin(pin, 1); + } +} + +void DriverBoardPinController::clear() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Clear Driver Board items!"; + write_pin(data_pin, 0); + + for(auto mux : mux_enable_pins) + { + select_mux(mux); + for(uint8_t i = 0; i<8; i++) + { + select_address(i); + } + this->deselect_all_muxes(); + } +} + +void DriverBoardPinController::set_address_pins(std::array address_pins) +{ + this->address_pins = address_pins; + + for(auto pin : address_pins) + { + initialize_output_pin(pin); + write_pin(pin, 1); + } + + CLOG(DEBUG, OUTPUT_LOGGER) << "Pin addresses for driver board set to: " + help::make_list_string>(address_pins); +} +void DriverBoardPinController::set_mux_pins(std::array mux_enable_pins) +{ + this->mux_enable_pins = mux_enable_pins; + + for(auto pin : mux_enable_pins) + { + initialize_output_pin(pin); + write_pin(pin, 1); + } + + CLOG(DEBUG, OUTPUT_LOGGER) << "Pin addresses for multiplexers set to: " + help::make_list_string>(mux_enable_pins); +} +void DriverBoardPinController::set_data_pin(uint8_t data_pin) +{ + this->data_pin = data_pin; + + CLOG(DEBUG, OUTPUT_LOGGER) << "Set data pin to: " << std::to_string(run_pin); + + initialize_output_pin(data_pin); + + write_pin(data_pin, 0); +} +void DriverBoardPinController::set_run_pin(uint8_t run_pin) +{ + this->run_pin = run_pin; + + CLOG(DEBUG, OUTPUT_LOGGER) << "Set run pin to: " << std::to_string(run_pin); + + initialize_output_pin(run_pin); + write_pin(run_pin, 0); +} + + + +} +} +} \ No newline at end of file diff --git a/FlippR-Driver/src/output/detail/DriverBoardPinController.h b/FlippR-Driver/src/output/detail/DriverBoardPinController.h new file mode 100644 index 0000000..9d71cd5 --- /dev/null +++ b/FlippR-Driver/src/output/detail/DriverBoardPinController.h @@ -0,0 +1,55 @@ +// +// Created by rhetenor on 14.12.18. +// + +#ifndef FLIPPR_DRIVER_OUTPUT_IMPL_DRIVERBOARDPINCONTROLLER_H +#define FLIPPR_DRIVER_OUTPUT_IMPL_DRIVERBOARDPINCONTROLLER_H + +#include "output/DriverBoardPinController.h" + +#include +#include +#include + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +class DriverBoardPinController : public output::DriverBoardPinController +{ +public: + virtual ~DriverBoardPinController() = default; + + DriverBoardPinController(std::shared_ptr output_item_mutex); + + void activate(items::DriverBoardItem & driver_board_item); + void deactivate(items::DriverBoardItem & driver_board_item); + void clear(); + + void set_address_pins(std::array address_pins); + void set_mux_pins(std::array mux_enable_pins); + void set_data_pin(uint8_t data_pin); + void set_run_pin(uint8_t run_pin); + +private: + void deselect_all_muxes(); + void select_mux(uint8_t mux); + void select_address(uint8_t address); + +private: + std::shared_ptr output_item_mutex; + + std::array address_pins; + std::array mux_enable_pins; + uint8_t data_pin; + uint8_t run_pin; +}; + +} +} +} + +#endif //FLIPPR_DRIVER_DRIVERBOARDPINCONTROLLER_H diff --git a/FlippR-Driver/src/output/detail/OutputDriver.cpp b/FlippR-Driver/src/output/detail/OutputDriver.cpp new file mode 100644 index 0000000..37444fc --- /dev/null +++ b/FlippR-Driver/src/output/detail/OutputDriver.cpp @@ -0,0 +1,166 @@ +/* + * OutputDriver.cpp + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include +#include +#include + +#include "output/OutputDriver.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ + +using namespace items; + +OutputDriver::OutputDriver(std::shared_ptr display_controller, std::map> solenoids, + std::map> lamps, std::map> sounds, + std::map> flippers, std::map> displays): + display_controller(std::move(display_controller)), + solenoids(std::move(solenoids)), + lamps(std::move(lamps)), + sounds(std::move(sounds)), + flippers(std::move(flippers)), + displays(std::move(displays)) +{ + CLOG(INFO, OUTPUT_LOGGER) << "OutputDriver created and running."; +} + +void OutputDriver::activate_displays() const +{ + display_controller->activate_displays(); +} + +void OutputDriver::deactivate_displays() const +{ + display_controller->deactivate_displays(); +} + + +void OutputDriver::deactivate_all_lamps() const +{ + std::for_each(lamps.begin(), lamps.end(), [](std::pair> lamp){lamp.second->deactivate();}); +} + +void OutputDriver::activate_all_lamps() const +{ + std::for_each(lamps.begin(), lamps.end(), [](std::pair> lamp){lamp.second->activate();}); +} + +void OutputDriver::rotate_all_lamps() const +{ + for(const auto & lamp : this->lamps) + { + lamp.second->activate(); + // ToDo is this thread safe?? + std::this_thread::sleep_for(lamp.second->get_activation_time()); + lamp.second->deactivate(); + } +} + +void OutputDriver::activate_all_flipper_relays() const +{ + for(auto flipper_relay : this->flippers) + { + flipper_relay.second->activate(); + } +} + +void OutputDriver::deactivate_all_flipper_relays() const +{ + for(auto flipper_relay : this->flippers) + { + flipper_relay.second->deactivate(); + } +} + +std::vector> OutputDriver::get_sounds() const +{ + std::vector> sounds; + + // TODO: why a copy? + boost::copy(this->sounds | boost::adaptors::map_values, std::back_inserter(sounds)); + + return sounds; +} + +std::vector> OutputDriver::get_displays() const +{ + std::vector> displays; + + boost::copy(this->displays | boost::adaptors::map_values, std::back_inserter(displays)); + + return displays; +} + +std::vector> OutputDriver::get_lamps() const +{ + std::vector> lamps; + + boost::copy(this->lamps | boost::adaptors::map_values, std::back_inserter(lamps)); + + return lamps; +} + +std::vector> OutputDriver::get_flippers() const +{ + std::vector> flippers; + + boost::copy(this->flippers | boost::adaptors::map_values, std::back_inserter(flippers)); + + return flippers; +} + +std::vector> OutputDriver::get_solenoids() const +{ + std::vector> solenoids; + + boost::copy(this->solenoids | boost::adaptors::map_values, std::back_inserter(solenoids)); + + return solenoids; +} + +boost::optional> OutputDriver::get_lamp(const std::string &name) const +{ + return this->lamps.find(name)->second; +} + +boost::optional> OutputDriver::get_solenoid(const std::string &name) const +{ + return this->solenoids.find(name)->second; +} + +boost::optional> OutputDriver::get_sound(const std::string &name) const +{ + return this->sounds.find(name)->second; +} + +boost::optional> OutputDriver::get_flipper(const std::string &name) const +{ + return this->flippers.find(name)->second; +} + +boost::optional> OutputDriver::get_display(const std::string &name) const +{ + return this->displays.find(name)->second; +} + +void OutputDriver::shut_down_driver() const +{ + this->deactivate_all_flipper_relays(); + this->deactivate_all_lamps(); + this->deactivate_displays(); + + CLOG(INFO, OUTPUT_LOGGER) << "Deactivated all output items."; +} + + +} +} /* namespace output */ diff --git a/FlippR-Driver/src/output/detail/SoundBoardPinController.cpp b/FlippR-Driver/src/output/detail/SoundBoardPinController.cpp new file mode 100644 index 0000000..b918199 --- /dev/null +++ b/FlippR-Driver/src/output/detail/SoundBoardPinController.cpp @@ -0,0 +1,95 @@ +// +// Created by rhetenor on 14.12.18. +// + +#include +#include "output/detail/SoundBoardPinController.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +SoundBoardPinController::SoundBoardPinController(std::shared_ptr output_item_mutex, + uint8_t fire_address, + const std::array address_pins) : + output_item_mutex{output_item_mutex}, + fire_address{fire_address}, + address_pins(address_pins) +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created SoundBoardPinController"; +} + + +SoundBoardPinController::SoundBoardPinController(std::shared_ptr output_item_mutex) : + output_item_mutex{output_item_mutex} +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created SoundBoardPinController without addresses!"; +} + +void SoundBoardPinController::activate(const items::detail::Sound &sound) +{ + std::lock_guard guard(*output_item_mutex); + + write_sound_address(sound.get_address()); + + fire_sound(); +} + +void SoundBoardPinController::deactivate(const items::detail::Sound &sound) +{ + std::lock_guard guard(*output_item_mutex); + + write_sound_address(0); + + fire_sound(); +} + + +void SoundBoardPinController::write_sound_address(const uint8_t &address) const +{ + write_pin(this->address_pins[0], address & 0b0000001u); + write_pin(this->address_pins[1], address & 0b0000010u); + write_pin(this->address_pins[2], address & 0b0000100u); + write_pin(this->address_pins[3], address & 0b0001000u); + write_pin(this->address_pins[4], address & 0b0010000u); + write_pin(this->address_pins[5], address & 0b0100000u); + write_pin(this->address_pins[6], address & 0b1000000u); +} + +void SoundBoardPinController::fire_sound() const +{ + PinController::write_pin(this->fire_address, true); + PinController::write_pin(this->fire_address, false); +} + +void SoundBoardPinController::write_pin(const uint8_t &pin, const bool &value) const +{ + PinController::write_pin(pin, value); +} + +void SoundBoardPinController::set_address_pins(std::array address_pins) +{ + this->address_pins = address_pins; + + for(auto & pin : address_pins) + { + this->initialize_output_pin(pin); + } + + CLOG(DEBUG, OUTPUT_LOGGER) << "Pin addresses for sounds set to: " + help::make_list_string>(address_pins); +} + +void SoundBoardPinController::set_fire_address(const uint8_t &fire_address) +{ + this->fire_address = fire_address; + CLOG(DEBUG, OUTPUT_LOGGER) << "Fire-pin address for sounds set to: " << int{fire_address}; +} + +} +} +} diff --git a/FlippR-Driver/src/output/detail/SoundBoardPinController.h b/FlippR-Driver/src/output/detail/SoundBoardPinController.h new file mode 100644 index 0000000..f664e0c --- /dev/null +++ b/FlippR-Driver/src/output/detail/SoundBoardPinController.h @@ -0,0 +1,49 @@ +// +// Created by rhetenor on 14.12.18. +// + +#ifndef FLIPPR_DRIVER_OUTPUT_IMPL_SOUNDBOARDPINCONTROLLER_H +#define FLIPPR_DRIVER_OUTPUT_IMPL_SOUNDBOARDPINCONTROLLER_H + +#include "output/SoundBoardPinController.h" + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace detail +{ + +class SoundBoardPinController : public output::SoundBoardPinController +{ +public: + explicit SoundBoardPinController(std::shared_ptr output_item_mutex, uint8_t fire_address, const std::array address_pins); + explicit SoundBoardPinController(std::shared_ptr output_item_mutex); + ~SoundBoardPinController() override = default; + + void activate(const items::detail::Sound &sound); + void deactivate(const items::detail::Sound &sound); + + void set_fire_address(const uint8_t & fire_address); + void set_address_pins(const std::array address_pins); + +private: + void write_sound_address(const uint8_t & address) const; + void fire_sound() const; + + void write_pin(const uint8_t & pin, const bool & value) const; + +private: + std::shared_ptr output_item_mutex; + + uint8_t pin_base; + uint8_t fire_address; + std::array address_pins; +}; + +} +} +} +#endif //FLIPPR_DRIVER_SOUNDBOARDPINCONTROLLER_H diff --git a/FlippR-Driver/src/output/factories/DisplayFactory.cpp b/FlippR-Driver/src/output/factories/DisplayFactory.cpp new file mode 100644 index 0000000..49613b4 --- /dev/null +++ b/FlippR-Driver/src/output/factories/DisplayFactory.cpp @@ -0,0 +1,62 @@ +/* + * DisplayFactory.cpp + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "output/DisplayBoardPinController.h" +#include "output/items/detail/EightDigitDisplay.h" +#include "output/items/detail/SevenDigitDisplay.h" +#include "DisplayFactory.h" + +namespace flippR_driver +{ +namespace output +{ + +DisplayFactory::DisplayFactory(nlohmann::json &object, std::shared_ptr pin_controller) : + ItemFactory{object, pin_controller} +{ + this->create_pin_map(); + pin_controller->set_pin_map(this->pin_map); +} + +std::map> DisplayFactory::getItemMap() +{ + std::map> display_map; + auto displays = this->object.at(config_path::display_list); + for (auto & display : displays) + { + auto name = display.at(config_path::item_name).get(); + auto address = display.at(config_path::item_address).get(); + auto digits = display.at(config_path::display_digits).get(); + if (digits == 8) + display_map.emplace(name, std::dynamic_pointer_cast(std::make_shared(address, name))); + else if (digits == 7) + display_map.emplace(name, std::dynamic_pointer_cast(std::make_shared(address, name))); + else + throw new std::logic_error{"Display digits can either be 7 or 8"}; + } + return display_map; +} + +void DisplayFactory::create_pin_map() +{ + nlohmann::json board_config = this->object.at(config_path::display_board); + this->pin_map["run"] = board_config.at(config_path::run_pin); + + nlohmann::json segment_select = board_config.at(config_path::display_segement_select); + this->pin_map["segment_select_A"] = segment_select.at("A"); + this->pin_map["segment_select_B"] = segment_select.at("B"); + this->pin_map["segment_select_C"] = segment_select.at("C"); + + nlohmann::json digit_select = board_config.at(config_path::display_digit_select); + this->pin_map["digit_select_A"] = digit_select.at("A"); + this->pin_map["digit_select_B"] = digit_select.at("B"); + this->pin_map["digit_select_C"] = digit_select.at("C"); + this->pin_map["digit_select_D"] = digit_select.at("D"); +} + +} +} diff --git a/FlippR-Driver/src/output/factories/DisplayFactory.h b/FlippR-Driver/src/output/factories/DisplayFactory.h new file mode 100644 index 0000000..ed1d1bd --- /dev/null +++ b/FlippR-Driver/src/output/factories/DisplayFactory.h @@ -0,0 +1,37 @@ +/* + * DisplayFactory.h + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_DISPLAYFACTORY_H +#define FLIPPR_DRIVER_DISPLAYFACTORY_H + +#include "ItemFactory.h" +#include "output/DisplayBoardPinController.h" + +namespace flippR_driver +{ +namespace output +{ + +class DisplayFactory : ItemFactory +{ +public: + DisplayFactory(nlohmann::json & object, std::shared_ptr pin_controller); + + std::map> getItemMap(); + +private: + void create_pin_map(); + +private: + std::map pin_map; +}; + +} +} + + +#endif //FLIPPR_DRIVER_DISPLAYFACTORY_H diff --git a/FlippR-Driver/src/output/factories/FlipperFactory.cpp b/FlippR-Driver/src/output/factories/FlipperFactory.cpp new file mode 100644 index 0000000..c737db3 --- /dev/null +++ b/FlippR-Driver/src/output/factories/FlipperFactory.cpp @@ -0,0 +1,37 @@ +/* + * FlipperFactory.cpp + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include +#include +#include "FlipperFactory.h" + +namespace flippR_driver +{ +namespace output +{ + +FlipperFactory::FlipperFactory(nlohmann::json &object, std::shared_ptr pin_controller) : + ItemFactory{object, pin_controller} +{} + +std::map> FlipperFactory::getItemMap() +{ + auto flippers = this->object.at(config_path::flipper_path); + std::map> flipper_map; + for (auto flipper : flippers) + { + auto name = flipper.at(config_path::item_name).get(); + auto address = flipper.at(config_path::item_address).get(); + + auto flipper_item = std::make_shared(std::static_pointer_cast(this->pin_controller), address, name); + flipper_map.emplace(name, flipper_item); + } + return flipper_map; +} + +} +} diff --git a/FlippR-Driver/src/output/factories/FlipperFactory.h b/FlippR-Driver/src/output/factories/FlipperFactory.h new file mode 100644 index 0000000..94dd741 --- /dev/null +++ b/FlippR-Driver/src/output/factories/FlipperFactory.h @@ -0,0 +1,32 @@ +/* + * FlipperFactory.h + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_FLIPPERFACTORY_H +#define FLIPPR_DRIVER_FLIPPERFACTORY_H + +#include "ItemFactory.h" +#include "output/items/Flipper.h" +#include + +namespace flippR_driver +{ +namespace output +{ + +class FlipperFactory : ItemFactory +{ +public: + FlipperFactory(nlohmann::json & object, std::shared_ptr pin_controller); + std::map > getItemMap(); + +}; + +} +} + + +#endif //FLIPPR_DRIVER_FLIPPERFACTORY_H diff --git a/FlippR-Driver/src/output/factories/ItemFactory.cpp b/FlippR-Driver/src/output/factories/ItemFactory.cpp new file mode 100644 index 0000000..207772a --- /dev/null +++ b/FlippR-Driver/src/output/factories/ItemFactory.cpp @@ -0,0 +1,54 @@ +/* + * ItemFactory.cpp + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "ItemFactory.h" + +namespace flippR_driver +{ +namespace output +{ + +ItemFactory::ItemFactory(nlohmann::json &object, std::shared_ptr pin_controller) : + pin_controller{pin_controller} +{ + this->object = object; + if (object.find(config_path::port_extenders) != object.end()) + { + this->port_extenders = object.at(config_path::port_extenders); + this->initialize_port_extenders(); + } +} + +void ItemFactory::initialize_port_extender(nlohmann::json &extender) +{ + auto i2c_address = extender.at("i2c_address").get(); + auto pin_base = extender.at("pin_base").get(); + this->pin_controller->initialize_port_expander(i2c_address, pin_base); +} + +void ItemFactory::initialize_port_extenders() +{ + for (auto extender : this->port_extenders) + { + this->initialize_port_extender(extender); + } +} + +uint8_t ItemFactory::get_extender_pin_base(std::string &name) +{ + for (auto extender : port_extenders) + { + if (extender.at("name").get() == name) + { + return extender.at("pin_base").get(); + } + } + return 0; +} + +} +} diff --git a/FlippR-Driver/src/output/factories/ItemFactory.h b/FlippR-Driver/src/output/factories/ItemFactory.h new file mode 100644 index 0000000..216bb2b --- /dev/null +++ b/FlippR-Driver/src/output/factories/ItemFactory.h @@ -0,0 +1,77 @@ +/* + * ItemFactory.h + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_ITEMFACTORY_H +#define FLIPPR_DRIVER_ITEMFACTORY_H + +#include +#include "utility/config.h" +#include "json/json.hpp" +#include "output/items/Item.h" + +namespace flippR_driver +{ +namespace output +{ + +namespace config_path +{ + const char item_name[] = "name"; + const char item_address[] = "address"; + const char item_extender[] = "extender"; + const char item_identifier[] = "id"; + const char port_extenders[] = "port_extenders"; + + const char deactivation_time[] = "deactivation_time_milliseconds"; + + const char sound_path[] = "sounds"; + const char fire_pin[] = "fire_pin"; + + const char flipper_path[] = "flippers"; + + const char solenoid_path[] = "solenoids"; + + const char lamps_path[] = "lamps"; + const char address_pins[] = "address_pins"; + const char enable_pins[] = "enable_pins"; + const char data_pin[] = "data_pin"; + + const char display_board[] = "display_board"; + const char run_pin[] = "run"; + const char display_update_frequency[] = "update_frequency"; + const char display_select[] = "display_select"; + const char display_segement_select[] = "segment_select"; + const char display_digit_select[] = "digit_select"; + const char display_digits[] = "digits"; + const char display_list[] = "displays"; +} + +class ItemFactory +{ +public: + ItemFactory(nlohmann::json &object, std::shared_ptr pin_controller); + + //virtual std::map> getItemMap() = 0; + +protected: + void initialize_port_extender(nlohmann::json & extender); + void initialize_port_extenders(); + uint8_t get_extender_pin_base(std::string & name); + +protected: + nlohmann::json object; + std::shared_ptr pin_controller; + +private: + nlohmann::json port_extenders; +}; + +} +} + + +#endif //FLIPPR_DRIVER_ITEMFACTORY_H diff --git a/FlippR-Driver/src/output/factories/LampFactory.cpp b/FlippR-Driver/src/output/factories/LampFactory.cpp new file mode 100644 index 0000000..1a8639d --- /dev/null +++ b/FlippR-Driver/src/output/factories/LampFactory.cpp @@ -0,0 +1,89 @@ +/* + * LampFactory.cpp + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include +#include +#include "LampFactory.h" +#include "output/items/detail/Lamp.h" + +namespace flippR_driver +{ +namespace output +{ + +LampFactory::LampFactory(nlohmann::json &object, std::shared_ptr pin_controller) : + ItemFactory{object, pin_controller} +{ + this->set_address_pins(); + this->set_mux_pins(); + + auto controller = std::dynamic_pointer_cast(this->pin_controller); + + auto data_pin = this->get_address_pin(this->object.at(config_path::data_pin)); + controller->set_data_pin(data_pin); + + auto run_pin = this->get_address_pin(this->object.at(config_path::run_pin)); + controller->set_run_pin(run_pin); +} + +std::map> LampFactory::getItemMap() +{ + auto lamps = this->object.at(config_path::lamps_path); + std::map> lamp_map; + for (auto lamp : lamps) + { + auto name = lamp.at(config_path::item_name).get(); + auto address = lamp.at(config_path::item_address).get(); + + auto lamp_item = std::make_shared(std::static_pointer_cast(this->pin_controller), address, name); + lamp_map.emplace(name, lamp_item); + } + return lamp_map; +} + +void LampFactory::set_address_pins() +{ + auto address_pins = this->object.at(config_path::address_pins); + + std::array pins; + + pins.at(0) = this->get_address_pin(address_pins.at("A0")); + pins.at(1) = this->get_address_pin(address_pins.at("A1")); + pins.at(2) = this->get_address_pin(address_pins.at("A2")); + + std::dynamic_pointer_cast(this->pin_controller)->set_address_pins(pins); +} + +uint8_t LampFactory::get_address_pin(nlohmann::json & pin_object) +{ + auto address = pin_object.at(config_path::item_address).get(); + uint8_t pin_base = 0; + if (pin_object.find(config_path::item_extender) != pin_object.end()) + { + auto extender = pin_object.at(config_path::item_extender).get(); + pin_base = this->get_extender_pin_base(extender); + } + + return address + pin_base; +} + +void LampFactory::set_mux_pins() +{ + auto address_pins = this->object.at(config_path::enable_pins); + + std::array pins; + + for(char i = 1; i < 14; i++) + { + pins.at(i-1) = this->get_address_pin(address_pins.at("E" + std::to_string(i))); + } + + std::dynamic_pointer_cast(this->pin_controller)->set_mux_pins(pins); +} + +} +} diff --git a/FlippR-Driver/src/output/factories/LampFactory.h b/FlippR-Driver/src/output/factories/LampFactory.h new file mode 100644 index 0000000..7d18546 --- /dev/null +++ b/FlippR-Driver/src/output/factories/LampFactory.h @@ -0,0 +1,36 @@ +/* + * LampFactory.h + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_LAMPFACTORY_H +#define FLIPPR_DRIVER_LAMPFACTORY_H + +#include "output/DriverBoardPinController.h" +#include "ItemFactory.h" +#include "output/items/Lamp.h" + +namespace flippR_driver +{ +namespace output +{ + +class LampFactory : ItemFactory +{ +public: + LampFactory(nlohmann::json & object, std::shared_ptr pin_controller); + std::map> getItemMap(); + +private: + void set_address_pins(); + void set_mux_pins(); + + uint8_t get_address_pin(nlohmann::json & pin_object); +}; + +} +} + +#endif //FLIPPR_DRIVER_LAMPFACTORY_H diff --git a/FlippR-Driver/src/output/factories/SolenoidFactory.cpp b/FlippR-Driver/src/output/factories/SolenoidFactory.cpp new file mode 100644 index 0000000..f27c3e1 --- /dev/null +++ b/FlippR-Driver/src/output/factories/SolenoidFactory.cpp @@ -0,0 +1,48 @@ +/* + * SolenoidFactory.cpp + * + * Created on: January 6, 2020 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "output/items/detail/Solenoid.h" +#include "SolenoidFactory.h" + +namespace flippR_driver +{ +namespace output +{ + +SolenoidFactory::SolenoidFactory(nlohmann::json &object, std::shared_ptr pin_controller) : + ItemFactory{object, pin_controller} +{ + if (object.find(config_path::deactivation_time) != object.end()) + { + this->deactivation_time = object.at(config_path::deactivation_time).get(); + } +} + +std::map> SolenoidFactory::getItemMap() +{ + auto solenoids = this->object.at(config_path::solenoid_path); + std::map> solenoid_map; + + for (auto solenoid : solenoids) + { + auto name = solenoid.at(config_path::item_name).get(); + auto address = solenoid.at(config_path::item_address).get(); + std::chrono::milliseconds deactivation_time_chrono{this->deactivation_time}; + + if (solenoid.find(config_path::deactivation_time) != solenoid.end()) + { + deactivation_time_chrono = std::chrono::milliseconds{solenoid.at(config_path::deactivation_time).get()}; + } + + auto solenoid_item = std::make_shared(std::static_pointer_cast(this->pin_controller), address, name, deactivation_time_chrono); + solenoid_map.emplace(name, solenoid_item); + } + return solenoid_map; +} + +} +} diff --git a/FlippR-Driver/src/output/factories/SolenoidFactory.h b/FlippR-Driver/src/output/factories/SolenoidFactory.h new file mode 100644 index 0000000..3a6e69f --- /dev/null +++ b/FlippR-Driver/src/output/factories/SolenoidFactory.h @@ -0,0 +1,34 @@ +/* + * SolenoidFactory.h + * + * Created on: January 6, 2020 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_SOLENOIDFACTORY_H +#define FLIPPR_DRIVER_SOLENOIDFACTORY_H + +#include "output/DriverBoardPinController.h" +#include "ItemFactory.h" +#include "output/items/Solenoid.h" + +namespace flippR_driver +{ +namespace output +{ + +class SolenoidFactory : public ItemFactory +{ +public: + SolenoidFactory(nlohmann::json &object, std::shared_ptr pin_controller); + + std::map> getItemMap(); + +private: + uint8_t deactivation_time; +}; + +} +} + +#endif //FLIPPR_DRIVER_SOLENOIDFACTORY_H diff --git a/FlippR-Driver/src/output/factories/SoundFactory.cpp b/FlippR-Driver/src/output/factories/SoundFactory.cpp new file mode 100644 index 0000000..9b59441 --- /dev/null +++ b/FlippR-Driver/src/output/factories/SoundFactory.cpp @@ -0,0 +1,74 @@ +/* + * SoundFactory.cpp + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "SoundFactory.h" + +namespace flippR_driver +{ +namespace output +{ + +SoundFactory::SoundFactory(nlohmann::json &object, std::shared_ptr pin_controller) : + ItemFactory{object, pin_controller} +{ + this->set_fire_pin(); + this->set_address_pins(); +} + +std::map> SoundFactory::getItemMap() +{ + auto sounds = this->object.at(config_path::sound_path); + std::map> sound_map; + for (auto sound : sounds) + { + auto name = sound.at(config_path::item_name).get(); + auto address = sound.at(config_path::item_address).get(); + auto id = sound.at(config_path::item_identifier).get(); + + auto sound_item = std::make_shared(std::static_pointer_cast(this->pin_controller), address, name, id); + + sound_map.emplace(name, sound_item); + } + return sound_map; +} + +void SoundFactory::set_fire_pin() +{ + auto fire_pin = object.at(config_path::fire_pin); + auto fire_pin_address = fire_pin.at(config_path::item_address).get(); + if (fire_pin.find(config_path::item_extender) != fire_pin.end()) + { + auto extender_name = fire_pin.at(config_path::item_extender).get(); + fire_pin_address += this->get_extender_pin_base(extender_name); + } + std::dynamic_pointer_cast(this->pin_controller)->set_fire_address(fire_pin_address); +} + +void SoundFactory::set_address_pins() +{ + auto address_pins = object.at(config_path::address_pins); + + std::array pins; + + for (auto & pin_json : address_pins) + { + uint8_t pin = pin_json.at(config_path::item_address).get(); + if (pin_json.find(config_path::item_extender) != pin_json.end()) + { + auto extender_name = pin_json.at(config_path::item_extender).get(); + pin += this->get_extender_pin_base(extender_name); + } + uint8_t id = pin_json.at(config_path::item_identifier).get(); + + pins[id] = pin; + } + + std::dynamic_pointer_cast(this->pin_controller)->set_address_pins(pins); +} + +} +} diff --git a/FlippR-Driver/src/output/factories/SoundFactory.h b/FlippR-Driver/src/output/factories/SoundFactory.h new file mode 100644 index 0000000..85a4471 --- /dev/null +++ b/FlippR-Driver/src/output/factories/SoundFactory.h @@ -0,0 +1,34 @@ +/* + * SoundFactory.h + * + * Created on: December 28, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_SOUNDFACTORY_H +#define FLIPPR_DRIVER_SOUNDFACTORY_H + +#include "ItemFactory.h" + +#include "output/detail/SoundBoardPinController.h" + +namespace flippR_driver +{ +namespace output +{ + +class SoundFactory : ItemFactory +{ +public: + SoundFactory(nlohmann::json & object, std::shared_ptr pin_controller); + std::map> getItemMap(); + +private: + void set_fire_pin(); + void set_address_pins(); +}; + +} +} + +#endif //FLIPPR_DRIVER_SOUNDFACTORY_H diff --git a/FlippR-Driver/src/output/items/DriverBoardItem.h b/FlippR-Driver/src/output/items/DriverBoardItem.h new file mode 100644 index 0000000..5c5a8d5 --- /dev/null +++ b/FlippR-Driver/src/output/items/DriverBoardItem.h @@ -0,0 +1,33 @@ +// +// Created by rhetenor on 23.11.18. +// + +#ifndef FLIPPR_DRIVER_IDRIVERBOARDITEM_H +#define FLIPPR_DRIVER_IDRIVERBOARDITEM_H + +#include "output/items/detail/Item.h" + +#include "../DriverBoardPinController.h" + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class DriverBoardItem +{ +public: + virtual ~DriverBoardItem() = default; + + virtual uint8_t get_address() const = 0; +}; + +} +} +} + +#endif //FLIPPR_DRIVER_IDRIVERBOARDITEM_H diff --git a/FlippR-Driver/src/output/items/OutputDisplay.h b/FlippR-Driver/src/output/items/OutputDisplay.h new file mode 100644 index 0000000..54b4571 --- /dev/null +++ b/FlippR-Driver/src/output/items/OutputDisplay.h @@ -0,0 +1,38 @@ +/* + * Display.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_IDISPLAY_H_ +#define _SRC_OUTPUT_IDISPLAY_H_ + +#include +#include +#include + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ + +class OutputDisplay : public virtual Display +{ + +public: + virtual ~OutputDisplay() = default; + + virtual uint8_t get_address() const = 0; + virtual std::string get_name() const = 0; + virtual std::string get_content() const = 0; +}; + +} +} /* namespace output */ +} +#endif diff --git a/FlippR-Driver/src/output/items/detail/Display.cpp b/FlippR-Driver/src/output/items/detail/Display.cpp new file mode 100644 index 0000000..dd8d037 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Display.cpp @@ -0,0 +1,80 @@ +// +// Created by rhetenor on 10.10.18. +// + +#include "Display.h" +#include "utility/config.h" + +#include +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +Display::Display(const uint8_t & address, const std::string & name) : + address{address}, + name{name} +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created display " << name << " with address " << int{address} << "."; +} + +std::string Display::get_name() const +{ + return this->name; +} + +void Display::write_score(const unsigned int & score, const unsigned int & length) +{ + auto score_string = std::to_string(score); + + fit_score_string(score_string, length); + + write_content(score_string, length); +} + +std::string Display::fit_score_string(std::string & score_string, const unsigned int & length) +{ + auto score_length = score_string.length(); + + if (score_length > length) + { + CLOG(DEBUG, OUTPUT_LOGGER) << "Score too long for display"; + std::string full_display; + return full_display.insert(0, length, '9'); + } + + score_string.insert(0, length - score_length, '\0'); + return score_string; +} + +void Display::write_content(std::string & content, const unsigned int & length) +{ + if(content.size() > length) + { + CLOG(WARNING, OUTPUT_LOGGER) << "Cannot write more than " << length << " digits on " << length << "-Digit Display. Truncating!"; + content = content.substr(0, length); + } + + this->content = content; +} + +std::string Display::get_content() const +{ + return this->content; +} + +uint8_t Display::get_address() const +{ + return this->address; +} + +} +} +} +} diff --git a/FlippR-Driver/src/output/items/detail/Display.h b/FlippR-Driver/src/output/items/detail/Display.h new file mode 100644 index 0000000..905514c --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Display.h @@ -0,0 +1,55 @@ +/* + * Display.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef FLIPPR_DRIVER_OUTPUT_ITEMS_IMPL_DISPLAY_H_ +#define FLIPPR_DRIVER_OUTPUT_ITEMS_IMPL_DISPLAY_H_ + +#include "output/items/OutputDisplay.h" + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class Display : public virtual items::OutputDisplay +{ +public: + Display(const uint8_t & address, const std::string & name); + virtual ~Display() = default; + + void write_score(const unsigned int & score, const unsigned int & length); + void write_content(std::string & content, const unsigned int & length); + + std::string get_content() const override; + uint8_t get_address() const override; + std::string get_name() const override; + +private: + std::string fit_score_string(std::string & score_string, const unsigned int & length); + +public: + std::string content; + +protected: + const std::string name; + const uint8_t address; + +}; + +} +} +} /* namespace output */ +} + + +#endif diff --git a/FlippR-Driver/src/output/items/detail/DriverBoardItem.cpp b/FlippR-Driver/src/output/items/detail/DriverBoardItem.cpp new file mode 100644 index 0000000..ae1aa98 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/DriverBoardItem.cpp @@ -0,0 +1,16 @@ +// +// Created by rhetenor on 5/6/19. +// + +#include "DriverBoardItem.h" + +using namespace flippR_driver::output; + +items::detail::DriverBoardItem::DriverBoardItem(std::shared_ptr pin_controller, const uint8_t & address) : + address(address) +{} + +uint8_t items::detail::DriverBoardItem::get_address() const +{ + return this->address; +} diff --git a/FlippR-Driver/src/output/items/detail/DriverBoardItem.h b/FlippR-Driver/src/output/items/detail/DriverBoardItem.h new file mode 100644 index 0000000..6c853c4 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/DriverBoardItem.h @@ -0,0 +1,40 @@ +// +// Created by rhetenor on 5/6/19. +// + +#ifndef FLIPPR_DRIVER_DRIVERBOARDITEM_H +#define FLIPPR_DRIVER_DRIVERBOARDITEM_H + +#include "output/items/DriverBoardItem.h" + +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class DriverBoardItem : public output::items::DriverBoardItem +{ +public: + DriverBoardItem(std::shared_ptr pin_controller, const uint8_t & address); + + ~DriverBoardItem() override = default; + + uint8_t get_address() const override; + +protected: + const uint8_t address; +}; + + +} +} +} +} + +#endif //FLIPPR_DRIVER_DRIVERBOARDITEM_H diff --git a/FlippR-Driver/src/output/items/detail/EightDigitDisplay.h b/FlippR-Driver/src/output/items/detail/EightDigitDisplay.h new file mode 100644 index 0000000..5305e79 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/EightDigitDisplay.h @@ -0,0 +1,55 @@ +// +// Created by rhetenor on 20.11.18. +// + +#ifndef FLIPPR_DRIVER_OUTPUT_ITEMS_IMPL_EIGHTDIGITDISPLAY_H +#define FLIPPR_DRIVER_OUTPUT_ITEMS_IMPL_EIGHTDIGITDISPLAY_H + +#include "output/items/detail/Display.h" + +#include "output/items/EightDigitDisplay.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class EightDigitDisplay : public virtual items::detail::Display, public virtual items::EightDigitDisplay +{ +public: + EightDigitDisplay(const uint8_t & address, const std::string & name) : + detail::Display(address, name) + { + CLOG(DEBUG, OUTPUT_LOGGER) << "Created EightDigitDisplay " << name << " with address " << int{this->address}; + } + + ~EightDigitDisplay() override = default; + + void write_score(unsigned int score) override + { + detail::Display::write_score(score, 8); + } + + void write_content(std::string content) override + { + detail::Display::write_content(content, 8); + } + + std::string get_name() const override + { + return name; + } + +}; + +} +} +} +} +#endif //FLIPPR_DRIVER_EIGHTDIGITDISPLAY_H diff --git a/FlippR-Driver/src/output/items/detail/Flipper.cpp b/FlippR-Driver/src/output/items/detail/Flipper.cpp new file mode 100644 index 0000000..b85c6d3 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Flipper.cpp @@ -0,0 +1,54 @@ +/* + * Flipper.cpp + * + * Created on: May 6, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "Flipper.h" +#include "../DriverBoardItem.h" + +#include "utility/config.h" + + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +Flipper::Flipper(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name) : + Item(std::move(name)), DriverBoardItem(pin_controller, address), pin_controller(std::move(pin_controller)) +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created flipper \"" << name << "\" with address " << int(address); +} + +Flipper::~Flipper() +{ + this->deactivate(); +} + +void Flipper::activate() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Flipper " << name << " activated"; + this->pin_controller->activate(*this); +} + +void Flipper::deactivate() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Flipper " << name << " deactivated"; + this->pin_controller->deactivate(*this); +} + +bool Flipper::is_activated() +{ + return this->is_activated(); +} + +} +} +} +} \ No newline at end of file diff --git a/FlippR-Driver/src/output/items/detail/Flipper.h b/FlippR-Driver/src/output/items/detail/Flipper.h new file mode 100644 index 0000000..89f8084 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Flipper.h @@ -0,0 +1,45 @@ +/* + * Flipper.h + * + * Created on: May 6, 2019 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_FLIPPR_CODE_FLIPPER_H +#define _SRC_FLIPPR_CODE_FLIPPER_H + +#include "output/items/Flipper.h" +#include "output/items/detail/DriverBoardItem.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class Flipper : public detail::Item, public items::Flipper, public detail::DriverBoardItem +{ +public: + Flipper(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name); + ~Flipper() override; + + void activate() override; + void deactivate() override; + bool is_activated() override; + +private: + const std::shared_ptr pin_controller; + bool activated; + +}; + +} +} +} +} + + +#endif //FLIPPR_CODE_FLIPPER_H diff --git a/FlippR-Driver/src/output/items/detail/Item.cpp b/FlippR-Driver/src/output/items/detail/Item.cpp new file mode 100644 index 0000000..942a730 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Item.cpp @@ -0,0 +1,28 @@ +// +// Created by rhetenor on 21.11.18. +// + +#include "Item.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +Item::Item(std::string name) : + name(std::move(name)) +{} + +std::string Item::get_name() const +{ + return this->name; +} + +} +} +} +} diff --git a/FlippR-Driver/src/output/items/detail/Item.h b/FlippR-Driver/src/output/items/detail/Item.h new file mode 100644 index 0000000..e896e36 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Item.h @@ -0,0 +1,41 @@ +/* + * CabinetItem.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_CABINETITEM_H_ +#define _SRC_OUTPUT_CABINETITEM_H_ + +#include "output/items/Item.h" + +#include +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class Item : public virtual items::Item +{ +public: + Item(std::string name); + ~Item() override = default; + + std::string get_name() const override; +protected: + const std::string name; + +}; + +} +} +} /* namespace output */ +} +#endif diff --git a/FlippR-Driver/src/output/items/detail/Lamp.cpp b/FlippR-Driver/src/output/items/detail/Lamp.cpp new file mode 100644 index 0000000..5cff0e7 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Lamp.cpp @@ -0,0 +1,59 @@ +/* + * Lamp.cpp + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "Lamp.h" + +#include +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +Lamp::Lamp(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name) : + detail::Item(std::move(name)), + DriverBoardItem(pin_controller, address), + pin_controller(std::move(pin_controller)), + activated(false), + activation_time(10) +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created lamp \"" << name << "\" with address " << int(address); +} + +void Lamp::activate() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Activate lamp " << name; + this->activated = true; + this->pin_controller->activate(*this); +} + +void Lamp::deactivate() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Deactivate lamp " << name; + this->activated = false; + this->pin_controller->deactivate(*this); +} + +bool Lamp::is_activated() +{ + return this->activated; +} + +std::chrono::milliseconds Lamp::get_activation_time() const +{ + return this->activation_time; +} + +} +} +} /* namespace output */ +} diff --git a/FlippR-Driver/src/output/items/detail/Lamp.h b/FlippR-Driver/src/output/items/detail/Lamp.h new file mode 100644 index 0000000..af7ff13 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Lamp.h @@ -0,0 +1,48 @@ +/* + * Lamp.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_LAMP_H_ +#define _SRC_OUTPUT_LAMP_H_ + +#include "output/items/Lamp.h" +#include "output/items/detail/Item.h" +#include "output/items/detail/DriverBoardItem.h" + +namespace flippR_driver +{ +namespace output +{ + +class DriverBoardPinController; + +namespace items +{ +namespace detail +{ + +class Lamp : public detail::DriverBoardItem, public detail::Item, public items::Lamp +{ +public: + Lamp(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name); + ~Lamp() override = default; + + void activate() override; + void deactivate() override; + bool is_activated() override; + std::chrono::milliseconds get_activation_time() const override; + +private: + const std::shared_ptr pin_controller; + bool activated; + std::chrono::milliseconds activation_time; +}; + +} +} +} /* namespace output */ +} +#endif diff --git a/FlippR-Driver/src/output/items/detail/SevenDigitDisplay.h b/FlippR-Driver/src/output/items/detail/SevenDigitDisplay.h new file mode 100644 index 0000000..bde4989 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/SevenDigitDisplay.h @@ -0,0 +1,51 @@ +// +// Created by rhetenor on 20.11.18. +// + +#ifndef FLIPPR_DRIVER_SEVENDIGITDISPLAY_H +#define FLIPPR_DRIVER_SEVENDIGITDISPLAY_H + +#include "output/items/SevenDigitDisplay.h" + +#include "output/items/detail/Display.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class SevenDigitDisplay : public virtual items::detail::Display, public virtual items::SevenDigitDisplay +{ +public: + SevenDigitDisplay(const uint8_t & address, const std::string & name) : + detail::Display(address, name) + { + CLOG(DEBUG, OUTPUT_LOGGER) << "Created SevenDigitDisplay " << name << " with address " << int{this->address}; + } + + void write_score(unsigned int score) override + { + detail::Display::write_score(score, 7); + } + void write_content(std::string & content) override + { + detail::Display::write_content(content, 7); + } + + ~SevenDigitDisplay() override = default; + + std::string get_name() const override + { + return name; + } + +}; +} +} +} +} +#endif //FLIPPR_DRIVER_SEVENDIGITDISPLAY_H diff --git a/FlippR-Driver/src/output/items/detail/Solenoid.cpp b/FlippR-Driver/src/output/items/detail/Solenoid.cpp new file mode 100644 index 0000000..d72ade6 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Solenoid.cpp @@ -0,0 +1,45 @@ +/* + * Solenoid.cppthis->pins_display_board.end(), + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "Solenoid.h" + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +Solenoid::Solenoid(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name, const std::chrono::milliseconds & deactivation_time) +: detail::Item(std::move(name)), DriverBoardItem(pin_controller, address), pin_controller(pin_controller), deactivation_time(deactivation_time) +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created solenoid " << name << " with address " << int{address} << " and deactivation-time: " << deactivation_time.count(); +} + +void Solenoid::triggerTask() +{ + this->pin_controller->activate(*this); + + std::this_thread::sleep_for(deactivation_time); + + this->pin_controller->deactivate(*this); +} + +void Solenoid::trigger() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Trigger Solenoid " << name << " for " << deactivation_time.count() << "ms"; + this->trigger_task = std::async(std::launch::async, &Solenoid::triggerTask, this); +} + +} +} +} /* namespace output */ +} diff --git a/FlippR-Driver/src/output/items/detail/Solenoid.h b/FlippR-Driver/src/output/items/detail/Solenoid.h new file mode 100644 index 0000000..e73fc92 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Solenoid.h @@ -0,0 +1,52 @@ +/* + * Solenoid.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_SOLENOID_H_ +#define _SRC_OUTPUT_SOLENOID_H_ + +#include "output/items/Solenoid.h" +#include "output/items/detail/Item.h" +#include "output/items/detail/DriverBoardItem.h" + +#include "output/DriverBoardPinController.h" + +#include +#include + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +class Solenoid : public DriverBoardItem, public detail::Item, public items::Solenoid +{ +public: + Solenoid(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name, const std::chrono::milliseconds & deactivation_time); + ~Solenoid() override = default; + + void trigger() override; + +private: + virtual void triggerTask(); + +private: + const std::shared_ptr pin_controller; + const std::chrono::milliseconds deactivation_time; + + std::future trigger_task; + +}; + +} +} /* namespace output */ +} +} +#endif diff --git a/FlippR-Driver/src/output/items/detail/Sound.cpp b/FlippR-Driver/src/output/items/detail/Sound.cpp new file mode 100644 index 0000000..d7d50ac --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Sound.cpp @@ -0,0 +1,43 @@ +/* + * Sound.cpp + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "Sound.h" + +#include + +#include "utility/config.h" + +namespace flippR_driver +{ +namespace output +{ +namespace items +{ +namespace detail +{ + +Sound::Sound(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name, const u_int id) +: detail::Item(std::move(name)), DriverBoardItem(pin_controller, address), pin_controller(std::move(pin_controller)), id(id) +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Created sound " << id << " \"" << name << "\" with address " << int(address); +} + +void Sound::play() +{ + CLOG(DEBUG, OUTPUT_LOGGER) << "Play Sound " << id << " " << name; + this->play_task = std::async(std::launch::async, &Sound::playTask, this); +} + +void Sound::playTask() +{ + pin_controller->activate(*this); +} + +} +} +} /* namespace output */ +} diff --git a/FlippR-Driver/src/output/items/detail/Sound.h b/FlippR-Driver/src/output/items/detail/Sound.h new file mode 100644 index 0000000..a98c3d2 --- /dev/null +++ b/FlippR-Driver/src/output/items/detail/Sound.h @@ -0,0 +1,56 @@ +/* + * Sound.h + * + * Created on: Aug 2, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef _SRC_OUTPUT_SOUND_H_ +#define _SRC_OUTPUT_SOUND_H_ + +#include "output/items/Sound.h" +#include "Item.h" +#include "DriverBoardItem.h" + +#include +#include +#include +#include + +namespace flippR_driver +{ +namespace output +{ + +class SoundBoardPinController; + +namespace items +{ +namespace detail +{ + +class Sound : public detail::Item, public items::Sound, public detail::DriverBoardItem +{ +public: + u_int id; + +public: + Sound(std::shared_ptr pin_controller, const uint8_t & address, const std::string & name, const u_int id); + ~Sound() override = default; + + void play() override; + +private: + const std::shared_ptr pin_controller; + + std::future play_task; + +private: + virtual void playTask(); +}; + +} +} +} /* namespace output */ +} +#endif diff --git a/FlippR-Driver/src/utilities/GPIOInterface.hpp b/FlippR-Driver/src/utilities/GPIOInterface.hpp deleted file mode 100644 index c098c81..0000000 --- a/FlippR-Driver/src/utilities/GPIOInterface.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * GPIOInterface.hpp - * - * Responsible for communicating with the actual GPIO hardware. - * - * Gets a JSON file with following style: - * TODO - * - * Created on: May 6, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_UTILITIES_GPIOINTERFACE_HPP_ -#define SRC_UTILITIES_GPIOINTERFACE_HPP_ - -#include -#include "config.h" - -#include "../lib/wiringPi/wiringPi.h" -#include "../lib/json/json.hpp" - -class GPIOInterface -{ -public: - GPIOInterface(); - virtual ~GPIOInterface(); - - static void write_pin(char address, char data) - { - digitalWrite(address, data); - } - - static bool read_pin(char address) - { - return digitalRead(address); - } -}; - - - - -#endif /* SRC_UTILITIES_GPIOINTERFACE_HPP_ */ diff --git a/FlippR-Driver/src/utilities/IEventHandler.h b/FlippR-Driver/src/utilities/IEventHandler.h deleted file mode 100644 index 00f6b03..0000000 --- a/FlippR-Driver/src/utilities/IEventHandler.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * IEventHandler.h - * - * Created on: Jun 13, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_IEVENTHANDLER_H_ -#define SRC_IEVENTHANDLER_H_ - -#include "../input/Event.hpp" - -class IEventHandler -{ -public: - virtual ~IEventHandler() = 0; - - virtual void handle(Input::Event& event) = 0; -}; - -#endif /* SRC_IEVENTHANDLER_H_ */ diff --git a/FlippR-Driver/src/utilities/InputGPIOInterface.cpp b/FlippR-Driver/src/utilities/InputGPIOInterface.cpp deleted file mode 100644 index 5724d60..0000000 --- a/FlippR-Driver/src/utilities/InputGPIOInterface.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * InputGPIOInterface.cpp - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#include -#include - -#include "InputGPIOInterface.h" -#include "../lib/json/json.hpp" -#include "../lib/easylogging/easylogging++.h" -#include "config.h" -#include -using namespace nlohmann; - -bool InputGPIOInterface::read_input_data(char pin) -{ - // setting address to read - write_input_row(pin / INPUT_MATRIX_SIZE); - write_input_col(pin % INPUT_MATRIX_SIZE); - - // wait for mux to set address - std::this_thread::sleep_for(std::chrono::nanoseconds(INPUT_SLEEP_DURATION_NANO)); - - return read_pin(this->input_data_address); -} - -void InputGPIOInterface::write_input_row(char data) -{ - write_pin(this->input_row_address_A, data & 0b001); - write_pin(this->input_row_address_B, data & 0b010); - write_pin(this->input_row_address_C, data & 0b100); -} - -void InputGPIOInterface::write_input_col(char data) -{ - write_pin(this->input_col_address_A, data & 0b001); - write_pin(this->input_col_address_B, data & 0b010); - write_pin(this->input_col_address_C, data & 0b100); -} - - -InputGPIOInterface::InputGPIOInterface(std::string matrix_config_path) -{ - std::ifstream matrix_config_stream(matrix_config_path); - json matrix_config; - matrix_config_stream >> matrix_config; - - try { - json matrix_config_input = matrix_config.at("input"); - - json row_json = matrix_config.at("row"); - input_row_address_A = row_json.at("A").get(); - input_row_address_B = row_json.at("B").get(); - input_row_address_C = row_json.at("C").get(); - - json col_json = matrix_config.at("col"); - input_col_address_A = col_json.at("A").get(); - input_col_address_B = col_json.at("B").get(); - input_col_address_C = col_json.at("C").get(); - - input_data_address = matrix_config.at("data").get(); - } catch (json::type_error& e) { - CLOG(ERROR, INPUT_LOGGER) << "ERROR"; - } catch (json::out_of_range& e) { - CLOG(ERROR, INPUT_LOGGER) << "ANOTHER ERROR!"; - } - -} diff --git a/FlippR-Driver/src/utilities/InputGPIOInterface.h b/FlippR-Driver/src/utilities/InputGPIOInterface.h deleted file mode 100644 index b375c48..0000000 --- a/FlippR-Driver/src/utilities/InputGPIOInterface.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * InputGPIOInterface.h - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_UTILITIES_INPUTGPIOINTERFACE_H_ -#define SRC_UTILITIES_INPUTGPIOINTERFACE_H_ - -#include "GPIOInterface.hpp" - -#include - -class InputGPIOInterface : GPIOInterface -{ -public: - InputGPIOInterface(std::string matrix_config_path); - bool read_input_data(char pin); - -private: - void write_input_row(char data); - void write_input_col(char data); - -private: - char input_row_address_A; - char input_row_address_B; - char input_row_address_C; - char input_col_address_A; - char input_col_address_B; - char input_col_address_C; - char input_data_address; -}; - - - -#endif /* SRC_UTILITIES_INPUTGPIOINTERFACE_H_ */ diff --git a/FlippR-Driver/src/utilities/OutputGPIOInterface.h b/FlippR-Driver/src/utilities/OutputGPIOInterface.h deleted file mode 100644 index 3b64b6e..0000000 --- a/FlippR-Driver/src/utilities/OutputGPIOInterface.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * OutputGPIOInterface.h - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_UTILITIES_OUTPUTGPIOINTERFACE_H_ -#define SRC_UTILITIES_OUTPUTGPIOINTERFACE_H_ - -#include "GPIOInterface.hpp" - -class OutputGPIOInterface : GPIOInterface -{ - -}; - - -#endif /* SRC_UTILITIES_OUTPUTGPIOINTERFACE_H_ */ diff --git a/FlippR-Driver/src/utilities/config.h b/FlippR-Driver/src/utilities/config.h deleted file mode 100644 index 148461c..0000000 --- a/FlippR-Driver/src/utilities/config.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * BlockingQueue.hpp - * - * Created on: May 17, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#include "../lib/easylogging/easylogging++.h" - -#define INPUT_LOGGER "driver_logger" -#define DRIVER_LOG_FILE "/var/log/flippr_driver.conf" - -#define HIGH_VERBOSITY 10 - -#define INPUT_MATRIX_SIZE 8 -#define INPUT_SLEEP_DURATION_NANO 800 diff --git a/FlippR-Driver/src/utilities/BlockingQueue.hpp b/FlippR-Driver/src/utility/BlockingQueue.hpp similarity index 60% rename from FlippR-Driver/src/utilities/BlockingQueue.hpp rename to FlippR-Driver/src/utility/BlockingQueue.hpp index 2ba177f..8263cbd 100644 --- a/FlippR-Driver/src/utilities/BlockingQueue.hpp +++ b/FlippR-Driver/src/utility/BlockingQueue.hpp @@ -12,34 +12,46 @@ #include #include +#include "IBlockingQueue.h" + using namespace boost; -template -class BlockingQueue +namespace flippR_driver +{ +namespace utility +{ + +template +class BlockingQueue : public IBlockingQueue { private: - std::mutex d_mutex; + std::mutex d_mutex; std::condition_variable d_condition; heap::priority_queue> p_queue; public: - void push(T const& value) + void push(T const &value) { - std::unique_lock lock(this->d_mutex); - p_queue.push(value); + { + std::unique_lock lock(this->d_mutex); + p_queue.push(value); + } this->d_condition.notify_one(); } T pop() { std::unique_lock lock(this->d_mutex); - this->d_condition.wait(lock, [=]{ return !this->p_queue.empty(); }); - T rc = *this->p_queue.end(); + this->d_condition.wait(lock, [=] + { return !this->p_queue.empty(); }); + T rc = *this->p_queue.begin(); this->p_queue.pop(); return rc; } }; +} +} -#endif /* SRC_UTILITIES_BLOCKINGQUEUE_HPP_ */ +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/utility/Colors.h b/FlippR-Driver/src/utility/Colors.h new file mode 100644 index 0000000..845a9bd --- /dev/null +++ b/FlippR-Driver/src/utility/Colors.h @@ -0,0 +1,29 @@ +// +// Created by johannes on 18.06.19. +// + +#ifndef _COLORS_ +#define _COLORS_ + +/* FOREGROUND */ +#define RST "\x1B[0m" +#define KRED "\x1B[31m" +#define KGRN "\x1B[32m" +#define KYEL "\x1B[33m" +#define KBLU "\x1B[34m" +#define KMAG "\x1B[35m" +#define KCYN "\x1B[36m" +#define KWHT "\x1B[37m" + +#define FRED(x) KRED x RST +#define FGRN(x) KGRN x RST +#define FYEL(x) KYEL x RST +#define FBLU(x) KBLU x RST +#define FMAG(x) KMAG x RST +#define FCYN(x) KCYN x RST +#define FWHT(x) KWHT x RST + +#define BOLD(x) "\x1B[1m" x RST +#define UNDL(x) "\x1B[4m" x RST + +#endif /* _COLORS_ */ \ No newline at end of file diff --git a/FlippR-Driver/src/utility/IBlockingQueue.h b/FlippR-Driver/src/utility/IBlockingQueue.h new file mode 100644 index 0000000..89504a4 --- /dev/null +++ b/FlippR-Driver/src/utility/IBlockingQueue.h @@ -0,0 +1,29 @@ +/* + * BlockingQueue.hpp + * + * Created on: May 17, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_UTILITIES_IBLOCKINGQUEUE_H_ +#define SRC_UTILITIES_IBLOCKINGQUEUE_H_ + +namespace flippR_driver +{ +namespace utility +{ +template +class IBlockingQueue +{ +public: + virtual ~IBlockingQueue() = default; + + virtual void push(T const &value) = 0; + virtual T pop() = 0; + +}; + +} +} + +#endif \ No newline at end of file diff --git a/FlippR-Driver/src/utility/LoggerFactory.cpp b/FlippR-Driver/src/utility/LoggerFactory.cpp new file mode 100644 index 0000000..99d3c83 --- /dev/null +++ b/FlippR-Driver/src/utility/LoggerFactory.cpp @@ -0,0 +1,88 @@ +// +// Created by rhetenor on 13.09.18. +// + +#include "LoggerFactory.h" + +#ifndef EASYLOGGING_IS_INITIALIZED +#define EASYLOGGING_IS_INITIALIZED +INITIALIZE_EASYLOGGINGPP +#endif + +namespace flippR_driver +{ +namespace utility +{ +namespace LoggerFactory +{ + +void CreateInputTestLogger(el::Level level) +{ + el::Loggers::getLogger(INPUT_LOGGER); + el::Configurations conf; + + conf.setToDefault(); + + conf.set(level, el::ConfigurationType::ToFile, "false"); + conf.set(level, el::ConfigurationType::Format, "%datetime [%level] [%fbase] : %msg"); + + el::Loggers::reconfigureAllLoggers(conf); +} + +el::Configurations createConfig(std::string logger) +{ + el::Configurations conf; + conf.setToDefault(); + + conf.setGlobally(el::ConfigurationType::ToStandardOutput, "false"); + conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "1500000"); //~1.5MB + + if (debug_log) + { + conf.set(el::Level::Debug, el::ConfigurationType::ToStandardOutput, "true"); + conf.set(el::Level::Debug, el::ConfigurationType::ToFile, "true"); + conf.set(el::Level::Debug, el::ConfigurationType::Format, "%datetime [%level] [%fbase] : %msg"); + conf.set(el::Level::Debug, el::ConfigurationType::Filename, LOGGER_FILE); + } + + conf.set(el::Level::Info, el::ConfigurationType::ToStandardOutput, "true"); + conf.set(el::Level::Info, el::ConfigurationType::ToFile, "true"); + conf.set(el::Level::Info, el::ConfigurationType::Filename, LOGGER_FILE); + conf.set(el::Level::Info, el::ConfigurationType::Format, "%datetime [%level] [%fbase] : %msg"); + + conf.set(el::Level::Warning, el::ConfigurationType::ToStandardOutput, "true"); + conf.set(el::Level::Warning, el::ConfigurationType::ToFile, "true"); + conf.set(el::Level::Warning, el::ConfigurationType::Filename, LOGGER_FILE); + conf.set(el::Level::Warning, el::ConfigurationType::Format, "%datetime [%level] [%fbase] : %msg"); + + conf.set(el::Level::Verbose, el::ConfigurationType::ToStandardOutput, "true"); + conf.set(el::Level::Verbose, el::ConfigurationType::ToFile, "true"); + conf.set(el::Level::Verbose, el::ConfigurationType::Filename, LOGGER_FILE); + conf.set(el::Level::Verbose, el::ConfigurationType::Format, "%datetime [%level] [%fbase] : %msg"); + + return conf; +} + +void CreateInputLogger() +{ + el::Loggers::getLogger(INPUT_LOGGER); + el::Configurations conf = createConfig(INPUT_LOGGER); + el::Loggers::reconfigureLogger(INPUT_LOGGER, conf); +} + +void CreateOutputLogger() +{ + el::Loggers::getLogger(OUTPUT_LOGGER); + el::Configurations conf = createConfig(OUTPUT_LOGGER); + el::Loggers::reconfigureLogger(OUTPUT_LOGGER, conf); +} + +void ActivateDebugLog() +{ + debug_log = true; +} + +} + +} +} \ No newline at end of file diff --git a/FlippR-Driver/src/utility/LoggerFactory.h b/FlippR-Driver/src/utility/LoggerFactory.h new file mode 100644 index 0000000..cd5a336 --- /dev/null +++ b/FlippR-Driver/src/utility/LoggerFactory.h @@ -0,0 +1,29 @@ +/* + * LoggerFactory.hpp + * + * Created on: Jun 19, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#ifndef SRC_UTILITIES_LOGGERFACTORY_HPP_ +#define SRC_UTILITIES_LOGGERFACTORY_HPP_ + +#include "config.h" + +namespace flippR_driver +{ +namespace utility +{ + +namespace LoggerFactory +{ + static bool debug_log = false; + void CreateInputTestLogger(el::Level level = el::Level::Global); + void CreateInputLogger(); + void CreateOutputLogger(); + void ActivateDebugLog(); +}; + +} +} +#endif diff --git a/FlippR-Driver/src/utility/config.h b/FlippR-Driver/src/utility/config.h new file mode 100644 index 0000000..7e5245d --- /dev/null +++ b/FlippR-Driver/src/utility/config.h @@ -0,0 +1,21 @@ +/* + * config.h + * + * Created on: May 17, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "easylogging++.h" + +#define INPUT_LOGGER "driver_logger" +#define OUTPUT_LOGGER "output_logger" + +#define LOGGER_FILE "driver.log" + +#define INPUT_MATRIX_SIZE 8 +#define INPUT_SLEEP_DURATION_NANO 800 +#define INPUT_HANDLER_TIMEOUT_MILLI 2000 + +#define PULLDOWN false + +#define DISPLAY_SLEEP_TIME_MILLI 1 diff --git a/FlippR-Driver/src/utility/helper_functions.hpp b/FlippR-Driver/src/utility/helper_functions.hpp new file mode 100644 index 0000000..2bfae15 --- /dev/null +++ b/FlippR-Driver/src/utility/helper_functions.hpp @@ -0,0 +1,24 @@ +/* + * helper_functions.hpp + * + * Created on: Jan 16, 2020 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ +#include +#include + +namespace help +{ + template + std::string make_list_string(Container container) + { + std::stringstream ss; + for(auto & elem : container) + { + ss << std::to_string(elem) << ", "; + } + ss << std::string(2, 0x08); + + return std::string("[") + ss.str() + "]"; + } +} diff --git a/FlippR-Driver/src/utility/wiringPiTesting.hpp b/FlippR-Driver/src/utility/wiringPiTesting.hpp new file mode 100644 index 0000000..b952d71 --- /dev/null +++ b/FlippR-Driver/src/utility/wiringPiTesting.hpp @@ -0,0 +1,45 @@ +// +// Created by johannes on 17.07.19. +// + +#ifndef FLIPPR_DRIVER_WIRINGPITESTING_H +#define FLIPPR_DRIVER_WIRINGPITESTING_H + +#include +#include + +#define INPUT 0 +#define OUTPUT 1 + +static int wiringPiSetup() +{ + //std::cout << "WiringPiSetup() called" << std::endl; + return 0; +} + +void pinMode(int pin, int mode) +{ + //std::cout << "Set pin " << pin << " into mode " << mode << std::endl; +} + +int digitalRead(int pin) +{ + //std::cout << "Reading pin " << pin << std::endl + return rand()%2 == 0 ? 1 : 0; +} + +void digitalWrite(int pin, int value) +{ + //std::cout << "Writing pin " << pin << " with value " << value << std::endl; +} + + +int mcp23017Setup(const int pinBase, const int i2cAddress) +{ + //std::cout << "mcp23017Setup called with pinBase " << pinBase << " and i2cAddress " << i2cAddress << std::endl; + + return 0; +} + + +#endif //FLIPPR_DRIVER_WIRINGPITESTING_H diff --git a/FlippR-Driver/tests/CMakeLists.txt b/FlippR-Driver/tests/CMakeLists.txt index eae509d..518b833 100644 --- a/FlippR-Driver/tests/CMakeLists.txt +++ b/FlippR-Driver/tests/CMakeLists.txt @@ -1,19 +1,26 @@ -cmake_minimum_required(VERSION 3.0) +###################### START_CMAKE ####################### +cmake_minimum_required(VERSION 3.6.2) +project(FlippR-Driver-Tests VERSION 0.1.0 LANGUAGES CXX) -project(cmake_test) +# Compile tests to output_path/tests +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/${OUTPUT_PATH}/tests) -# Prepare "Catch" library for other executables -set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../src/tests) -add_library(Catch INTERFACE) -target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR}/*) -# Make test executable -set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/tests/input) -include_directories(${TEST_SOURCES}) -include_directories(${TEST_SOURCES}/mocks) +file(GLOB_RECURSE SOURCES *.cpp) -file(GLOB SOURCES ${TEST_SOURCES}/*.cpp) -file(GLOB SOURCES ${TEST_SOURCES}/*.hpp) -add_executable(tests ${SOURCES}) +add_executable(${PROJECT_NAME} ${SOURCES}) -target_link_libraries(tests Catch) +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/tests) +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/include) + +#find_library(flippr-driver NAMES lib${CMAKE_PROJECT_NAME}.a HINTS ${CMAKE_SOURCE_DIR}/bin) +#if(NOT flippr-driver) +# message(FATAL_ERROR "Could not find FlippR library") +#endif() + +target_link_libraries(${PROJECT_NAME} PRIVATE FlippR-Driver) + +enable_testing() + +add_test(tests ${PROJECT_NAME}) diff --git a/FlippR-Driver/tests/catch.hpp b/FlippR-Driver/tests/catch.hpp index 362f869..bf5e0e7 100644 --- a/FlippR-Driver/tests/catch.hpp +++ b/FlippR-Driver/tests/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.0.1 - * Generated: 2017-11-03 11:53:39.642003 + * Catch v2.7.2 + * Generated: 2019-04-22 23:13:14.687465 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2017 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,6 +13,10 @@ // start catch.hpp +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 7 +#define CATCH_VERSION_PATCH 2 + #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ @@ -26,37 +30,45 @@ # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC -# pragma clang diagnostic ignored "-Wglobal-constructors" -# pragma clang diagnostic ignored "-Wvariadic-macros" -# pragma clang diagnostic ignored "-Wc99-extensions" -# pragma clang diagnostic ignored "-Wunused-variable" # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ -# pragma GCC diagnostic ignored "-Wvariadic-macros" -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wparentheses" +// Because REQUIREs trigger GCC's -Wparentheses, and because still +// supported version of g++ have only buggy support for _Pragmas, +// Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) # define CATCH_CONFIG_EXTERNAL_INTERFACES # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h #ifdef __APPLE__ # include -# if TARGET_OS_MAC == 1 +# if TARGET_OS_OSX == 1 # define CATCH_PLATFORM_MAC # elif TARGET_OS_IPHONE == 1 # define CATCH_PLATFORM_IPHONE @@ -65,11 +77,12 @@ #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h + #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED @@ -77,6 +90,13 @@ # endif #endif +// start catch_user_interfaces.h + +namespace Catch { +unsigned int rngSeed(); +} + +// end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h @@ -89,6 +109,7 @@ // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too @@ -101,10 +122,18 @@ #ifdef __cplusplus -# if __cplusplus >= 201402L +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS #endif #ifdef __clang__ @@ -122,16 +151,24 @@ # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic pop" ) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic push" ) \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic pop" ) + #endif // __clang__ +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) +#define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# endif - +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) +#define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ @@ -139,6 +176,24 @@ # define CATCH_CONFIG_COLOUR_NONE #endif +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ @@ -146,13 +201,24 @@ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #ifdef _MSC_VER +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -161,8 +227,33 @@ # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif + #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) +#define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in @@ -171,19 +262,95 @@ // Otherwise all supported compilers support COUNTER macro, // but user still might want to turn it off #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER +#define CATCH_INTERNAL_CONFIG_COUNTER #endif +//////////////////////////////////////////////////////////////////////////////// +// Check if string_view is available and usable +// The check is split apart to work around v140 (VS2015) preprocessor issue... +#if defined(__has_include) +#if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW +#endif +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Check if optional is available and usable +#if defined(__has_include) +# if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL +# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // __has_include + +//////////////////////////////////////////////////////////////////////////////// +// Check if variant is available and usable +#if defined(__has_include) +# if __has_include() && defined(CATCH_CPP17_OR_GREATER) +# if defined(__clang__) && (__clang_major__ < 8) +// work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 +// fix should be in clang 8, workaround in libstdc++ 8.2 +# include +# if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) +# define CATCH_CONFIG_NO_CPP17_VARIANT +# else +# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT +# endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) +# else +# define CATCH_INTERNAL_CONFIG_CPP17_VARIANT +# endif // defined(__clang__) && (__clang_major__ < 8) +# endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // __has_include + #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS @@ -193,6 +360,24 @@ # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS #endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +# define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif // end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line @@ -207,60 +392,67 @@ #include #include +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + namespace Catch { - struct CaseSensitive { enum Choice { - Yes, - No - }; }; +struct CaseSensitive { enum Choice { +Yes, +No +}; }; - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; +class NonCopyable { +NonCopyable( NonCopyable const& ) = delete; +NonCopyable( NonCopyable && ) = delete; +NonCopyable& operator = ( NonCopyable const& ) = delete; +NonCopyable& operator = ( NonCopyable && ) = delete; - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; +protected: +NonCopyable(); +virtual ~NonCopyable(); +}; - struct SourceLineInfo { +struct SourceLineInfo { - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept; +SourceLineInfo() = delete; +SourceLineInfo( char const* _file, std::size_t _line ) noexcept +: file( _file ), +line( _line ) +{} - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; +SourceLineInfo( SourceLineInfo const& other ) = default; +SourceLineInfo& operator = ( SourceLineInfo const& ) = default; +SourceLineInfo( SourceLineInfo&& ) noexcept = default; +SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; - bool empty() const noexcept; - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; +bool empty() const noexcept; +bool operator == ( SourceLineInfo const& other ) const noexcept; +bool operator < ( SourceLineInfo const& other ) const noexcept; - char const* file; - std::size_t line; - }; +char const* file; +std::size_t line; +}; - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); +std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - // This is just here to avoid compiler warnings with macro constants and boolean literals - bool isTrue( bool value ); - bool alwaysTrue(); - bool alwaysFalse(); +// Bring in operator<< from global namespace into Catch namespace +// This is necessary because the overload of operator<< above makes +// lookup stop at namespace Catch +using ::operator<<; - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } +// Use this in variadic streaming macros to allow +// >> +StreamEndStop +// as well as +// >> stuff +StreamEndStop +struct StreamEndStop { +std::string operator+() const; +}; +template +T const& operator + ( T const& value, StreamEndStop ) { +return value; +} } #define CATCH_INTERNAL_LINEINFO \ @@ -269,13 +461,16 @@ namespace Catch { // end catch_common.h namespace Catch { - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; +struct RegistrarForTagAliases { +RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); +}; } // end namespace Catch -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h @@ -283,31 +478,28 @@ namespace Catch { // start catch_interfaces_testcase.h #include -#include namespace Catch { - class TestSpec; +class TestSpec; - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; +struct ITestInvoker { +virtual void invoke () const = 0; +virtual ~ITestInvoker(); +}; - using ITestCasePtr = std::shared_ptr; +class TestCase; +struct IConfig; - class TestCase; - struct IConfig; +struct ITestCaseRegistry { +virtual ~ITestCaseRegistry(); +virtual std::vector const& getAllTests() const = 0; +virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; +}; - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); +bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); +std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); +std::vector const& getAllTestCasesSorted( IConfig const& config ); } @@ -320,168 +512,664 @@ namespace Catch { namespace Catch { - class StringData; +/// A non-owning string class (similar to the forthcoming std::string_view) +/// Note that, because a StringRef may be a substring of another string, +/// it may not be null terminated. c_str() must return a null terminated +/// string, however, and so the StringRef will internally take ownership +/// (taking a copy), if necessary. In theory this ownership is not externally +/// visible - but it does mean (substring) StringRefs should not be shared between +/// threads. +class StringRef { +public: +using size_type = std::size_t; - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. - class StringRef { - friend struct StringRefTestAccess; +private: +friend struct StringRefTestAccess; - using size_type = std::size_t; +char const* m_start; +size_type m_size; - char const* m_start; - size_type m_size; +char* m_data = nullptr; - char* m_data = nullptr; +void takeOwnership(); - void takeOwnership(); +static constexpr char const* const s_empty = ""; - public: // construction/ assignment - StringRef() noexcept; - StringRef( StringRef const& other ) noexcept; - StringRef( StringRef&& other ) noexcept; - StringRef( char const* rawChars ) noexcept; - StringRef( char const* rawChars, size_type size ) noexcept; - StringRef( std::string const& stdString ) noexcept; - ~StringRef() noexcept; +public: // construction/ assignment +StringRef() noexcept +: StringRef( s_empty, 0 ) +{} - auto operator = ( StringRef other ) noexcept -> StringRef&; - operator std::string() const; +StringRef( StringRef const& other ) noexcept +: m_start( other.m_start ), +m_size( other.m_size ) +{} - void swap( StringRef& other ) noexcept; +StringRef( StringRef&& other ) noexcept +: m_start( other.m_start ), +m_size( other.m_size ), +m_data( other.m_data ) +{ +other.m_data = nullptr; +} - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; +StringRef( char const* rawChars ) noexcept; - auto operator[] ( size_type index ) const noexcept -> char; +StringRef( char const* rawChars, size_type size ) noexcept +: m_start( rawChars ), +m_size( size ) +{} - public: // named queries - auto empty() const noexcept -> bool; - auto size() const noexcept -> size_type; - auto numberOfCharacters() const noexcept -> size_type; - auto c_str() const -> char const*; +StringRef( std::string const& stdString ) noexcept +: m_start( stdString.c_str() ), +m_size( stdString.size() ) +{} - public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; +~StringRef() noexcept { +delete[] m_data; +} - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - auto data() const noexcept -> char const*; - }; +auto operator = ( StringRef const &other ) noexcept -> StringRef& { +delete[] m_data; +m_data = nullptr; +m_start = other.m_start; +m_size = other.m_size; +return *this; +} - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; +operator std::string() const; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; +void swap( StringRef& other ) noexcept; + +public: // operators +auto operator == ( StringRef const& other ) const noexcept -> bool; +auto operator != ( StringRef const& other ) const noexcept -> bool; + +auto operator[] ( size_type index ) const noexcept -> char; + +public: // named queries +auto empty() const noexcept -> bool { +return m_size == 0; +} +auto size() const noexcept -> size_type { +return m_size; +} + +auto numberOfCharacters() const noexcept -> size_type; +auto c_str() const -> char const*; + +public: // substrings and searches +auto substr( size_type start, size_type size ) const noexcept -> StringRef; + +// Returns the current start pointer. +// Note that the pointer can change when if the StringRef is a substring +auto currentData() const noexcept -> char const*; + +private: // ownership queries - may not be consistent between calls +auto isOwned() const noexcept -> bool; +auto isSubstring() const noexcept -> bool; +}; + +auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; +auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; +auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; + +auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; +auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + +inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { +return StringRef( rawChars, size ); +} } // namespace Catch +inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { +return Catch::StringRef( rawChars, size ); +} + // end catch_stringref.h +// start catch_type_traits.hpp + + +#include + +namespace Catch{ + +#ifdef CATCH_CPP17_OR_GREATER +template +inline constexpr auto is_unique = std::true_type{}; + +template +inline constexpr auto is_unique = std::bool_constant< +(!std::is_same_v && ...) && is_unique +>{}; +#else + +template +struct is_unique : std::true_type{}; + +template +struct is_unique : std::integral_constant +::value +&& is_unique::value +&& is_unique::value +>{}; + +#endif +} + +// end catch_type_traits.hpp +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__ +#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +// MSVC is adding extra space and needs more calls to properly remove () +#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__ +#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__) +#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types)) + +// end catch_preprocessor.hpp +// start catch_meta.hpp + + +#include + +namespace Catch { +template< typename... > +struct TypeList {}; + +template< typename... > +struct append; + +template< template class L1 +, typename...E1 +, template class L2 +, typename...E2 +> +struct append< L1, L2 > { +using type = L1; +}; + +template< template class L1 +, typename...E1 +, template class L2 +, typename...E2 +, typename...Rest +> +struct append< L1, L2, Rest...> { +using type = typename append< L1, Rest... >::type; +}; + +template< template class +, typename... +> +struct rewrap; + +template< template class Container +, template class List +, typename...elems +> +struct rewrap> { +using type = TypeList< Container< elems... > >; +}; + +template< template class Container +, template class List +, class...Elems +, typename...Elements> +struct rewrap, Elements...> { +using type = typename append>, typename rewrap::type>::type; +}; + +template< template class...Containers > +struct combine { +template< typename...Types > +struct with_types { +template< template class Final > +struct into { +using type = typename append, typename rewrap::type...>::type; +}; +}; +}; + +template +struct always_false : std::false_type {}; + +} // namespace Catch + +// end catch_meta.hpp namespace Catch { template class TestInvokerAsMethod : public ITestInvoker { - void (C::*m_testAsMethod)(); +void (C::*m_testAsMethod)(); public: - TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} +TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} - void invoke() const override { - C obj; - (obj.*m_testAsMethod)(); - } +void invoke() const override { +C obj; +(obj.*m_testAsMethod)(); +} }; auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; template auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); +return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); } struct NameAndTags { - NameAndTags( StringRef name_ = "", StringRef tags_ = "" ) noexcept; - StringRef name; - StringRef tags; +NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; +StringRef name; +StringRef tags; }; struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept; - ~AutoReg(); +AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; +~AutoReg(); }; } // end namespace Catch #if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ +#define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ static void TestName() - #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ +#define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ namespace{ \ - struct TestName : ClassName { \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ } \ void TestName::test() - +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \ + template \ + static void TestName() +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ + namespace{ \ + template \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName ) { \ + void test(); \ + }; \ + } \ + template \ + void TestName::test() #endif - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ static void TestName(); \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static void TestName() - #define INTERNAL_CATCH_TESTCASE( ... ) \ +#define INTERNAL_CATCH_TESTCASE( ... ) \ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ \ - struct TestName : ClassName{ \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ void test(); \ }; \ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ } \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ void TestName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ +#define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + template \ + static void TestFunc();\ + namespace {\ + template \ + struct TestName{\ + template \ + TestName(Ts...names){\ + CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \ + using expander = int[];\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \ + }\ + };\ + INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \ + }\ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + template \ + static void TestFunc() + +#if defined(CATCH_CPP17_OR_GREATER) +#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case"); +#else +#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case"); +#endif + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) +#else +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) ) +#endif + +#define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + TestName(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\ + return 0;\ + }(); + +#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + template static void TestFuncName(); \ + namespace { \ + template \ + struct TestName { \ + TestName() { \ + CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \ + int index = 0; \ + using expander = int[]; \ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\ + } \ + }; \ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ + using TestInit = Catch::combine \ + ::with_types::into::type; \ + TestInit(); \ + return 0; \ + }(); \ + } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + template \ + static void TestFuncName() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__) +#else +#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) ) +#endif + +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ \ + template \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName ) { \ + void test();\ + };\ + template \ + struct TestNameClass{\ + template \ + TestNameClass(Ts...names){\ + CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \ + using expander = int[];\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \ + }\ + };\ + INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\ + }\ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\ + template \ + void TestName::test() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) +#else +#define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) ) +#endif + +#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + template \ + struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName ) { \ + void test();\ + };\ + namespace {\ + template\ + struct TestNameClass{\ + TestNameClass(){\ + CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\ + int index = 0;\ + using expander = int[];\ + constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ + constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ + constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \ + }\ + };\ + static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ + using TestInit = Catch::combine\ + ::with_types::into::type;\ + TestInit();\ + return 0;\ + }(); \ + }\ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ + template \ + void TestName::test() + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) +#else +#define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) ) +#endif + // end catch_test_registry.h // start catch_capture.hpp // start catch_assertionhandler.h +// start catch_assertioninfo.h + +// start catch_result_type.h + +namespace Catch { + +// ResultWas::OfType enum +struct ResultWas { enum OfType { +Unknown = -1, +Ok = 0, +Info = 1, +Warning = 2, + +FailureBit = 0x10, + +ExpressionFailed = FailureBit | 1, +ExplicitFailure = FailureBit | 2, + +Exception = 0x100 | FailureBit, + +ThrewException = Exception | 1, +DidntThrowException = Exception | 2, + +FatalErrorCondition = 0x200 | FailureBit + +}; }; + +bool isOk( ResultWas::OfType resultType ); +bool isJustInfo( int flags ); + +// ResultDisposition::Flags enum +struct ResultDisposition { enum Flags { +Normal = 0x01, + +ContinueOnFailure = 0x02, // Failures fail test, but execution continues +FalseTest = 0x04, // Prefix expression with ! +SuppressFail = 0x08 // Failures are reported but do not fail the test +}; }; + +ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); + +bool shouldContinueOnFailure( int flags ); +inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } +bool shouldSuppressFailure( int flags ); + +} // end namespace Catch + +// end catch_result_type.h +namespace Catch { + +struct AssertionInfo +{ +StringRef macroName; +SourceLineInfo lineInfo; +StringRef capturedExpression; +ResultDisposition::Flags resultDisposition; + +// We want to delete this constructor but a compiler bug in 4.8 means +// the struct is then treated as non-aggregate +//AssertionInfo() = delete; +}; + +} // end namespace Catch + +// end catch_assertioninfo.h // start catch_decomposer.h // start catch_tostring.h -#include #include #include #include #include +// start catch_stream.h + +#include +#include +#include + +namespace Catch { + +std::ostream& cout(); +std::ostream& cerr(); +std::ostream& clog(); + +class StringRef; + +struct IStream { +virtual ~IStream(); +virtual std::ostream& stream() const = 0; +}; + +auto makeStream( StringRef const &filename ) -> IStream const*; + +class ReusableStringStream { +std::size_t m_index; +std::ostream* m_oss; +public: +ReusableStringStream(); +~ReusableStringStream(); + +auto str() const -> std::string; + +template +auto operator << ( T const& value ) -> ReusableStringStream& { +*m_oss << value; +return *this; +} +auto get() -> std::ostream& { return *m_oss; } +}; +} + +// end catch_stream.h + +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +#include +#endif #ifdef __OBJC__ // start catch_objc_arc.hpp @@ -499,12 +1187,12 @@ id performOptionalSelector( id obj, SEL sel ); #if !CATCH_ARC_ENABLED inline void arcSafeRelease( NSObject* obj ) { - [obj release]; +[obj release]; } inline id performOptionalSelector( id obj, SEL sel ) { - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; - return nil; +if( [obj respondsToSelector: sel] ) +return [obj performSelector: sel]; +return nil; } #define CATCH_UNSAFE_UNRETAINED #define CATCH_ARC_STRONG @@ -515,12 +1203,12 @@ inline id performOptionalSelector( id obj, SEL sel ) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" #endif - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; +if( [obj respondsToSelector: sel] ) +return [obj performSelector: sel]; #ifdef __clang__ #pragma clang diagnostic pop #endif - return nil; +return nil; } #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained #define CATCH_ARC_STRONG __strong @@ -534,249 +1222,310 @@ inline id performOptionalSelector( id obj, SEL sel ) { #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless #endif -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - namespace Catch { - // Bring in operator<< from global namespace into Catch namespace - using ::operator<<; +namespace Detail { - namespace Detail { +extern const std::string unprintableString; - extern const std::string unprintableString; +std::string rawMemoryToString( const void *object, std::size_t size ); - std::string rawMemoryToString( const void *object, std::size_t size ); +template +std::string rawMemoryToString( const T& object ) { +return rawMemoryToString( &object, sizeof(object) ); +} - template - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } +template +class IsStreamInsertable { +template +static auto test(int) +-> decltype(std::declval() << std::declval(), std::true_type()); - template - class IsStreamInsertable { - template - static auto test(int) - -> decltype(std::declval() << std::declval(), std::true_type()); +template +static auto test(...)->std::false_type; - template - static auto test(...)->std::false_type; +public: +static const bool value = decltype(test(0))::value; +}; - public: - static const bool value = decltype(test(0))::value; - }; +template +std::string convertUnknownEnumToString( E e ); - } // namespace Detail +template +typename std::enable_if< +!std::is_enum::value && !std::is_base_of::value, +std::string>::type convertUnstreamable( T const& ) { +return Detail::unprintableString; +} +template +typename std::enable_if< +!std::is_enum::value && std::is_base_of::value, +std::string>::type convertUnstreamable(T const& ex) { +return ex.what(); +} - // If we decide for C++14, change these to enable_if_ts - template - struct StringMaker { - template - static - typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& t) { - std::ostringstream sstr; - sstr << t; - return sstr.str(); - } +template +typename std::enable_if< +std::is_enum::value +, std::string>::type convertUnstreamable( T const& value ) { +return convertUnknownEnumToString( value ); +} - template - static - typename std::enable_if::value, std::string>::type - convert(const Fake&) { - return Detail::unprintableString; - } - }; +#if defined(_MANAGED) +//! Convert a CLR string to a utf8 std::string +template +std::string clrReferenceToString( T^ ref ) { +if (ref == nullptr) +return std::string("null"); +auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); +cli::pin_ptr p = &bytes[0]; +return std::string(reinterpret_cast(p), bytes->Length); +} +#endif - namespace Detail { +} // namespace Detail - // This function dispatches all stringification requests inside of Catch. - // Should be preferably called fully qualified, like ::Catch::Detail::stringify - template - std::string stringify(const T& e) { - return ::Catch::StringMaker::type>::type>::convert(e); - } +// If we decide for C++14, change these to enable_if_ts +template +struct StringMaker { +template +static +typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type +convert(const Fake& value) { +ReusableStringStream rss; +// NB: call using the function-like syntax to avoid ambiguity with +// user-defined templated operator<< under clang. +rss.operator<<(value); +return rss.str(); +} - } // namespace Detail +template +static +typename std::enable_if::value, std::string>::type +convert( const Fake& value ) { +#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) +return Detail::convertUnstreamable(value); +#else +return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); +#endif +} +}; - // Some predefined specializations +namespace Detail { - template<> - struct StringMaker { - static std::string convert(const std::string& str); - }; - template<> - struct StringMaker { - static std::string convert(const std::wstring& wstr); - }; +// This function dispatches all stringification requests inside of Catch. +// Should be preferably called fully qualified, like ::Catch::Detail::stringify +template +std::string stringify(const T& e) { +return ::Catch::StringMaker::type>::type>::convert(e); +} - template<> - struct StringMaker { - static std::string convert(char const * str); - }; - template<> - struct StringMaker { - static std::string convert(char * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t const * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t * str); - }; +template +std::string convertUnknownEnumToString( E e ) { +return ::Catch::Detail::stringify(static_cast::type>(e)); +} - template - struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - template - struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - template - struct StringMaker { - static std::string convert(const char* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; +#if defined(_MANAGED) +template +std::string stringify( T^ e ) { +return ::Catch::StringMaker::convert(e); +} +#endif - template<> - struct StringMaker { - static std::string convert(int value); - }; - template<> - struct StringMaker { - static std::string convert(long value); - }; - template<> - struct StringMaker { - static std::string convert(long long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned int value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long long value); - }; +} // namespace Detail - template<> - struct StringMaker { - static std::string convert(bool b); - }; +// Some predefined specializations - template<> - struct StringMaker { - static std::string convert(char c); - }; - template<> - struct StringMaker { - static std::string convert(signed char c); - }; - template<> - struct StringMaker { - static std::string convert(unsigned char c); - }; +template<> +struct StringMaker { +static std::string convert(const std::string& str); +}; - template<> - struct StringMaker { - static std::string convert(std::nullptr_t); - }; +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +template<> +struct StringMaker { +static std::string convert(std::string_view str); +}; +#endif - template<> - struct StringMaker { - static std::string convert(float value); - }; - template<> - struct StringMaker { - static std::string convert(double value); - }; +template<> +struct StringMaker { +static std::string convert(char const * str); +}; +template<> +struct StringMaker { +static std::string convert(char * str); +}; - template - struct StringMaker { - template - static std::string convert(U* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; +#ifdef CATCH_CONFIG_WCHAR +template<> +struct StringMaker { +static std::string convert(const std::wstring& wstr); +}; - template - struct StringMaker { - static std::string convert(R C::* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; +# ifdef CATCH_CONFIG_CPP17_STRING_VIEW +template<> +struct StringMaker { +static std::string convert(std::wstring_view str); +}; +# endif - namespace Detail { - template - std::string rangeToString(InputIterator first, InputIterator last) { - std::ostringstream oss; - oss << "{ "; - if (first != last) { - oss << ::Catch::Detail::stringify(*first); - for (++first; first != last; ++first) - oss << ", " << ::Catch::Detail::stringify(*first); - } - oss << " }"; - return oss.str(); - } - } +template<> +struct StringMaker { +static std::string convert(wchar_t const * str); +}; +template<> +struct StringMaker { +static std::string convert(wchar_t * str); +}; +#endif - template - struct StringMaker > { - static std::string convert( std::vector const& v ) { - return ::Catch::Detail::rangeToString( v.begin(), v.end() ); - } - }; +// TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, +// while keeping string semantics? +template +struct StringMaker { +static std::string convert(char const* str) { +return ::Catch::Detail::stringify(std::string{ str }); +} +}; +template +struct StringMaker { +static std::string convert(signed char const* str) { +return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); +} +}; +template +struct StringMaker { +static std::string convert(unsigned char const* str) { +return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); +} +}; - template - struct EnumStringMaker { - static std::string convert(const T& t) { - return ::Catch::Detail::stringify(static_cast::type>(t)); - } - }; +template<> +struct StringMaker { +static std::string convert(int value); +}; +template<> +struct StringMaker { +static std::string convert(long value); +}; +template<> +struct StringMaker { +static std::string convert(long long value); +}; +template<> +struct StringMaker { +static std::string convert(unsigned int value); +}; +template<> +struct StringMaker { +static std::string convert(unsigned long value); +}; +template<> +struct StringMaker { +static std::string convert(unsigned long long value); +}; + +template<> +struct StringMaker { +static std::string convert(bool b); +}; + +template<> +struct StringMaker { +static std::string convert(char c); +}; +template<> +struct StringMaker { +static std::string convert(signed char c); +}; +template<> +struct StringMaker { +static std::string convert(unsigned char c); +}; + +template<> +struct StringMaker { +static std::string convert(std::nullptr_t); +}; + +template<> +struct StringMaker { +static std::string convert(float value); +}; +template<> +struct StringMaker { +static std::string convert(double value); +}; + +template +struct StringMaker { +template +static std::string convert(U* p) { +if (p) { +return ::Catch::Detail::rawMemoryToString(p); +} else { +return "nullptr"; +} +} +}; + +template +struct StringMaker { +static std::string convert(R C::* p) { +if (p) { +return ::Catch::Detail::rawMemoryToString(p); +} else { +return "nullptr"; +} +} +}; + +#if defined(_MANAGED) +template +struct StringMaker { +static std::string convert( T^ ref ) { +return ::Catch::Detail::clrReferenceToString(ref); +} +}; +#endif + +namespace Detail { +template +std::string rangeToString(InputIterator first, InputIterator last) { +ReusableStringStream rss; +rss << "{ "; +if (first != last) { +rss << ::Catch::Detail::stringify(*first); +for (++first; first != last; ++first) +rss << ", " << ::Catch::Detail::stringify(*first); +} +rss << " }"; +return rss.str(); +} +} #ifdef __OBJC__ - template<> - struct StringMaker { - static std::string convert(NSString * nsstring) { - if (!nsstring) - return "nil"; - return std::string("@") + [nsstring UTF8String]; - } - }; - template<> - struct StringMaker { - static std::string convert(NSObject* nsObject) { - return ::Catch::Detail::stringify([nsObject description]); - } +template<> +struct StringMaker { +static std::string convert(NSString * nsstring) { +if (!nsstring) +return "nil"; +return std::string("@") + [nsstring UTF8String]; +} +}; +template<> +struct StringMaker { +static std::string convert(NSObject* nsObject) { +return ::Catch::Detail::stringify([nsObject description]); +} - }; - namespace Detail { - inline std::string stringify( NSString* nsstring ) { - return StringMaker::convert( nsstring ); - } +}; +namespace Detail { +inline std::string stringify( NSString* nsstring ) { +return StringMaker::convert( nsstring ); +} - } // namespace Detail +} // namespace Detail #endif // __OBJC__ } // namespace Catch @@ -788,182 +1537,293 @@ namespace Catch { #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER #endif // Separate std::pair specialization #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) #include namespace Catch { - template - struct StringMaker > { - static std::string convert(const std::pair& pair) { - std::ostringstream oss; - oss << "{ " - << ::Catch::Detail::stringify(pair.first) - << ", " - << ::Catch::Detail::stringify(pair.second) - << " }"; - return oss.str(); - } - }; +template +struct StringMaker > { +static std::string convert(const std::pair& pair) { +ReusableStringStream rss; +rss << "{ " +<< ::Catch::Detail::stringify(pair.first) +<< ", " +<< ::Catch::Detail::stringify(pair.second) +<< " }"; +return rss.str(); +} +}; } #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER +#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) +#include +namespace Catch { +template +struct StringMaker > { +static std::string convert(const std::optional& optional) { +ReusableStringStream rss; +if (optional.has_value()) { +rss << ::Catch::Detail::stringify(*optional); +} else { +rss << "{ }"; +} +return rss.str(); +} +}; +} +#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER + // Separate std::tuple specialization #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) #include namespace Catch { - namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get(tuple)); - TupleElementPrinter::print(tuple, os); - } - }; +namespace Detail { +template< +typename Tuple, +std::size_t N = 0, +bool = (N < std::tuple_size::value) +> +struct TupleElementPrinter { +static void print(const Tuple& tuple, std::ostream& os) { +os << (N ? ", " : " ") +<< ::Catch::Detail::stringify(std::get(tuple)); +TupleElementPrinter::print(tuple, os); +} +}; - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter { - static void print(const Tuple&, std::ostream&) {} - }; +template< +typename Tuple, +std::size_t N +> +struct TupleElementPrinter { +static void print(const Tuple&, std::ostream&) {} +}; - } +} - template - struct StringMaker> { - static std::string convert(const std::tuple& tuple) { - std::ostringstream os; - os << '{'; - Detail::TupleElementPrinter>::print(tuple, os); - os << " }"; - return os.str(); - } - }; +template +struct StringMaker> { +static std::string convert(const std::tuple& tuple) { +ReusableStringStream rss; +rss << '{'; +Detail::TupleElementPrinter>::print(tuple, rss.get()); +rss << " }"; +return rss.str(); +} +}; } #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER +#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) +#include +namespace Catch { +template<> +struct StringMaker { +static std::string convert(const std::monostate&) { +return "{ }"; +} +}; + +template +struct StringMaker> { +static std::string convert(const std::variant& variant) { +if (variant.valueless_by_exception()) { +return "{valueless variant}"; +} else { +return std::visit( +[](const auto& value) { +return ::Catch::Detail::stringify(value); +}, +variant +); +} +} +}; +} +#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER + +namespace Catch { +struct not_this_one {}; // Tag type for detecting which begin/ end are being selected + +// Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace +using std::begin; +using std::end; + +not_this_one begin( ... ); +not_this_one end( ... ); + +template +struct is_range { +static const bool value = +!std::is_same())), not_this_one>::value && +!std::is_same())), not_this_one>::value; +}; + +#if defined(_MANAGED) // Managed types are never ranges +template +struct is_range { +static const bool value = false; +}; +#endif + +template +std::string rangeToString( Range const& range ) { +return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); +} + +// Handle vector specially +template +std::string rangeToString( std::vector const& v ) { +ReusableStringStream rss; +rss << "{ "; +bool first = true; +for( bool b : v ) { +if( first ) +first = false; +else +rss << ", "; +rss << ::Catch::Detail::stringify( b ); +} +rss << " }"; +return rss.str(); +} + +template +struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { +static std::string convert( R const& range ) { +return rangeToString( range ); +} +}; + +template +struct StringMaker { +static std::string convert(T const(&arr)[SZ]) { +return rangeToString(arr); +} +}; + +} // namespace Catch + // Separate std::chrono::duration specialization #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) #include #include #include +namespace Catch { + template struct ratio_string { - static std::string symbol(); +static std::string symbol(); }; template std::string ratio_string::symbol() { - std::ostringstream oss; - oss << '[' << Ratio::num << '/' - << Ratio::den << ']'; - return oss.str(); +Catch::ReusableStringStream rss; +rss << '[' << Ratio::num << '/' +<< Ratio::den << ']'; +return rss.str(); } template <> struct ratio_string { - static std::string symbol() { return "a"; } +static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "f"; } +static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "p"; } +static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "n"; } +static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "u"; } +static std::string symbol(); }; template <> struct ratio_string { - static std::string symbol() { return "m"; } +static std::string symbol(); }; -namespace Catch { - //////////// - // std::chrono::duration specializations - template - struct StringMaker> { - static std::string convert(std::chrono::duration const& duration) { - std::ostringstream oss; - oss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return oss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " s"; - return oss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " m"; - return oss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - std::ostringstream oss; - oss << duration.count() << " h"; - return oss.str(); - } - }; +//////////// +// std::chrono::duration specializations +template +struct StringMaker> { +static std::string convert(std::chrono::duration const& duration) { +ReusableStringStream rss; +rss << duration.count() << ' ' << ratio_string::symbol() << 's'; +return rss.str(); +} +}; +template +struct StringMaker>> { +static std::string convert(std::chrono::duration> const& duration) { +ReusableStringStream rss; +rss << duration.count() << " s"; +return rss.str(); +} +}; +template +struct StringMaker>> { +static std::string convert(std::chrono::duration> const& duration) { +ReusableStringStream rss; +rss << duration.count() << " m"; +return rss.str(); +} +}; +template +struct StringMaker>> { +static std::string convert(std::chrono::duration> const& duration) { +ReusableStringStream rss; +rss << duration.count() << " h"; +return rss.str(); +} +}; - //////////// - // std::chrono::time_point specialization - // Generic time_point cannot be specialized, only std::chrono::time_point - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; - } - }; - // std::chrono::time_point specialization - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - auto converted = std::chrono::system_clock::to_time_t(time_point); +//////////// +// std::chrono::time_point specialization +// Generic time_point cannot be specialized, only std::chrono::time_point +template +struct StringMaker> { +static std::string convert(std::chrono::time_point const& time_point) { +return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; +} +}; +// std::chrono::time_point specialization +template +struct StringMaker> { +static std::string convert(std::chrono::time_point const& time_point) { +auto converted = std::chrono::system_clock::to_time_t(time_point); #ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &converted); +std::tm timeInfo = {}; +gmtime_s(&timeInfo, &converted); #else - std::tm* timeInfo = std::gmtime(&converted); +std::tm* timeInfo = std::gmtime(&converted); #endif - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; +auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); +char timeStamp[timeStampSize]; +const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif - return std::string(timeStamp); - } - }; +return std::string(timeStamp); +} +}; } #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER @@ -972,7 +1832,7 @@ namespace Catch { #endif // end catch_tostring.h -#include +#include #ifdef _MSC_VER #pragma warning(push) @@ -980,144 +1840,221 @@ namespace Catch { #pragma warning(disable:4018) // more "signed/unsigned mismatch" #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) #pragma warning(disable:4180) // qualifier applied to function type has no meaning +#pragma warning(disable:4800) // Forcing result to true or false #endif namespace Catch { - struct ITransientExpression { - virtual auto isBinaryExpression() const -> bool = 0; - virtual auto getResult() const -> bool = 0; - virtual void streamReconstructedExpression( std::ostream &os ) const = 0; +struct ITransientExpression { +auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } +auto getResult() const -> bool { return m_result; } +virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - // We don't actually need a virtual destructore, but many static analysers - // complain if it's not here :-( - virtual ~ITransientExpression(); - }; +ITransientExpression( bool isBinaryExpression, bool result ) +: m_isBinaryExpression( isBinaryExpression ), +m_result( result ) +{} - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); +// We don't actually need a virtual destructor, but many static analysers +// complain if it's not here :-( +virtual ~ITransientExpression(); - template - class BinaryExpr : public ITransientExpression { - bool m_result; - LhsT m_lhs; - StringRef m_op; - RhsT m_rhs; +bool m_isBinaryExpression; +bool m_result; - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } +}; - void streamReconstructedExpression( std::ostream &os ) const override { - formatReconstructedExpression - ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); - } +void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - public: - BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : m_result( comparisonResult ), - m_lhs( lhs ), - m_op( op ), - m_rhs( rhs ) - {} - }; +template +class BinaryExpr : public ITransientExpression { +LhsT m_lhs; +StringRef m_op; +RhsT m_rhs; - template - class UnaryExpr : public ITransientExpression { - LhsT m_lhs; +void streamReconstructedExpression( std::ostream &os ) const override { +formatReconstructedExpression +( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); +} - auto isBinaryExpression() const -> bool override { return false; } - auto getResult() const -> bool override { return m_lhs ? true : false; } +public: +BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) +: ITransientExpression{ true, comparisonResult }, +m_lhs( lhs ), +m_op( op ), +m_rhs( rhs ) +{} - void streamReconstructedExpression( std::ostream &os ) const override { - os << Catch::Detail::stringify( m_lhs ); - } +template +auto operator && ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - public: - UnaryExpr( LhsT lhs ) : m_lhs( lhs ) {} - }; +template +auto operator || ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) - template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return lhs == rhs; }; - template - auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - template - auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } +template +auto operator == ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return lhs != rhs; }; - template - auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - template - auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } +template +auto operator != ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - template - class ExprLhs { - LhsT m_lhs; - public: - ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} +template +auto operator > ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - template - auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareEqual( m_lhs, rhs ), m_lhs, "==", rhs ); - } - auto operator == ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs == rhs, m_lhs, "==", rhs ); - } +template +auto operator < ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - template - auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs ); - } - auto operator != ( bool rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs != rhs, m_lhs, "!=", rhs ); - } +template +auto operator >= ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} - template - auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs > rhs, m_lhs, ">", rhs ); - } - template - auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs < rhs, m_lhs, "<", rhs ); - } - template - auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs >= rhs, m_lhs, ">=", rhs ); - } - template - auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return BinaryExpr( m_lhs <= rhs, m_lhs, "<=", rhs ); - } +template +auto operator <= ( T ) const -> BinaryExpr const { +static_assert(always_false::value, +"chained comparisons are not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} +}; - auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr( m_lhs ); - } - }; +template +class UnaryExpr : public ITransientExpression { +LhsT m_lhs; - void handleExpression( ITransientExpression const& expr ); +void streamReconstructedExpression( std::ostream &os ) const override { +os << Catch::Detail::stringify( m_lhs ); +} - template - void handleExpression( ExprLhs const& expr ) { - handleExpression( expr.makeUnaryExpr() ); - } +public: +explicit UnaryExpr( LhsT lhs ) +: ITransientExpression{ false, static_cast(lhs) }, +m_lhs( lhs ) +{} +}; - struct Decomposer { - template - auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs( lhs ); - } - auto operator <=( bool value ) -> ExprLhs { - return ExprLhs( value ); - } - }; +// Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) +template +auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } +template +auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } +template +auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } +template +auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } +template +auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } + +template +auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } +template +auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } +template +auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } +template +auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } +template +auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } + +template +class ExprLhs { +LhsT m_lhs; +public: +explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} + +template +auto operator == ( RhsT const& rhs ) -> BinaryExpr const { +return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; +} +auto operator == ( bool rhs ) -> BinaryExpr const { +return { m_lhs == rhs, m_lhs, "==", rhs }; +} + +template +auto operator != ( RhsT const& rhs ) -> BinaryExpr const { +return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; +} +auto operator != ( bool rhs ) -> BinaryExpr const { +return { m_lhs != rhs, m_lhs, "!=", rhs }; +} + +template +auto operator > ( RhsT const& rhs ) -> BinaryExpr const { +return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; +} +template +auto operator < ( RhsT const& rhs ) -> BinaryExpr const { +return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; +} +template +auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { +return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; +} +template +auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { +return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; +} + +template +auto operator && ( RhsT const& ) -> BinaryExpr const { +static_assert(always_false::value, +"operator&& is not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} + +template +auto operator || ( RhsT const& ) -> BinaryExpr const { +static_assert(always_false::value, +"operator|| is not supported inside assertions, " +"wrap the expression inside parentheses, or decompose it"); +} + +auto makeUnaryExpr() const -> UnaryExpr { +return UnaryExpr{ m_lhs }; +} +}; + +void handleExpression( ITransientExpression const& expr ); + +template +void handleExpression( ExprLhs const& expr ) { +handleExpression( expr.makeUnaryExpr() ); +} + +struct Decomposer { +template +auto operator <= ( T const& lhs ) -> ExprLhs { +return ExprLhs{ lhs }; +} + +auto operator <=( bool value ) -> ExprLhs { +return ExprLhs{ value }; +} +}; } // end namespace Catch @@ -1126,127 +2063,153 @@ namespace Catch { #endif // end catch_decomposer.h -// start catch_assertioninfo.h +// start catch_interfaces_capture.h -// start catch_result_type.h +#include namespace Catch { - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, +class AssertionResult; +struct AssertionInfo; +struct SectionInfo; +struct SectionEndInfo; +struct MessageInfo; +struct MessageBuilder; +struct Counts; +struct BenchmarkInfo; +struct BenchmarkStats; +struct AssertionReaction; +struct SourceLineInfo; - FailureBit = 0x10, +struct ITransientExpression; +struct IGeneratorTracker; - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, +struct IResultCapture { - Exception = 0x100 | FailureBit, +virtual ~IResultCapture(); - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, +virtual bool sectionStarted( SectionInfo const& sectionInfo, +Counts& assertions ) = 0; +virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; +virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - FatalErrorCondition = 0x200 | FailureBit +virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; - }; }; +virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; +virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); +virtual void pushScopedMessage( MessageInfo const& message ) = 0; +virtual void popScopedMessage( MessageInfo const& message ) = 0; - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, +virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; +virtual void handleFatalErrorCondition( StringRef message ) = 0; - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); +virtual void handleExpr +( AssertionInfo const& info, +ITransientExpression const& expr, +AssertionReaction& reaction ) = 0; +virtual void handleMessage +( AssertionInfo const& info, +ResultWas::OfType resultType, +StringRef const& message, +AssertionReaction& reaction ) = 0; +virtual void handleUnexpectedExceptionNotThrown +( AssertionInfo const& info, +AssertionReaction& reaction ) = 0; +virtual void handleUnexpectedInflightException +( AssertionInfo const& info, +std::string const& message, +AssertionReaction& reaction ) = 0; +virtual void handleIncomplete +( AssertionInfo const& info ) = 0; +virtual void handleNonExpr +( AssertionInfo const &info, +ResultWas::OfType resultType, +AssertionReaction &reaction ) = 0; - bool shouldContinueOnFailure( int flags ); - bool isFalseTest( int flags ); - bool shouldSuppressFailure( int flags ); +virtual bool lastAssertionPassed() = 0; +virtual void assertionPassed() = 0; -} // end namespace Catch +// Deprecated, do not use: +virtual std::string getCurrentTestName() const = 0; +virtual const AssertionResult* getLastResult() const = 0; +virtual void exceptionEarlyReported() = 0; +}; -// end catch_result_type.h +IResultCapture& getResultCapture(); +} + +// end catch_interfaces_capture.h namespace Catch { - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; +struct TestFailureException{}; +struct AssertionResultData; +struct IResultCapture; +class RunContext; - // We want to delete this constructor but a compiler bug in 4.8 means - // the struct is then treated as non-aggregate - //AssertionInfo() = delete; - }; +class LazyExpression { +friend class AssertionHandler; +friend struct AssertionStats; +friend class RunContext; -} // end namespace Catch +ITransientExpression const* m_transientExpression = nullptr; +bool m_isNegated; +public: +LazyExpression( bool isNegated ); +LazyExpression( LazyExpression const& other ); +LazyExpression& operator = ( LazyExpression const& ) = delete; -// end catch_assertioninfo.h -namespace Catch { +explicit operator bool() const; - struct TestFailureException{}; - struct AssertionResultData; +friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; +}; - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; +struct AssertionReaction { +bool shouldDebugBreak = false; +bool shouldThrow = false; +}; - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ); - LazyExpression( LazyExpression const& other ); - LazyExpression& operator = ( LazyExpression const& ) = delete; +class AssertionHandler { +AssertionInfo m_assertionInfo; +AssertionReaction m_reaction; +bool m_completed = false; +IResultCapture& m_resultCapture; - explicit operator bool() const; +public: +AssertionHandler +( StringRef const& macroName, +SourceLineInfo const& lineInfo, +StringRef capturedExpression, +ResultDisposition::Flags resultDisposition ); +~AssertionHandler() { +if ( !m_completed ) { +m_resultCapture.handleIncomplete( m_assertionInfo ); +} +} - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; +template +void handleExpr( ExprLhs const& expr ) { +handleExpr( expr.makeUnaryExpr() ); +} +void handleExpr( ITransientExpression const& expr ); - class AssertionHandler { - AssertionInfo m_assertionInfo; - bool m_shouldDebugBreak = false; - bool m_shouldThrow = false; - bool m_inExceptionGuard = false; +void handleMessage(ResultWas::OfType resultType, StringRef const& message); - public: - AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ); - ~AssertionHandler(); +void handleExceptionThrownAsExpected(); +void handleUnexpectedExceptionNotThrown(); +void handleExceptionNotThrownAsExpected(); +void handleThrowingCallSkipped(); +void handleUnexpectedInflightException(); - void handle( ITransientExpression const& expr ); +void complete(); +void setCompleted(); - template - void handle( ExprLhs const& expr ) { - handle( expr.makeUnaryExpr() ); - } - void handle( ResultWas::OfType resultType ); - void handle( ResultWas::OfType resultType, StringRef const& message ); - void handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ); - void handle( AssertionResultData const& resultData, ITransientExpression const* expr ); +// query +auto allowThrows() const -> bool; +}; - auto shouldDebugBreak() const -> bool; - auto allowThrows() const -> bool; - void reactWithDebugBreak() const; - void reactWithoutDebugBreak() const; - void useActiveException(); - void setExceptionGuard(); - void unsetExceptionGuard(); - }; - - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); +void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); } // namespace Catch @@ -1254,199 +2217,125 @@ namespace Catch { // start catch_message.h #include -#include +#include namespace Catch { - struct MessageInfo { - MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); +struct MessageInfo { +MessageInfo( StringRef const& _macroName, +SourceLineInfo const& _lineInfo, +ResultWas::OfType _type ); - std::string macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; +StringRef macroName; +std::string message; +SourceLineInfo lineInfo; +ResultWas::OfType type; +unsigned int sequence; - bool operator == ( MessageInfo const& other ) const; - bool operator < ( MessageInfo const& other ) const; - private: - static unsigned int globalCount; - }; +bool operator == ( MessageInfo const& other ) const; +bool operator < ( MessageInfo const& other ) const; +private: +static unsigned int globalCount; +}; - struct MessageStream { +struct MessageStream { - template - MessageStream& operator << ( T const& value ) { - m_stream << value; - return *this; - } +template +MessageStream& operator << ( T const& value ) { +m_stream << value; +return *this; +} - // !TBD reuse a global/ thread-local stream - std::ostringstream m_stream; - }; +ReusableStringStream m_stream; +}; - struct MessageBuilder : MessageStream { - MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ); +struct MessageBuilder : MessageStream { +MessageBuilder( StringRef const& macroName, +SourceLineInfo const& lineInfo, +ResultWas::OfType type ); - template - MessageBuilder& operator << ( T const& value ) { - m_stream << value; - return *this; - } +template +MessageBuilder& operator << ( T const& value ) { +m_stream << value; +return *this; +} - MessageInfo m_info; - }; +MessageInfo m_info; +}; - class ScopedMessage { - public: - ScopedMessage( MessageBuilder const& builder ); - ~ScopedMessage(); +class ScopedMessage { +public: +explicit ScopedMessage( MessageBuilder const& builder ); +ScopedMessage( ScopedMessage& duplicate ) = delete; +ScopedMessage( ScopedMessage&& old ); +~ScopedMessage(); - MessageInfo m_info; - }; +MessageInfo m_info; +bool m_moved; +}; + +class Capturer { +std::vector m_messages; +IResultCapture& m_resultCapture = getResultCapture(); +size_t m_captured = 0; +public: +Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); +~Capturer(); + +void captureValue( size_t index, std::string const& value ); + +template +void captureValues( size_t index, T const& value ) { +captureValue( index, Catch::Detail::stringify( value ) ); +} + +template +void captureValues( size_t index, T const& value, Ts const&... values ) { +captureValue( index, Catch::Detail::stringify(value) ); +captureValues( index+1, values... ); +} +}; } // end namespace Catch // end catch_message.h -// start catch_interfaces_capture.h - -#include - -namespace Catch { - - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual void assertionStarting( AssertionInfo const& info ) = 0; - virtual void assertionEnded( AssertionResult const& result ) = 0; - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - - virtual void exceptionEarlyReported() = 0; - - virtual void handleFatalErrorCondition( StringRef message ) = 0; - - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; - virtual void assertionRun() = 0; - }; - - IResultCapture& getResultCapture(); -} - -// end catch_interfaces_capture.h -// start catch_debugger.h - -namespace Catch { - bool isDebuggerActive(); -} - -#ifdef CATCH_PLATFORM_MAC - - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ - -#elif defined(CATCH_PLATFORM_LINUX) - // If we can use inline assembler, do it because this allows us to break - // directly at the location of the failing check instead of breaking inside - // raise() called from it, i.e. one stack frame below. - #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) - #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ - #else // Fall back to the generic way. - #include - - #define CATCH_TRAP() raise(SIGTRAP) - #endif -#elif defined(_MSC_VER) - #define CATCH_TRAP() __debugbreak() -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_TRAP() DebugBreak() -#endif - -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); -#endif - -// end catch_debugger.h #if !defined(CATCH_CONFIG_DISABLE) #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ +#define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ #else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" +#define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" #endif -#if defined(CATCH_CONFIG_FAST_COMPILE) -/////////////////////////////////////////////////////////////////////////////// -// We can speedup compilation significantly by breaking into debugger lower in -// the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER -// macro in each assertion -#define INTERNAL_CATCH_REACT( handler ) \ - handler.reactWithDebugBreak(); +#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) /////////////////////////////////////////////////////////////////////////////// // Another way to speed-up compilation is to omit local try-catch for REQUIRE* // macros. -// This can potentially cause false negative, if the test code catches -// the exception before it propagates back up to the runner. -#define INTERNAL_CATCH_TRY( capturer ) capturer.setExceptionGuard(); -#define INTERNAL_CATCH_CATCH( capturer ) capturer.unsetExceptionGuard(); +#define INTERNAL_CATCH_TRY +#define INTERNAL_CATCH_CATCH( capturer ) #else // CATCH_CONFIG_FAST_COMPILE -/////////////////////////////////////////////////////////////////////////////// -// In the event of a failure works out if the debugger needs to be invoked -// and/or an exception thrown and takes appropriate action. -// This needs to be done as a macro so the debugger will stop in the user -// source code rather than in Catch library code -#define INTERNAL_CATCH_REACT( handler ) \ - if( handler.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ - handler.reactWithoutDebugBreak(); - -#define INTERNAL_CATCH_TRY( capturer ) try -#define INTERNAL_CATCH_CATCH( capturer ) catch(...) { capturer.useActiveException(); } +#define INTERNAL_CATCH_TRY try +#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } #endif +#define INTERNAL_CATCH_REACT( handler ) handler.complete(); + /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handle( Catch::Decomposer() <= __VA_ARGS__ ); \ + catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::isTrue( false && static_cast( !!(__VA_ARGS__) ) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + } while( (void)0, (false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look +// The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ @@ -1461,83 +2350,92 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(expr); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ) { \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleExceptionThrownAsExpected(); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - catchAssertionHandler.handle( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ + catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ + auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ + varName.captureValues( 0, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_INFO( macroName, log ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ + Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) /////////////////////////////////////////////////////////////////////////////// // Although this is matcher-based, it can be used with just a string #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( ... ) { \ - handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ + Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) #endif // CATCH_CONFIG_DISABLE @@ -1552,29 +2450,30 @@ namespace Catch { namespace Catch { - struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); +struct Counts { +Counts operator - ( Counts const& other ) const; +Counts& operator += ( Counts const& other ); - std::size_t total() const; - bool allPassed() const; - bool allOk() const; +std::size_t total() const; +bool allPassed() const; +bool allOk() const; - std::size_t passed = 0; - std::size_t failed = 0; - std::size_t failedButOk = 0; - }; +std::size_t passed = 0; +std::size_t failed = 0; +std::size_t failedButOk = 0; +}; - struct Totals { +struct Totals { - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); +Totals operator - ( Totals const& other ) const; +Totals& operator += ( Totals const& other ); - Totals delta( Totals const& prevTotals ) const; +Totals delta( Totals const& prevTotals ) const; - Counts assertions; - Counts testCases; - }; +int error = 0; +Counts assertions; +Counts testCases; +}; } // end catch_totals.h @@ -1582,24 +2481,27 @@ namespace Catch { namespace Catch { - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); +struct SectionInfo { +SectionInfo +( SourceLineInfo const& _lineInfo, +std::string const& _name ); - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; +// Deprecated +SectionInfo +( SourceLineInfo const& _lineInfo, +std::string const& _name, +std::string const& ) : SectionInfo( _lineInfo, _name ) {} - struct SectionEndInfo { - SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); +std::string name; +std::string description; // !Deprecated: this will always be empty +SourceLineInfo lineInfo; +}; - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; +struct SectionEndInfo { +SectionInfo sectionInfo; +Counts prevAssertions; +double durationInSeconds; +}; } // end namespace Catch @@ -1610,18 +2512,18 @@ namespace Catch { namespace Catch { - auto getCurrentNanosecondsSinceEpoch() -> uint64_t; - auto getEstimatedClockResolution() -> uint64_t; +auto getCurrentNanosecondsSinceEpoch() -> uint64_t; +auto getEstimatedClockResolution() -> uint64_t; - class Timer { - uint64_t m_nanoseconds = 0; - public: - void start(); - auto getElapsedNanoseconds() const -> unsigned int; - auto getElapsedMicroseconds() const -> unsigned int; - auto getElapsedMilliseconds() const -> unsigned int; - auto getElapsedSeconds() const -> double; - }; +class Timer { +uint64_t m_nanoseconds = 0; +public: +void start(); +auto getElapsedNanoseconds() const -> uint64_t; +auto getElapsedMicroseconds() const -> uint64_t; +auto getElapsedMilliseconds() const -> unsigned int; +auto getElapsedSeconds() const -> double; +}; } // namespace Catch @@ -1630,27 +2532,34 @@ namespace Catch { namespace Catch { - class Section : NonCopyable { - public: - Section( SectionInfo const& info ); - ~Section(); +class Section : NonCopyable { +public: +Section( SectionInfo const& info ); +~Section(); - // This indicates whether the section should be executed or not - explicit operator bool() const; +// This indicates whether the section should be executed or not +explicit operator bool() const; - private: - SectionInfo m_info; +private: +SectionInfo m_info; - std::string m_name; - Counts m_assertions; - bool m_sectionIncluded; - Timer m_timer; - }; +std::string m_name; +Counts m_assertions; +bool m_sectionIncluded; +Timer m_timer; +}; } // end namespace Catch - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#define INTERNAL_CATCH_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS + +#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ + CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ + CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS // end catch_section.h // start catch_benchmark.h @@ -1660,38 +2569,38 @@ namespace Catch { namespace Catch { - class BenchmarkLooper { +class BenchmarkLooper { - std::string m_name; - std::size_t m_count = 0; - std::size_t m_iterationsToRun = 1; - uint64_t m_resolution; - Timer m_timer; +std::string m_name; +std::size_t m_count = 0; +std::size_t m_iterationsToRun = 1; +uint64_t m_resolution; +Timer m_timer; - static auto getResolution() -> uint64_t; - public: - // Keep most of this inline as it's on the code path that is being timed - BenchmarkLooper( StringRef name ) - : m_name( name ), - m_resolution( getResolution() ) - { - reportStart(); - m_timer.start(); - } +static auto getResolution() -> uint64_t; +public: +// Keep most of this inline as it's on the code path that is being timed +BenchmarkLooper( StringRef name ) +: m_name( name ), +m_resolution( getResolution() ) +{ +reportStart(); +m_timer.start(); +} - explicit operator bool() { - if( m_count < m_iterationsToRun ) - return true; - return needsMoreIterations(); - } +explicit operator bool() { +if( m_count < m_iterationsToRun ) +return true; +return needsMoreIterations(); +} - void increment() { - ++m_count; - } +void increment() { +++m_count; +} - void reportStart(); - auto needsMoreIterations() -> bool; - }; +void reportStart(); +auto needsMoreIterations() -> bool; +}; } // end namespace Catch @@ -1708,49 +2617,49 @@ namespace Catch { namespace Catch { - class TestCase; - struct ITestCaseRegistry; - struct IExceptionTranslatorRegistry; - struct IExceptionTranslator; - struct IReporterRegistry; - struct IReporterFactory; - struct ITagAliasRegistry; - class StartupExceptionRegistry; +class TestCase; +struct ITestCaseRegistry; +struct IExceptionTranslatorRegistry; +struct IExceptionTranslator; +struct IReporterRegistry; +struct IReporterFactory; +struct ITagAliasRegistry; +class StartupExceptionRegistry; - using IReporterFactoryPtr = std::shared_ptr; +using IReporterFactoryPtr = std::shared_ptr; - struct IRegistryHub { - virtual ~IRegistryHub(); +struct IRegistryHub { +virtual ~IRegistryHub(); - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; +virtual IReporterRegistry const& getReporterRegistry() const = 0; +virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; +virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; +virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; - }; +virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; +}; - struct IMutableRegistryHub { - virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; - virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; - virtual void registerTest( TestCase const& testInfo ) = 0; - virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - virtual void registerStartupException() noexcept = 0; - }; +struct IMutableRegistryHub { +virtual ~IMutableRegistryHub(); +virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; +virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; +virtual void registerTest( TestCase const& testInfo ) = 0; +virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; +virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; +virtual void registerStartupException() noexcept = 0; +}; - IRegistryHub& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); +IRegistryHub const& getRegistryHub(); +IMutableRegistryHub& getMutableRegistryHub(); +void cleanUp(); +std::string translateActiveException(); } // end catch_interfaces_registry_hub.h #if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ static std::string translatorName( signature ) #endif @@ -1759,60 +2668,62 @@ namespace Catch { #include namespace Catch { - using exceptionTranslateFunction = std::string(*)(); +using exceptionTranslateFunction = std::string(*)(); - struct IExceptionTranslator; - using ExceptionTranslators = std::vector>; +struct IExceptionTranslator; +using ExceptionTranslators = std::vector>; - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; - }; +struct IExceptionTranslator { +virtual ~IExceptionTranslator(); +virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; +}; - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); +struct IExceptionTranslatorRegistry { +virtual ~IExceptionTranslatorRegistry(); - virtual std::string translateActiveException() const = 0; - }; +virtual std::string translateActiveException() const = 0; +}; - class ExceptionTranslatorRegistrar { - template - class ExceptionTranslator : public IExceptionTranslator { - public: +class ExceptionTranslatorRegistrar { +template +class ExceptionTranslator : public IExceptionTranslator { +public: - ExceptionTranslator( std::string(*translateFunction)( T& ) ) - : m_translateFunction( translateFunction ) - {} +ExceptionTranslator( std::string(*translateFunction)( T& ) ) +: m_translateFunction( translateFunction ) +{} - std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { - try { - if( it == itEnd ) - std::rethrow_exception(std::current_exception()); - else - return (*it)->translate( it+1, itEnd ); - } - catch( T& ex ) { - return m_translateFunction( ex ); - } - } +std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { +try { +if( it == itEnd ) +std::rethrow_exception(std::current_exception()); +else +return (*it)->translate( it+1, itEnd ); +} +catch( T& ex ) { +return m_translateFunction( ex ); +} +} - protected: - std::string(*m_translateFunction)( T& ); - }; +protected: +std::string(*m_translateFunction)( T& ); +}; - public: - template - ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { - getMutableRegistryHub().registerTranslator - ( new ExceptionTranslator( translateFunction ) ); - } - }; +public: +template +ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { +getMutableRegistryHub().registerTranslator +( new ExceptionTranslator( translateFunction ) ); +} +}; } /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ static std::string translatorName( signature ); \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ + CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ static std::string translatorName( signature ) #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) @@ -1820,128 +2731,120 @@ namespace Catch { // end catch_interfaces_exception.h // start catch_approx.h -// start catch_enforce.h - -#include -#include - -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( static_cast( std::ostringstream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); -#define CATCH_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) - -// end catch_enforce.h #include namespace Catch { namespace Detail { - class Approx { - private: - bool equalityComparisonImpl(double other) const; +class Approx { +private: +bool equalityComparisonImpl(double other) const; +// Validates the new margin (margin >= 0) +// out-of-line to avoid including stdexcept in the header +void setMargin(double margin); +// Validates the new epsilon (0 < epsilon < 1) +// out-of-line to avoid including stdexcept in the header +void setEpsilon(double epsilon); - public: - explicit Approx ( double value ); +public: +explicit Approx ( double value ); - static Approx custom(); +static Approx custom(); - template ::value>::type> - Approx operator()( T const& value ) { - Approx approx( static_cast(value) ); - approx.epsilon( m_epsilon ); - approx.margin( m_margin ); - approx.scale( m_scale ); - return approx; - } +Approx operator-() const; - template ::value>::type> - explicit Approx( T const& value ): Approx(static_cast(value)) - {} - - template ::value>::type> - friend bool operator == ( const T& lhs, Approx const& rhs ) { - auto lhs_v = static_cast(lhs); - return rhs.equalityComparisonImpl(lhs_v); - } - - template ::value>::type> - friend bool operator == ( Approx const& lhs, const T& rhs ) { - return operator==( rhs, lhs ); - } - - template ::value>::type> - friend bool operator != ( T const& lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - template ::value>::type> - friend bool operator != ( Approx const& lhs, T const& rhs ) { - return !operator==( rhs, lhs ); - } - - template ::value>::type> - friend bool operator <= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) < rhs.m_value || lhs == rhs; - } - - template ::value>::type> - friend bool operator <= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value < static_cast(rhs) || lhs == rhs; - } - - template ::value>::type> - friend bool operator >= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) > rhs.m_value || lhs == rhs; - } - - template ::value>::type> - friend bool operator >= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value > static_cast(rhs) || lhs == rhs; - } - - template ::value>::type> - Approx& epsilon( T const& newEpsilon ) { - double epsilonAsDouble = static_cast(newEpsilon); - CATCH_ENFORCE(epsilonAsDouble >= 0 && epsilonAsDouble <= 1.0, - "Invalid Approx::epsilon: " << epsilonAsDouble - << ", Approx::epsilon has to be between 0 and 1"); - m_epsilon = epsilonAsDouble; - return *this; - } - - template ::value>::type> - Approx& margin( T const& newMargin ) { - double marginAsDouble = static_cast(newMargin); - CATCH_ENFORCE(marginAsDouble >= 0, - "Invalid Approx::margin: " << marginAsDouble - << ", Approx::Margin has to be non-negative."); - m_margin = marginAsDouble; - return *this; - } - - template ::value>::type> - Approx& scale( T const& newScale ) { - m_scale = static_cast(newScale); - return *this; - } - - std::string toString() const; - - private: - double m_epsilon; - double m_margin; - double m_scale; - double m_value; - }; +template ::value>::type> +Approx operator()( T const& value ) { +Approx approx( static_cast(value) ); +approx.m_epsilon = m_epsilon; +approx.m_margin = m_margin; +approx.m_scale = m_scale; +return approx; } +template ::value>::type> +explicit Approx( T const& value ): Approx(static_cast(value)) +{} + +template ::value>::type> +friend bool operator == ( const T& lhs, Approx const& rhs ) { +auto lhs_v = static_cast(lhs); +return rhs.equalityComparisonImpl(lhs_v); +} + +template ::value>::type> +friend bool operator == ( Approx const& lhs, const T& rhs ) { +return operator==( rhs, lhs ); +} + +template ::value>::type> +friend bool operator != ( T const& lhs, Approx const& rhs ) { +return !operator==( lhs, rhs ); +} + +template ::value>::type> +friend bool operator != ( Approx const& lhs, T const& rhs ) { +return !operator==( rhs, lhs ); +} + +template ::value>::type> +friend bool operator <= ( T const& lhs, Approx const& rhs ) { +return static_cast(lhs) < rhs.m_value || lhs == rhs; +} + +template ::value>::type> +friend bool operator <= ( Approx const& lhs, T const& rhs ) { +return lhs.m_value < static_cast(rhs) || lhs == rhs; +} + +template ::value>::type> +friend bool operator >= ( T const& lhs, Approx const& rhs ) { +return static_cast(lhs) > rhs.m_value || lhs == rhs; +} + +template ::value>::type> +friend bool operator >= ( Approx const& lhs, T const& rhs ) { +return lhs.m_value > static_cast(rhs) || lhs == rhs; +} + +template ::value>::type> +Approx& epsilon( T const& newEpsilon ) { +double epsilonAsDouble = static_cast(newEpsilon); +setEpsilon(epsilonAsDouble); +return *this; +} + +template ::value>::type> +Approx& margin( T const& newMargin ) { +double marginAsDouble = static_cast(newMargin); +setMargin(marginAsDouble); +return *this; +} + +template ::value>::type> +Approx& scale( T const& newScale ) { +m_scale = static_cast(newScale); +return *this; +} + +std::string toString() const; + +private: +double m_epsilon; +double m_margin; +double m_scale; +double m_value; +}; +} // end namespace Detail + +namespace literals { +Detail::Approx operator "" _a(long double val); +Detail::Approx operator "" _a(unsigned long long val); +} // end namespace literals + template<> struct StringMaker { - static std::string convert(Catch::Detail::Approx const& value); +static std::string convert(Catch::Detail::Approx const& value); }; } // end namespace Catch @@ -1954,24 +2857,24 @@ struct StringMaker { namespace Catch { - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); +bool startsWith( std::string const& s, std::string const& prefix ); +bool startsWith( std::string const& s, char prefix ); +bool endsWith( std::string const& s, std::string const& suffix ); +bool endsWith( std::string const& s, char suffix ); +bool contains( std::string const& s, std::string const& infix ); +void toLowerInPlace( std::string& s ); +std::string toLower( std::string const& s ); +std::string trim( std::string const& str ); +bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - struct pluralise { - pluralise( std::size_t count, std::string const& label ); +struct pluralise { +pluralise( std::size_t count, std::string const& label ); - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); +friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - std::size_t m_count; - std::string m_label; - }; +std::size_t m_count; +std::string m_label; +}; } // end catch_string_manip.h @@ -1985,137 +2888,142 @@ namespace Catch { namespace Catch { namespace Matchers { - namespace Impl { +namespace Impl { - template struct MatchAllOf; - template struct MatchAnyOf; - template struct MatchNotOf; +template struct MatchAllOf; +template struct MatchAnyOf; +template struct MatchNotOf; - class MatcherUntypedBase { - public: - MatcherUntypedBase() = default; - MatcherUntypedBase ( MatcherUntypedBase const& ) = default; - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; - std::string toString() const; +class MatcherUntypedBase { +public: +MatcherUntypedBase() = default; +MatcherUntypedBase ( MatcherUntypedBase const& ) = default; +MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; +std::string toString() const; - protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; - }; +protected: +virtual ~MatcherUntypedBase(); +virtual std::string describe() const = 0; +mutable std::string m_cachedToString; +}; - template - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; - template - struct MatcherMethod { - virtual bool match( PtrT* arg ) const = 0; - }; +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { +template +struct MatcherMethod { +virtual bool match( ObjectT const& arg ) const = 0; +}; - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; - }; +#ifdef __clang__ +# pragma clang diagnostic pop +#endif - template - struct MatchAllOf : MatcherBase { - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (!matcher->match(arg)) - return false; - } - return true; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " and "; - description += matcher->toString(); - } - description += " )"; - return description; - } +template +struct MatcherBase : MatcherUntypedBase, MatcherMethod { - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } +MatchAllOf operator && ( MatcherBase const& other ) const; +MatchAnyOf operator || ( MatcherBase const& other ) const; +MatchNotOf operator ! () const; +}; - std::vector const*> m_matchers; - }; - template - struct MatchAnyOf : MatcherBase { +template +struct MatchAllOf : MatcherBase { +bool match( ArgT const& arg ) const override { +for( auto matcher : m_matchers ) { +if (!matcher->match(arg)) +return false; +} +return true; +} +std::string describe() const override { +std::string description; +description.reserve( 4 + m_matchers.size()*32 ); +description += "( "; +bool first = true; +for( auto matcher : m_matchers ) { +if( first ) +first = false; +else +description += " and "; +description += matcher->toString(); +} +description += " )"; +return description; +} - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (matcher->match(arg)) - return true; - } - return false; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " or "; - description += matcher->toString(); - } - description += " )"; - return description; - } +MatchAllOf& operator && ( MatcherBase const& other ) { +m_matchers.push_back( &other ); +return *this; +} - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } +std::vector const*> m_matchers; +}; +template +struct MatchAnyOf : MatcherBase { - std::vector const*> m_matchers; - }; +bool match( ArgT const& arg ) const override { +for( auto matcher : m_matchers ) { +if (matcher->match(arg)) +return true; +} +return false; +} +std::string describe() const override { +std::string description; +description.reserve( 4 + m_matchers.size()*32 ); +description += "( "; +bool first = true; +for( auto matcher : m_matchers ) { +if( first ) +first = false; +else +description += " or "; +description += matcher->toString(); +} +description += " )"; +return description; +} - template - struct MatchNotOf : MatcherBase { +MatchAnyOf& operator || ( MatcherBase const& other ) { +m_matchers.push_back( &other ); +return *this; +} - MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} +std::vector const*> m_matchers; +}; - bool match( ArgT const& arg ) const override { - return !m_underlyingMatcher.match( arg ); - } +template +struct MatchNotOf : MatcherBase { - std::string describe() const override { - return "not " + m_underlyingMatcher.toString(); - } - MatcherBase const& m_underlyingMatcher; - }; +MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; - } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; - } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); - } +bool match( ArgT const& arg ) const override { +return !m_underlyingMatcher.match( arg ); +} - } // namespace Impl +std::string describe() const override { +return "not " + m_underlyingMatcher.toString(); +} +MatcherBase const& m_underlyingMatcher; +}; + +template +MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { +return MatchAllOf() && *this && other; +} +template +MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { +return MatchAnyOf() || *this || other; +} +template +MatchNotOf MatcherBase::operator ! () const { +return MatchNotOf( *this ); +} + +} // namespace Impl } // namespace Matchers @@ -2125,6 +3033,97 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.h +// start catch_matchers_floating.h + +#include +#include + +namespace Catch { +namespace Matchers { + +namespace Floating { + +enum class FloatingPointKind : uint8_t; + +struct WithinAbsMatcher : MatcherBase { +WithinAbsMatcher(double target, double margin); +bool match(double const& matchee) const override; +std::string describe() const override; +private: +double m_target; +double m_margin; +}; + +struct WithinUlpsMatcher : MatcherBase { +WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); +bool match(double const& matchee) const override; +std::string describe() const override; +private: +double m_target; +int m_ulps; +FloatingPointKind m_type; +}; + +} // namespace Floating + +// The following functions create the actual matcher objects. +// This allows the types to be inferred +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); +Floating::WithinAbsMatcher WithinAbs(double target, double margin); + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.h +// start catch_matchers_generic.hpp + +#include +#include + +namespace Catch { +namespace Matchers { +namespace Generic { + +namespace Detail { +std::string finalizeDescription(const std::string& desc); +} + +template +class PredicateMatcher : public MatcherBase { +std::function m_predicate; +std::string m_description; +public: + +PredicateMatcher(std::function const& elem, std::string const& descr) +:m_predicate(std::move(elem)), +m_description(Detail::finalizeDescription(descr)) +{} + +bool match( T const& item ) const override { +return m_predicate(item); +} + +std::string describe() const override { +return m_description; +} +}; + +} // namespace Generic + +// The following functions create the actual matcher objects. +// The user has to explicitly specify type to the function, because +// inferring std::function is hard (but possible) and +// requires a lot of TMP. +template +Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { +return Generic::PredicateMatcher(predicate, description); +} + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_generic.hpp // start catch_matchers_string.h #include @@ -2132,52 +3131,63 @@ using Matchers::Impl::MatcherBase; namespace Catch { namespace Matchers { - namespace StdString { +namespace StdString { - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); - std::string adjustString( std::string const& str ) const; - std::string caseSensitivitySuffix() const; +struct CasedString +{ +CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); +std::string adjustString( std::string const& str ) const; +std::string caseSensitivitySuffix() const; - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; - }; +CaseSensitive::Choice m_caseSensitivity; +std::string m_str; +}; - struct StringMatcherBase : MatcherBase { - StringMatcherBase( std::string const& operation, CasedString const& comparator ); - std::string describe() const override; +struct StringMatcherBase : MatcherBase { +StringMatcherBase( std::string const& operation, CasedString const& comparator ); +std::string describe() const override; - CasedString m_comparator; - std::string m_operation; - }; +CasedString m_comparator; +std::string m_operation; +}; - struct EqualsMatcher : StringMatcherBase { - EqualsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct ContainsMatcher : StringMatcherBase { - ContainsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct StartsWithMatcher : StringMatcherBase { - StartsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct EndsWithMatcher : StringMatcherBase { - EndsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; +struct EqualsMatcher : StringMatcherBase { +EqualsMatcher( CasedString const& comparator ); +bool match( std::string const& source ) const override; +}; +struct ContainsMatcher : StringMatcherBase { +ContainsMatcher( CasedString const& comparator ); +bool match( std::string const& source ) const override; +}; +struct StartsWithMatcher : StringMatcherBase { +StartsWithMatcher( CasedString const& comparator ); +bool match( std::string const& source ) const override; +}; +struct EndsWithMatcher : StringMatcherBase { +EndsWithMatcher( CasedString const& comparator ); +bool match( std::string const& source ) const override; +}; - } // namespace StdString +struct RegexMatcher : MatcherBase { +RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); +bool match( std::string const& matchee ) const override; +std::string describe() const override; - // The following functions create the actual matcher objects. - // This allows the types to be inferred +private: +std::string m_regex; +CaseSensitive::Choice m_caseSensitivity; +}; - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); +} // namespace StdString + +// The following functions create the actual matcher objects. +// This allows the types to be inferred + +StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); +StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); +StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); +StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); +StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); } // namespace Matchers } // namespace Catch @@ -2185,104 +3195,170 @@ namespace Matchers { // end catch_matchers_string.h // start catch_matchers_vector.h +#include + namespace Catch { namespace Matchers { - namespace Vector { +namespace Vector { +template +struct ContainsElementMatcher : MatcherBase> { - template - struct ContainsElementMatcher : MatcherBase, T> { +ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} +bool match(std::vector const &v) const override { +for (auto const& el : v) { +if (el == m_comparator) { +return true; +} +} +return false; +} - bool match(std::vector const &v) const override { - for (auto const& el : v) { - if (el == m_comparator) { - return true; - } - } - return false; - } +std::string describe() const override { +return "Contains: " + ::Catch::Detail::stringify( m_comparator ); +} - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } +T const& m_comparator; +}; - T const& m_comparator; - }; +template +struct ContainsMatcher : MatcherBase> { - template - struct ContainsMatcher : MatcherBase, std::vector > { +ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} +bool match(std::vector const &v) const override { +// !TBD: see note in EqualsMatcher +if (m_comparator.size() > v.size()) +return false; +for (auto const& comparator : m_comparator) { +auto present = false; +for (const auto& el : v) { +if (el == comparator) { +present = true; +break; +} +} +if (!present) { +return false; +} +} +return true; +} +std::string describe() const override { +return "Contains: " + ::Catch::Detail::stringify( m_comparator ); +} - bool match(std::vector const &v) const override { - // !TBD: see note in EqualsMatcher - if (m_comparator.size() > v.size()) - return false; - for (auto const& comparator : m_comparator) { - auto present = false; - for (const auto& el : v) { - if (el == comparator) { - present = true; - break; - } - } - if (!present) { - return false; - } - } - return true; - } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } +std::vector const& m_comparator; +}; - std::vector const& m_comparator; - }; +template +struct EqualsMatcher : MatcherBase> { - template - struct EqualsMatcher : MatcherBase, std::vector > { +EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} +bool match(std::vector const &v) const override { +// !TBD: This currently works if all elements can be compared using != +// - a more general approach would be via a compare template that defaults +// to using !=. but could be specialised for, e.g. std::vector etc +// - then just call that directly +if (m_comparator.size() != v.size()) +return false; +for (std::size_t i = 0; i < v.size(); ++i) +if (m_comparator[i] != v[i]) +return false; +return true; +} +std::string describe() const override { +return "Equals: " + ::Catch::Detail::stringify( m_comparator ); +} +std::vector const& m_comparator; +}; - bool match(std::vector const &v) const override { - // !TBD: This currently works if all elements can be compared using != - // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector etc - // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; - return true; - } - std::string describe() const override { - return "Equals: " + ::Catch::Detail::stringify( m_comparator ); - } - std::vector const& m_comparator; - }; +template +struct ApproxMatcher : MatcherBase> { - } // namespace Vector +ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} - // The following functions create the actual matcher objects. - // This allows the types to be inferred +bool match(std::vector const &v) const override { +if (m_comparator.size() != v.size()) +return false; +for (std::size_t i = 0; i < v.size(); ++i) +if (m_comparator[i] != approx(v[i])) +return false; +return true; +} +std::string describe() const override { +return "is approx: " + ::Catch::Detail::stringify( m_comparator ); +} +template ::value>::type> +ApproxMatcher& epsilon( T const& newEpsilon ) { +approx.epsilon(newEpsilon); +return *this; +} +template ::value>::type> +ApproxMatcher& margin( T const& newMargin ) { +approx.margin(newMargin); +return *this; +} +template ::value>::type> +ApproxMatcher& scale( T const& newScale ) { +approx.scale(newScale); +return *this; +} - template - Vector::ContainsMatcher Contains( std::vector const& comparator ) { - return Vector::ContainsMatcher( comparator ); - } +std::vector const& m_comparator; +mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); +}; - template - Vector::ContainsElementMatcher VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher( comparator ); - } +template +struct UnorderedEqualsMatcher : MatcherBase> { +UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} +bool match(std::vector const& vec) const override { +// Note: This is a reimplementation of std::is_permutation, +// because I don't want to include inside the common path +if (m_target.size() != vec.size()) { +return false; +} +return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); +} - template - Vector::EqualsMatcher Equals( std::vector const& comparator ) { - return Vector::EqualsMatcher( comparator ); - } +std::string describe() const override { +return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); +} +private: +std::vector const& m_target; +}; + +} // namespace Vector + +// The following functions create the actual matcher objects. +// This allows the types to be inferred + +template +Vector::ContainsMatcher Contains( std::vector const& comparator ) { +return Vector::ContainsMatcher( comparator ); +} + +template +Vector::ContainsElementMatcher VectorContains( T const& comparator ) { +return Vector::ContainsElementMatcher( comparator ); +} + +template +Vector::EqualsMatcher Equals( std::vector const& comparator ) { +return Vector::EqualsMatcher( comparator ); +} + +template +Vector::ApproxMatcher Approx( std::vector const& comparator ) { +return Vector::ApproxMatcher( comparator ); +} + +template +Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { +return Vector::UnorderedEqualsMatcher(target); +} } // namespace Matchers } // namespace Catch @@ -2290,76 +3366,808 @@ namespace Matchers { // end catch_matchers_vector.h namespace Catch { - template - class MatchExpr : public ITransientExpression { - ArgT const& m_arg; - MatcherT m_matcher; - StringRef m_matcherString; - bool m_result; - public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : m_arg( arg ), - m_matcher( matcher ), - m_matcherString( matcherString ), - m_result( matcher.match( arg ) ) - {} +template +class MatchExpr : public ITransientExpression { +ArgT const& m_arg; +MatcherT m_matcher; +StringRef m_matcherString; +public: +MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) +: ITransientExpression{ true, matcher.match( arg ) }, +m_arg( arg ), +m_matcher( matcher ), +m_matcherString( matcherString ) +{} - auto isBinaryExpression() const -> bool override { return true; } - auto getResult() const -> bool override { return m_result; } +void streamReconstructedExpression( std::ostream &os ) const override { +auto matcherAsString = m_matcher.toString(); +os << Catch::Detail::stringify( m_arg ) << ' '; +if( matcherAsString == Detail::unprintableString ) +os << m_matcherString; +else +os << matcherAsString; +} +}; - void streamReconstructedExpression( std::ostream &os ) const override { - auto matcherAsString = m_matcher.toString(); - os << Catch::Detail::stringify( m_arg ) << ' '; - if( matcherAsString == Detail::unprintableString ) - os << m_matcherString; - else - os << matcherAsString; - } - }; +using StringMatcher = Matchers::Impl::MatcherBase; - using StringMatcher = Matchers::Impl::MatcherBase; +void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); - - template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { - return MatchExpr( arg, matcher, matcherString ); - } +template +auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr { +return MatchExpr( arg, matcher, matcherString ); +} } // namespace Catch /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + INTERNAL_CATCH_TRY { \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ + Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ if( catchAssertionHandler.allowThrows() ) \ try { \ static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handle( Catch::ResultWas::DidntThrowException ); \ + catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ } \ catch( exceptionType const& ex ) { \ - catchAssertionHandler.handle( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ + catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ } \ catch( ... ) { \ - catchAssertionHandler.useActiveException(); \ + catchAssertionHandler.handleUnexpectedInflightException(); \ } \ else \ - catchAssertionHandler.handle( Catch::ResultWas::Ok ); \ + catchAssertionHandler.handleThrowingCallSkipped(); \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( Catch::alwaysFalse() ) + } while( false ) // end catch_capture_matchers.h #endif +// start catch_generators.hpp + +// start catch_interfaces_generatortracker.h + + +#include + +namespace Catch { + +namespace Generators { +class GeneratorUntypedBase { +public: +GeneratorUntypedBase() = default; +virtual ~GeneratorUntypedBase(); +// Attempts to move the generator to the next element +// +// Returns true iff the move succeeded (and a valid element +// can be retrieved). +virtual bool next() = 0; +}; +using GeneratorBasePtr = std::unique_ptr; + +} // namespace Generators + +struct IGeneratorTracker { +virtual ~IGeneratorTracker(); +virtual auto hasGenerator() const -> bool = 0; +virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; +virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; +}; + +} // namespace Catch + +// end catch_interfaces_generatortracker.h +// start catch_enforce.h + +#include + +namespace Catch { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +template +[[noreturn]] +void throw_exception(Ex const& e) { +throw e; +} +#else // ^^ Exceptions are enabled // Exceptions are disabled vv +[[noreturn]] +void throw_exception(std::exception const& e); +#endif +} // namespace Catch; + +#define CATCH_PREPARE_EXCEPTION( type, msg ) \ + type( ( Catch::ReusableStringStream() << msg ).str() ) +#define CATCH_INTERNAL_ERROR( msg ) \ + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) +#define CATCH_ERROR( msg ) \ + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) +#define CATCH_RUNTIME_ERROR( msg ) \ + Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) +#define CATCH_ENFORCE( condition, msg ) \ + do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) + +// end catch_enforce.h +#include +#include +#include + +#include +#include + +namespace Catch { + +class GeneratorException : public std::exception { +const char* const m_msg = ""; + +public: +GeneratorException(const char* msg): +m_msg(msg) +{} + +const char* what() const noexcept override final; +}; + +namespace Generators { + +// !TBD move this into its own location? +namespace pf{ +template +std::unique_ptr make_unique( Args&&... args ) { +return std::unique_ptr(new T(std::forward(args)...)); +} +} + +template +struct IGenerator : GeneratorUntypedBase { +virtual ~IGenerator() = default; + +// Returns the current element of the generator +// +// \Precondition The generator is either freshly constructed, +// or the last call to `next()` returned true +virtual T const& get() const = 0; +using type = T; +}; + +template +class SingleValueGenerator final : public IGenerator { +T m_value; +public: +SingleValueGenerator(T const& value) : m_value( value ) {} +SingleValueGenerator(T&& value) : m_value(std::move(value)) {} + +T const& get() const override { +return m_value; +} +bool next() override { +return false; +} +}; + +template +class FixedValuesGenerator final : public IGenerator { +std::vector m_values; +size_t m_idx = 0; +public: +FixedValuesGenerator( std::initializer_list values ) : m_values( values ) {} + +T const& get() const override { +return m_values[m_idx]; +} +bool next() override { +++m_idx; +return m_idx < m_values.size(); +} +}; + +template +class GeneratorWrapper final { +std::unique_ptr> m_generator; +public: +GeneratorWrapper(std::unique_ptr> generator): +m_generator(std::move(generator)) +{} +T const& get() const { +return m_generator->get(); +} +bool next() { +return m_generator->next(); +} +}; + +template +GeneratorWrapper value(T&& value) { +return GeneratorWrapper(pf::make_unique>(std::forward(value))); +} +template +GeneratorWrapper values(std::initializer_list values) { +return GeneratorWrapper(pf::make_unique>(values)); +} + +template +class Generators : public IGenerator { +std::vector> m_generators; +size_t m_current = 0; + +void populate(GeneratorWrapper&& generator) { +m_generators.emplace_back(std::move(generator)); +} +void populate(T&& val) { +m_generators.emplace_back(value(std::move(val))); +} +template +void populate(U&& val) { +populate(T(std::move(val))); +} +template +void populate(U&& valueOrGenerator, Gs... moreGenerators) { +populate(std::forward(valueOrGenerator)); +populate(std::forward(moreGenerators)...); +} + +public: +template +Generators(Gs... moreGenerators) { +m_generators.reserve(sizeof...(Gs)); +populate(std::forward(moreGenerators)...); +} + +T const& get() const override { +return m_generators[m_current].get(); +} + +bool next() override { +if (m_current >= m_generators.size()) { +return false; +} +const bool current_status = m_generators[m_current].next(); +if (!current_status) { +++m_current; +} +return m_current < m_generators.size(); +} +}; + +template +GeneratorWrapper> table( std::initializer_list::type...>> tuples ) { +return values>( tuples ); +} + +// Tag type to signal that a generator sequence should convert arguments to a specific type +template +struct as {}; + +template +auto makeGenerators( GeneratorWrapper&& generator, Gs... moreGenerators ) -> Generators { +return Generators(std::move(generator), std::forward(moreGenerators)...); +} +template +auto makeGenerators( GeneratorWrapper&& generator ) -> Generators { +return Generators(std::move(generator)); +} +template +auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators { +return makeGenerators( value( std::forward( val ) ), std::forward( moreGenerators )... ); +} +template +auto makeGenerators( as, U&& val, Gs... moreGenerators ) -> Generators { +return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); +} + +auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + +template +// Note: The type after -> is weird, because VS2015 cannot parse +// the expression used in the typedef inside, when it is in +// return type. Yeah. +auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { +using UnderlyingType = typename decltype(generatorExpression())::type; + +IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); +if (!tracker.hasGenerator()) { +tracker.setGenerator(pf::make_unique>(generatorExpression())); +} + +auto const& generator = static_cast const&>( *tracker.getGenerator() ); +return generator.get(); +} + +} // namespace Generators +} // namespace Catch + +#define GENERATE( ... ) \ + Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) +#define GENERATE_COPY( ... ) \ + Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) +#define GENERATE_REF( ... ) \ + Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) + +// end catch_generators.hpp +// start catch_generators_generic.hpp + +namespace Catch { +namespace Generators { + +template +class TakeGenerator : public IGenerator { +GeneratorWrapper m_generator; +size_t m_returned = 0; +size_t m_target; +public: +TakeGenerator(size_t target, GeneratorWrapper&& generator): +m_generator(std::move(generator)), +m_target(target) +{ +assert(target != 0 && "Empty generators are not allowed"); +} +T const& get() const override { +return m_generator.get(); +} +bool next() override { +++m_returned; +if (m_returned >= m_target) { +return false; +} + +const auto success = m_generator.next(); +// If the underlying generator does not contain enough values +// then we cut short as well +if (!success) { +m_returned = m_target; +} +return success; +} +}; + +template +GeneratorWrapper take(size_t target, GeneratorWrapper&& generator) { +return GeneratorWrapper(pf::make_unique>(target, std::move(generator))); +} + +template +class FilterGenerator : public IGenerator { +GeneratorWrapper m_generator; +Predicate m_predicate; +public: +template +FilterGenerator(P&& pred, GeneratorWrapper&& generator): +m_generator(std::move(generator)), +m_predicate(std::forward

(pred)) +{ +if (!m_predicate(m_generator.get())) { +// It might happen that there are no values that pass the +// filter. In that case we throw an exception. +auto has_initial_value = next(); +if (!has_initial_value) { +Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); +} +} +} + +T const& get() const override { +return m_generator.get(); +} + +bool next() override { +bool success = m_generator.next(); +if (!success) { +return false; +} +while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); +return success; +} +}; + +template +GeneratorWrapper filter(Predicate&& pred, GeneratorWrapper&& generator) { +return GeneratorWrapper(std::unique_ptr>(pf::make_unique>(std::forward(pred), std::move(generator)))); +} + +template +class RepeatGenerator : public IGenerator { +GeneratorWrapper m_generator; +mutable std::vector m_returned; +size_t m_target_repeats; +size_t m_current_repeat = 0; +size_t m_repeat_index = 0; +public: +RepeatGenerator(size_t repeats, GeneratorWrapper&& generator): +m_generator(std::move(generator)), +m_target_repeats(repeats) +{ +assert(m_target_repeats > 0 && "Repeat generator must repeat at least once"); +} + +T const& get() const override { +if (m_current_repeat == 0) { +m_returned.push_back(m_generator.get()); +return m_returned.back(); +} +return m_returned[m_repeat_index]; +} + +bool next() override { +// There are 2 basic cases: +// 1) We are still reading the generator +// 2) We are reading our own cache + +// In the first case, we need to poke the underlying generator. +// If it happily moves, we are left in that state, otherwise it is time to start reading from our cache +if (m_current_repeat == 0) { +const auto success = m_generator.next(); +if (!success) { +++m_current_repeat; +} +return m_current_repeat < m_target_repeats; +} + +// In the second case, we need to move indices forward and check that we haven't run up against the end +++m_repeat_index; +if (m_repeat_index == m_returned.size()) { +m_repeat_index = 0; +++m_current_repeat; +} +return m_current_repeat < m_target_repeats; +} +}; + +template +GeneratorWrapper repeat(size_t repeats, GeneratorWrapper&& generator) { +return GeneratorWrapper(pf::make_unique>(repeats, std::move(generator))); +} + +template +class MapGenerator : public IGenerator { +// TBD: provide static assert for mapping function, for friendly error message +GeneratorWrapper m_generator; +Func m_function; +// To avoid returning dangling reference, we have to save the values +T m_cache; +public: +template +MapGenerator(F2&& function, GeneratorWrapper&& generator) : +m_generator(std::move(generator)), +m_function(std::forward(function)), +m_cache(m_function(m_generator.get())) +{} + +T const& get() const override { +return m_cache; +} +bool next() override { +const auto success = m_generator.next(); +if (success) { +m_cache = m_function(m_generator.get()); +} +return success; +} +}; + +#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 +// std::result_of is deprecated in C++17 and removed in C++20. Hence, it is +// replaced with std::invoke_result here. Also *_t format is preferred over +// typename *::type format. +template +using MapFunctionReturnType = std::remove_reference_t>>; +#else +template +using MapFunctionReturnType = typename std::remove_reference::type>::type>::type; +#endif + +template > +GeneratorWrapper map(Func&& function, GeneratorWrapper&& generator) { +return GeneratorWrapper( +pf::make_unique>(std::forward(function), std::move(generator)) +); +} + +template +GeneratorWrapper map(Func&& function, GeneratorWrapper&& generator) { +return GeneratorWrapper( +pf::make_unique>(std::forward(function), std::move(generator)) +); +} + +template +class ChunkGenerator final : public IGenerator> { +std::vector m_chunk; +size_t m_chunk_size; +GeneratorWrapper m_generator; +bool m_used_up = false; +public: +ChunkGenerator(size_t size, GeneratorWrapper generator) : +m_chunk_size(size), m_generator(std::move(generator)) +{ +m_chunk.reserve(m_chunk_size); +m_chunk.push_back(m_generator.get()); +for (size_t i = 1; i < m_chunk_size; ++i) { +if (!m_generator.next()) { +Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk")); +} +m_chunk.push_back(m_generator.get()); +} +} +std::vector const& get() const override { +return m_chunk; +} +bool next() override { +m_chunk.clear(); +for (size_t idx = 0; idx < m_chunk_size; ++idx) { +if (!m_generator.next()) { +return false; +} +m_chunk.push_back(m_generator.get()); +} +return true; +} +}; + +template +GeneratorWrapper> chunk(size_t size, GeneratorWrapper&& generator) { +return GeneratorWrapper>( +pf::make_unique>(size, std::move(generator)) +); +} + +} // namespace Generators +} // namespace Catch + +// end catch_generators_generic.hpp +// start catch_generators_specific.hpp + +// start catch_context.h + +#include + +namespace Catch { + +struct IResultCapture; +struct IRunner; +struct IConfig; +struct IMutableContext; + +using IConfigPtr = std::shared_ptr; + +struct IContext +{ +virtual ~IContext(); + +virtual IResultCapture* getResultCapture() = 0; +virtual IRunner* getRunner() = 0; +virtual IConfigPtr const& getConfig() const = 0; +}; + +struct IMutableContext : IContext +{ +virtual ~IMutableContext(); +virtual void setResultCapture( IResultCapture* resultCapture ) = 0; +virtual void setRunner( IRunner* runner ) = 0; +virtual void setConfig( IConfigPtr const& config ) = 0; + +private: +static IMutableContext *currentContext; +friend IMutableContext& getCurrentMutableContext(); +friend void cleanUpContext(); +static void createContext(); +}; + +inline IMutableContext& getCurrentMutableContext() +{ +if( !IMutableContext::currentContext ) +IMutableContext::createContext(); +return *IMutableContext::currentContext; +} + +inline IContext& getCurrentContext() +{ +return getCurrentMutableContext(); +} + +void cleanUpContext(); +} + +// end catch_context.h +// start catch_interfaces_config.h + +#include +#include +#include +#include + +namespace Catch { + +enum class Verbosity { +Quiet = 0, +Normal, +High +}; + +struct WarnAbout { enum What { +Nothing = 0x00, +NoAssertions = 0x01, +NoTests = 0x02 +}; }; + +struct ShowDurations { enum OrNot { +DefaultForReporter, +Always, +Never +}; }; +struct RunTests { enum InWhatOrder { +InDeclarationOrder, +InLexicographicalOrder, +InRandomOrder +}; }; +struct UseColour { enum YesOrNo { +Auto, +Yes, +No +}; }; +struct WaitForKeypress { enum When { +Never, +BeforeStart = 1, +BeforeExit = 2, +BeforeStartAndExit = BeforeStart | BeforeExit +}; }; + +class TestSpec; + +struct IConfig : NonCopyable { + +virtual ~IConfig(); + +virtual bool allowThrows() const = 0; +virtual std::ostream& stream() const = 0; +virtual std::string name() const = 0; +virtual bool includeSuccessfulResults() const = 0; +virtual bool shouldDebugBreak() const = 0; +virtual bool warnAboutMissingAssertions() const = 0; +virtual bool warnAboutNoTests() const = 0; +virtual int abortAfter() const = 0; +virtual bool showInvisibles() const = 0; +virtual ShowDurations::OrNot showDurations() const = 0; +virtual TestSpec const& testSpec() const = 0; +virtual bool hasTestFilters() const = 0; +virtual std::vector const& getTestsOrTags() const = 0; +virtual RunTests::InWhatOrder runOrder() const = 0; +virtual unsigned int rngSeed() const = 0; +virtual int benchmarkResolutionMultiple() const = 0; +virtual UseColour::YesOrNo useColour() const = 0; +virtual std::vector const& getSectionsToRun() const = 0; +virtual Verbosity verbosity() const = 0; +}; + +using IConfigPtr = std::shared_ptr; +} + +// end catch_interfaces_config.h +#include + +namespace Catch { +namespace Generators { + +template +class RandomFloatingGenerator final : public IGenerator { +// FIXME: What is the right seed? +std::minstd_rand m_rand; +std::uniform_real_distribution m_dist; +Float m_current_number; +public: + +RandomFloatingGenerator(Float a, Float b): +m_rand(getCurrentContext().getConfig()->rngSeed()), +m_dist(a, b) { +static_cast(next()); +} + +Float const& get() const override { +return m_current_number; +} +bool next() override { +m_current_number = m_dist(m_rand); +return true; +} +}; + +template +class RandomIntegerGenerator final : public IGenerator { +std::minstd_rand m_rand; +std::uniform_int_distribution m_dist; +Integer m_current_number; +public: + +RandomIntegerGenerator(Integer a, Integer b): +m_rand(getCurrentContext().getConfig()->rngSeed()), +m_dist(a, b) { +static_cast(next()); +} + +Integer const& get() const override { +return m_current_number; +} +bool next() override { +m_current_number = m_dist(m_rand); +return true; +} +}; + +// TODO: Ideally this would be also constrained against the various char types, +// but I don't expect users to run into that in practice. +template +typename std::enable_if::value && !std::is_same::value, +GeneratorWrapper>::type +random(T a, T b) { +return GeneratorWrapper( +pf::make_unique>(a, b) +); +} + +template +typename std::enable_if::value, +GeneratorWrapper>::type +random(T a, T b) { +return GeneratorWrapper( +pf::make_unique>(a, b) +); +} + +template +class RangeGenerator final : public IGenerator { +T m_current; +T m_end; +T m_step; +bool m_positive; + +public: +RangeGenerator(T const& start, T const& end, T const& step): +m_current(start), +m_end(end), +m_step(step), +m_positive(m_step > T(0)) +{ +assert(m_current != m_end && "Range start and end cannot be equal"); +assert(m_step != T(0) && "Step size cannot be zero"); +assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end"); +} + +RangeGenerator(T const& start, T const& end): +RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) +{} + +T const& get() const override { +return m_current; +} + +bool next() override { +m_current += m_step; +return (m_positive) ? (m_current < m_end) : (m_current > m_end); +} +}; + +template +GeneratorWrapper range(T const& start, T const& end, T const& step) { +static_assert(std::is_integral::value && !std::is_same::value, "Type must be an integer"); +return GeneratorWrapper(pf::make_unique>(start, end, step)); +} + +template +GeneratorWrapper range(T const& start, T const& end) { +static_assert(std::is_integral::value && !std::is_same::value, "Type must be an integer"); +return GeneratorWrapper(pf::make_unique>(start, end)); +} + +} // namespace Generators +} // namespace Catch + +// end catch_generators_specific.hpp // These files are included here so the single_include script doesn't put them // in the conditionally compiled sections @@ -2376,66 +4184,65 @@ namespace Catch { namespace Catch { - struct ITestInvoker; +struct ITestInvoker; - struct TestCaseInfo { - enum SpecialProperties{ - None = 0, - IsHidden = 1 << 1, - ShouldFail = 1 << 2, - MayFail = 1 << 3, - Throws = 1 << 4, - NonPortable = 1 << 5, - Benchmark = 1 << 6 - }; +struct TestCaseInfo { +enum SpecialProperties{ +None = 0, +IsHidden = 1 << 1, +ShouldFail = 1 << 2, +MayFail = 1 << 3, +Throws = 1 << 4, +NonPortable = 1 << 5, +Benchmark = 1 << 6 +}; - TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ); +TestCaseInfo( std::string const& _name, +std::string const& _className, +std::string const& _description, +std::vector const& _tags, +SourceLineInfo const& _lineInfo ); - friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); +friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); - bool isHidden() const; - bool throws() const; - bool okToFail() const; - bool expectedToFail() const; +bool isHidden() const; +bool throws() const; +bool okToFail() const; +bool expectedToFail() const; - std::string tagsAsString() const; +std::string tagsAsString() const; - std::string name; - std::string className; - std::string description; - std::vector tags; - std::vector lcaseTags; - SourceLineInfo lineInfo; - SpecialProperties properties; - }; +std::string name; +std::string className; +std::string description; +std::vector tags; +std::vector lcaseTags; +SourceLineInfo lineInfo; +SpecialProperties properties; +}; - class TestCase : public TestCaseInfo { - public: +class TestCase : public TestCaseInfo { +public: - TestCase( ITestInvoker* testCase, TestCaseInfo const& info ); +TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); - TestCase withName( std::string const& _newName ) const; +TestCase withName( std::string const& _newName ) const; - void invoke() const; +void invoke() const; - TestCaseInfo const& getTestCaseInfo() const; +TestCaseInfo const& getTestCaseInfo() const; - bool operator == ( TestCase const& other ) const; - bool operator < ( TestCase const& other ) const; +bool operator == ( TestCase const& other ) const; +bool operator < ( TestCase const& other ) const; - private: - std::shared_ptr test; - }; +private: +std::shared_ptr test; +}; - TestCase makeTestCase( ITestInvoker* testCase, - std::string const& className, - std::string const& name, - std::string const& description, - SourceLineInfo const& lineInfo ); +TestCase makeTestCase( ITestInvoker* testCase, +std::string const& className, +NameAndTags const& nameAndTags, +SourceLineInfo const& lineInfo ); } #ifdef __clang__ @@ -2447,10 +4254,10 @@ namespace Catch { namespace Catch { - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; +struct IRunner { +virtual ~IRunner(); +virtual bool aborting() const = 0; +}; } // end catch_interfaces_runner.h @@ -2480,162 +4287,162 @@ namespace Catch { namespace Catch { - class OcMethod : public ITestInvoker { +class OcMethod : public ITestInvoker { - public: - OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} +public: +OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - virtual void invoke() const { - id obj = [[m_cls alloc] init]; +virtual void invoke() const { +id obj = [[m_cls alloc] init]; - performOptionalSelector( obj, @selector(setUp) ); - performOptionalSelector( obj, m_sel ); - performOptionalSelector( obj, @selector(tearDown) ); +performOptionalSelector( obj, @selector(setUp) ); +performOptionalSelector( obj, m_sel ); +performOptionalSelector( obj, @selector(tearDown) ); - arcSafeRelease( obj ); - } - private: - virtual ~OcMethod() {} +arcSafeRelease( obj ); +} +private: +virtual ~OcMethod() {} - Class m_cls; - SEL m_sel; - }; +Class m_cls; +SEL m_sel; +}; - namespace Detail{ +namespace Detail{ - inline std::string getAnnotation( Class cls, - std::string const& annotationName, - std::string const& testCaseName ) { - NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; - SEL sel = NSSelectorFromString( selStr ); - arcSafeRelease( selStr ); - id value = performOptionalSelector( cls, sel ); - if( value ) - return [(NSString*)value UTF8String]; - return ""; - } - } +inline std::string getAnnotation( Class cls, +std::string const& annotationName, +std::string const& testCaseName ) { +NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; +SEL sel = NSSelectorFromString( selStr ); +arcSafeRelease( selStr ); +id value = performOptionalSelector( cls, sel ); +if( value ) +return [(NSString*)value UTF8String]; +return ""; +} +} - inline std::size_t registerTestMethods() { - std::size_t noTestMethods = 0; - int noClasses = objc_getClassList( nullptr, 0 ); +inline std::size_t registerTestMethods() { +std::size_t noTestMethods = 0; +int noClasses = objc_getClassList( nullptr, 0 ); - Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); - objc_getClassList( classes, noClasses ); +Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); +objc_getClassList( classes, noClasses ); - for( int c = 0; c < noClasses; c++ ) { - Class cls = classes[c]; - { - u_int count; - Method* methods = class_copyMethodList( cls, &count ); - for( u_int m = 0; m < count ; m++ ) { - SEL selector = method_getName(methods[m]); - std::string methodName = sel_getName(selector); - if( startsWith( methodName, "Catch_TestCase_" ) ) { - std::string testCaseName = methodName.substr( 15 ); - std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); - std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); - const char* className = class_getName( cls ); +for( int c = 0; c < noClasses; c++ ) { +Class cls = classes[c]; +{ +u_int count; +Method* methods = class_copyMethodList( cls, &count ); +for( u_int m = 0; m < count ; m++ ) { +SEL selector = method_getName(methods[m]); +std::string methodName = sel_getName(selector); +if( startsWith( methodName, "Catch_TestCase_" ) ) { +std::string testCaseName = methodName.substr( 15 ); +std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); +std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); +const char* className = class_getName( cls ); - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); - noTestMethods++; - } - } - free(methods); - } - } - return noTestMethods; - } +getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); +noTestMethods++; +} +} +free(methods); +} +} +return noTestMethods; +} #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - namespace Matchers { - namespace Impl { - namespace NSStringMatchers { +namespace Matchers { +namespace Impl { +namespace NSStringMatchers { - struct StringHolder : MatcherBase{ - StringHolder( NSString* substr ) : m_substr( [substr copy] ){} - StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} - StringHolder() { - arcSafeRelease( m_substr ); - } +struct StringHolder : MatcherBase{ +StringHolder( NSString* substr ) : m_substr( [substr copy] ){} +StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} +StringHolder() { +arcSafeRelease( m_substr ); +} - bool match( NSString* arg ) const override { - return false; - } +bool match( NSString* const& str ) const override { +return false; +} - NSString* CATCH_ARC_STRONG m_substr; - }; +NSString* CATCH_ARC_STRONG m_substr; +}; - struct Equals : StringHolder { - Equals( NSString* substr ) : StringHolder( substr ){} +struct Equals : StringHolder { +Equals( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str isEqualToString:m_substr]; - } +bool match( NSString* const& str ) const override { +return (str != nil || m_substr == nil ) && +[str isEqualToString:m_substr]; +} - std::string describe() const override { - return "equals string: " + Catch::Detail::stringify( m_substr ); - } - }; +std::string describe() const override { +return "equals string: " + Catch::Detail::stringify( m_substr ); +} +}; - struct Contains : StringHolder { - Contains( NSString* substr ) : StringHolder( substr ){} +struct Contains : StringHolder { +Contains( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location != NSNotFound; - } +bool match( NSString* const& str ) const override { +return (str != nil || m_substr == nil ) && +[str rangeOfString:m_substr].location != NSNotFound; +} - std::string describe() const override { - return "contains string: " + Catch::Detail::stringify( m_substr ); - } - }; +std::string describe() const override { +return "contains string: " + Catch::Detail::stringify( m_substr ); +} +}; - struct StartsWith : StringHolder { - StartsWith( NSString* substr ) : StringHolder( substr ){} +struct StartsWith : StringHolder { +StartsWith( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == 0; - } +bool match( NSString* const& str ) const override { +return (str != nil || m_substr == nil ) && +[str rangeOfString:m_substr].location == 0; +} - std::string describe() const override { - return "starts with: " + Catch::Detail::stringify( m_substr ); - } - }; - struct EndsWith : StringHolder { - EndsWith( NSString* substr ) : StringHolder( substr ){} +std::string describe() const override { +return "starts with: " + Catch::Detail::stringify( m_substr ); +} +}; +struct EndsWith : StringHolder { +EndsWith( NSString* substr ) : StringHolder( substr ){} - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == [str length] - [m_substr length]; - } +bool match( NSString* const& str ) const override { +return (str != nil || m_substr == nil ) && +[str rangeOfString:m_substr].location == [str length] - [m_substr length]; +} - std::string describe() const override { - return "ends with: " + Catch::Detail::stringify( m_substr ); - } - }; +std::string describe() const override { +return "ends with: " + Catch::Detail::stringify( m_substr ); +} +}; - } // namespace NSStringMatchers - } // namespace Impl +} // namespace NSStringMatchers +} // namespace Impl - inline Impl::NSStringMatchers::Equals - Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } +inline Impl::NSStringMatchers::Equals +Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } - inline Impl::NSStringMatchers::Contains - Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } +inline Impl::NSStringMatchers::Contains +Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } - inline Impl::NSStringMatchers::StartsWith - StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } +inline Impl::NSStringMatchers::StartsWith +StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } - inline Impl::NSStringMatchers::EndsWith - EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } +inline Impl::NSStringMatchers::EndsWith +EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } - } // namespace Matchers +} // namespace Matchers - using namespace Matchers; +using namespace Matchers; #endif // CATCH_CONFIG_DISABLE_MATCHERS @@ -2686,26 +4493,26 @@ return @ desc; \ namespace Catch { - class WildcardPattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; +class WildcardPattern { +enum WildcardPosition { +NoWildcard = 0, +WildcardAtStart = 1, +WildcardAtEnd = 2, +WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd +}; - public: +public: - WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); - virtual ~WildcardPattern() = default; - virtual bool matches( std::string const& str ) const; +WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); +virtual ~WildcardPattern() = default; +virtual bool matches( std::string const& str ) const; - private: - std::string adjustCase( std::string const& str ) const; - CaseSensitive::Choice m_caseSensitivity; - WildcardPosition m_wildcard = NoWildcard; - std::string m_pattern; - }; +private: +std::string adjustCase( std::string const& str ) const; +CaseSensitive::Choice m_caseSensitivity; +WildcardPosition m_wildcard = NoWildcard; +std::string m_pattern; +}; } // end catch_wildcard_pattern.h @@ -2715,55 +4522,55 @@ namespace Catch namespace Catch { - class TestSpec { - struct Pattern { - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - }; - using PatternPtr = std::shared_ptr; +class TestSpec { +struct Pattern { +virtual ~Pattern(); +virtual bool matches( TestCaseInfo const& testCase ) const = 0; +}; +using PatternPtr = std::shared_ptr; - class NamePattern : public Pattern { - public: - NamePattern( std::string const& name ); - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - WildcardPattern m_wildcardPattern; - }; +class NamePattern : public Pattern { +public: +NamePattern( std::string const& name ); +virtual ~NamePattern(); +bool matches( TestCaseInfo const& testCase ) const override; +private: +WildcardPattern m_wildcardPattern; +}; - class TagPattern : public Pattern { - public: - TagPattern( std::string const& tag ); - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - std::string m_tag; - }; +class TagPattern : public Pattern { +public: +TagPattern( std::string const& tag ); +virtual ~TagPattern(); +bool matches( TestCaseInfo const& testCase ) const override; +private: +std::string m_tag; +}; - class ExcludedPattern : public Pattern { - public: - ExcludedPattern( PatternPtr const& underlyingPattern ); - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - PatternPtr m_underlyingPattern; - }; +class ExcludedPattern : public Pattern { +public: +ExcludedPattern( PatternPtr const& underlyingPattern ); +virtual ~ExcludedPattern(); +bool matches( TestCaseInfo const& testCase ) const override; +private: +PatternPtr m_underlyingPattern; +}; - struct Filter { - std::vector m_patterns; +struct Filter { +std::vector m_patterns; - bool matches( TestCaseInfo const& testCase ) const; - }; +bool matches( TestCaseInfo const& testCase ) const; +}; - public: - bool hasFilters() const; - bool matches( TestCaseInfo const& testCase ) const; +public: +bool hasFilters() const; +bool matches( TestCaseInfo const& testCase ) const; - private: - std::vector m_filters; +private: +std::vector m_filters; - friend class TestSpecParser; - }; +friend class TestSpecParser; +}; } #ifdef __clang__ @@ -2777,68 +4584,68 @@ namespace Catch { namespace Catch { - struct TagAlias; +struct TagAlias; - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - // Nullptr if not present - virtual TagAlias const* find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; +struct ITagAliasRegistry { +virtual ~ITagAliasRegistry(); +// Nullptr if not present +virtual TagAlias const* find( std::string const& alias ) const = 0; +virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - static ITagAliasRegistry const& get(); - }; +static ITagAliasRegistry const& get(); +}; } // end namespace Catch // end catch_interfaces_tag_alias_registry.h namespace Catch { - class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag, EscapedName }; - Mode m_mode = None; - bool m_exclusion = false; - std::size_t m_start = std::string::npos, m_pos = 0; - std::string m_arg; - std::vector m_escapeChars; - TestSpec::Filter m_currentFilter; - TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases = nullptr; +class TestSpecParser { +enum Mode{ None, Name, QuotedName, Tag, EscapedName }; +Mode m_mode = None; +bool m_exclusion = false; +std::size_t m_start = std::string::npos, m_pos = 0; +std::string m_arg; +std::vector m_escapeChars; +TestSpec::Filter m_currentFilter; +TestSpec m_testSpec; +ITagAliasRegistry const* m_tagAliases = nullptr; - public: - TestSpecParser( ITagAliasRegistry const& tagAliases ); +public: +TestSpecParser( ITagAliasRegistry const& tagAliases ); - TestSpecParser& parse( std::string const& arg ); - TestSpec testSpec(); +TestSpecParser& parse( std::string const& arg ); +TestSpec testSpec(); - private: - void visitChar( char c ); - void startNewMode( Mode mode, std::size_t start ); - void escape(); - std::string subString() const; +private: +void visitChar( char c ); +void startNewMode( Mode mode, std::size_t start ); +void escape(); +std::string subString() const; - template - void addPattern() { - std::string token = subString(); - for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) - token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); - m_escapeChars.clear(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - TestSpec::PatternPtr pattern = std::make_shared( token ); - if( m_exclusion ) - pattern = std::make_shared( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_exclusion = false; - m_mode = None; - } +template +void addPattern() { +std::string token = subString(); +for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) +token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); +m_escapeChars.clear(); +if( startsWith( token, "exclude:" ) ) { +m_exclusion = true; +token = token.substr( 8 ); +} +if( !token.empty() ) { +TestSpec::PatternPtr pattern = std::make_shared( token ); +if( m_exclusion ) +pattern = std::make_shared( pattern ); +m_currentFilter.m_patterns.push_back( pattern ); +} +m_exclusion = false; +m_mode = None; +} - void addFilter(); - }; - TestSpec parseTestSpec( std::string const& arg ); +void addFilter(); +}; +TestSpec parseTestSpec( std::string const& arg ); } // namespace Catch @@ -2847,140 +4654,7 @@ namespace Catch { #endif // end catch_test_spec_parser.h -// start catch_interfaces_config.h - -#include -#include -#include -#include - -namespace Catch { - - enum class Verbosity { - Quiet = 0, - Normal, - High - }; - - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01 - }; }; - - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - struct UseColour { enum YesOrNo { - Auto, - Yes, - No - }; }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - - struct IConfig : NonCopyable { - - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - virtual int benchmarkResolutionMultiple() const = 0; - virtual UseColour::YesOrNo useColour() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - }; - - using IConfigPtr = std::shared_ptr; -} - -// end catch_interfaces_config.h // Libstdc++ doesn't like incomplete classes for unique_ptr -// start catch_stream.h - -// start catch_streambuf.h - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase(); - }; -} - -// end catch_streambuf.h -#include -#include -#include -#include - -namespace Catch { - - std::ostream& cout(); - std::ostream& cerr(); - std::ostream& clog(); - - struct IStream { - virtual ~IStream(); - virtual std::ostream& stream() const = 0; - }; - - class FileStream : public IStream { - mutable std::ofstream m_ofs; - public: - FileStream( std::string const& filename ); - ~FileStream() override = default; - public: // IStream - std::ostream& stream() const override; - }; - - class CoutStream : public IStream { - mutable std::ostream m_os; - public: - CoutStream(); - ~CoutStream() override = default; - - public: // IStream - std::ostream& stream() const override; - }; - - class DebugOutStream : public IStream { - std::unique_ptr m_streamBuf; - mutable std::ostream m_os; - public: - DebugOutStream(); - ~DebugOutStream() override = default; - - public: // IStream - std::ostream& stream() const override; - }; -} - -// end catch_stream.h #include #include @@ -2992,89 +4666,97 @@ namespace Catch { namespace Catch { - struct IStream; +struct IStream; - struct ConfigData { - bool listTests = false; - bool listTags = false; - bool listReporters = false; - bool listTestNamesOnly = false; +struct ConfigData { +bool listTests = false; +bool listTags = false; +bool listReporters = false; +bool listTestNamesOnly = false; - bool showSuccessfulTests = false; - bool shouldDebugBreak = false; - bool noThrow = false; - bool showHelp = false; - bool showInvisibles = false; - bool filenamesAsTags = false; - bool libIdentify = false; +bool showSuccessfulTests = false; +bool shouldDebugBreak = false; +bool noThrow = false; +bool showHelp = false; +bool showInvisibles = false; +bool filenamesAsTags = false; +bool libIdentify = false; - int abortAfter = -1; - unsigned int rngSeed = 0; - int benchmarkResolutionMultiple = 100; +int abortAfter = -1; +unsigned int rngSeed = 0; +int benchmarkResolutionMultiple = 100; - Verbosity verbosity = Verbosity::Normal; - WarnAbout::What warnings = WarnAbout::Nothing; - ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; - RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; - UseColour::YesOrNo useColour = UseColour::Auto; - WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; +Verbosity verbosity = Verbosity::Normal; +WarnAbout::What warnings = WarnAbout::Nothing; +ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; +RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; +UseColour::YesOrNo useColour = UseColour::Auto; +WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; - std::string outputFilename; - std::string name; - std::string processName; +std::string outputFilename; +std::string name; +std::string processName; +#ifndef CATCH_CONFIG_DEFAULT_REPORTER +#define CATCH_CONFIG_DEFAULT_REPORTER "console" +#endif +std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; +#undef CATCH_CONFIG_DEFAULT_REPORTER - std::vector reporterNames; - std::vector testsOrTags; - std::vector sectionsToRun; - }; +std::vector testsOrTags; +std::vector sectionsToRun; +}; - class Config : public IConfig { - public: +class Config : public IConfig { +public: - Config() = default; - Config( ConfigData const& data ); - virtual ~Config() = default; +Config() = default; +Config( ConfigData const& data ); +virtual ~Config() = default; - std::string const& getFilename() const; +std::string const& getFilename() const; - bool listTests() const; - bool listTestNamesOnly() const; - bool listTags() const; - bool listReporters() const; +bool listTests() const; +bool listTestNamesOnly() const; +bool listTags() const; +bool listReporters() const; - std::string getProcessName() const; +std::string getProcessName() const; +std::string const& getReporterName() const; - std::vector const& getReporterNames() const; - std::vector const& getSectionsToRun() const override; +std::vector const& getTestsOrTags() const override; +std::vector const& getSectionsToRun() const override; - virtual TestSpec const& testSpec() const override; +TestSpec const& testSpec() const override; +bool hasTestFilters() const override; - bool showHelp() const; +bool showHelp() const; - // IConfig interface - bool allowThrows() const override; - std::ostream& stream() const override; - std::string name() const override; - bool includeSuccessfulResults() const override; - bool warnAboutMissingAssertions() const override; - ShowDurations::OrNot showDurations() const override; - RunTests::InWhatOrder runOrder() const override; - unsigned int rngSeed() const override; - int benchmarkResolutionMultiple() const override; - UseColour::YesOrNo useColour() const override; - bool shouldDebugBreak() const override; - int abortAfter() const override; - bool showInvisibles() const override; - Verbosity verbosity() const override; +// IConfig interface +bool allowThrows() const override; +std::ostream& stream() const override; +std::string name() const override; +bool includeSuccessfulResults() const override; +bool warnAboutMissingAssertions() const override; +bool warnAboutNoTests() const override; +ShowDurations::OrNot showDurations() const override; +RunTests::InWhatOrder runOrder() const override; +unsigned int rngSeed() const override; +int benchmarkResolutionMultiple() const override; +UseColour::YesOrNo useColour() const override; +bool shouldDebugBreak() const override; +int abortAfter() const override; +bool showInvisibles() const override; +Verbosity verbosity() const override; - private: +private: - IStream const* openStream(); - ConfigData m_data; +IStream const* openStream(); +ConfigData m_data; - std::unique_ptr m_stream; - TestSpec m_testSpec; - }; +std::unique_ptr m_stream; +TestSpec m_testSpec; +bool m_hasTestFilters = false; +}; } // end namespace Catch @@ -3085,42 +4767,42 @@ namespace Catch { namespace Catch { - struct AssertionResultData - { - AssertionResultData() = delete; +struct AssertionResultData +{ +AssertionResultData() = delete; - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); +AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; +std::string message; +mutable std::string reconstructedExpression; +LazyExpression lazyExpression; +ResultWas::OfType resultType; - std::string reconstructExpression() const; - }; +std::string reconstructExpression() const; +}; - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); +class AssertionResult { +public: +AssertionResult() = delete; +AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - std::string getTestMacroName() const; +bool isOk() const; +bool succeeded() const; +ResultWas::OfType getResultType() const; +bool hasExpression() const; +bool hasMessage() const; +std::string getExpression() const; +std::string getExpressionInMacro() const; +bool hasExpandedExpression() const; +std::string getExpandedExpression() const; +std::string getMessage() const; +SourceLineInfo getSourceInfo() const; +StringRef getTestMacroName() const; - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; +//protected: +AssertionInfo m_info; +AssertionResultData m_resultData; +}; } // end namespace Catch @@ -3129,63 +4811,63 @@ namespace Catch { namespace Catch { - // An optional type - template - class Option { - public: - Option() : nullableValue( nullptr ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} +// An optional type +template +class Option { +public: +Option() : nullableValue( nullptr ) {} +Option( T const& _value ) +: nullableValue( new( storage ) T( _value ) ) +{} +Option( Option const& _other ) +: nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) +{} - ~Option() { - reset(); - } +~Option() { +reset(); +} - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } +Option& operator= ( Option const& _other ) { +if( &_other != this ) { +reset(); +if( _other ) +nullableValue = new( storage ) T( *_other ); +} +return *this; +} +Option& operator = ( T const& _value ) { +reset(); +nullableValue = new( storage ) T( _value ); +return *this; +} - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = nullptr; - } +void reset() { +if( nullableValue ) +nullableValue->~T(); +nullableValue = nullptr; +} - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } +T& operator*() { return *nullableValue; } +T const& operator*() const { return *nullableValue; } +T* operator->() { return nullableValue; } +const T* operator->() const { return nullableValue; } - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } +T valueOr( T const& defaultValue ) const { +return nullableValue ? *nullableValue : defaultValue; +} - bool some() const { return nullableValue != nullptr; } - bool none() const { return nullableValue == nullptr; } +bool some() const { return nullableValue != nullptr; } +bool none() const { return nullableValue == nullptr; } - bool operator !() const { return nullableValue == nullptr; } - explicit operator bool() const { - return some(); - } +bool operator !() const { return nullableValue == nullptr; } +explicit operator bool() const { +return some(); +} - private: - T *nullableValue; - alignas(alignof(T)) char storage[sizeof(T)]; - }; +private: +T *nullableValue; +alignas(alignof(T)) char storage[sizeof(T)]; +}; } // end namespace Catch @@ -3198,206 +4880,205 @@ namespace Catch { namespace Catch { - struct ReporterConfig { - explicit ReporterConfig( IConfigPtr const& _fullConfig ); +struct ReporterConfig { +explicit ReporterConfig( IConfigPtr const& _fullConfig ); - ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); +ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); - std::ostream& stream() const; - IConfigPtr fullConfig() const; +std::ostream& stream() const; +IConfigPtr fullConfig() const; - private: - std::ostream* m_stream; - IConfigPtr m_fullConfig; - }; +private: +std::ostream* m_stream; +IConfigPtr m_fullConfig; +}; - struct ReporterPreferences { - bool shouldRedirectStdOut = false; - }; +struct ReporterPreferences { +bool shouldRedirectStdOut = false; +bool shouldReportAllAssertions = false; +}; - template - struct LazyStat : Option { - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used = false; - }; +template +struct LazyStat : Option { +LazyStat& operator=( T const& _value ) { +Option::operator=( _value ); +used = false; +return *this; +} +void reset() { +Option::reset(); +used = false; +} +bool used = false; +}; - struct TestRunInfo { - TestRunInfo( std::string const& _name ); - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ); +struct TestRunInfo { +TestRunInfo( std::string const& _name ); +std::string name; +}; +struct GroupInfo { +GroupInfo( std::string const& _name, +std::size_t _groupIndex, +std::size_t _groupsCount ); - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; +std::string name; +std::size_t groupIndex; +std::size_t groupsCounts; +}; - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); +struct AssertionStats { +AssertionStats( AssertionResult const& _assertionResult, +std::vector const& _infoMessages, +Totals const& _totals ); - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; - virtual ~AssertionStats(); +AssertionStats( AssertionStats const& ) = default; +AssertionStats( AssertionStats && ) = default; +AssertionStats& operator = ( AssertionStats const& ) = delete; +AssertionStats& operator = ( AssertionStats && ) = delete; +virtual ~AssertionStats(); - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; +AssertionResult assertionResult; +std::vector infoMessages; +Totals totals; +}; - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; - virtual ~SectionStats(); +struct SectionStats { +SectionStats( SectionInfo const& _sectionInfo, +Counts const& _assertions, +double _durationInSeconds, +bool _missingAssertions ); +SectionStats( SectionStats const& ) = default; +SectionStats( SectionStats && ) = default; +SectionStats& operator = ( SectionStats const& ) = default; +SectionStats& operator = ( SectionStats && ) = default; +virtual ~SectionStats(); - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; +SectionInfo sectionInfo; +Counts assertions; +double durationInSeconds; +bool missingAssertions; +}; - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ); +struct TestCaseStats { +TestCaseStats( TestCaseInfo const& _testInfo, +Totals const& _totals, +std::string const& _stdOut, +std::string const& _stdErr, +bool _aborting ); - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; - virtual ~TestCaseStats(); +TestCaseStats( TestCaseStats const& ) = default; +TestCaseStats( TestCaseStats && ) = default; +TestCaseStats& operator = ( TestCaseStats const& ) = default; +TestCaseStats& operator = ( TestCaseStats && ) = default; +virtual ~TestCaseStats(); - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; +TestCaseInfo testInfo; +Totals totals; +std::string stdOut; +std::string stdErr; +bool aborting; +}; - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ); - TestGroupStats( GroupInfo const& _groupInfo ); +struct TestGroupStats { +TestGroupStats( GroupInfo const& _groupInfo, +Totals const& _totals, +bool _aborting ); +TestGroupStats( GroupInfo const& _groupInfo ); - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; - virtual ~TestGroupStats(); +TestGroupStats( TestGroupStats const& ) = default; +TestGroupStats( TestGroupStats && ) = default; +TestGroupStats& operator = ( TestGroupStats const& ) = default; +TestGroupStats& operator = ( TestGroupStats && ) = default; +virtual ~TestGroupStats(); - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; +GroupInfo groupInfo; +Totals totals; +bool aborting; +}; - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); +struct TestRunStats { +TestRunStats( TestRunInfo const& _runInfo, +Totals const& _totals, +bool _aborting ); - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; - virtual ~TestRunStats(); +TestRunStats( TestRunStats const& ) = default; +TestRunStats( TestRunStats && ) = default; +TestRunStats& operator = ( TestRunStats const& ) = default; +TestRunStats& operator = ( TestRunStats && ) = default; +virtual ~TestRunStats(); - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; +TestRunInfo runInfo; +Totals totals; +bool aborting; +}; - struct BenchmarkInfo { - std::string name; - }; - struct BenchmarkStats { - BenchmarkInfo info; - std::size_t iterations; - uint64_t elapsedTimeInNanoseconds; - }; +struct BenchmarkInfo { +std::string name; +}; +struct BenchmarkStats { +BenchmarkInfo info; +std::size_t iterations; +uint64_t elapsedTimeInNanoseconds; +}; - struct IStreamingReporter { - virtual ~IStreamingReporter() = default; +struct IStreamingReporter { +virtual ~IStreamingReporter() = default; - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - // static std::set getSupportedVerbosities() +// Implementing class must also provide the following static methods: +// static std::string getDescription(); +// static std::set getSupportedVerbosities() - virtual ReporterPreferences getPreferences() const = 0; +virtual ReporterPreferences getPreferences() const = 0; - virtual void noMatchingTestCases( std::string const& spec ) = 0; +virtual void noMatchingTestCases( std::string const& spec ) = 0; - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; +virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; +virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; +virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; +virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - // *** experimental *** - virtual void benchmarkStarting( BenchmarkInfo const& ) {} +// *** experimental *** +virtual void benchmarkStarting( BenchmarkInfo const& ) {} - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; +virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; +// The return value indicates if the messages buffer should be cleared: +virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - // *** experimental *** - virtual void benchmarkEnded( BenchmarkStats const& ) {} +// *** experimental *** +virtual void benchmarkEnded( BenchmarkStats const& ) {} - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; +virtual void sectionEnded( SectionStats const& sectionStats ) = 0; +virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; +virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; +virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; +virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - // Default empty implementation provided - virtual void fatalErrorEncountered( StringRef name ); +// Default empty implementation provided +virtual void fatalErrorEncountered( StringRef name ); - virtual bool isMulti() const; - }; - using IStreamingReporterPtr = std::unique_ptr; +virtual bool isMulti() const; +}; +using IStreamingReporterPtr = std::unique_ptr; - struct IReporterFactory { - virtual ~IReporterFactory(); - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - using IReporterFactoryPtr = std::shared_ptr; +struct IReporterFactory { +virtual ~IReporterFactory(); +virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; +virtual std::string getDescription() const = 0; +}; +using IReporterFactoryPtr = std::shared_ptr; - struct IReporterRegistry { - using FactoryMap = std::map; - using Listeners = std::vector; +struct IReporterRegistry { +using FactoryMap = std::map; +using Listeners = std::vector; - virtual ~IReporterRegistry(); - virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ); +virtual ~IReporterRegistry(); +virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; +virtual FactoryMap const& getFactories() const = 0; +virtual Listeners const& getListeners() const = 0; +}; } // end namespace Catch @@ -3406,255 +5087,263 @@ namespace Catch { #include #include #include -#include +#include #include +#include namespace Catch { - void prepareExpandedExpression(AssertionResult& result); +void prepareExpandedExpression(AssertionResult& result); - // Returns double formatted as %.3f (format expected on output) - std::string getFormattedDuration( double duration ); +// Returns double formatted as %.3f (format expected on output) +std::string getFormattedDuration( double duration ); - template - struct StreamingReporterBase : IStreamingReporter { +std::string serializeFilters( std::vector const& container ); - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); - } +template +struct StreamingReporterBase : IStreamingReporter { - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } +StreamingReporterBase( ReporterConfig const& _config ) +: m_config( _config.fullConfig() ), +stream( _config.stream() ) +{ +m_reporterPrefs.shouldRedirectStdOut = false; +if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) +CATCH_ERROR( "Verbosity level not supported by this reporter" ); +} - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } +ReporterPreferences getPreferences() const override { +return m_reporterPrefs; +} - ~StreamingReporterBase() override = default; +static std::set getSupportedVerbosities() { +return { Verbosity::Normal }; +} - void noMatchingTestCases(std::string const&) override {} +~StreamingReporterBase() override = default; - void testRunStarting(TestRunInfo const& _testRunInfo) override { - currentTestRunInfo = _testRunInfo; - } - void testGroupStarting(GroupInfo const& _groupInfo) override { - currentGroupInfo = _groupInfo; - } +void noMatchingTestCases(std::string const&) override {} - void testCaseStarting(TestCaseInfo const& _testInfo) override { - currentTestCaseInfo = _testInfo; - } - void sectionStarting(SectionInfo const& _sectionInfo) override { - m_sectionStack.push_back(_sectionInfo); - } +void testRunStarting(TestRunInfo const& _testRunInfo) override { +currentTestRunInfo = _testRunInfo; +} - void sectionEnded(SectionStats const& /* _sectionStats */) override { - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { - currentTestCaseInfo.reset(); - } - void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { - currentGroupInfo.reset(); - } - void testRunEnded(TestRunStats const& /* _testRunStats */) override { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } +void testGroupStarting(GroupInfo const& _groupInfo) override { +currentGroupInfo = _groupInfo; +} - void skipTest(TestCaseInfo const&) override { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } +void testCaseStarting(TestCaseInfo const& _testInfo) override { +currentTestCaseInfo = _testInfo; +} +void sectionStarting(SectionInfo const& _sectionInfo) override { +m_sectionStack.push_back(_sectionInfo); +} - IConfigPtr m_config; - std::ostream& stream; +void sectionEnded(SectionStats const& /* _sectionStats */) override { +m_sectionStack.pop_back(); +} +void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { +currentTestCaseInfo.reset(); +} +void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { +currentGroupInfo.reset(); +} +void testRunEnded(TestRunStats const& /* _testRunStats */) override { +currentTestCaseInfo.reset(); +currentGroupInfo.reset(); +currentTestRunInfo.reset(); +} - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; +void skipTest(TestCaseInfo const&) override { +// Don't do anything with this by default. +// It can optionally be overridden in the derived class. +} - std::vector m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; +IConfigPtr m_config; +std::ostream& stream; - template - struct CumulativeReporterBase : IStreamingReporter { - template - struct Node { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} +LazyStat currentTestRunInfo; +LazyStat currentGroupInfo; +LazyStat currentTestCaseInfo; - using ChildNodes = std::vector>; - T value; - ChildNodes children; - }; - struct SectionNode { - explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} - virtual ~SectionNode() = default; +std::vector m_sectionStack; +ReporterPreferences m_reporterPrefs; +}; - bool operator == (SectionNode const& other) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == (std::shared_ptr const& other) const { - return operator==(*other); - } +template +struct CumulativeReporterBase : IStreamingReporter { +template +struct Node { +explicit Node( T const& _value ) : value( _value ) {} +virtual ~Node() {} - SectionStats stats; - using ChildSections = std::vector>; - using Assertions = std::vector; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; +using ChildNodes = std::vector>; +T value; +ChildNodes children; +}; +struct SectionNode { +explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} +virtual ~SectionNode() = default; - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() (std::shared_ptr const& node) const { - return ((node->stats.sectionInfo.name == m_other.name) && - (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); - } - void operator=(BySectionInfo const&) = delete; +bool operator == (SectionNode const& other) const { +return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; +} +bool operator == (std::shared_ptr const& other) const { +return operator==(*other); +} - private: - SectionInfo const& m_other; - }; +SectionStats stats; +using ChildSections = std::vector>; +using Assertions = std::vector; +ChildSections childSections; +Assertions assertions; +std::string stdOut; +std::string stdErr; +}; - using TestCaseNode = Node; - using TestGroupNode = Node; - using TestRunNode = Node; +struct BySectionInfo { +BySectionInfo( SectionInfo const& other ) : m_other( other ) {} +BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} +bool operator() (std::shared_ptr const& node) const { +return ((node->stats.sectionInfo.name == m_other.name) && +(node->stats.sectionInfo.lineInfo == m_other.lineInfo)); +} +void operator=(BySectionInfo const&) = delete; - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - CATCH_ENFORCE( DerivedT::getSupportedVerbosities().count( m_config->verbosity() ), "Verbosity level not supported by this reporter" ); - } - ~CumulativeReporterBase() override = default; +private: +SectionInfo const& m_other; +}; - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } +using TestCaseNode = Node; +using TestGroupNode = Node; +using TestRunNode = Node; - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } +CumulativeReporterBase( ReporterConfig const& _config ) +: m_config( _config.fullConfig() ), +stream( _config.stream() ) +{ +m_reporterPrefs.shouldRedirectStdOut = false; +if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) +CATCH_ERROR( "Verbosity level not supported by this reporter" ); +} +~CumulativeReporterBase() override = default; - void testRunStarting( TestRunInfo const& ) override {} - void testGroupStarting( GroupInfo const& ) override {} +ReporterPreferences getPreferences() const override { +return m_reporterPrefs; +} - void testCaseStarting( TestCaseInfo const& ) override {} +static std::set getSupportedVerbosities() { +return { Verbosity::Normal }; +} - void sectionStarting( SectionInfo const& sectionInfo ) override { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - std::shared_ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = std::make_shared( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - auto it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = std::make_shared( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; - } - m_sectionStack.push_back( node ); - m_deepestSection = std::move(node); - } +void testRunStarting( TestRunInfo const& ) override {} +void testGroupStarting( GroupInfo const& ) override {} - void assertionStarting(AssertionInfo const&) override {} +void testCaseStarting( TestCaseInfo const& ) override {} - bool assertionEnded(AssertionStats const& assertionStats) override { - assert(!m_sectionStack.empty()); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back(assertionStats); - return true; - } - void sectionEnded(SectionStats const& sectionStats) override { - assert(!m_sectionStack.empty()); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& testCaseStats) override { - auto node = std::make_shared(testCaseStats); - assert(m_sectionStack.size() == 0); - node->children.push_back(m_rootSection); - m_testCases.push_back(node); - m_rootSection.reset(); +void sectionStarting( SectionInfo const& sectionInfo ) override { +SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); +std::shared_ptr node; +if( m_sectionStack.empty() ) { +if( !m_rootSection ) +m_rootSection = std::make_shared( incompleteStats ); +node = m_rootSection; +} +else { +SectionNode& parentNode = *m_sectionStack.back(); +auto it = +std::find_if( parentNode.childSections.begin(), +parentNode.childSections.end(), +BySectionInfo( sectionInfo ) ); +if( it == parentNode.childSections.end() ) { +node = std::make_shared( incompleteStats ); +parentNode.childSections.push_back( node ); +} +else +node = *it; +} +m_sectionStack.push_back( node ); +m_deepestSection = std::move(node); +} - assert(m_deepestSection); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - void testGroupEnded(TestGroupStats const& testGroupStats) override { - auto node = std::make_shared(testGroupStats); - node->children.swap(m_testCases); - m_testGroups.push_back(node); - } - void testRunEnded(TestRunStats const& testRunStats) override { - auto node = std::make_shared(testRunStats); - node->children.swap(m_testGroups); - m_testRuns.push_back(node); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; +void assertionStarting(AssertionInfo const&) override {} - void skipTest(TestCaseInfo const&) override {} +bool assertionEnded(AssertionStats const& assertionStats) override { +assert(!m_sectionStack.empty()); +// AssertionResult holds a pointer to a temporary DecomposedExpression, +// which getExpandedExpression() calls to build the expression string. +// Our section stack copy of the assertionResult will likely outlive the +// temporary, so it must be expanded or discarded now to avoid calling +// a destroyed object later. +prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); +SectionNode& sectionNode = *m_sectionStack.back(); +sectionNode.assertions.push_back(assertionStats); +return true; +} +void sectionEnded(SectionStats const& sectionStats) override { +assert(!m_sectionStack.empty()); +SectionNode& node = *m_sectionStack.back(); +node.stats = sectionStats; +m_sectionStack.pop_back(); +} +void testCaseEnded(TestCaseStats const& testCaseStats) override { +auto node = std::make_shared(testCaseStats); +assert(m_sectionStack.size() == 0); +node->children.push_back(m_rootSection); +m_testCases.push_back(node); +m_rootSection.reset(); - IConfigPtr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector>> m_sections; - std::vector> m_testCases; - std::vector> m_testGroups; +assert(m_deepestSection); +m_deepestSection->stdOut = testCaseStats.stdOut; +m_deepestSection->stdErr = testCaseStats.stdErr; +} +void testGroupEnded(TestGroupStats const& testGroupStats) override { +auto node = std::make_shared(testGroupStats); +node->children.swap(m_testCases); +m_testGroups.push_back(node); +} +void testRunEnded(TestRunStats const& testRunStats) override { +auto node = std::make_shared(testRunStats); +node->children.swap(m_testGroups); +m_testRuns.push_back(node); +testRunEndedCumulative(); +} +virtual void testRunEndedCumulative() = 0; - std::vector> m_testRuns; +void skipTest(TestCaseInfo const&) override {} - std::shared_ptr m_rootSection; - std::shared_ptr m_deepestSection; - std::vector> m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; +IConfigPtr m_config; +std::ostream& stream; +std::vector m_assertions; +std::vector>> m_sections; +std::vector> m_testCases; +std::vector> m_testGroups; - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; - } +std::vector> m_testRuns; - struct TestEventListenerBase : StreamingReporterBase { - TestEventListenerBase( ReporterConfig const& _config ); +std::shared_ptr m_rootSection; +std::shared_ptr m_deepestSection; +std::vector> m_sectionStack; +ReporterPreferences m_reporterPrefs; +}; - void assertionStarting(AssertionInfo const&) override; - bool assertionEnded(AssertionStats const&) override; - }; +template +char const* getLineOfChars() { +static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; +if( !*line ) { +std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); +line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; +} +return line; +} + +struct TestEventListenerBase : StreamingReporterBase { +TestEventListenerBase( ReporterConfig const& _config ); + +static std::set getSupportedVerbosities(); + +void assertionStarting(AssertionInfo const&) override; +bool assertionEnded(AssertionStats const&) override; +}; } // end namespace Catch @@ -3663,56 +5352,57 @@ namespace Catch { namespace Catch { - struct Colour { - enum Code { - None = 0, +struct Colour { +enum Code { +None = 0, - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, +White, +Red, +Green, +Blue, +Cyan, +Yellow, +Grey, - Bright = 0x10, +Bright = 0x10, - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, +BrightRed = Bright | Red, +BrightGreen = Bright | Green, +LightGrey = Bright | Grey, +BrightWhite = Bright | White, +BrightYellow = Bright | Yellow, - // By intention - FileName = LightGrey, - Warning = Yellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, +// By intention +FileName = LightGrey, +Warning = BrightYellow, +ResultError = BrightRed, +ResultSuccess = BrightGreen, +ResultExpectedFailure = Warning, - Error = BrightRed, - Success = Green, +Error = BrightRed, +Success = Green, - OriginalExpression = Cyan, - ReconstructedExpression = Yellow, +OriginalExpression = Cyan, +ReconstructedExpression = BrightYellow, - SecondaryText = LightGrey, - Headers = White - }; +SecondaryText = LightGrey, +Headers = White +}; - // Use constructed object for RAII guard - Colour( Code _colourCode ); - Colour( Colour&& other ) noexcept; - Colour& operator=( Colour&& other ) noexcept; - ~Colour(); +// Use constructed object for RAII guard +Colour( Code _colourCode ); +Colour( Colour&& other ) noexcept; +Colour& operator=( Colour&& other ) noexcept; +~Colour(); - // Use static method for one-shot changes - static void use( Code _colourCode ); +// Use static method for one-shot changes +static void use( Code _colourCode ); - private: - bool m_moved = false; - }; +private: +bool m_moved = false; +}; - std::ostream& operator << ( std::ostream& os, Colour const& ); +std::ostream& operator << ( std::ostream& os, Colour const& ); } // end namespace Catch @@ -3722,46 +5412,46 @@ namespace Catch { namespace Catch { - template - class ReporterRegistrar { +template +class ReporterRegistrar { - class ReporterFactory : public IReporterFactory { +class ReporterFactory : public IReporterFactory { - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } +IStreamingReporterPtr create( ReporterConfig const& config ) const override { +return std::unique_ptr( new T( config ) ); +} - virtual std::string getDescription() const override { - return T::getDescription(); - } - }; +std::string getDescription() const override { +return T::getDescription(); +} +}; - public: +public: - ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, std::make_shared() ); - } - }; +explicit ReporterRegistrar( std::string const& name ) { +getMutableRegistryHub().registerReporter( name, std::make_shared() ); +} +}; - template - class ListenerRegistrar { +template +class ListenerRegistrar { - class ListenerFactory : public IReporterFactory { +class ListenerFactory : public IReporterFactory { - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - virtual std::string getDescription() const override { - return std::string(); - } - }; +IStreamingReporterPtr create( ReporterConfig const& config ) const override { +return std::unique_ptr( new T( config ) ); +} +std::string getDescription() const override { +return std::string(); +} +}; - public: +public: - ListenerRegistrar() { - getMutableRegistryHub().registerListener( std::make_shared() ); - } - }; +ListenerRegistrar() { +getMutableRegistryHub().registerListener( std::make_shared() ); +} +}; } #if !defined(CATCH_CONFIG_DISABLE) @@ -3783,9 +5473,304 @@ namespace Catch { #endif // CATCH_CONFIG_DISABLE // end catch_reporter_registrars.hpp +// Allow users to base their work off existing reporters +// start catch_reporter_compact.h + +namespace Catch { + +struct CompactReporter : StreamingReporterBase { + +using StreamingReporterBase::StreamingReporterBase; + +~CompactReporter() override; + +static std::string getDescription(); + +ReporterPreferences getPreferences() const override; + +void noMatchingTestCases(std::string const& spec) override; + +void assertionStarting(AssertionInfo const&) override; + +bool assertionEnded(AssertionStats const& _assertionStats) override; + +void sectionEnded(SectionStats const& _sectionStats) override; + +void testRunEnded(TestRunStats const& _testRunStats) override; + +}; + +} // end namespace Catch + +// end catch_reporter_compact.h +// start catch_reporter_console.h + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch +// Note that 4062 (not all labels are handled +// and default is missing) is enabled +#endif + +namespace Catch { +// Fwd decls +struct SummaryColumn; +class TablePrinter; + +struct ConsoleReporter : StreamingReporterBase { +std::unique_ptr m_tablePrinter; + +ConsoleReporter(ReporterConfig const& config); +~ConsoleReporter() override; +static std::string getDescription(); + +void noMatchingTestCases(std::string const& spec) override; + +void assertionStarting(AssertionInfo const&) override; + +bool assertionEnded(AssertionStats const& _assertionStats) override; + +void sectionStarting(SectionInfo const& _sectionInfo) override; +void sectionEnded(SectionStats const& _sectionStats) override; + +void benchmarkStarting(BenchmarkInfo const& info) override; +void benchmarkEnded(BenchmarkStats const& stats) override; + +void testCaseEnded(TestCaseStats const& _testCaseStats) override; +void testGroupEnded(TestGroupStats const& _testGroupStats) override; +void testRunEnded(TestRunStats const& _testRunStats) override; +void testRunStarting(TestRunInfo const& _testRunInfo) override; +private: + +void lazyPrint(); + +void lazyPrintWithoutClosingBenchmarkTable(); +void lazyPrintRunInfo(); +void lazyPrintGroupInfo(); +void printTestCaseAndSectionHeader(); + +void printClosedHeader(std::string const& _name); +void printOpenHeader(std::string const& _name); + +// if string has a : in first line will set indent to follow it on +// subsequent lines +void printHeaderString(std::string const& _string, std::size_t indent = 0); + +void printTotals(Totals const& totals); +void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); + +void printTotalsDivider(Totals const& totals); +void printSummaryDivider(); +void printTestFilters(); + +private: +bool m_headerPrinted = false; +}; + +} // end namespace Catch + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +// end catch_reporter_console.h +// start catch_reporter_junit.h + +// start catch_xmlwriter.h + +#include + +namespace Catch { + +class XmlEncode { +public: +enum ForWhat { ForTextNodes, ForAttributes }; + +XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); + +void encodeTo( std::ostream& os ) const; + +friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); + +private: +std::string m_str; +ForWhat m_forWhat; +}; + +class XmlWriter { +public: + +class ScopedElement { +public: +ScopedElement( XmlWriter* writer ); + +ScopedElement( ScopedElement&& other ) noexcept; +ScopedElement& operator=( ScopedElement&& other ) noexcept; + +~ScopedElement(); + +ScopedElement& writeText( std::string const& text, bool indent = true ); + +template +ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { +m_writer->writeAttribute( name, attribute ); +return *this; +} + +private: +mutable XmlWriter* m_writer = nullptr; +}; + +XmlWriter( std::ostream& os = Catch::cout() ); +~XmlWriter(); + +XmlWriter( XmlWriter const& ) = delete; +XmlWriter& operator=( XmlWriter const& ) = delete; + +XmlWriter& startElement( std::string const& name ); + +ScopedElement scopedElement( std::string const& name ); + +XmlWriter& endElement(); + +XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); + +XmlWriter& writeAttribute( std::string const& name, bool attribute ); + +template +XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { +ReusableStringStream rss; +rss << attribute; +return writeAttribute( name, rss.str() ); +} + +XmlWriter& writeText( std::string const& text, bool indent = true ); + +XmlWriter& writeComment( std::string const& text ); + +void writeStylesheetRef( std::string const& url ); + +XmlWriter& writeBlankLine(); + +void ensureTagClosed(); + +private: + +void writeDeclaration(); + +void newlineIfNecessary(); + +bool m_tagIsOpen = false; +bool m_needsNewline = false; +std::vector m_tags; +std::string m_indent; +std::ostream& m_os; +}; + +} + +// end catch_xmlwriter.h +namespace Catch { + +class JunitReporter : public CumulativeReporterBase { +public: +JunitReporter(ReporterConfig const& _config); + +~JunitReporter() override; + +static std::string getDescription(); + +void noMatchingTestCases(std::string const& /*spec*/) override; + +void testRunStarting(TestRunInfo const& runInfo) override; + +void testGroupStarting(GroupInfo const& groupInfo) override; + +void testCaseStarting(TestCaseInfo const& testCaseInfo) override; +bool assertionEnded(AssertionStats const& assertionStats) override; + +void testCaseEnded(TestCaseStats const& testCaseStats) override; + +void testGroupEnded(TestGroupStats const& testGroupStats) override; + +void testRunEndedCumulative() override; + +void writeGroup(TestGroupNode const& groupNode, double suiteTime); + +void writeTestCase(TestCaseNode const& testCaseNode); + +void writeSection(std::string const& className, +std::string const& rootName, +SectionNode const& sectionNode); + +void writeAssertions(SectionNode const& sectionNode); +void writeAssertion(AssertionStats const& stats); + +XmlWriter xml; +Timer suiteTimer; +std::string stdOutForSuite; +std::string stdErrForSuite; +unsigned int unexpectedExceptions = 0; +bool m_okToFail = false; +}; + +} // end namespace Catch + +// end catch_reporter_junit.h +// start catch_reporter_xml.h + +namespace Catch { +class XmlReporter : public StreamingReporterBase { +public: +XmlReporter(ReporterConfig const& _config); + +~XmlReporter() override; + +static std::string getDescription(); + +virtual std::string getStylesheetRef() const; + +void writeSourceInfo(SourceLineInfo const& sourceInfo); + +public: // StreamingReporterBase + +void noMatchingTestCases(std::string const& s) override; + +void testRunStarting(TestRunInfo const& testInfo) override; + +void testGroupStarting(GroupInfo const& groupInfo) override; + +void testCaseStarting(TestCaseInfo const& testInfo) override; + +void sectionStarting(SectionInfo const& sectionInfo) override; + +void assertionStarting(AssertionInfo const&) override; + +bool assertionEnded(AssertionStats const& assertionStats) override; + +void sectionEnded(SectionStats const& sectionStats) override; + +void testCaseEnded(TestCaseStats const& testCaseStats) override; + +void testGroupEnded(TestGroupStats const& testGroupStats) override; + +void testRunEnded(TestRunStats const& testRunStats) override; + +private: +Timer m_testCaseTimer; +XmlWriter m_xml; +int m_sectionDepth = 0; +}; + +} // end namespace Catch + +// end catch_reporter_xml.h + // end catch_external_interfaces.h #endif +#endif // ! CATCH_CONFIG_IMPL_ONLY + #ifdef CATCH_IMPL // start catch_impl.hpp @@ -3804,164 +5789,140 @@ namespace Catch { namespace Catch { namespace TestCaseTracking { - struct NameAndLocation { - std::string name; - SourceLineInfo location; +struct NameAndLocation { +std::string name; +SourceLineInfo location; - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); - }; +NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); +}; - struct ITracker; +struct ITracker; - using ITrackerPtr = std::shared_ptr; +using ITrackerPtr = std::shared_ptr; - struct ITracker { - virtual ~ITracker(); +struct ITracker { +virtual ~ITracker(); - // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; +// static queries +virtual NameAndLocation const& nameAndLocation() const = 0; - // dynamic queries - virtual bool isComplete() const = 0; // Successfully completed or failed - virtual bool isSuccessfullyCompleted() const = 0; - virtual bool isOpen() const = 0; // Started but not complete - virtual bool hasChildren() const = 0; +// dynamic queries +virtual bool isComplete() const = 0; // Successfully completed or failed +virtual bool isSuccessfullyCompleted() const = 0; +virtual bool isOpen() const = 0; // Started but not complete +virtual bool hasChildren() const = 0; - virtual ITracker& parent() = 0; +virtual ITracker& parent() = 0; - // actions - virtual void close() = 0; // Successfully complete - virtual void fail() = 0; - virtual void markAsNeedingAnotherRun() = 0; +// actions +virtual void close() = 0; // Successfully complete +virtual void fail() = 0; +virtual void markAsNeedingAnotherRun() = 0; - virtual void addChild( ITrackerPtr const& child ) = 0; - virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; - virtual void openChild() = 0; +virtual void addChild( ITrackerPtr const& child ) = 0; +virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; +virtual void openChild() = 0; - // Debug/ checking - virtual bool isSectionTracker() const = 0; - virtual bool isIndexTracker() const = 0; - }; +// Debug/ checking +virtual bool isSectionTracker() const = 0; +virtual bool isGeneratorTracker() const = 0; +}; - class TrackerContext { +class TrackerContext { - enum RunState { - NotStarted, - Executing, - CompletedCycle - }; +enum RunState { +NotStarted, +Executing, +CompletedCycle +}; - ITrackerPtr m_rootTracker; - ITracker* m_currentTracker = nullptr; - RunState m_runState = NotStarted; +ITrackerPtr m_rootTracker; +ITracker* m_currentTracker = nullptr; +RunState m_runState = NotStarted; - public: +public: - static TrackerContext& instance(); +ITracker& startRun(); +void endRun(); - ITracker& startRun(); - void endRun(); +void startCycle(); +void completeCycle(); - void startCycle(); - void completeCycle(); +bool completedCycle() const; +ITracker& currentTracker(); +void setCurrentTracker( ITracker* tracker ); +}; - bool completedCycle() const; - ITracker& currentTracker(); - void setCurrentTracker( ITracker* tracker ); - }; +class TrackerBase : public ITracker { +protected: +enum CycleState { +NotStarted, +Executing, +ExecutingChildren, +NeedsAnotherRun, +CompletedSuccessfully, +Failed +}; - class TrackerBase : public ITracker { - protected: - enum CycleState { - NotStarted, - Executing, - ExecutingChildren, - NeedsAnotherRun, - CompletedSuccessfully, - Failed - }; +using Children = std::vector; +NameAndLocation m_nameAndLocation; +TrackerContext& m_ctx; +ITracker* m_parent; +Children m_children; +CycleState m_runState = NotStarted; - class TrackerHasName { - NameAndLocation m_nameAndLocation; - public: - TrackerHasName( NameAndLocation const& nameAndLocation ); - bool operator ()( ITrackerPtr const& tracker ) const; - }; +public: +TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - using Children = std::vector; - NameAndLocation m_nameAndLocation; - TrackerContext& m_ctx; - ITracker* m_parent; - Children m_children; - CycleState m_runState = NotStarted; +NameAndLocation const& nameAndLocation() const override; +bool isComplete() const override; +bool isSuccessfullyCompleted() const override; +bool isOpen() const override; +bool hasChildren() const override; - public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); +void addChild( ITrackerPtr const& child ) override; - NameAndLocation const& nameAndLocation() const override; - bool isComplete() const override; - bool isSuccessfullyCompleted() const override; - bool isOpen() const override; - bool hasChildren() const override; +ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; +ITracker& parent() override; - void addChild( ITrackerPtr const& child ) override; +void openChild() override; - ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; - ITracker& parent() override; +bool isSectionTracker() const override; +bool isGeneratorTracker() const override; - void openChild() override; +void open(); - bool isSectionTracker() const override; - bool isIndexTracker() const override; +void close() override; +void fail() override; +void markAsNeedingAnotherRun() override; - void open(); +private: +void moveToParent(); +void moveToThis(); +}; - void close() override; - void fail() override; - void markAsNeedingAnotherRun() override; +class SectionTracker : public TrackerBase { +std::vector m_filters; +public: +SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - private: - void moveToParent(); - void moveToThis(); - }; +bool isSectionTracker() const override; - class SectionTracker : public TrackerBase { - std::vector m_filters; - public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); +bool isComplete() const override; - bool isSectionTracker() const override; +static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); +void tryOpen(); - void tryOpen(); - - void addInitialFilters( std::vector const& filters ); - void addNextFilters( std::vector const& filters ); - }; - - class IndexTracker : public TrackerBase { - int m_size; - int m_index = -1; - public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); - - bool isIndexTracker() const override; - void close() override; - - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); - - int index() const; - - void moveNext(); - }; +void addInitialFilters( std::vector const& filters ); +void addNextFilters( std::vector const& filters ); +}; } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; } // namespace Catch @@ -3971,9 +5932,10 @@ using TestCaseTracking::IndexTracker; namespace Catch { - struct LeakDetector { - LeakDetector(); - }; +struct LeakDetector { +LeakDetector(); +~LeakDetector(); +}; } // end catch_leak_detector.h @@ -3988,7 +5950,7 @@ namespace { // Performs equivalent check of std::fabs(lhs - rhs) <= margin // But without the subtraction to allow for INFINITY in comparison bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); +return (lhs + margin >= rhs) && (rhs + margin >= lhs); } } @@ -3996,293 +5958,508 @@ bool marginComparison(double lhs, double rhs, double margin) { namespace Catch { namespace Detail { - Approx::Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_margin( 0.0 ), - m_scale( 0.0 ), - m_value( value ) - {} +Approx::Approx ( double value ) +: m_epsilon( std::numeric_limits::epsilon()*100 ), +m_margin( 0.0 ), +m_scale( 0.0 ), +m_value( value ) +{} - Approx Approx::custom() { - return Approx( 0 ); - } +Approx Approx::custom() { +return Approx( 0 ); +} - std::string Approx::toString() const { - std::ostringstream oss; - oss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return oss.str(); - } +Approx Approx::operator-() const { +auto temp(*this); +temp.m_value = -temp.m_value; +return temp; +} - bool Approx::equalityComparisonImpl(const double other) const { - // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value - // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); - } +std::string Approx::toString() const { +ReusableStringStream rss; +rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; +return rss.str(); +} + +bool Approx::equalityComparisonImpl(const double other) const { +// First try with fixed margin, then compute margin based on epsilon, scale and Approx's value +// Thanks to Richard Harris for his help refining the scaled margin value +return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); +} + +void Approx::setMargin(double newMargin) { +CATCH_ENFORCE(newMargin >= 0, +"Invalid Approx::margin: " << newMargin << '.' +<< " Approx::Margin has to be non-negative."); +m_margin = newMargin; +} + +void Approx::setEpsilon(double newEpsilon) { +CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, +"Invalid Approx::epsilon: " << newEpsilon << '.' +<< " Approx::epsilon has to be in [0, 1]"); +m_epsilon = newEpsilon; +} } // end namespace Detail +namespace literals { +Detail::Approx operator "" _a(long double val) { +return Detail::Approx(val); +} +Detail::Approx operator "" _a(unsigned long long val) { +return Detail::Approx(val); +} +} // end namespace literals + std::string StringMaker::convert(Catch::Detail::Approx const& value) { - return value.toString(); +return value.toString(); } } // end namespace Catch // end catch_approx.cpp // start catch_assertionhandler.cpp -// start catch_context.h - -#include +// start catch_debugger.h namespace Catch { - - struct IResultCapture; - struct IRunner; - struct IConfig; - - using IConfigPtr = std::shared_ptr; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual IConfigPtr getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( IConfigPtr const& config ) = 0; - }; - - IContext& getCurrentContext(); - IMutableContext& getCurrentMutableContext(); - void cleanUpContext(); +bool isDebuggerActive(); } -// end catch_context.h -#include +#ifdef CATCH_PLATFORM_MAC + +#define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + +#elif defined(CATCH_PLATFORM_LINUX) +// If we can use inline assembler, do it because this allows us to break +// directly at the location of the failing check instead of breaking inside +// raise() called from it, i.e. one stack frame below. +#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) +#define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ +#else // Fall back to the generic way. +#include + +#define CATCH_TRAP() raise(SIGTRAP) +#endif +#elif defined(_MSC_VER) +#define CATCH_TRAP() __debugbreak() +#elif defined(__MINGW32__) +extern "C" __declspec(dllimport) void __stdcall DebugBreak(); +#define CATCH_TRAP() DebugBreak() +#endif + +#ifdef CATCH_TRAP +#define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() +#else +#define CATCH_BREAK_INTO_DEBUGGER() []{}() +#endif + +// end catch_debugger.h +// start catch_run_context.h + +// start catch_fatal_condition.h + +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h +#if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { - auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { - expr.streamReconstructedExpression( os ); - return os; - } +struct FatalConditionHandler { - LazyExpression::LazyExpression( bool isNegated ) - : m_isNegated( isNegated ) - {} +static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); +FatalConditionHandler(); +static void reset(); +~FatalConditionHandler(); - LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} +private: +static bool isSet; +static ULONG guaranteeSize; +static PVOID exceptionHandlerHandle; +}; - LazyExpression::operator bool() const { - return m_transientExpression != nullptr; - } +} // namespace Catch - auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { - if( lazyExpr.m_isNegated ) - os << "!"; +#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) - if( lazyExpr ) { - if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) - os << "(" << *lazyExpr.m_transientExpression << ")"; - else - os << *lazyExpr.m_transientExpression; - } - else { - os << "{** error - unchecked empty expression requested **}"; - } - return os; - } +#include - AssertionHandler::AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition } - { - getCurrentContext().getResultCapture()->assertionStarting( m_assertionInfo ); - } - AssertionHandler::~AssertionHandler() { - if ( m_inExceptionGuard ) { - handle( ResultWas::ThrewException, "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ); - getCurrentContext().getResultCapture()->exceptionEarlyReported(); - } - } +namespace Catch { - void AssertionHandler::handle( ITransientExpression const& expr ) { +struct FatalConditionHandler { - bool negated = isFalseTest( m_assertionInfo.resultDisposition ); - bool result = expr.getResult() != negated; +static bool isSet; +static struct sigaction oldSigActions[]; +static stack_t oldSigStack; +static char altStackMem[]; - handle( result ? ResultWas::Ok : ResultWas::ExpressionFailed, &expr, negated ); - } - void AssertionHandler::handle( ResultWas::OfType resultType ) { - handle( resultType, nullptr, false ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, StringRef const& message ) { - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - handle( data, nullptr ); - } - void AssertionHandler::handle( ResultWas::OfType resultType, ITransientExpression const* expr, bool negated ) { - AssertionResultData data( resultType, LazyExpression( negated ) ); - handle( data, expr ); - } - void AssertionHandler::handle( AssertionResultData const& resultData, ITransientExpression const* expr ) { +static void handleSignal( int sig ); - getResultCapture().assertionRun(); +FatalConditionHandler(); +~FatalConditionHandler(); +static void reset(); +}; - AssertionResult assertionResult{ m_assertionInfo, resultData }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; +} // namespace Catch - getResultCapture().assertionEnded( assertionResult ); +#else - if( !assertionResult.isOk() ) { - m_shouldDebugBreak = getCurrentContext().getConfig()->shouldDebugBreak(); - m_shouldThrow = - getCurrentContext().getRunner()->aborting() || - (m_assertionInfo.resultDisposition & ResultDisposition::Normal); - } - } +namespace Catch { +struct FatalConditionHandler { +void reset(); +}; +} - auto AssertionHandler::allowThrows() const -> bool { - return getCurrentContext().getConfig()->allowThrows(); - } +#endif - auto AssertionHandler::shouldDebugBreak() const -> bool { - return m_shouldDebugBreak; - } - void AssertionHandler::reactWithDebugBreak() const { - if (m_shouldDebugBreak) { - /////////////////////////////////////////////////////////////////// - // To inspect the state during test, you need to go one level up the callstack - // To go back to the test and change execution, jump over the reactWithoutDebugBreak() call - /////////////////////////////////////////////////////////////////// - CATCH_BREAK_INTO_DEBUGGER(); - } - reactWithoutDebugBreak(); - } - void AssertionHandler::reactWithoutDebugBreak() const { - if( m_shouldThrow ) - throw Catch::TestFailureException(); - } +// end catch_fatal_condition.h +#include - void AssertionHandler::useActiveException() { - handle( ResultWas::ThrewException, Catch::translateActiveException() ); - } +namespace Catch { - void AssertionHandler::setExceptionGuard() { - assert( m_inExceptionGuard == false ); - m_inExceptionGuard = true; - } - void AssertionHandler::unsetExceptionGuard() { - assert( m_inExceptionGuard == true ); - m_inExceptionGuard = false; - } +struct IMutableContext; - // This is the overload that takes a string and infers the Equals matcher from it - // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { - handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); - } +/////////////////////////////////////////////////////////////////////////// + +class RunContext : public IResultCapture, public IRunner { + +public: +RunContext( RunContext const& ) = delete; +RunContext& operator =( RunContext const& ) = delete; + +explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); + +~RunContext() override; + +void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); +void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); + +Totals runTest(TestCase const& testCase); + +IConfigPtr config() const; +IStreamingReporter& reporter() const; + +public: // IResultCapture + +// Assertion handlers +void handleExpr +( AssertionInfo const& info, +ITransientExpression const& expr, +AssertionReaction& reaction ) override; +void handleMessage +( AssertionInfo const& info, +ResultWas::OfType resultType, +StringRef const& message, +AssertionReaction& reaction ) override; +void handleUnexpectedExceptionNotThrown +( AssertionInfo const& info, +AssertionReaction& reaction ) override; +void handleUnexpectedInflightException +( AssertionInfo const& info, +std::string const& message, +AssertionReaction& reaction ) override; +void handleIncomplete +( AssertionInfo const& info ) override; +void handleNonExpr +( AssertionInfo const &info, +ResultWas::OfType resultType, +AssertionReaction &reaction ) override; + +bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; + +void sectionEnded( SectionEndInfo const& endInfo ) override; +void sectionEndedEarly( SectionEndInfo const& endInfo ) override; + +auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + +void benchmarkStarting( BenchmarkInfo const& info ) override; +void benchmarkEnded( BenchmarkStats const& stats ) override; + +void pushScopedMessage( MessageInfo const& message ) override; +void popScopedMessage( MessageInfo const& message ) override; + +void emplaceUnscopedMessage( MessageBuilder const& builder ) override; + +std::string getCurrentTestName() const override; + +const AssertionResult* getLastResult() const override; + +void exceptionEarlyReported() override; + +void handleFatalErrorCondition( StringRef message ) override; + +bool lastAssertionPassed() override; + +void assertionPassed() override; + +public: +// !TBD We need to do this another way! +bool aborting() const final; + +private: + +void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); +void invokeActiveTestCase(); + +void resetAssertionInfo(); +bool testForMissingAssertions( Counts& assertions ); + +void assertionEnded( AssertionResult const& result ); +void reportExpr +( AssertionInfo const &info, +ResultWas::OfType resultType, +ITransientExpression const *expr, +bool negated ); + +void populateReaction( AssertionReaction& reaction ); + +private: + +void handleUnfinishedSections(); + +TestRunInfo m_runInfo; +IMutableContext& m_context; +TestCase const* m_activeTestCase = nullptr; +ITracker* m_testCaseTracker = nullptr; +Option m_lastResult; + +IConfigPtr m_config; +Totals m_totals; +IStreamingReporterPtr m_reporter; +std::vector m_messages; +std::vector m_messageScopes; /* Keeps owners of so-called unscoped messages. */ +AssertionInfo m_lastAssertionInfo; +std::vector m_unfinishedSections; +std::vector m_activeSections; +TrackerContext m_trackerContext; +bool m_lastAssertionPassed = false; +bool m_shouldReportUnexpected = true; +bool m_includeSuccessfulResults; +}; + +} // end namespace Catch + +// end catch_run_context.h +namespace Catch { + +namespace { +auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { +expr.streamReconstructedExpression( os ); +return os; +} +} + +LazyExpression::LazyExpression( bool isNegated ) +: m_isNegated( isNegated ) +{} + +LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} + +LazyExpression::operator bool() const { +return m_transientExpression != nullptr; +} + +auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { +if( lazyExpr.m_isNegated ) +os << "!"; + +if( lazyExpr ) { +if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) +os << "(" << *lazyExpr.m_transientExpression << ")"; +else +os << *lazyExpr.m_transientExpression; +} +else { +os << "{** error - unchecked empty expression requested **}"; +} +return os; +} + +AssertionHandler::AssertionHandler +( StringRef const& macroName, +SourceLineInfo const& lineInfo, +StringRef capturedExpression, +ResultDisposition::Flags resultDisposition ) +: m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, +m_resultCapture( getResultCapture() ) +{} + +void AssertionHandler::handleExpr( ITransientExpression const& expr ) { +m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); +} +void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { +m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); +} + +auto AssertionHandler::allowThrows() const -> bool { +return getCurrentContext().getConfig()->allowThrows(); +} + +void AssertionHandler::complete() { +setCompleted(); +if( m_reaction.shouldDebugBreak ) { + +// If you find your debugger stopping you here then go one level up on the +// call-stack for the code that caused it (typically a failed assertion) + +// (To go back to the test and change execution, jump over the throw, next) +CATCH_BREAK_INTO_DEBUGGER(); +} +if (m_reaction.shouldThrow) { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +throw Catch::TestFailureException(); +#else +CATCH_ERROR( "Test failure requires aborting test!" ); +#endif +} +} +void AssertionHandler::setCompleted() { +m_completed = true; +} + +void AssertionHandler::handleUnexpectedInflightException() { +m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); +} + +void AssertionHandler::handleExceptionThrownAsExpected() { +m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); +} +void AssertionHandler::handleExceptionNotThrownAsExpected() { +m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); +} + +void AssertionHandler::handleUnexpectedExceptionNotThrown() { +m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); +} + +void AssertionHandler::handleThrowingCallSkipped() { +m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); +} + +// This is the overload that takes a string and infers the Equals matcher from it +// The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp +void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { +handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); +} } // namespace Catch // end catch_assertionhandler.cpp // start catch_assertionresult.cpp namespace Catch { - AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): - lazyExpression(_lazyExpression), - resultType(_resultType) {} +AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): +lazyExpression(_lazyExpression), +resultType(_resultType) {} - std::string AssertionResultData::reconstructExpression() const { +std::string AssertionResultData::reconstructExpression() const { - if( reconstructedExpression.empty() ) { - if( lazyExpression ) { - // !TBD Use stringstream for now, but rework above to pass stream in - std::ostringstream oss; - oss << lazyExpression; - reconstructedExpression = oss.str(); - } - } - return reconstructedExpression; - } +if( reconstructedExpression.empty() ) { +if( lazyExpression ) { +ReusableStringStream rss; +rss << lazyExpression; +reconstructedExpression = rss.str(); +} +} +return reconstructedExpression; +} - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} +AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) +: m_info( info ), +m_resultData( data ) +{} - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } +// Result was a success +bool AssertionResult::succeeded() const { +return Catch::isOk( m_resultData.resultType ); +} - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } +// Result was a success, or failure is suppressed +bool AssertionResult::isOk() const { +return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); +} - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } +ResultWas::OfType AssertionResult::getResultType() const { +return m_resultData.resultType; +} - bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; - } +bool AssertionResult::hasExpression() const { +return m_info.capturedExpression[0] != 0; +} - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } +bool AssertionResult::hasMessage() const { +return !m_resultData.message.empty(); +} - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + std::string(m_info.capturedExpression) + ")"; - else - return m_info.capturedExpression; - } +std::string AssertionResult::getExpression() const { +if( isFalseTest( m_info.resultDisposition ) ) +return "!(" + m_info.capturedExpression + ")"; +else +return m_info.capturedExpression; +} - std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName[0] == 0 ) - expr = m_info.capturedExpression; - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; - } - return expr; - } +std::string AssertionResult::getExpressionInMacro() const { +std::string expr; +if( m_info.macroName[0] == 0 ) +expr = m_info.capturedExpression; +else { +expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); +expr += m_info.macroName; +expr += "( "; +expr += m_info.capturedExpression; +expr += " )"; +} +return expr; +} - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } +bool AssertionResult::hasExpandedExpression() const { +return hasExpression() && getExpandedExpression() != getExpression(); +} - std::string AssertionResult::getExpandedExpression() const { - std::string expr = m_resultData.reconstructExpression(); - return expr.empty() - ? getExpression() - : expr; - } +std::string AssertionResult::getExpandedExpression() const { +std::string expr = m_resultData.reconstructExpression(); +return expr.empty() +? getExpression() +: expr; +} - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } +std::string AssertionResult::getMessage() const { +return m_resultData.message; +} +SourceLineInfo AssertionResult::getSourceInfo() const { +return m_info.lineInfo; +} - std::string AssertionResult::getTestMacroName() const { - return m_info.macroName; - } +StringRef AssertionResult::getTestMacroName() const { +return m_info.macroName; +} } // end namespace Catch // end catch_assertionresult.cpp @@ -4290,25 +6467,25 @@ namespace Catch { namespace Catch { - auto BenchmarkLooper::getResolution() -> uint64_t { - return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); - } +auto BenchmarkLooper::getResolution() -> uint64_t { +return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); +} - void BenchmarkLooper::reportStart() { - getResultCapture().benchmarkStarting( { m_name } ); - } - auto BenchmarkLooper::needsMoreIterations() -> bool { - auto elapsed = m_timer.getElapsedNanoseconds(); +void BenchmarkLooper::reportStart() { +getResultCapture().benchmarkStarting( { m_name } ); +} +auto BenchmarkLooper::needsMoreIterations() -> bool { +auto elapsed = m_timer.getElapsedNanoseconds(); - // Exponentially increasing iterations until we're confident in our timer resolution - if( elapsed < m_resolution ) { - m_iterationsToRun *= 10; - return true; - } +// Exponentially increasing iterations until we're confident in our timer resolution +if( elapsed < m_resolution ) { +m_iterationsToRun *= 10; +return true; +} - getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); - return false; - } +getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); +return false; +} } // end namespace Catch // end catch_benchmark.cpp @@ -4316,16 +6493,16 @@ namespace Catch { namespace Catch { - using StringMatcher = Matchers::Impl::MatcherBase; +using StringMatcher = Matchers::Impl::MatcherBase; - // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers - // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { - std::string exceptionMessage = Catch::translateActiveException(); - MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handle( expr ); - } +// This is the general overload that takes a any string matcher +// There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers +// the Equals matcher (so the header does not mention matchers) +void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { +std::string exceptionMessage = Catch::translateActiveException(); +MatchExpr expr( exceptionMessage, matcher, matcherString ); +handler.handleExpr( expr ); +} } // namespace Catch // end catch_capture_matchers.cpp @@ -4350,8 +6527,14 @@ namespace Catch { #endif // start clara.hpp -// v1.0-develop.2 -// See https://github.com/philsquared/Clara +// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See https://github.com/philsquared/Clara for more details + +// Clara v1.1.5 #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH @@ -4362,14 +6545,23 @@ namespace Catch { #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH #endif +#ifndef CLARA_CONFIG_OPTIONAL_TYPE +#ifdef __has_include +#if __has_include() && __cplusplus >= 201703L +#include +#define CLARA_CONFIG_OPTIONAL_TYPE std::optional +#endif +#endif +#endif + // ----------- #included from clara_textflow.hpp ----------- // TextFlowCpp // // A single-header library for wrapping and laying out basic text, by Phil Nash // -// This work is licensed under the BSD 2-Clause license. -// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // This project is hosted at https://github.com/philsquared/textflowcpp @@ -4383,314 +6575,328 @@ namespace Catch { #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 #endif -namespace Catch { namespace clara { namespace TextFlow { +namespace Catch { +namespace clara { +namespace TextFlow { - inline auto isWhitespace( char c ) -> bool { - static std::string chars = " \t\n\r"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableBefore( char c ) -> bool { - static std::string chars = "[({<|"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableAfter( char c ) -> bool { - static std::string chars = "])}>.,:;*+-=&/\\"; - return chars.find( c ) != std::string::npos; - } +inline auto isWhitespace(char c) -> bool { +static std::string chars = " \t\n\r"; +return chars.find(c) != std::string::npos; +} +inline auto isBreakableBefore(char c) -> bool { +static std::string chars = "[({<|"; +return chars.find(c) != std::string::npos; +} +inline auto isBreakableAfter(char c) -> bool { +static std::string chars = "])}>.,:;*+-=&/\\"; +return chars.find(c) != std::string::npos; +} - class Columns; +class Columns; - class Column { - std::vector m_strings; - size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; - size_t m_indent = 0; - size_t m_initialIndent = std::string::npos; +class Column { +std::vector m_strings; +size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; +size_t m_indent = 0; +size_t m_initialIndent = std::string::npos; - public: - class iterator { - friend Column; +public: +class iterator { +friend Column; - Column const& m_column; - size_t m_stringIndex = 0; - size_t m_pos = 0; +Column const& m_column; +size_t m_stringIndex = 0; +size_t m_pos = 0; - size_t m_len = 0; - size_t m_end = 0; - bool m_suffix = false; +size_t m_len = 0; +size_t m_end = 0; +bool m_suffix = false; - iterator( Column const& column, size_t stringIndex ) - : m_column( column ), - m_stringIndex( stringIndex ) - {} +iterator(Column const& column, size_t stringIndex) +: m_column(column), +m_stringIndex(stringIndex) {} - auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } +auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } - auto isBoundary( size_t at ) const -> bool { - assert( at > 0 ); - assert( at <= line().size() ); +auto isBoundary(size_t at) const -> bool { +assert(at > 0); +assert(at <= line().size()); - return at == line().size() || - ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || - isBreakableBefore( line()[at] ) || - isBreakableAfter( line()[at-1] ); - } +return at == line().size() || +(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || +isBreakableBefore(line()[at]) || +isBreakableAfter(line()[at - 1]); +} - void calcLength() { - assert( m_stringIndex < m_column.m_strings.size() ); +void calcLength() { +assert(m_stringIndex < m_column.m_strings.size()); - m_suffix = false; - auto width = m_column.m_width-indent(); - m_end = m_pos; - while( m_end < line().size() && line()[m_end] != '\n' ) - ++m_end; +m_suffix = false; +auto width = m_column.m_width - indent(); +m_end = m_pos; +if (line()[m_pos] == '\n') { +++m_end; +} +while (m_end < line().size() && line()[m_end] != '\n') +++m_end; - if( m_end < m_pos + width ) { - m_len = m_end - m_pos; - } - else { - size_t len = width; - while (len > 0 && !isBoundary(m_pos + len)) - --len; - while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) - --len; +if (m_end < m_pos + width) { +m_len = m_end - m_pos; +} else { +size_t len = width; +while (len > 0 && !isBoundary(m_pos + len)) +--len; +while (len > 0 && isWhitespace(line()[m_pos + len - 1])) +--len; - if (len > 0) { - m_len = len; - } else { - m_suffix = true; - m_len = width - 1; - } - } - } +if (len > 0) { +m_len = len; +} else { +m_suffix = true; +m_len = width - 1; +} +} +} - auto indent() const -> size_t { - auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; - return initial == std::string::npos ? m_column.m_indent : initial; - } +auto indent() const -> size_t { +auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; +return initial == std::string::npos ? m_column.m_indent : initial; +} - auto addIndentAndSuffix(std::string const &plain) const -> std::string { - return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); - } +auto addIndentAndSuffix(std::string const &plain) const -> std::string { +return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); +} - public: - explicit iterator( Column const& column ) : m_column( column ) { - assert( m_column.m_width > m_column.m_indent ); - assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); - calcLength(); - if( m_len == 0 ) - m_stringIndex++; // Empty string - } +public: +using difference_type = std::ptrdiff_t; +using value_type = std::string; +using pointer = value_type * ; +using reference = value_type & ; +using iterator_category = std::forward_iterator_tag; - auto operator *() const -> std::string { - assert( m_stringIndex < m_column.m_strings.size() ); - assert( m_pos <= m_end ); - if( m_pos + m_column.m_width < m_end ) - return addIndentAndSuffix(line().substr(m_pos, m_len)); - else - return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); - } +explicit iterator(Column const& column) : m_column(column) { +assert(m_column.m_width > m_column.m_indent); +assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); +calcLength(); +if (m_len == 0) +m_stringIndex++; // Empty string +} - auto operator ++() -> iterator& { - m_pos += m_len; - if( m_pos < line().size() && line()[m_pos] == '\n' ) - m_pos += 1; - else - while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) - ++m_pos; +auto operator *() const -> std::string { +assert(m_stringIndex < m_column.m_strings.size()); +assert(m_pos <= m_end); +return addIndentAndSuffix(line().substr(m_pos, m_len)); +} - if( m_pos == line().size() ) { - m_pos = 0; - ++m_stringIndex; - } - if( m_stringIndex < m_column.m_strings.size() ) - calcLength(); - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } +auto operator ++() -> iterator& { +m_pos += m_len; +if (m_pos < line().size() && line()[m_pos] == '\n') +m_pos += 1; +else +while (m_pos < line().size() && isWhitespace(line()[m_pos])) +++m_pos; - auto operator ==( iterator const& other ) const -> bool { - return - m_pos == other.m_pos && - m_stringIndex == other.m_stringIndex && - &m_column == &other.m_column; - } - auto operator !=( iterator const& other ) const -> bool { - return !operator==( other ); - } - }; - using const_iterator = iterator; +if (m_pos == line().size()) { +m_pos = 0; +++m_stringIndex; +} +if (m_stringIndex < m_column.m_strings.size()) +calcLength(); +return *this; +} +auto operator ++(int) -> iterator { +iterator prev(*this); +operator++(); +return prev; +} - explicit Column( std::string const& text ) { m_strings.push_back( text ); } +auto operator ==(iterator const& other) const -> bool { +return +m_pos == other.m_pos && +m_stringIndex == other.m_stringIndex && +&m_column == &other.m_column; +} +auto operator !=(iterator const& other) const -> bool { +return !operator==(other); +} +}; +using const_iterator = iterator; - auto width( size_t newWidth ) -> Column& { - assert( newWidth > 0 ); - m_width = newWidth; - return *this; - } - auto indent( size_t newIndent ) -> Column& { - m_indent = newIndent; - return *this; - } - auto initialIndent( size_t newIndent ) -> Column& { - m_initialIndent = newIndent; - return *this; - } +explicit Column(std::string const& text) { m_strings.push_back(text); } - auto width() const -> size_t { return m_width; } - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, m_strings.size() }; } +auto width(size_t newWidth) -> Column& { +assert(newWidth > 0); +m_width = newWidth; +return *this; +} +auto indent(size_t newIndent) -> Column& { +m_indent = newIndent; +return *this; +} +auto initialIndent(size_t newIndent) -> Column& { +m_initialIndent = newIndent; +return *this; +} - inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { - bool first = true; - for( auto line : col ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } +auto width() const -> size_t { return m_width; } +auto begin() const -> iterator { return iterator(*this); } +auto end() const -> iterator { return { *this, m_strings.size() }; } - auto operator + ( Column const& other ) -> Columns; +inline friend std::ostream& operator << (std::ostream& os, Column const& col) { +bool first = true; +for (auto line : col) { +if (first) +first = false; +else +os << "\n"; +os << line; +} +return os; +} - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; +auto operator + (Column const& other)->Columns; - class Spacer : public Column { +auto toString() const -> std::string { +std::ostringstream oss; +oss << *this; +return oss.str(); +} +}; - public: - explicit Spacer( size_t spaceWidth ) : Column( "" ) { - width( spaceWidth ); - } - }; +class Spacer : public Column { - class Columns { - std::vector m_columns; +public: +explicit Spacer(size_t spaceWidth) : Column("") { +width(spaceWidth); +} +}; - public: +class Columns { +std::vector m_columns; - class iterator { - friend Columns; - struct EndTag {}; +public: - std::vector const& m_columns; - std::vector m_iterators; - size_t m_activeIterators; +class iterator { +friend Columns; +struct EndTag {}; - iterator( Columns const& columns, EndTag ) - : m_columns( columns.m_columns ), - m_activeIterators( 0 ) - { - m_iterators.reserve( m_columns.size() ); +std::vector const& m_columns; +std::vector m_iterators; +size_t m_activeIterators; - for( auto const& col : m_columns ) - m_iterators.push_back( col.end() ); - } +iterator(Columns const& columns, EndTag) +: m_columns(columns.m_columns), +m_activeIterators(0) { +m_iterators.reserve(m_columns.size()); - public: - explicit iterator( Columns const& columns ) - : m_columns( columns.m_columns ), - m_activeIterators( m_columns.size() ) - { - m_iterators.reserve( m_columns.size() ); +for (auto const& col : m_columns) +m_iterators.push_back(col.end()); +} - for( auto const& col : m_columns ) - m_iterators.push_back( col.begin() ); - } +public: +using difference_type = std::ptrdiff_t; +using value_type = std::string; +using pointer = value_type * ; +using reference = value_type & ; +using iterator_category = std::forward_iterator_tag; - auto operator ==( iterator const& other ) const -> bool { - return m_iterators == other.m_iterators; - } - auto operator !=( iterator const& other ) const -> bool { - return m_iterators != other.m_iterators; - } - auto operator *() const -> std::string { - std::string row, padding; +explicit iterator(Columns const& columns) +: m_columns(columns.m_columns), +m_activeIterators(m_columns.size()) { +m_iterators.reserve(m_columns.size()); - for( size_t i = 0; i < m_columns.size(); ++i ) { - auto width = m_columns[i].width(); - if( m_iterators[i] != m_columns[i].end() ) { - std::string col = *m_iterators[i]; - row += padding + col; - if( col.size() < width ) - padding = std::string( width - col.size(), ' ' ); - else - padding = ""; - } - else { - padding += std::string( width, ' ' ); - } - } - return row; - } - auto operator ++() -> iterator& { - for( size_t i = 0; i < m_columns.size(); ++i ) { - if (m_iterators[i] != m_columns[i].end()) - ++m_iterators[i]; - } - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - }; - using const_iterator = iterator; +for (auto const& col : m_columns) +m_iterators.push_back(col.begin()); +} - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, iterator::EndTag() }; } +auto operator ==(iterator const& other) const -> bool { +return m_iterators == other.m_iterators; +} +auto operator !=(iterator const& other) const -> bool { +return m_iterators != other.m_iterators; +} +auto operator *() const -> std::string { +std::string row, padding; - auto operator += ( Column const& col ) -> Columns& { - m_columns.push_back( col ); - return *this; - } - auto operator + ( Column const& col ) -> Columns { - Columns combined = *this; - combined += col; - return combined; - } +for (size_t i = 0; i < m_columns.size(); ++i) { +auto width = m_columns[i].width(); +if (m_iterators[i] != m_columns[i].end()) { +std::string col = *m_iterators[i]; +row += padding + col; +if (col.size() < width) +padding = std::string(width - col.size(), ' '); +else +padding = ""; +} else { +padding += std::string(width, ' '); +} +} +return row; +} +auto operator ++() -> iterator& { +for (size_t i = 0; i < m_columns.size(); ++i) { +if (m_iterators[i] != m_columns[i].end()) +++m_iterators[i]; +} +return *this; +} +auto operator ++(int) -> iterator { +iterator prev(*this); +operator++(); +return prev; +} +}; +using const_iterator = iterator; - inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { +auto begin() const -> iterator { return iterator(*this); } +auto end() const -> iterator { return { *this, iterator::EndTag() }; } - bool first = true; - for( auto line : cols ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } +auto operator += (Column const& col) -> Columns& { +m_columns.push_back(col); +return *this; +} +auto operator + (Column const& col) -> Columns { +Columns combined = *this; +combined += col; +return combined; +} - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; +inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { - inline auto Column::operator + ( Column const& other ) -> Columns { - Columns cols; - cols += *this; - cols += other; - return cols; - } -}}} // namespace Catch::clara::TextFlow +bool first = true; +for (auto line : cols) { +if (first) +first = false; +else +os << "\n"; +os << line; +} +return os; +} + +auto toString() const -> std::string { +std::ostringstream oss; +oss << *this; +return oss.str(); +} +}; + +inline auto Column::operator + (Column const& other) -> Columns { +Columns cols; +cols += *this; +cols += other; +return cols; +} +} + +} +} // ----------- end of #include from clara_textflow.hpp ----------- // ........... back in clara.hpp +#include +#include #include #include #include @@ -4702,843 +6908,851 @@ namespace Catch { namespace clara { namespace TextFlow { namespace Catch { namespace clara { namespace detail { - // Traits for extracting arg and return type of lambdas (for single argument lambdas) - template - struct UnaryLambdaTraits : UnaryLambdaTraits {}; +// Traits for extracting arg and return type of lambdas (for single argument lambdas) +template +struct UnaryLambdaTraits : UnaryLambdaTraits {}; - template - struct UnaryLambdaTraits { - static const bool isValid = false; - }; +template +struct UnaryLambdaTraits { +static const bool isValid = false; +}; - template - struct UnaryLambdaTraits { - static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type;; - using ReturnType = ReturnT; - }; +template +struct UnaryLambdaTraits { +static const bool isValid = true; +using ArgType = typename std::remove_const::type>::type; +using ReturnType = ReturnT; +}; - class TokenStream; +class TokenStream; - // Transport for raw args (copied from main args, or supplied via init list for testing) - class Args { - friend TokenStream; - std::string m_exeName; - std::vector m_args; +// Transport for raw args (copied from main args, or supplied via init list for testing) +class Args { +friend TokenStream; +std::string m_exeName; +std::vector m_args; - public: - Args( int argc, char *argv[] ) { - m_exeName = argv[0]; - for( int i = 1; i < argc; ++i ) - m_args.push_back( argv[i] ); - } +public: +Args( int argc, char const* const* argv ) +: m_exeName(argv[0]), +m_args(argv + 1, argv + argc) {} - Args( std::initializer_list args ) - : m_exeName( *args.begin() ), - m_args( args.begin()+1, args.end() ) - {} +Args( std::initializer_list args ) +: m_exeName( *args.begin() ), +m_args( args.begin()+1, args.end() ) +{} - auto exeName() const -> std::string { - return m_exeName; - } - }; +auto exeName() const -> std::string { +return m_exeName; +} +}; - // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string - // may encode an option + its argument if the : or = form is used - enum class TokenType { - Option, Argument - }; - struct Token { - TokenType type; - std::string token; - }; +// Wraps a token coming from a token stream. These may not directly correspond to strings as a single string +// may encode an option + its argument if the : or = form is used +enum class TokenType { +Option, Argument +}; +struct Token { +TokenType type; +std::string token; +}; - inline auto isOptPrefix( char c ) -> bool { - return c == '-' +inline auto isOptPrefix( char c ) -> bool { +return c == '-' #ifdef CATCH_PLATFORM_WINDOWS - || c == '/' +|| c == '/' #endif - ; - } - - // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled - class TokenStream { - using Iterator = std::vector::const_iterator; - Iterator it; - Iterator itEnd; - std::vector m_tokenBuffer; - - void loadBuffer() { - m_tokenBuffer.resize( 0 ); - - // Skip any empty strings - while( it != itEnd && it->empty() ) - ++it; - - if( it != itEnd ) { - auto const &next = *it; - if( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if( delimiterPos != std::string::npos ) { - m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); - m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); - } else { - if( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; - for( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; - m_tokenBuffer.push_back( { TokenType::Option, opt } ); - } - } else { - m_tokenBuffer.push_back( { TokenType::Option, next } ); - } - } - } else { - m_tokenBuffer.push_back( { TokenType::Argument, next } ); - } - } - } - - public: - explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} - - TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { - loadBuffer(); - } - - explicit operator bool() const { - return !m_tokenBuffer.empty() || it != itEnd; - } - - auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } - - auto operator*() const -> Token { - assert( !m_tokenBuffer.empty() ); - return m_tokenBuffer.front(); - } - - auto operator->() const -> Token const * { - assert( !m_tokenBuffer.empty() ); - return &m_tokenBuffer.front(); - } - - auto operator++() -> TokenStream & { - if( m_tokenBuffer.size() >= 2 ) { - m_tokenBuffer.erase( m_tokenBuffer.begin() ); - } else { - if( it != itEnd ) - ++it; - loadBuffer(); - } - return *this; - } - }; - - class ResultBase { - public: - enum Type { - Ok, LogicError, RuntimeError - }; - - protected: - ResultBase( Type type ) : m_type( type ) {} - virtual ~ResultBase() = default; - - virtual void enforceOk() const = 0; - - Type m_type; - }; - - template - class ResultValueBase : public ResultBase { - public: - auto value() const -> T const & { - enforceOk(); - return m_value; - } - - protected: - ResultValueBase( Type type ) : ResultBase( type ) {} - - ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - } - - ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { - new( &m_value ) T( value ); - } - - auto operator=( ResultValueBase const &other ) -> ResultValueBase & { - if( m_type == ResultBase::Ok ) - m_value.~T(); - ResultBase::operator=(other); - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - return *this; - } - - ~ResultValueBase() { - if( m_type == Ok ) - m_value.~T(); - } - - union { - T m_value; - }; - }; - - template<> - class ResultValueBase : public ResultBase { - protected: - using ResultBase::ResultBase; - }; - - template - class BasicResult : public ResultValueBase { - public: - template - explicit BasicResult( BasicResult const &other ) - : ResultValueBase( other.type() ), - m_errorMessage( other.errorMessage() ) - { - assert( type() != ResultBase::Ok ); - } - - template - static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } - static auto ok() -> BasicResult { return { ResultBase::Ok }; } - static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } - static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } - - explicit operator bool() const { return m_type == ResultBase::Ok; } - auto type() const -> ResultBase::Type { return m_type; } - auto errorMessage() const -> std::string { return m_errorMessage; } - - protected: - virtual void enforceOk() const { - // !TBD: If no exceptions, std::terminate here or something - switch( m_type ) { - case ResultBase::LogicError: - throw std::logic_error( m_errorMessage ); - case ResultBase::RuntimeError: - throw std::runtime_error( m_errorMessage ); - case ResultBase::Ok: - break; - } - } - - std::string m_errorMessage; // Only populated if resultType is an error - - BasicResult( ResultBase::Type type, std::string const &message ) - : ResultValueBase(type), - m_errorMessage(message) - { - assert( m_type != ResultBase::Ok ); - } - - using ResultValueBase::ResultValueBase; - using ResultBase::m_type; - }; - - enum class ParseResultType { - Matched, NoMatch, ShortCircuitAll, ShortCircuitSame - }; - - class ParseState { - public: - - ParseState( ParseResultType type, TokenStream const &remainingTokens ) - : m_type(type), - m_remainingTokens( remainingTokens ) - {} - - auto type() const -> ParseResultType { return m_type; } - auto remainingTokens() const -> TokenStream { return m_remainingTokens; } - - private: - ParseResultType m_type; - TokenStream m_remainingTokens; - }; - - using Result = BasicResult; - using ParserResult = BasicResult; - using InternalParseResult = BasicResult; - - struct HelpColumns { - std::string left; - std::string right; - }; - - template - inline auto convertInto( std::string const &source, T& target ) -> ParserResult { - std::stringstream ss; - ss << source; - ss >> target; - if( ss.fail() ) - return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { - target = source; - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { - std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); - if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") - target = true; - else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") - target = false; - else - return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - } - - struct BoundRefBase { - BoundRefBase() = default; - BoundRefBase( BoundRefBase const & ) = delete; - BoundRefBase( BoundRefBase && ) = delete; - BoundRefBase &operator=( BoundRefBase const & ) = delete; - BoundRefBase &operator=( BoundRefBase && ) = delete; - - virtual ~BoundRefBase() = default; - - virtual auto isFlag() const -> bool = 0; - virtual auto isContainer() const -> bool { return false; } - virtual auto setValue( std::string const &arg ) -> ParserResult = 0; - virtual auto setFlag( bool flag ) -> ParserResult = 0; - }; - - struct BoundValueRefBase : BoundRefBase { - auto isFlag() const -> bool override { return false; } - - auto setFlag( bool ) -> ParserResult override { - return ParserResult::logicError( "Flags can only be set on boolean fields" ); - } - }; - - struct BoundFlagRefBase : BoundRefBase { - auto isFlag() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - bool flag; - auto result = convertInto( arg, flag ); - if( result ) - setFlag( flag ); - return result; - } - }; - - template - struct BoundRef : BoundValueRefBase { - T &m_ref; - - explicit BoundRef( T &ref ) : m_ref( ref ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return convertInto( arg, m_ref ); - } - }; - - template - struct BoundRef> : BoundValueRefBase { - std::vector &m_ref; - - explicit BoundRef( std::vector &ref ) : m_ref( ref ) {} - - auto isContainer() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - T temp; - auto result = convertInto( arg, temp ); - if( result ) - m_ref.push_back( temp ); - return result; - } - }; - - struct BoundFlagRef : BoundFlagRefBase { - bool &m_ref; - - explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} - - auto setFlag( bool flag ) -> ParserResult override { - m_ref = flag; - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - struct LambdaInvoker { - static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); - - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - return lambda( arg ); - } - }; - - template<> - struct LambdaInvoker { - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - lambda( arg ); - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp; - auto result = convertInto( arg, temp ); - return !result - ? result - : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - }; - - template - struct BoundLambda : BoundValueRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return invokeLambda::ArgType>( m_lambda, arg ); - } - }; - - template - struct BoundFlagLambda : BoundFlagRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); - - explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setFlag( bool flag ) -> ParserResult override { - return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); - } - }; - - enum class Optionality { Optional, Required }; - - struct Parser; - - class ParserBase { - public: - virtual ~ParserBase() = default; - virtual auto validate() const -> Result { return Result::ok(); } - virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; - virtual auto cardinality() const -> size_t { return 1; } - - auto parse( Args const &args ) const -> InternalParseResult { - return parse( args.exeName(), TokenStream( args ) ); - } - }; - - template - class ComposableParserImpl : public ParserBase { - public: - template - auto operator|( T const &other ) const -> Parser; - }; - - // Common code and state for Args and Opts - template - class ParserRefImpl : public ComposableParserImpl { - protected: - Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; - std::string m_hint; - std::string m_description; - - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} - - public: - template - ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint( hint ) - {} - - template - ParserRefImpl( LambdaT const &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint(hint) - {} - - auto operator()( std::string const &description ) -> DerivedT & { - m_description = description; - return static_cast( *this ); - } - - auto optional() -> DerivedT & { - m_optionality = Optionality::Optional; - return static_cast( *this ); - }; - - auto required() -> DerivedT & { - m_optionality = Optionality::Required; - return static_cast( *this ); - }; - - auto isOptional() const -> bool { - return m_optionality == Optionality::Optional; - } - - auto cardinality() const -> size_t override { - if( m_ref->isContainer() ) - return 0; - else - return 1; - } - - auto hint() const -> std::string { return m_hint; } - }; - - class ExeName : public ComposableParserImpl { - std::shared_ptr m_name; - std::shared_ptr m_ref; - - template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { - return std::make_shared>( lambda) ; - } - - public: - ExeName() : m_name( std::make_shared( "" ) ) {} - - explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); - } - - template - explicit ExeName( LambdaT const& lambda ) : ExeName() { - m_ref = std::make_shared>( lambda ); - } - - // The exe name is not parsed out of the normal tokens, but is handled specially - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - } - - auto name() const -> std::string { return *m_name; } - auto set( std::string const& newName ) -> ParserResult { - - auto lastSlash = newName.find_last_of( "\\/" ); - auto filename = ( lastSlash == std::string::npos ) - ? newName - : newName.substr( lastSlash+1 ); - - *m_name = filename; - if( m_ref ) - return m_ref->setValue( filename ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - class Arg : public ParserRefImpl { - public: - using ParserRefImpl::ParserRefImpl; - - auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - auto const &token = *remainingTokens; - if( token.type != TokenType::Argument ) - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - - auto result = m_ref->setValue( remainingTokens->token ); - if( !result ) - return InternalParseResult( result ); - else - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - }; - - inline auto normaliseOpt( std::string const &optName ) -> std::string { +; +} + +// Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled +class TokenStream { +using Iterator = std::vector::const_iterator; +Iterator it; +Iterator itEnd; +std::vector m_tokenBuffer; + +void loadBuffer() { +m_tokenBuffer.resize( 0 ); + +// Skip any empty strings +while( it != itEnd && it->empty() ) +++it; + +if( it != itEnd ) { +auto const &next = *it; +if( isOptPrefix( next[0] ) ) { +auto delimiterPos = next.find_first_of( " :=" ); +if( delimiterPos != std::string::npos ) { +m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); +m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); +} else { +if( next[1] != '-' && next.size() > 2 ) { +std::string opt = "- "; +for( size_t i = 1; i < next.size(); ++i ) { +opt[1] = next[i]; +m_tokenBuffer.push_back( { TokenType::Option, opt } ); +} +} else { +m_tokenBuffer.push_back( { TokenType::Option, next } ); +} +} +} else { +m_tokenBuffer.push_back( { TokenType::Argument, next } ); +} +} +} + +public: +explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} + +TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { +loadBuffer(); +} + +explicit operator bool() const { +return !m_tokenBuffer.empty() || it != itEnd; +} + +auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } + +auto operator*() const -> Token { +assert( !m_tokenBuffer.empty() ); +return m_tokenBuffer.front(); +} + +auto operator->() const -> Token const * { +assert( !m_tokenBuffer.empty() ); +return &m_tokenBuffer.front(); +} + +auto operator++() -> TokenStream & { +if( m_tokenBuffer.size() >= 2 ) { +m_tokenBuffer.erase( m_tokenBuffer.begin() ); +} else { +if( it != itEnd ) +++it; +loadBuffer(); +} +return *this; +} +}; + +class ResultBase { +public: +enum Type { +Ok, LogicError, RuntimeError +}; + +protected: +ResultBase( Type type ) : m_type( type ) {} +virtual ~ResultBase() = default; + +virtual void enforceOk() const = 0; + +Type m_type; +}; + +template +class ResultValueBase : public ResultBase { +public: +auto value() const -> T const & { +enforceOk(); +return m_value; +} + +protected: +ResultValueBase( Type type ) : ResultBase( type ) {} + +ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { +if( m_type == ResultBase::Ok ) +new( &m_value ) T( other.m_value ); +} + +ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { +new( &m_value ) T( value ); +} + +auto operator=( ResultValueBase const &other ) -> ResultValueBase & { +if( m_type == ResultBase::Ok ) +m_value.~T(); +ResultBase::operator=(other); +if( m_type == ResultBase::Ok ) +new( &m_value ) T( other.m_value ); +return *this; +} + +~ResultValueBase() override { +if( m_type == Ok ) +m_value.~T(); +} + +union { +T m_value; +}; +}; + +template<> +class ResultValueBase : public ResultBase { +protected: +using ResultBase::ResultBase; +}; + +template +class BasicResult : public ResultValueBase { +public: +template +explicit BasicResult( BasicResult const &other ) +: ResultValueBase( other.type() ), +m_errorMessage( other.errorMessage() ) +{ +assert( type() != ResultBase::Ok ); +} + +template +static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } +static auto ok() -> BasicResult { return { ResultBase::Ok }; } +static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } +static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } + +explicit operator bool() const { return m_type == ResultBase::Ok; } +auto type() const -> ResultBase::Type { return m_type; } +auto errorMessage() const -> std::string { return m_errorMessage; } + +protected: +void enforceOk() const override { + +// Errors shouldn't reach this point, but if they do +// the actual error message will be in m_errorMessage +assert( m_type != ResultBase::LogicError ); +assert( m_type != ResultBase::RuntimeError ); +if( m_type != ResultBase::Ok ) +std::abort(); +} + +std::string m_errorMessage; // Only populated if resultType is an error + +BasicResult( ResultBase::Type type, std::string const &message ) +: ResultValueBase(type), +m_errorMessage(message) +{ +assert( m_type != ResultBase::Ok ); +} + +using ResultValueBase::ResultValueBase; +using ResultBase::m_type; +}; + +enum class ParseResultType { +Matched, NoMatch, ShortCircuitAll, ShortCircuitSame +}; + +class ParseState { +public: + +ParseState( ParseResultType type, TokenStream const &remainingTokens ) +: m_type(type), +m_remainingTokens( remainingTokens ) +{} + +auto type() const -> ParseResultType { return m_type; } +auto remainingTokens() const -> TokenStream { return m_remainingTokens; } + +private: +ParseResultType m_type; +TokenStream m_remainingTokens; +}; + +using Result = BasicResult; +using ParserResult = BasicResult; +using InternalParseResult = BasicResult; + +struct HelpColumns { +std::string left; +std::string right; +}; + +template +inline auto convertInto( std::string const &source, T& target ) -> ParserResult { +std::stringstream ss; +ss << source; +ss >> target; +if( ss.fail() ) +return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); +else +return ParserResult::ok( ParseResultType::Matched ); +} +inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { +target = source; +return ParserResult::ok( ParseResultType::Matched ); +} +inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { +std::string srcLC = source; +std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( std::tolower(c) ); } ); +if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") +target = true; +else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") +target = false; +else +return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); +return ParserResult::ok( ParseResultType::Matched ); +} +#ifdef CLARA_CONFIG_OPTIONAL_TYPE +template +inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { +T temp; +auto result = convertInto( source, temp ); +if( result ) +target = std::move(temp); +return result; +} +#endif // CLARA_CONFIG_OPTIONAL_TYPE + +struct NonCopyable { +NonCopyable() = default; +NonCopyable( NonCopyable const & ) = delete; +NonCopyable( NonCopyable && ) = delete; +NonCopyable &operator=( NonCopyable const & ) = delete; +NonCopyable &operator=( NonCopyable && ) = delete; +}; + +struct BoundRef : NonCopyable { +virtual ~BoundRef() = default; +virtual auto isContainer() const -> bool { return false; } +virtual auto isFlag() const -> bool { return false; } +}; +struct BoundValueRefBase : BoundRef { +virtual auto setValue( std::string const &arg ) -> ParserResult = 0; +}; +struct BoundFlagRefBase : BoundRef { +virtual auto setFlag( bool flag ) -> ParserResult = 0; +virtual auto isFlag() const -> bool { return true; } +}; + +template +struct BoundValueRef : BoundValueRefBase { +T &m_ref; + +explicit BoundValueRef( T &ref ) : m_ref( ref ) {} + +auto setValue( std::string const &arg ) -> ParserResult override { +return convertInto( arg, m_ref ); +} +}; + +template +struct BoundValueRef> : BoundValueRefBase { +std::vector &m_ref; + +explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} + +auto isContainer() const -> bool override { return true; } + +auto setValue( std::string const &arg ) -> ParserResult override { +T temp; +auto result = convertInto( arg, temp ); +if( result ) +m_ref.push_back( temp ); +return result; +} +}; + +struct BoundFlagRef : BoundFlagRefBase { +bool &m_ref; + +explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} + +auto setFlag( bool flag ) -> ParserResult override { +m_ref = flag; +return ParserResult::ok( ParseResultType::Matched ); +} +}; + +template +struct LambdaInvoker { +static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); + +template +static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { +return lambda( arg ); +} +}; + +template<> +struct LambdaInvoker { +template +static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { +lambda( arg ); +return ParserResult::ok( ParseResultType::Matched ); +} +}; + +template +inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { +ArgType temp{}; +auto result = convertInto( arg, temp ); +return !result +? result +: LambdaInvoker::ReturnType>::invoke( lambda, temp ); +} + +template +struct BoundLambda : BoundValueRefBase { +L m_lambda; + +static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); +explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} + +auto setValue( std::string const &arg ) -> ParserResult override { +return invokeLambda::ArgType>( m_lambda, arg ); +} +}; + +template +struct BoundFlagLambda : BoundFlagRefBase { +L m_lambda; + +static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); +static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); + +explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} + +auto setFlag( bool flag ) -> ParserResult override { +return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); +} +}; + +enum class Optionality { Optional, Required }; + +struct Parser; + +class ParserBase { +public: +virtual ~ParserBase() = default; +virtual auto validate() const -> Result { return Result::ok(); } +virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; +virtual auto cardinality() const -> size_t { return 1; } + +auto parse( Args const &args ) const -> InternalParseResult { +return parse( args.exeName(), TokenStream( args ) ); +} +}; + +template +class ComposableParserImpl : public ParserBase { +public: +template +auto operator|( T const &other ) const -> Parser; + +template +auto operator+( T const &other ) const -> Parser; +}; + +// Common code and state for Args and Opts +template +class ParserRefImpl : public ComposableParserImpl { +protected: +Optionality m_optionality = Optionality::Optional; +std::shared_ptr m_ref; +std::string m_hint; +std::string m_description; + +explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} + +public: +template +ParserRefImpl( T &ref, std::string const &hint ) +: m_ref( std::make_shared>( ref ) ), +m_hint( hint ) +{} + +template +ParserRefImpl( LambdaT const &ref, std::string const &hint ) +: m_ref( std::make_shared>( ref ) ), +m_hint(hint) +{} + +auto operator()( std::string const &description ) -> DerivedT & { +m_description = description; +return static_cast( *this ); +} + +auto optional() -> DerivedT & { +m_optionality = Optionality::Optional; +return static_cast( *this ); +}; + +auto required() -> DerivedT & { +m_optionality = Optionality::Required; +return static_cast( *this ); +}; + +auto isOptional() const -> bool { +return m_optionality == Optionality::Optional; +} + +auto cardinality() const -> size_t override { +if( m_ref->isContainer() ) +return 0; +else +return 1; +} + +auto hint() const -> std::string { return m_hint; } +}; + +class ExeName : public ComposableParserImpl { +std::shared_ptr m_name; +std::shared_ptr m_ref; + +template +static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { +return std::make_shared>( lambda) ; +} + +public: +ExeName() : m_name( std::make_shared( "" ) ) {} + +explicit ExeName( std::string &ref ) : ExeName() { +m_ref = std::make_shared>( ref ); +} + +template +explicit ExeName( LambdaT const& lambda ) : ExeName() { +m_ref = std::make_shared>( lambda ); +} + +// The exe name is not parsed out of the normal tokens, but is handled specially +auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { +return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); +} + +auto name() const -> std::string { return *m_name; } +auto set( std::string const& newName ) -> ParserResult { + +auto lastSlash = newName.find_last_of( "\\/" ); +auto filename = ( lastSlash == std::string::npos ) +? newName +: newName.substr( lastSlash+1 ); + +*m_name = filename; +if( m_ref ) +return m_ref->setValue( filename ); +else +return ParserResult::ok( ParseResultType::Matched ); +} +}; + +class Arg : public ParserRefImpl { +public: +using ParserRefImpl::ParserRefImpl; + +auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { +auto validationResult = validate(); +if( !validationResult ) +return InternalParseResult( validationResult ); + +auto remainingTokens = tokens; +auto const &token = *remainingTokens; +if( token.type != TokenType::Argument ) +return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); + +assert( !m_ref->isFlag() ); +auto valueRef = static_cast( m_ref.get() ); + +auto result = valueRef->setValue( remainingTokens->token ); +if( !result ) +return InternalParseResult( result ); +else +return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); +} +}; + +inline auto normaliseOpt( std::string const &optName ) -> std::string { #ifdef CATCH_PLATFORM_WINDOWS - if( optName[0] == '/' ) - return "-" + optName.substr( 1 ); - else +if( optName[0] == '/' ) +return "-" + optName.substr( 1 ); +else #endif - return optName; - } +return optName; +} - class Opt : public ParserRefImpl { - protected: - std::vector m_optNames; +class Opt : public ParserRefImpl { +protected: +std::vector m_optNames; - public: - template - explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} +public: +template +explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} - explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} +explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} - template - Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} +template +Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - template - Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} +template +Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - auto operator[]( std::string const &optName ) -> Opt & { - m_optNames.push_back( optName ); - return *this; - } +auto operator[]( std::string const &optName ) -> Opt & { +m_optNames.push_back( optName ); +return *this; +} - auto getHelpColumns() const -> std::vector { - std::ostringstream oss; - bool first = true; - for( auto const &opt : m_optNames ) { - if (first) - first = false; - else - oss << ", "; - oss << opt; - } - if( !m_hint.empty() ) - oss << " <" << m_hint << ">"; - return { { oss.str(), m_description } }; - } +auto getHelpColumns() const -> std::vector { +std::ostringstream oss; +bool first = true; +for( auto const &opt : m_optNames ) { +if (first) +first = false; +else +oss << ", "; +oss << opt; +} +if( !m_hint.empty() ) +oss << " <" << m_hint << ">"; +return { { oss.str(), m_description } }; +} - auto isMatch( std::string const &optToken ) const -> bool { - auto normalisedToken = normaliseOpt( optToken ); - for( auto const &name : m_optNames ) { - if( normaliseOpt( name ) == normalisedToken ) - return true; - } - return false; - } +auto isMatch( std::string const &optToken ) const -> bool { +auto normalisedToken = normaliseOpt( optToken ); +for( auto const &name : m_optNames ) { +if( normaliseOpt( name ) == normalisedToken ) +return true; +} +return false; +} - using ParserBase::parse; +using ParserBase::parse; - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); +auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { +auto validationResult = validate(); +if( !validationResult ) +return InternalParseResult( validationResult ); - auto remainingTokens = tokens; - if( remainingTokens && remainingTokens->type == TokenType::Option ) { - auto const &token = *remainingTokens; - if( isMatch(token.token ) ) { - if( m_ref->isFlag() ) { - auto result = m_ref->setFlag( true ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } else { - ++remainingTokens; - if( !remainingTokens ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto const &argToken = *remainingTokens; - if( argToken.type != TokenType::Argument ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto result = m_ref->setValue( argToken.token ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - } - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - } +auto remainingTokens = tokens; +if( remainingTokens && remainingTokens->type == TokenType::Option ) { +auto const &token = *remainingTokens; +if( isMatch(token.token ) ) { +if( m_ref->isFlag() ) { +auto flagRef = static_cast( m_ref.get() ); +auto result = flagRef->setFlag( true ); +if( !result ) +return InternalParseResult( result ); +if( result.value() == ParseResultType::ShortCircuitAll ) +return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); +} else { +auto valueRef = static_cast( m_ref.get() ); +++remainingTokens; +if( !remainingTokens ) +return InternalParseResult::runtimeError( "Expected argument following " + token.token ); +auto const &argToken = *remainingTokens; +if( argToken.type != TokenType::Argument ) +return InternalParseResult::runtimeError( "Expected argument following " + token.token ); +auto result = valueRef->setValue( argToken.token ); +if( !result ) +return InternalParseResult( result ); +if( result.value() == ParseResultType::ShortCircuitAll ) +return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); +} +return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); +} +} +return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); +} - auto validate() const -> Result override { - if( m_optNames.empty() ) - return Result::logicError( "No options supplied to Opt" ); - for( auto const &name : m_optNames ) { - if( name.empty() ) - return Result::logicError( "Option name cannot be empty" ); +auto validate() const -> Result override { +if( m_optNames.empty() ) +return Result::logicError( "No options supplied to Opt" ); +for( auto const &name : m_optNames ) { +if( name.empty() ) +return Result::logicError( "Option name cannot be empty" ); #ifdef CATCH_PLATFORM_WINDOWS - if( name[0] != '-' && name[0] != '/' ) - return Result::logicError( "Option name must begin with '-' or '/'" ); +if( name[0] != '-' && name[0] != '/' ) +return Result::logicError( "Option name must begin with '-' or '/'" ); #else - if( name[0] != '-' ) - return Result::logicError( "Option name must begin with '-'" ); +if( name[0] != '-' ) +return Result::logicError( "Option name must begin with '-'" ); #endif - } - return ParserRefImpl::validate(); - } - }; +} +return ParserRefImpl::validate(); +} +}; - struct Help : Opt { - Help( bool &showHelpFlag ) - : Opt([&]( bool flag ) { - showHelpFlag = flag; - return ParserResult::ok( ParseResultType::ShortCircuitAll ); - }) - { - static_cast( *this ) - ("display usage information") - ["-?"]["-h"]["--help"] - .optional(); - } - }; +struct Help : Opt { +Help( bool &showHelpFlag ) +: Opt([&]( bool flag ) { +showHelpFlag = flag; +return ParserResult::ok( ParseResultType::ShortCircuitAll ); +}) +{ +static_cast( *this ) +("display usage information") +["-?"]["-h"]["--help"] +.optional(); +} +}; - struct Parser : ParserBase { +struct Parser : ParserBase { - mutable ExeName m_exeName; - std::vector m_options; - std::vector m_args; +mutable ExeName m_exeName; +std::vector m_options; +std::vector m_args; - auto operator|=( ExeName const &exeName ) -> Parser & { - m_exeName = exeName; - return *this; - } +auto operator|=( ExeName const &exeName ) -> Parser & { +m_exeName = exeName; +return *this; +} - auto operator|=( Arg const &arg ) -> Parser & { - m_args.push_back(arg); - return *this; - } +auto operator|=( Arg const &arg ) -> Parser & { +m_args.push_back(arg); +return *this; +} - auto operator|=( Opt const &opt ) -> Parser & { - m_options.push_back(opt); - return *this; - } +auto operator|=( Opt const &opt ) -> Parser & { +m_options.push_back(opt); +return *this; +} - auto operator|=( Parser const &other ) -> Parser & { - m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); - m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); - return *this; - } +auto operator|=( Parser const &other ) -> Parser & { +m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); +m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); +return *this; +} - template - auto operator|( T const &other ) const -> Parser { - return Parser( *this ) |= other; - } +template +auto operator|( T const &other ) const -> Parser { +return Parser( *this ) |= other; +} - auto getHelpColumns() const -> std::vector { - std::vector cols; - for (auto const &o : m_options) { - auto childCols = o.getHelpColumns(); - cols.insert( cols.end(), childCols.begin(), childCols.end() ); - } - return cols; - } +// Forward deprecated interface with '+' instead of '|' +template +auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } +template +auto operator+( T const &other ) const -> Parser { return operator|( other ); } - void writeToStream( std::ostream &os ) const { - if (!m_exeName.name().empty()) { - os << "usage:\n" << " " << m_exeName.name() << " "; - bool required = true, first = true; - for( auto const &arg : m_args ) { - if (first) - first = false; - else - os << " "; - if( arg.isOptional() && required ) { - os << "["; - required = false; - } - os << "<" << arg.hint() << ">"; - if( arg.cardinality() == 0 ) - os << " ... "; - } - if( !required ) - os << "]"; - if( !m_options.empty() ) - os << " options"; - os << "\n\nwhere options are:" << std::endl; - } +auto getHelpColumns() const -> std::vector { +std::vector cols; +for (auto const &o : m_options) { +auto childCols = o.getHelpColumns(); +cols.insert( cols.end(), childCols.begin(), childCols.end() ); +} +return cols; +} - auto rows = getHelpColumns(); - size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; - size_t optWidth = 0; - for( auto const &cols : rows ) - optWidth = (std::max)(optWidth, cols.left.size() + 2); +void writeToStream( std::ostream &os ) const { +if (!m_exeName.name().empty()) { +os << "usage:\n" << " " << m_exeName.name() << " "; +bool required = true, first = true; +for( auto const &arg : m_args ) { +if (first) +first = false; +else +os << " "; +if( arg.isOptional() && required ) { +os << "["; +required = false; +} +os << "<" << arg.hint() << ">"; +if( arg.cardinality() == 0 ) +os << " ... "; +} +if( !required ) +os << "]"; +if( !m_options.empty() ) +os << " options"; +os << "\n\nwhere options are:" << std::endl; +} - for( auto const &cols : rows ) { - auto row = - TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + - TextFlow::Spacer(4) + - TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); - os << row << std::endl; - } - } +auto rows = getHelpColumns(); +size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; +size_t optWidth = 0; +for( auto const &cols : rows ) +optWidth = (std::max)(optWidth, cols.left.size() + 2); - friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { - parser.writeToStream( os ); - return os; - } +optWidth = (std::min)(optWidth, consoleWidth/2); - auto validate() const -> Result override { - for( auto const &opt : m_options ) { - auto result = opt.validate(); - if( !result ) - return result; - } - for( auto const &arg : m_args ) { - auto result = arg.validate(); - if( !result ) - return result; - } - return Result::ok(); - } +for( auto const &cols : rows ) { +auto row = +TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + +TextFlow::Spacer(4) + +TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); +os << row << std::endl; +} +} - using ParserBase::parse; +friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { +parser.writeToStream( os ); +return os; +} - auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { +auto validate() const -> Result override { +for( auto const &opt : m_options ) { +auto result = opt.validate(); +if( !result ) +return result; +} +for( auto const &arg : m_args ) { +auto result = arg.validate(); +if( !result ) +return result; +} +return Result::ok(); +} - struct ParserInfo { - ParserBase const* parser = nullptr; - size_t count = 0; - }; - const size_t totalParsers = m_options.size() + m_args.size(); - assert( totalParsers < 512 ); - // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do - ParserInfo parseInfos[512]; +using ParserBase::parse; - { - size_t i = 0; - for (auto const &opt : m_options) parseInfos[i++].parser = &opt; - for (auto const &arg : m_args) parseInfos[i++].parser = &arg; - } +auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { - m_exeName.set( exeName ); +struct ParserInfo { +ParserBase const* parser = nullptr; +size_t count = 0; +}; +const size_t totalParsers = m_options.size() + m_args.size(); +assert( totalParsers < 512 ); +// ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do +ParserInfo parseInfos[512]; - auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - while( result.value().remainingTokens() ) { - bool tokenParsed = false; +{ +size_t i = 0; +for (auto const &opt : m_options) parseInfos[i++].parser = &opt; +for (auto const &arg : m_args) parseInfos[i++].parser = &arg; +} - for( size_t i = 0; i < totalParsers; ++i ) { - auto& parseInfo = parseInfos[i]; - if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { - result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); - if (!result) - return result; - if (result.value().type() != ParseResultType::NoMatch) { - tokenParsed = true; - ++parseInfo.count; - break; - } - } - } +m_exeName.set( exeName ); - if( result.value().type() == ParseResultType::ShortCircuitAll ) - return result; - if( !tokenParsed ) - return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); - } - // !TBD Check missing required options - return result; - } - }; +auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); +while( result.value().remainingTokens() ) { +bool tokenParsed = false; - template - template - auto ComposableParserImpl::operator|( T const &other ) const -> Parser { - return Parser() | static_cast( *this ) | other; - } +for( size_t i = 0; i < totalParsers; ++i ) { +auto& parseInfo = parseInfos[i]; +if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { +result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); +if (!result) +return result; +if (result.value().type() != ParseResultType::NoMatch) { +tokenParsed = true; +++parseInfo.count; +break; +} +} +} + +if( result.value().type() == ParseResultType::ShortCircuitAll ) +return result; +if( !tokenParsed ) +return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); +} +// !TBD Check missing required options +return result; +} +}; + +template +template +auto ComposableParserImpl::operator|( T const &other ) const -> Parser { +return Parser() | static_cast( *this ) | other; +} } // namespace detail // A Combined parser @@ -5581,7 +7795,7 @@ using detail::ParserResult; // end catch_clara.h namespace Catch { - clara::Parser makeCommandLineParser( ConfigData& config ); +clara::Parser makeCommandLineParser( ConfigData& config ); } // end namespace Catch @@ -5591,171 +7805,193 @@ namespace Catch { namespace Catch { - clara::Parser makeCommandLineParser( ConfigData& config ) { +clara::Parser makeCommandLineParser( ConfigData& config ) { - using namespace clara; +using namespace clara; - auto const setWarning = [&]( std::string const& warning ) { - if( warning != "NoAssertions" ) - return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); - config.warnings = static_cast( config.warnings | WarnAbout::NoAssertions ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const loadTestNamesFromFile = [&]( std::string const& filename ) { - std::ifstream f( filename.c_str() ); - if( !f.is_open() ) - return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); +auto const setWarning = [&]( std::string const& warning ) { +auto warningSet = [&]() { +if( warning == "NoAssertions" ) +return WarnAbout::NoAssertions; - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - config.testsOrTags.push_back( line + ',' ); - } - } - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setTestOrder = [&]( std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setRngSeed = [&]( std::string const& seed ) { - if( seed != "time" ) - return clara::detail::convertInto( seed, config.rngSeed ); - config.rngSeed = static_cast( std::time(nullptr) ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setColourUsage = [&]( std::string const& useColour ) { - auto mode = toLower( useColour ); +if ( warning == "NoTests" ) +return WarnAbout::NoTests; - if( mode == "yes" ) - config.useColour = UseColour::Yes; - else if( mode == "no" ) - config.useColour = UseColour::No; - else if( mode == "auto" ) - config.useColour = UseColour::Auto; - else - return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setWaitForKeypress = [&]( std::string const& keypress ) { - auto keypressLc = toLower( keypress ); - if( keypressLc == "start" ) - config.waitForKeypress = WaitForKeypress::BeforeStart; - else if( keypressLc == "exit" ) - config.waitForKeypress = WaitForKeypress::BeforeExit; - else if( keypressLc == "both" ) - config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; - else - return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setVerbosity = [&]( std::string const& verbosity ) { - auto lcVerbosity = toLower( verbosity ); - if( lcVerbosity == "quiet" ) - config.verbosity = Verbosity::Quiet; - else if( lcVerbosity == "normal" ) - config.verbosity = Verbosity::Normal; - else if( lcVerbosity == "high" ) - config.verbosity = Verbosity::High; - else - return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; +return WarnAbout::Nothing; +}(); - auto cli - = ExeName( config.processName ) - | Help( config.showHelp ) - | Opt( config.listTests ) - ["-l"]["--list-tests"] - ( "list all/matching test cases" ) - | Opt( config.listTags ) - ["-t"]["--list-tags"] - ( "list all/matching tags" ) - | Opt( config.showSuccessfulTests ) - ["-s"]["--success"] - ( "include successful tests in output" ) - | Opt( config.shouldDebugBreak ) - ["-b"]["--break"] - ( "break into debugger on failure" ) - | Opt( config.noThrow ) - ["-e"]["--nothrow"] - ( "skip exception tests" ) - | Opt( config.showInvisibles ) - ["-i"]["--invisibles"] - ( "show invisibles (tabs, newlines)" ) - | Opt( config.outputFilename, "filename" ) - ["-o"]["--out"] - ( "output filename" ) - | Opt( config.reporterNames, "name" ) - ["-r"]["--reporter"] - ( "reporter to use (defaults to console)" ) - | Opt( config.name, "name" ) - ["-n"]["--name"] - ( "suite name" ) - | Opt( [&]( bool ){ config.abortAfter = 1; } ) - ["-a"]["--abort"] - ( "abort at first failure" ) - | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) - ["-x"]["--abortx"] - ( "abort after x failures" ) - | Opt( setWarning, "warning name" ) - ["-w"]["--warn"] - ( "enable warnings" ) - | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) - ["-d"]["--durations"] - ( "show test durations" ) - | Opt( loadTestNamesFromFile, "filename" ) - ["-f"]["--input-file"] - ( "load test names to run from a file" ) - | Opt( config.filenamesAsTags ) - ["-#"]["--filenames-as-tags"] - ( "adds a tag for the filename" ) - | Opt( config.sectionsToRun, "section name" ) - ["-c"]["--section"] - ( "specify section to run" ) - | Opt( setVerbosity, "quiet|normal|high" ) - ["-v"]["--verbosity"] - ( "set output verbosity" ) - | Opt( config.listTestNamesOnly ) - ["--list-test-names-only"] - ( "list all/matching test cases names only" ) - | Opt( config.listReporters ) - ["--list-reporters"] - ( "list all reporters" ) - | Opt( setTestOrder, "decl|lex|rand" ) - ["--order"] - ( "test case order (defaults to decl)" ) - | Opt( setRngSeed, "'time'|number" ) - ["--rng-seed"] - ( "set a specific seed for random numbers" ) - | Opt( setColourUsage, "yes|no" ) - ["--use-colour"] - ( "should output be colourised" ) - | Opt( config.libIdentify ) - ["--libidentify"] - ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "start|exit|both" ) - ["--wait-for-keypress"] - ( "waits for a keypress before exiting" ) - | Opt( config.benchmarkResolutionMultiple, "multiplier" ) - ["--benchmark-resolution-multiple"] - ( "multiple of clock resolution to run benchmarks" ) +if (warningSet == WarnAbout::Nothing) +return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); +config.warnings = static_cast( config.warnings | warningSet ); +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const loadTestNamesFromFile = [&]( std::string const& filename ) { +std::ifstream f( filename.c_str() ); +if( !f.is_open() ) +return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); - | Arg( config.testsOrTags, "test name|pattern|tags" ) - ( "which test or tests to use" ); +std::string line; +while( std::getline( f, line ) ) { +line = trim(line); +if( !line.empty() && !startsWith( line, '#' ) ) { +if( !startsWith( line, '"' ) ) +line = '"' + line + '"'; +config.testsOrTags.push_back( line + ',' ); +} +} +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const setTestOrder = [&]( std::string const& order ) { +if( startsWith( "declared", order ) ) +config.runOrder = RunTests::InDeclarationOrder; +else if( startsWith( "lexical", order ) ) +config.runOrder = RunTests::InLexicographicalOrder; +else if( startsWith( "random", order ) ) +config.runOrder = RunTests::InRandomOrder; +else +return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const setRngSeed = [&]( std::string const& seed ) { +if( seed != "time" ) +return clara::detail::convertInto( seed, config.rngSeed ); +config.rngSeed = static_cast( std::time(nullptr) ); +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const setColourUsage = [&]( std::string const& useColour ) { +auto mode = toLower( useColour ); - return cli; - } +if( mode == "yes" ) +config.useColour = UseColour::Yes; +else if( mode == "no" ) +config.useColour = UseColour::No; +else if( mode == "auto" ) +config.useColour = UseColour::Auto; +else +return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const setWaitForKeypress = [&]( std::string const& keypress ) { +auto keypressLc = toLower( keypress ); +if( keypressLc == "start" ) +config.waitForKeypress = WaitForKeypress::BeforeStart; +else if( keypressLc == "exit" ) +config.waitForKeypress = WaitForKeypress::BeforeExit; +else if( keypressLc == "both" ) +config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; +else +return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const setVerbosity = [&]( std::string const& verbosity ) { +auto lcVerbosity = toLower( verbosity ); +if( lcVerbosity == "quiet" ) +config.verbosity = Verbosity::Quiet; +else if( lcVerbosity == "normal" ) +config.verbosity = Verbosity::Normal; +else if( lcVerbosity == "high" ) +config.verbosity = Verbosity::High; +else +return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); +return ParserResult::ok( ParseResultType::Matched ); +}; +auto const setReporter = [&]( std::string const& reporter ) { +IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + +auto lcReporter = toLower( reporter ); +auto result = factories.find( lcReporter ); + +if( factories.end() != result ) +config.reporterName = lcReporter; +else +return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); +return ParserResult::ok( ParseResultType::Matched ); +}; + +auto cli += ExeName( config.processName ) +| Help( config.showHelp ) +| Opt( config.listTests ) +["-l"]["--list-tests"] +( "list all/matching test cases" ) +| Opt( config.listTags ) +["-t"]["--list-tags"] +( "list all/matching tags" ) +| Opt( config.showSuccessfulTests ) +["-s"]["--success"] +( "include successful tests in output" ) +| Opt( config.shouldDebugBreak ) +["-b"]["--break"] +( "break into debugger on failure" ) +| Opt( config.noThrow ) +["-e"]["--nothrow"] +( "skip exception tests" ) +| Opt( config.showInvisibles ) +["-i"]["--invisibles"] +( "show invisibles (tabs, newlines)" ) +| Opt( config.outputFilename, "filename" ) +["-o"]["--out"] +( "output filename" ) +| Opt( setReporter, "name" ) +["-r"]["--reporter"] +( "reporter to use (defaults to console)" ) +| Opt( config.name, "name" ) +["-n"]["--name"] +( "suite name" ) +| Opt( [&]( bool ){ config.abortAfter = 1; } ) +["-a"]["--abort"] +( "abort at first failure" ) +| Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) +["-x"]["--abortx"] +( "abort after x failures" ) +| Opt( setWarning, "warning name" ) +["-w"]["--warn"] +( "enable warnings" ) +| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) +["-d"]["--durations"] +( "show test durations" ) +| Opt( loadTestNamesFromFile, "filename" ) +["-f"]["--input-file"] +( "load test names to run from a file" ) +| Opt( config.filenamesAsTags ) +["-#"]["--filenames-as-tags"] +( "adds a tag for the filename" ) +| Opt( config.sectionsToRun, "section name" ) +["-c"]["--section"] +( "specify section to run" ) +| Opt( setVerbosity, "quiet|normal|high" ) +["-v"]["--verbosity"] +( "set output verbosity" ) +| Opt( config.listTestNamesOnly ) +["--list-test-names-only"] +( "list all/matching test cases names only" ) +| Opt( config.listReporters ) +["--list-reporters"] +( "list all reporters" ) +| Opt( setTestOrder, "decl|lex|rand" ) +["--order"] +( "test case order (defaults to decl)" ) +| Opt( setRngSeed, "'time'|number" ) +["--rng-seed"] +( "set a specific seed for random numbers" ) +| Opt( setColourUsage, "yes|no" ) +["--use-colour"] +( "should output be colourised" ) +| Opt( config.libIdentify ) +["--libidentify"] +( "report name and version according to libidentify standard" ) +| Opt( setWaitForKeypress, "start|exit|both" ) +["--wait-for-keypress"] +( "waits for a keypress before exiting" ) +| Opt( config.benchmarkResolutionMultiple, "multiplier" ) +["--benchmark-resolution-multiple"] +( "multiple of clock resolution to run benchmarks" ) + +| Arg( config.testsOrTags, "test name|pattern|tags" ) +( "which test or tests to use" ); + +return cli; +} } // end namespace Catch // end catch_commandline.cpp @@ -5766,39 +8002,33 @@ namespace Catch { namespace Catch { - SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - bool SourceLineInfo::empty() const noexcept { - return file[0] == '\0'; - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { - return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); - } +bool SourceLineInfo::empty() const noexcept { +return file[0] == '\0'; +} +bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { +return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); +} +bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { +// We can assume that the same file will usually have the same pointer. +// Thus, if the pointers are the same, there is no point in calling the strcmp +return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); +} - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; +os << info.file << '(' << info.line << ')'; #else - os << info.file << ':' << info.line; +os << info.file << ':' << info.line; #endif - return os; - } +return os; +} - bool isTrue( bool value ){ return value; } - bool alwaysTrue() { return true; } - bool alwaysFalse() { return false; } +std::string StreamEndStop::operator+() const { +return std::string(); +} - std::string StreamEndStop::operator+() const { - return std::string(); - } - - NonCopyable::NonCopyable() = default; - NonCopyable::~NonCopyable() = default; +NonCopyable::NonCopyable() = default; +NonCopyable::~NonCopyable() = default; } // end catch_common.cpp @@ -5806,64 +8036,59 @@ namespace Catch { namespace Catch { - Config::Config( ConfigData const& data ) - : m_data( data ), - m_stream( openStream() ) - { - if( !data.testsOrTags.empty() ) { - TestSpecParser parser( ITagAliasRegistry::get() ); - for( auto const& testOrTags : data.testsOrTags ) - parser.parse( testOrTags ); - m_testSpec = parser.testSpec(); - } - } +Config::Config( ConfigData const& data ) +: m_data( data ), +m_stream( openStream() ) +{ +TestSpecParser parser(ITagAliasRegistry::get()); +if (!data.testsOrTags.empty()) { +m_hasTestFilters = true; +for( auto const& testOrTags : data.testsOrTags ) +parser.parse( testOrTags ); +} +m_testSpec = parser.testSpec(); +} - std::string const& Config::getFilename() const { - return m_data.outputFilename ; - } +std::string const& Config::getFilename() const { +return m_data.outputFilename ; +} - bool Config::listTests() const { return m_data.listTests; } - bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool Config::listTags() const { return m_data.listTags; } - bool Config::listReporters() const { return m_data.listReporters; } +bool Config::listTests() const { return m_data.listTests; } +bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } +bool Config::listTags() const { return m_data.listTags; } +bool Config::listReporters() const { return m_data.listReporters; } - std::string Config::getProcessName() const { return m_data.processName; } +std::string Config::getProcessName() const { return m_data.processName; } +std::string const& Config::getReporterName() const { return m_data.reporterName; } - std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } +std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } +std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } - TestSpec const& Config::testSpec() const { return m_testSpec; } +TestSpec const& Config::testSpec() const { return m_testSpec; } +bool Config::hasTestFilters() const { return m_hasTestFilters; } - bool Config::showHelp() const { return m_data.showHelp; } +bool Config::showHelp() const { return m_data.showHelp; } - // IConfig interface - bool Config::allowThrows() const { return !m_data.noThrow; } - std::ostream& Config::stream() const { return m_stream->stream(); } - std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - bool Config::warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } - ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } - RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } - unsigned int Config::rngSeed() const { return m_data.rngSeed; } - int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } - UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } - bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } - int Config::abortAfter() const { return m_data.abortAfter; } - bool Config::showInvisibles() const { return m_data.showInvisibles; } - Verbosity Config::verbosity() const { return m_data.verbosity; } +// IConfig interface +bool Config::allowThrows() const { return !m_data.noThrow; } +std::ostream& Config::stream() const { return m_stream->stream(); } +std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } +bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } +bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } +bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } +ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } +RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } +unsigned int Config::rngSeed() const { return m_data.rngSeed; } +int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } +UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } +bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } +int Config::abortAfter() const { return m_data.abortAfter; } +bool Config::showInvisibles() const { return m_data.showInvisibles; } +Verbosity Config::verbosity() const { return m_data.verbosity; } - IStream const* Config::openStream() { - if( m_data.outputFilename.empty() ) - return new CoutStream(); - else if( m_data.outputFilename[0] == '%' ) { - if( m_data.outputFilename == "%debug" ) - return new DebugOutStream(); - else - CATCH_ERROR( "Unrecognised stream: '" << m_data.outputFilename << "'" ); - } - else - return new FileStream( m_data.outputFilename ); - } +IStream const* Config::openStream() { +return Catch::makeStream(m_data.outputFilename); +} } // end namespace Catch // end catch_config.cpp @@ -5878,65 +8103,37 @@ namespace Catch { namespace Catch { - class ErrnoGuard { - public: - ErrnoGuard(); - ~ErrnoGuard(); - private: - int m_oldErrno; - }; +class ErrnoGuard { +public: +ErrnoGuard(); +~ErrnoGuard(); +private: +int m_oldErrno; +}; } // end catch_errno_guard.h -// start catch_windows_h_proxy.h +#include - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -#ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif - -#endif // defined(CATCH_PLATFORM_WINDOWS) - -// end catch_windows_h_proxy.h namespace Catch { - namespace { +namespace { - struct IColourImpl { - virtual ~IColourImpl() = default; - virtual void use( Colour::Code _colourCode ) = 0; - }; +struct IColourImpl { +virtual ~IColourImpl() = default; +virtual void use( Colour::Code _colourCode ) = 0; +}; - struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} +struct NoColourImpl : IColourImpl { +void use( Colour::Code ) {} - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; +static IColourImpl* instance() { +static NoColourImpl s_instance; +return &s_instance; +} +}; - } // anon namespace +} // anon namespace } // namespace Catch #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) @@ -5952,58 +8149,62 @@ namespace Catch { namespace Catch { namespace { - class Win32ColourImpl : public IColourImpl { - public: - Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); - originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); - } +class Win32ColourImpl : public IColourImpl { +public: +Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) +{ +CONSOLE_SCREEN_BUFFER_INFO csbiInfo; +GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); +originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); +originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); +} - virtual void use( Colour::Code _colourCode ) override { - switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalForegroundAttributes ); - case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Red: return setTextAttribute( FOREGROUND_RED ); - case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); +void use( Colour::Code _colourCode ) override { +switch( _colourCode ) { +case Colour::None: return setTextAttribute( originalForegroundAttributes ); +case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); +case Colour::Red: return setTextAttribute( FOREGROUND_RED ); +case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); +case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); +case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); +case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); +case Colour::Grey: return setTextAttribute( 0 ); - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); +case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); +case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); +case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); +case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); +case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - } - } +case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - private: - void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); - } - HANDLE stdoutHandle; - WORD originalForegroundAttributes; - WORD originalBackgroundAttributes; - }; +default: +CATCH_ERROR( "Unknown colour requested" ); +} +} - IColourImpl* platformColourInstance() { - static Win32ColourImpl s_instance; +private: +void setTextAttribute( WORD _textAttribute ) { +SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); +} +HANDLE stdoutHandle; +WORD originalForegroundAttributes; +WORD originalBackgroundAttributes; +}; - IConfigPtr config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = UseColour::Yes; - return colourMode == UseColour::Yes - ? &s_instance - : NoColourImpl::instance(); - } +IColourImpl* platformColourInstance() { +static Win32ColourImpl s_instance; + +IConfigPtr config = getCurrentContext().getConfig(); +UseColour::YesOrNo colourMode = config +? config->useColour() +: UseColour::Auto; +if( colourMode == UseColour::Auto ) +colourMode = UseColour::Yes; +return colourMode == UseColour::Yes +? &s_instance +: NoColourImpl::instance(); +} } // end anon namespace } // end namespace Catch @@ -6015,63 +8216,71 @@ namespace { namespace Catch { namespace { - // use POSIX/ ANSI console terminal codes - // Thanks to Adam Strzelecki for original contribution - // (http://github.com/nanoant) - // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public IColourImpl { - public: - virtual void use( Colour::Code _colourCode ) override { - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0;34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); +// use POSIX/ ANSI console terminal codes +// Thanks to Adam Strzelecki for original contribution +// (http://github.com/nanoant) +// https://github.com/philsquared/Catch/pull/131 +class PosixColourImpl : public IColourImpl { +public: +void use( Colour::Code _colourCode ) override { +switch( _colourCode ) { +case Colour::None: +case Colour::White: return setColour( "[0m" ); +case Colour::Red: return setColour( "[0;31m" ); +case Colour::Green: return setColour( "[0;32m" ); +case Colour::Blue: return setColour( "[0;34m" ); +case Colour::Cyan: return setColour( "[0;36m" ); +case Colour::Yellow: return setColour( "[0;33m" ); +case Colour::Grey: return setColour( "[1;30m" ); - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); +case Colour::LightGrey: return setColour( "[0;37m" ); +case Colour::BrightRed: return setColour( "[1;31m" ); +case Colour::BrightGreen: return setColour( "[1;32m" ); +case Colour::BrightWhite: return setColour( "[1;37m" ); +case Colour::BrightYellow: return setColour( "[1;33m" ); - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - } - } - static IColourImpl* instance() { - static PosixColourImpl s_instance; - return &s_instance; - } +case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); +default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); +} +} +static IColourImpl* instance() { +static PosixColourImpl s_instance; +return &s_instance; +} - private: - void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; - } - }; +private: +void setColour( const char* _escapeCode ) { +getCurrentContext().getConfig()->stream() +<< '\033' << _escapeCode; +} +}; - bool useColourOnPlatform() { - return +bool useColourOnPlatform() { +return #ifdef CATCH_PLATFORM_MAC - !isDebuggerActive() && +!isDebuggerActive() && #endif - isatty(STDOUT_FILENO); - } - IColourImpl* platformColourInstance() { - ErrnoGuard guard; - IConfigPtr config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = useColourOnPlatform() - ? UseColour::Yes - : UseColour::No; - return colourMode == UseColour::Yes - ? PosixColourImpl::instance() - : NoColourImpl::instance(); - } +#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) +isatty(STDOUT_FILENO) +#else +false +#endif +; +} +IColourImpl* platformColourInstance() { +ErrnoGuard guard; +IConfigPtr config = getCurrentContext().getConfig(); +UseColour::YesOrNo colourMode = config +? config->useColour() +: UseColour::Auto; +if( colourMode == UseColour::Auto ) +colourMode = useColourOnPlatform() +? UseColour::Yes +: UseColour::No; +return colourMode == UseColour::Yes +? PosixColourImpl::instance() +: NoColourImpl::instance(); +} } // end anon namespace } // end namespace Catch @@ -6080,7 +8289,7 @@ namespace { namespace Catch { - static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } +static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } } // end namespace Catch @@ -6088,27 +8297,27 @@ namespace Catch { namespace Catch { - Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - } - Colour& Colour::operator=( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - return *this; - } +Colour::Colour( Code _colourCode ) { use( _colourCode ); } +Colour::Colour( Colour&& rhs ) noexcept { +m_moved = rhs.m_moved; +rhs.m_moved = true; +} +Colour& Colour::operator=( Colour&& rhs ) noexcept { +m_moved = rhs.m_moved; +rhs.m_moved = true; +return *this; +} - Colour::~Colour(){ if( !m_moved ) use( None ); } +Colour::~Colour(){ if( !m_moved ) use( None ); } - void Colour::use( Code _colourCode ) { - static IColourImpl* impl = platformColourInstance(); - impl->use( _colourCode ); - } +void Colour::use( Code _colourCode ) { +static IColourImpl* impl = platformColourInstance(); +impl->use( _colourCode ); +} - std::ostream& operator << ( std::ostream& os, Colour const& ) { - return os; - } +std::ostream& operator << ( std::ostream& os, Colour const& ) { +return os; +} } // end namespace Catch @@ -6121,60 +8330,55 @@ namespace Catch { namespace Catch { - class Context : public IMutableContext, NonCopyable { +class Context : public IMutableContext, NonCopyable { - public: // IContext - virtual IResultCapture* getResultCapture() override { - return m_resultCapture; - } - virtual IRunner* getRunner() override { - return m_runner; - } +public: // IContext +IResultCapture* getResultCapture() override { +return m_resultCapture; +} +IRunner* getRunner() override { +return m_runner; +} - virtual IConfigPtr getConfig() const override { - return m_config; - } +IConfigPtr const& getConfig() const override { +return m_config; +} - virtual ~Context() override; +~Context() override; - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) override { - m_runner = runner; - } - virtual void setConfig( IConfigPtr const& config ) override { - m_config = config; - } +public: // IMutableContext +void setResultCapture( IResultCapture* resultCapture ) override { +m_resultCapture = resultCapture; +} +void setRunner( IRunner* runner ) override { +m_runner = runner; +} +void setConfig( IConfigPtr const& config ) override { +m_config = config; +} - friend IMutableContext& getCurrentMutableContext(); +friend IMutableContext& getCurrentMutableContext(); - private: - IConfigPtr m_config; - IRunner* m_runner = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; +private: +IConfigPtr m_config; +IRunner* m_runner = nullptr; +IResultCapture* m_resultCapture = nullptr; +}; - namespace { - Context* currentContext = nullptr; - } - IMutableContext& getCurrentMutableContext() { - if( !currentContext ) - currentContext = new Context(); - return *currentContext; - } - IContext& getCurrentContext() { - return getCurrentMutableContext(); - } +IMutableContext *IMutableContext::currentContext = nullptr; - void cleanUpContext() { - delete currentContext; - currentContext = nullptr; - } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; +void IMutableContext::createContext() +{ +currentContext = new Context(); +} + +void cleanUpContext() { +delete IMutableContext::currentContext; +IMutableContext::currentContext = nullptr; +} +IContext::~IContext() = default; +IMutableContext::~IMutableContext() = default; +Context::~Context() = default; } // end catch_context.cpp // start catch_debug_console.cpp @@ -6184,149 +8388,177 @@ namespace Catch { #include namespace Catch { - void writeToDebugConsole( std::string const& text ); +void writeToDebugConsole( std::string const& text ); } // end catch_debug_console.h #ifdef CATCH_PLATFORM_WINDOWS - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } +namespace Catch { +void writeToDebugConsole( std::string const& text ) { +::OutputDebugStringA( text.c_str() ); +} +} + #else - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } + +namespace Catch { +void writeToDebugConsole( std::string const& text ) { +// !TBD: Need a version for Mac/ XCode and other IDEs +Catch::cout() << text; +} +} + #endif // Platform // end catch_debug_console.cpp // start catch_debugger.cpp #ifdef CATCH_PLATFORM_MAC - #include - #include - #include - #include - #include +# include +# include +# include +# include +# include +# include - namespace Catch { +#ifdef __apple_build_version__ +// These headers will only compile with AppleClang (XCode) +// For other compilers (Clang, GCC, ... ) we need to exclude them +# include +#endif - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html +namespace Catch { +#ifdef __apple_build_version__ +// The following function is taken directly from the following technical note: +// https://developer.apple.com/library/archive/qa/qa1361/_index.html - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive(){ +// Returns true if the current process is being debugged (either +// running under the debugger or has a debugger attached post facto). +bool isDebuggerActive(){ +int mib[4]; +struct kinfo_proc info; +std::size_t size; - int mib[4]; - struct kinfo_proc info; - std::size_t size; +// Initialize the flags so that, if sysctl fails for some bizarre +// reason, we get a predictable result. - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. +info.kp_proc.p_flag = 0; - info.kp_proc.p_flag = 0; +// Initialize mib, which tells sysctl the info we want, in this case +// we're looking for information about a specific process ID. - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. +mib[0] = CTL_KERN; +mib[1] = KERN_PROC; +mib[2] = KERN_PROC_PID; +mib[3] = getpid(); - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); +// Call sysctl. - // Call sysctl. +size = sizeof(info); +if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { +Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; +return false; +} - size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { - Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; - return false; - } +// We're being debugged if the P_TRACED flag is set. - // We're being debugged if the P_TRACED flag is set. - - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - } // namespace Catch +return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); +} +#else +bool isDebuggerActive() { +// We need to find another way to determine this for non-appleclang compilers on macOS +return false; +} +#endif +} // namespace Catch #elif defined(CATCH_PLATFORM_LINUX) - #include - #include +#include +#include - namespace Catch{ - // The standard POSIX way of detecting a debugger is to attempt to - // ptrace() the process, but this needs to be done from a child and not - // this process itself to still allow attaching to this process later - // if wanted, so is rather heavy. Under Linux we have the PID of the - // "debugger" (which doesn't need to be gdb, of course, it could also - // be strace, for example) in /proc/$PID/status, so just get it from - // there instead. - bool isDebuggerActive(){ - // Libstdc++ has a bug, where std::ifstream sets errno to 0 - // This way our users can properly assert over errno values - ErrnoGuard guard; - std::ifstream in("/proc/self/status"); - for( std::string line; std::getline(in, line); ) { - static const int PREFIX_LEN = 11; - if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { - // We're traced if the PID is not 0 and no other PID starts - // with 0 digit, so it's enough to check for just a single - // character. - return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; - } - } +namespace Catch{ +// The standard POSIX way of detecting a debugger is to attempt to +// ptrace() the process, but this needs to be done from a child and not +// this process itself to still allow attaching to this process later +// if wanted, so is rather heavy. Under Linux we have the PID of the +// "debugger" (which doesn't need to be gdb, of course, it could also +// be strace, for example) in /proc/$PID/status, so just get it from +// there instead. +bool isDebuggerActive(){ +// Libstdc++ has a bug, where std::ifstream sets errno to 0 +// This way our users can properly assert over errno values +ErrnoGuard guard; +std::ifstream in("/proc/self/status"); +for( std::string line; std::getline(in, line); ) { +static const int PREFIX_LEN = 11; +if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { +// We're traced if the PID is not 0 and no other PID starts +// with 0 digit, so it's enough to check for just a single +// character. +return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; +} +} - return false; - } - } // namespace Catch +return false; +} +} // namespace Catch #elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +namespace Catch { +bool isDebuggerActive() { +return IsDebuggerPresent() != 0; +} +} #elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } +extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); +namespace Catch { +bool isDebuggerActive() { +return IsDebuggerPresent() != 0; +} +} #else - namespace Catch { - bool isDebuggerActive() { return false; } - } +namespace Catch { +bool isDebuggerActive() { return false; } +} #endif // Platform // end catch_debugger.cpp // start catch_decomposer.cpp namespace Catch { - ITransientExpression::~ITransientExpression() = default; +ITransientExpression::~ITransientExpression() = default; - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { - if( lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ) - os << lhs << " " << op << " " << rhs; - else - os << lhs << "\n" << op << "\n" << rhs; - } +void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { +if( lhs.size() + rhs.size() < 40 && +lhs.find('\n') == std::string::npos && +rhs.find('\n') == std::string::npos ) +os << lhs << " " << op << " " << rhs; +else +os << lhs << "\n" << op << "\n" << rhs; +} } // end catch_decomposer.cpp +// start catch_enforce.cpp + +namespace Catch { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) +[[noreturn]] +void throw_exception(std::exception const& e) { +Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" +<< "The message was: " << e.what() << '\n'; +std::terminate(); +} +#endif +} // namespace Catch; +// end catch_enforce.cpp // start catch_errno_guard.cpp #include namespace Catch { - ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} - ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } +ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} +ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } } // end catch_errno_guard.cpp // start catch_exception_translator_registry.cpp @@ -6339,16 +8571,16 @@ namespace Catch { namespace Catch { - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry(); - virtual void registerTranslator( const IExceptionTranslator* translator ); - virtual std::string translateActiveException() const override; - std::string tryTranslators() const; +class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { +public: +~ExceptionTranslatorRegistry(); +virtual void registerTranslator( const IExceptionTranslator* translator ); +std::string translateActiveException() const override; +std::string tryTranslators() const; - private: - std::vector> m_translators; - }; +private: +std::vector> m_translators; +}; } // end catch_exception_translator_registry.h @@ -6358,192 +8590,144 @@ namespace Catch { namespace Catch { - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { - } +ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { +} - void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( std::unique_ptr( translator ) ); - } +void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { +m_translators.push_back( std::unique_ptr( translator ) ); +} - std::string ExceptionTranslatorRegistry::translateActiveException() const { - try { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +std::string ExceptionTranslatorRegistry::translateActiveException() const { +try { #ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - return tryTranslators(); - } - @catch (NSException *exception) { - return Catch::Detail::stringify( [exception description] ); - } +// In Objective-C try objective-c exceptions first +@try { +return tryTranslators(); +} +@catch (NSException *exception) { +return Catch::Detail::stringify( [exception description] ); +} #else - return tryTranslators(); +// Compiling a mixed mode project with MSVC means that CLR +// exceptions will be caught in (...) as well. However, these +// do not fill-in std::current_exception and thus lead to crash +// when attempting rethrow. +// /EHa switch also causes structured exceptions to be caught +// here, but they fill-in current_exception properly, so +// at worst the output should be a little weird, instead of +// causing a crash. +if (std::current_exception() == nullptr) { +return "Non C++ exception. Possibly a CLR exception."; +} +return tryTranslators(); +#endif +} +catch( TestFailureException& ) { +std::rethrow_exception(std::current_exception()); +} +catch( std::exception& ex ) { +return ex.what(); +} +catch( std::string& msg ) { +return msg; +} +catch( const char* msg ) { +return msg; +} +catch(...) { +return "Unknown exception"; +} +} + +std::string ExceptionTranslatorRegistry::tryTranslators() const { +if (m_translators.empty()) { +std::rethrow_exception(std::current_exception()); +} else { +return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); +} +} + +#else // ^^ Exceptions are enabled // Exceptions are disabled vv +std::string ExceptionTranslatorRegistry::translateActiveException() const { +CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); +} + +std::string ExceptionTranslatorRegistry::tryTranslators() const { +CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); +} #endif - } - catch( TestFailureException& ) { - std::rethrow_exception(std::current_exception()); - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; - } - } - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if( m_translators.empty() ) - std::rethrow_exception(std::current_exception()); - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); - } } // end catch_exception_translator_registry.cpp // start catch_fatal_condition.cpp -// start catch_fatal_condition.h +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif -#include +#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// - -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_WINDOWS_SEH is defined - -namespace Catch { - - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); - FatalConditionHandler(); - static void reset(); - ~FatalConditionHandler(); - - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -# else // CATCH_CONFIG_POSIX_SIGNALS is defined - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); - - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); - }; - -} // namespace Catch - -# endif // CATCH_CONFIG_POSIX_SIGNALS - -#endif // not Windows - -// end catch_fatal_condition.h namespace { - // Report the error condition - void reportFatal( char const * const message ) { - Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); - } +// Report the error condition +void reportFatal( char const * const message ) { +Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); +} } -#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// +#endif // signals/SEH handling -# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) +#if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { - void FatalConditionHandler::reset() {} +struct SignalDefs { DWORD id; const char* name; }; + +// There is no 1-1 mapping between signals and windows exceptions. +// Windows can easily distinguish between SO and SigSegV, +// but SigInt, SigTerm, etc are handled differently. +static SignalDefs signalDefs[] = { +{ static_cast(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, +{ static_cast(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, +{ static_cast(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, +{ static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, +}; + +LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { +for (auto const& def : signalDefs) { +if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { +reportFatal(def.name); +} +} +// If its not an exception we care about, pass it along. +// This stops us from eating debugger breaks etc. +return EXCEPTION_CONTINUE_SEARCH; } -# else // CATCH_CONFIG_WINDOWS_SEH is defined +FatalConditionHandler::FatalConditionHandler() { +isSet = true; +// 32k seems enough for Catch to handle stack overflow, +// but the value was found experimentally, so there is no strong guarantee +guaranteeSize = 32 * 1024; +exceptionHandlerHandle = nullptr; +// Register as first handler in current chain +exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); +// Pass in guarantee size to be filled +SetThreadStackGuarantee(&guaranteeSize); +} -namespace Catch { - struct SignalDefs { DWORD id; const char* name; }; +void FatalConditionHandler::reset() { +if (isSet) { +RemoveVectoredExceptionHandler(exceptionHandlerHandle); +SetThreadStackGuarantee(&guaranteeSize); +exceptionHandlerHandle = nullptr; +isSet = false; +} +} - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - static SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; - - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for (auto const& def : signalDefs) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { - reportFatal(def.name); - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = nullptr; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } - - void FatalConditionHandler::reset() { - if (isSet) { - // Unregister handler and restore the old guarantee - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = nullptr; - isSet = false; - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } +FatalConditionHandler::~FatalConditionHandler() { +reset(); +} bool FatalConditionHandler::isSet = false; ULONG FatalConditionHandler::guaranteeSize = 0; @@ -6551,322 +8735,350 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; } // namespace Catch -# endif // CATCH_CONFIG_WINDOWS_SEH - -#else // Not Windows - assumed to be POSIX compatible ////////////////////////// - -# if !defined(CATCH_CONFIG_POSIX_SIGNALS) +#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace Catch { - void FatalConditionHandler::reset() {} + +struct SignalDefs { +int id; +const char* name; +}; + +// 32kb for the alternate stack seems to be sufficient. However, this value +// is experimentally determined, so that's not guaranteed. +constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; + +static SignalDefs signalDefs[] = { +{ SIGINT, "SIGINT - Terminal interrupt signal" }, +{ SIGILL, "SIGILL - Illegal instruction signal" }, +{ SIGFPE, "SIGFPE - Floating point error signal" }, +{ SIGSEGV, "SIGSEGV - Segmentation violation signal" }, +{ SIGTERM, "SIGTERM - Termination request signal" }, +{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } +}; + +void FatalConditionHandler::handleSignal( int sig ) { +char const * name = ""; +for (auto const& def : signalDefs) { +if (sig == def.id) { +name = def.name; +break; +} +} +reset(); +reportFatal(name); +raise( sig ); } -# else // CATCH_CONFIG_POSIX_SIGNALS is defined +FatalConditionHandler::FatalConditionHandler() { +isSet = true; +stack_t sigStack; +sigStack.ss_sp = altStackMem; +sigStack.ss_size = sigStackSize; +sigStack.ss_flags = 0; +sigaltstack(&sigStack, &oldSigStack); +struct sigaction sa = { }; -#include +sa.sa_handler = handleSignal; +sa.sa_flags = SA_ONSTACK; +for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { +sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); +} +} -namespace Catch { +FatalConditionHandler::~FatalConditionHandler() { +reset(); +} - struct SignalDefs { - int id; - const char* name; - }; - static SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; +void FatalConditionHandler::reset() { +if( isSet ) { +// Set signals back to previous values -- hopefully nobody overwrote them in the meantime +for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { +sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); +} +// Return the old stack +sigaltstack(&oldSigStack, nullptr); +isSet = false; +} +} - void FatalConditionHandler::handleSignal( int sig ) { - char const * name = ""; - for (auto const& def : signalDefs) { - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise( sig ); - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = SIGSTKSZ; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = { }; - - sa.sa_handler = handleSignal; - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - - void FatalConditionHandler::reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; +bool FatalConditionHandler::isSet = false; +struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; +stack_t FatalConditionHandler::oldSigStack = {}; +char FatalConditionHandler::altStackMem[sigStackSize] = {}; } // namespace Catch -# endif // CATCH_CONFIG_POSIX_SIGNALS +#else -#endif // not Windows +namespace Catch { +void FatalConditionHandler::reset() {} +} + +#endif // signals/SEH handling + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif // end catch_fatal_condition.cpp +// start catch_generators.cpp + +// start catch_random_number_generator.h + +#include +#include + +namespace Catch { + +struct IConfig; + +std::mt19937& rng(); +void seedRng( IConfig const& config ); +unsigned int rngSeed(); + +} + +// end catch_random_number_generator.h +#include +#include + +namespace Catch { + +IGeneratorTracker::~IGeneratorTracker() {} + +const char* GeneratorException::what() const noexcept { +return m_msg; +} + +namespace Generators { + +GeneratorUntypedBase::~GeneratorUntypedBase() {} + +auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { +return getResultCapture().acquireGeneratorTracker( lineInfo ); +} + +} // namespace Generators +} // namespace Catch +// end catch_generators.cpp // start catch_interfaces_capture.cpp namespace Catch { - IResultCapture::~IResultCapture() = default; +IResultCapture::~IResultCapture() = default; } // end catch_interfaces_capture.cpp // start catch_interfaces_config.cpp namespace Catch { - IConfig::~IConfig() = default; +IConfig::~IConfig() = default; } // end catch_interfaces_config.cpp // start catch_interfaces_exception.cpp namespace Catch { - IExceptionTranslator::~IExceptionTranslator() = default; - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; +IExceptionTranslator::~IExceptionTranslator() = default; +IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; } // end catch_interfaces_exception.cpp // start catch_interfaces_registry_hub.cpp namespace Catch { - IRegistryHub::~IRegistryHub() = default; - IMutableRegistryHub::~IMutableRegistryHub() = default; +IRegistryHub::~IRegistryHub() = default; +IMutableRegistryHub::~IMutableRegistryHub() = default; } // end catch_interfaces_registry_hub.cpp // start catch_interfaces_reporter.cpp -// start catch_reporter_multi.h +// start catch_reporter_listening.h namespace Catch { - class MultipleReporters : public IStreamingReporter { - using Reporters = std::vector; - Reporters m_reporters; +class ListeningReporter : public IStreamingReporter { +using Reporters = std::vector; +Reporters m_listeners; +IStreamingReporterPtr m_reporter = nullptr; +ReporterPreferences m_preferences; - public: - void add( IStreamingReporterPtr&& reporter ); +public: +ListeningReporter(); - public: // IStreamingReporter +void addListener( IStreamingReporterPtr&& listener ); +void addReporter( IStreamingReporterPtr&& reporter ); - ReporterPreferences getPreferences() const override; +public: // IStreamingReporter - void noMatchingTestCases( std::string const& spec ) override; +ReporterPreferences getPreferences() const override; - static std::set getSupportedVerbosities(); +void noMatchingTestCases( std::string const& spec ) override; - void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; - void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; +static std::set getSupportedVerbosities(); - void testRunStarting( TestRunInfo const& testRunInfo ) override; - void testGroupStarting( GroupInfo const& groupInfo ) override; - void testCaseStarting( TestCaseInfo const& testInfo ) override; - void sectionStarting( SectionInfo const& sectionInfo ) override; - void assertionStarting( AssertionInfo const& assertionInfo ) override; +void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; +void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; - // The return value indicates if the messages buffer should be cleared: - bool assertionEnded( AssertionStats const& assertionStats ) override; - void sectionEnded( SectionStats const& sectionStats ) override; - void testCaseEnded( TestCaseStats const& testCaseStats ) override; - void testGroupEnded( TestGroupStats const& testGroupStats ) override; - void testRunEnded( TestRunStats const& testRunStats ) override; +void testRunStarting( TestRunInfo const& testRunInfo ) override; +void testGroupStarting( GroupInfo const& groupInfo ) override; +void testCaseStarting( TestCaseInfo const& testInfo ) override; +void sectionStarting( SectionInfo const& sectionInfo ) override; +void assertionStarting( AssertionInfo const& assertionInfo ) override; - void skipTest( TestCaseInfo const& testInfo ) override; - bool isMulti() const override; +// The return value indicates if the messages buffer should be cleared: +bool assertionEnded( AssertionStats const& assertionStats ) override; +void sectionEnded( SectionStats const& sectionStats ) override; +void testCaseEnded( TestCaseStats const& testCaseStats ) override; +void testGroupEnded( TestGroupStats const& testGroupStats ) override; +void testRunEnded( TestRunStats const& testRunStats ) override; - }; +void skipTest( TestCaseInfo const& testInfo ) override; +bool isMulti() const override; + +}; } // end namespace Catch -// end catch_reporter_multi.h +// end catch_reporter_listening.h namespace Catch { - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} +ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) +: m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} +ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) +: m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - std::ostream& ReporterConfig::stream() const { return *m_stream; } - IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } +std::ostream& ReporterConfig::stream() const { return *m_stream; } +IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } - TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} +TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} - GroupInfo::GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} +GroupInfo::GroupInfo( std::string const& _name, +std::size_t _groupIndex, +std::size_t _groupsCount ) +: name( _name ), +groupIndex( _groupIndex ), +groupsCounts( _groupsCount ) +{} - AssertionStats::AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; +AssertionStats::AssertionStats( AssertionResult const& _assertionResult, +std::vector const& _infoMessages, +Totals const& _totals ) +: assertionResult( _assertionResult ), +infoMessages( _infoMessages ), +totals( _totals ) +{ +assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); +if( assertionResult.hasMessage() ) { +// Copy message into messages list. +// !TBD This should have been done earlier, somewhere +MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); +builder << assertionResult.getMessage(); +builder.m_info.message = builder.m_stream.str(); - infoMessages.push_back( builder.m_info ); - } - } +infoMessages.push_back( builder.m_info ); +} +} - AssertionStats::~AssertionStats() = default; +AssertionStats::~AssertionStats() = default; - SectionStats::SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} +SectionStats::SectionStats( SectionInfo const& _sectionInfo, +Counts const& _assertions, +double _durationInSeconds, +bool _missingAssertions ) +: sectionInfo( _sectionInfo ), +assertions( _assertions ), +durationInSeconds( _durationInSeconds ), +missingAssertions( _missingAssertions ) +{} - SectionStats::~SectionStats() = default; +SectionStats::~SectionStats() = default; - TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} +TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, +Totals const& _totals, +std::string const& _stdOut, +std::string const& _stdErr, +bool _aborting ) +: testInfo( _testInfo ), +totals( _totals ), +stdOut( _stdOut ), +stdErr( _stdErr ), +aborting( _aborting ) +{} - TestCaseStats::~TestCaseStats() = default; +TestCaseStats::~TestCaseStats() = default; - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} +TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, +Totals const& _totals, +bool _aborting ) +: groupInfo( _groupInfo ), +totals( _totals ), +aborting( _aborting ) +{} - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} +TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) +: groupInfo( _groupInfo ), +aborting( false ) +{} - TestGroupStats::~TestGroupStats() = default; +TestGroupStats::~TestGroupStats() = default; - TestRunStats::TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} +TestRunStats::TestRunStats( TestRunInfo const& _runInfo, +Totals const& _totals, +bool _aborting ) +: runInfo( _runInfo ), +totals( _totals ), +aborting( _aborting ) +{} - TestRunStats::~TestRunStats() = default; +TestRunStats::~TestRunStats() = default; - void IStreamingReporter::fatalErrorEncountered( StringRef ) {} - bool IStreamingReporter::isMulti() const { return false; } +void IStreamingReporter::fatalErrorEncountered( StringRef ) {} +bool IStreamingReporter::isMulti() const { return false; } - IReporterFactory::~IReporterFactory() = default; - IReporterRegistry::~IReporterRegistry() = default; - - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) { - - if( !existingReporter ) { - existingReporter = std::move( additionalReporter ); - return; - } - - MultipleReporters* multi = nullptr; - - if( existingReporter->isMulti() ) { - multi = static_cast( existingReporter.get() ); - } - else { - auto newMulti = std::unique_ptr( new MultipleReporters ); - newMulti->add( std::move( existingReporter ) ); - multi = newMulti.get(); - existingReporter = std::move( newMulti ); - } - multi->add( std::move( additionalReporter ) ); - } +IReporterFactory::~IReporterFactory() = default; +IReporterRegistry::~IReporterRegistry() = default; } // end namespace Catch // end catch_interfaces_reporter.cpp // start catch_interfaces_runner.cpp namespace Catch { - IRunner::~IRunner() = default; +IRunner::~IRunner() = default; } // end catch_interfaces_runner.cpp // start catch_interfaces_testcase.cpp namespace Catch { - ITestInvoker::~ITestInvoker() = default; - ITestCaseRegistry::~ITestCaseRegistry() = default; +ITestInvoker::~ITestInvoker() = default; +ITestCaseRegistry::~ITestCaseRegistry() = default; } // end catch_interfaces_testcase.cpp // start catch_leak_detector.cpp -namespace Catch { - #ifdef CATCH_CONFIG_WINDOWS_CRTDBG #include - LeakDetector::LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } +namespace Catch { + +LeakDetector::LeakDetector() { +int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); +flag |= _CRTDBG_LEAK_CHECK_DF; +flag |= _CRTDBG_ALLOC_MEM_DF; +_CrtSetDbgFlag(flag); +_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); +_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); +// Change this to leaking allocation's number to break there +_CrtSetBreakAlloc(-1); +} +} #else - LeakDetector::LeakDetector(){} +Catch::LeakDetector::LeakDetector() {} #endif +Catch::LeakDetector::~LeakDetector() { +Catch::cleanUp(); } // end catch_leak_detector.cpp // start catch_list.cpp @@ -6877,23 +9089,23 @@ namespace Catch { namespace Catch { - std::size_t listTests( Config const& config ); +std::size_t listTests( Config const& config ); - std::size_t listTestsNamesOnly( Config const& config ); +std::size_t listTestsNamesOnly( Config const& config ); - struct TagInfo { - void add( std::string const& spelling ); - std::string all() const; +struct TagInfo { +void add( std::string const& spelling ); +std::string all() const; - std::set spellings; - std::size_t count = 0; - }; +std::set spellings; +std::size_t count = 0; +}; - std::size_t listTags( Config const& config ); +std::size_t listTags( Config const& config ); - std::size_t listReporters( Config const& /*config*/ ); +std::size_t listReporters(); - Option list( Config const& config ); +Option list( std::shared_ptr const& config ); } // end namespace Catch @@ -6901,7 +9113,7 @@ namespace Catch { // start catch_text.h namespace Catch { - using namespace clara::TextFlow; +using namespace clara::TextFlow; } // end catch_text.h @@ -6911,141 +9123,139 @@ namespace Catch { namespace Catch { - std::size_t listTests( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } +std::size_t listTests( Config const& config ) { +TestSpec testSpec = config.testSpec(); +if( config.hasTestFilters() ) +Catch::cout() << "Matching test cases:\n"; +else { +Catch::cout() << "All available test cases:\n"; +} - auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); +auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); +for( auto const& testCaseInfo : matchedTestCases ) { +Colour::Code colour = testCaseInfo.isHidden() +? Colour::SecondaryText +: Colour::None; +Colour colourGuard( colour ); - Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; - if( config.verbosity() >= Verbosity::High ) { - Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; - std::string description = testCaseInfo.description; - if( description.empty() ) - description = "(NO DESCRIPTION)"; - Catch::cout() << Column( description ).indent(4) << std::endl; - } - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; - } +Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; +if( config.verbosity() >= Verbosity::High ) { +Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; +std::string description = testCaseInfo.description; +if( description.empty() ) +description = "(NO DESCRIPTION)"; +Catch::cout() << Column( description ).indent(4) << std::endl; +} +if( !testCaseInfo.tags.empty() ) +Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; +} - if( !config.testSpec().hasFilters() ) - Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; - else - Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; - return matchedTestCases.size(); - } +if( !config.hasTestFilters() ) +Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; +else +Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; +return matchedTestCases.size(); +} - std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( !config.testSpec().hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - matchedTests++; - if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"'; - else - Catch::cout() << testCaseInfo.name; - if ( config.verbosity() >= Verbosity::High ) - Catch::cout() << "\t@" << testCaseInfo.lineInfo; - Catch::cout() << std::endl; - } - return matchedTests; - } +std::size_t listTestsNamesOnly( Config const& config ) { +TestSpec testSpec = config.testSpec(); +std::size_t matchedTests = 0; +std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); +for( auto const& testCaseInfo : matchedTestCases ) { +matchedTests++; +if( startsWith( testCaseInfo.name, '#' ) ) +Catch::cout() << '"' << testCaseInfo.name << '"'; +else +Catch::cout() << testCaseInfo.name; +if ( config.verbosity() >= Verbosity::High ) +Catch::cout() << "\t@" << testCaseInfo.lineInfo; +Catch::cout() << std::endl; +} +return matchedTests; +} - void TagInfo::add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); - } +void TagInfo::add( std::string const& spelling ) { +++count; +spellings.insert( spelling ); +} - std::string TagInfo::all() const { - std::string out; - for( auto const& spelling : spellings ) - out += "[" + spelling + "]"; - return out; - } +std::string TagInfo::all() const { +std::string out; +for( auto const& spelling : spellings ) +out += "[" + spelling + "]"; +return out; +} - std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.testSpec().hasFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); - } +std::size_t listTags( Config const& config ) { +TestSpec testSpec = config.testSpec(); +if( config.hasTestFilters() ) +Catch::cout() << "Tags for matching test cases:\n"; +else { +Catch::cout() << "All available tags:\n"; +} - std::map tagCounts; +std::map tagCounts; - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCase : matchedTestCases ) { - for( auto const& tagName : testCase.getTestCaseInfo().tags ) { - std::string lcaseTagName = toLower( tagName ); - auto countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } +std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); +for( auto const& testCase : matchedTestCases ) { +for( auto const& tagName : testCase.getTestCaseInfo().tags ) { +std::string lcaseTagName = toLower( tagName ); +auto countIt = tagCounts.find( lcaseTagName ); +if( countIt == tagCounts.end() ) +countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; +countIt->second.add( tagName ); +} +} - for( auto const& tagCount : tagCounts ) { - std::ostringstream oss; - oss << " " << std::setw(2) << tagCount.second.count << " "; - auto wrapper = Column( tagCount.second.all() ) - .initialIndent( 0 ) - .indent( oss.str().size() ) - .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); - Catch::cout() << oss.str() << wrapper << '\n'; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; - return tagCounts.size(); - } +for( auto const& tagCount : tagCounts ) { +ReusableStringStream rss; +rss << " " << std::setw(2) << tagCount.second.count << " "; +auto str = rss.str(); +auto wrapper = Column( tagCount.second.all() ) +.initialIndent( 0 ) +.indent( str.size() ) +.width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); +Catch::cout() << str << wrapper << '\n'; +} +Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; +return tagCounts.size(); +} - std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - std::size_t maxNameLen = 0; - for( auto const& factoryKvp : factories ) - maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); +std::size_t listReporters() { +Catch::cout() << "Available reporters:\n"; +IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); +std::size_t maxNameLen = 0; +for( auto const& factoryKvp : factories ) +maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); - for( auto const& factoryKvp : factories ) { - Catch::cout() - << Column( factoryKvp.first + ":" ) - .indent(2) - .width( 5+maxNameLen ) - + Column( factoryKvp.second->getDescription() ) - .initialIndent(0) - .indent(2) - .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) - << "\n"; - } - Catch::cout() << std::endl; - return factories.size(); - } +for( auto const& factoryKvp : factories ) { +Catch::cout() +<< Column( factoryKvp.first + ":" ) +.indent(2) +.width( 5+maxNameLen ) ++ Column( factoryKvp.second->getDescription() ) +.initialIndent(0) +.indent(2) +.width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) +<< "\n"; +} +Catch::cout() << std::endl; +return factories.size(); +} - Option list( Config const& config ) { - Option listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } +Option list( std::shared_ptr const& config ) { +Option listedCount; +getCurrentMutableContext().setConfig( config ); +if( config->listTests() ) +listedCount = listedCount.valueOr(0) + listTests( *config ); +if( config->listTestNamesOnly() ) +listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); +if( config->listTags() ) +listedCount = listedCount.valueOr(0) + listTags( *config ); +if( config->listReporters() ) +listedCount = listedCount.valueOr(0) + listReporters(); +return listedCount; +} } // end namespace Catch // end catch_list.cpp @@ -7053,17 +9263,17 @@ namespace Catch { namespace Catch { namespace Matchers { - namespace Impl { +namespace Impl { - std::string MatcherUntypedBase::toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } +std::string MatcherUntypedBase::toString() const { +if( m_cachedToString.empty() ) +m_cachedToString = describe(); +return m_cachedToString; +} - MatcherUntypedBase::~MatcherUntypedBase() = default; +MatcherUntypedBase::~MatcherUntypedBase() = default; - } // namespace Impl +} // namespace Impl } // namespace Matchers using namespace Matchers; @@ -7071,187 +9281,691 @@ using Matchers::Impl::MatcherBase; } // namespace Catch // end catch_matchers.cpp +// start catch_matchers_floating.cpp + +// start catch_polyfills.hpp + +namespace Catch { +bool isnan(float f); +bool isnan(double d); +} + +// end catch_polyfills.hpp +// start catch_to_string.hpp + +#include + +namespace Catch { +template +std::string to_string(T const& t) { +#if defined(CATCH_CONFIG_CPP11_TO_STRING) +return std::to_string(t); +#else +ReusableStringStream rss; +rss << t; +return rss.str(); +#endif +} +} // end namespace Catch + +// end catch_to_string.hpp +#include +#include +#include + +namespace Catch { +namespace Matchers { +namespace Floating { +enum class FloatingPointKind : uint8_t { +Float, +Double +}; +} +} +} + +namespace { + +template +struct Converter; + +template <> +struct Converter { +static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); +Converter(float f) { +std::memcpy(&i, &f, sizeof(f)); +} +int32_t i; +}; + +template <> +struct Converter { +static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); +Converter(double d) { +std::memcpy(&i, &d, sizeof(d)); +} +int64_t i; +}; + +template +auto convert(T t) -> Converter { +return Converter(t); +} + +template +bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { +// Comparison with NaN should always be false. +// This way we can rule it out before getting into the ugly details +if (Catch::isnan(lhs) || Catch::isnan(rhs)) { +return false; +} + +auto lc = convert(lhs); +auto rc = convert(rhs); + +if ((lc.i < 0) != (rc.i < 0)) { +// Potentially we can have +0 and -0 +return lhs == rhs; +} + +auto ulpDiff = std::abs(lc.i - rc.i); +return ulpDiff <= maxUlpDiff; +} + +} + +namespace Catch { +namespace Matchers { +namespace Floating { +WithinAbsMatcher::WithinAbsMatcher(double target, double margin) +:m_target{ target }, m_margin{ margin } { +CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' +<< " Margin has to be non-negative."); +} + +// Performs equivalent check of std::fabs(lhs - rhs) <= margin +// But without the subtraction to allow for INFINITY in comparison +bool WithinAbsMatcher::match(double const& matchee) const { +return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); +} + +std::string WithinAbsMatcher::describe() const { +return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); +} + +WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) +:m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { +CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.' +<< " ULPs have to be non-negative."); +} + +#if defined(__clang__) +#pragma clang diagnostic push +// Clang <3.5 reports on the default branch in the switch below +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + +bool WithinUlpsMatcher::match(double const& matchee) const { +switch (m_type) { +case FloatingPointKind::Float: +return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); +case FloatingPointKind::Double: +return almostEqualUlps(matchee, m_target, m_ulps); +default: +CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); +} +} + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + +std::string WithinUlpsMatcher::describe() const { +return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); +} + +}// namespace Floating + +Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { +return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); +} + +Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { +return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); +} + +Floating::WithinAbsMatcher WithinAbs(double target, double margin) { +return Floating::WithinAbsMatcher(target, margin); +} + +} // namespace Matchers +} // namespace Catch + +// end catch_matchers_floating.cpp +// start catch_matchers_generic.cpp + +std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { +if (desc.empty()) { +return "matches undescribed predicate"; +} else { +return "matches predicate: \"" + desc + '"'; +} +} +// end catch_matchers_generic.cpp // start catch_matchers_string.cpp +#include + namespace Catch { namespace Matchers { - namespace StdString { +namespace StdString { - CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string CasedString::adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - } - std::string CasedString::caseSensitivitySuffix() const { - return m_caseSensitivity == CaseSensitive::No - ? " (case insensitive)" - : std::string(); - } +CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) +: m_caseSensitivity( caseSensitivity ), +m_str( adjustString( str ) ) +{} +std::string CasedString::adjustString( std::string const& str ) const { +return m_caseSensitivity == CaseSensitive::No +? toLower( str ) +: str; +} +std::string CasedString::caseSensitivitySuffix() const { +return m_caseSensitivity == CaseSensitive::No +? " (case insensitive)" +: std::string(); +} - StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) - : m_comparator( comparator ), - m_operation( operation ) { - } +StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) +: m_comparator( comparator ), +m_operation( operation ) { +} - std::string StringMatcherBase::describe() const { - std::string description; - description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + - m_comparator.caseSensitivitySuffix().size()); - description += m_operation; - description += ": \""; - description += m_comparator.m_str; - description += "\""; - description += m_comparator.caseSensitivitySuffix(); - return description; - } +std::string StringMatcherBase::describe() const { +std::string description; +description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + +m_comparator.caseSensitivitySuffix().size()); +description += m_operation; +description += ": \""; +description += m_comparator.m_str; +description += "\""; +description += m_comparator.caseSensitivitySuffix(); +return description; +} - EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} +EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} - bool EqualsMatcher::match( std::string const& source ) const { - return m_comparator.adjustString( source ) == m_comparator.m_str; - } +bool EqualsMatcher::match( std::string const& source ) const { +return m_comparator.adjustString( source ) == m_comparator.m_str; +} - ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} +ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} - bool ContainsMatcher::match( std::string const& source ) const { - return contains( m_comparator.adjustString( source ), m_comparator.m_str ); - } +bool ContainsMatcher::match( std::string const& source ) const { +return contains( m_comparator.adjustString( source ), m_comparator.m_str ); +} - StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} +StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} - bool StartsWithMatcher::match( std::string const& source ) const { - return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } +bool StartsWithMatcher::match( std::string const& source ) const { +return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); +} - EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} +EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} - bool EndsWithMatcher::match( std::string const& source ) const { - return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } +bool EndsWithMatcher::match( std::string const& source ) const { +return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); +} - } // namespace StdString +RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } +bool RegexMatcher::match(std::string const& matchee) const { +auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway +if (m_caseSensitivity == CaseSensitive::Choice::No) { +flags |= std::regex::icase; +} +auto reg = std::regex(m_regex, flags); +return std::regex_match(matchee, reg); +} + +std::string RegexMatcher::describe() const { +return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); +} + +} // namespace StdString + +StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { +return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); +} +StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { +return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); +} +StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { +return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); +} +StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { +return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); +} + +StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { +return StdString::RegexMatcher(regex, caseSensitivity); +} } // namespace Matchers } // namespace Catch // end catch_matchers_string.cpp // start catch_message.cpp +// start catch_uncaught_exceptions.h + +namespace Catch { +bool uncaught_exceptions(); +} // end namespace Catch + +// end catch_uncaught_exceptions.h +#include +#include + namespace Catch { - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} +MessageInfo::MessageInfo( StringRef const& _macroName, +SourceLineInfo const& _lineInfo, +ResultWas::OfType _type ) +: macroName( _macroName ), +lineInfo( _lineInfo ), +type( _type ), +sequence( ++globalCount ) +{} - bool MessageInfo::operator==( MessageInfo const& other ) const { - return sequence == other.sequence; - } +bool MessageInfo::operator==( MessageInfo const& other ) const { +return sequence == other.sequence; +} - bool MessageInfo::operator<( MessageInfo const& other ) const { - return sequence < other.sequence; - } +bool MessageInfo::operator<( MessageInfo const& other ) const { +return sequence < other.sequence; +} - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; +// This may need protecting if threading support is added +unsigned int MessageInfo::globalCount = 0; - //////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// - Catch::MessageBuilder::MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - :m_info(macroName, lineInfo, type) {} +Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, +SourceLineInfo const& lineInfo, +ResultWas::OfType type ) +:m_info(macroName, lineInfo, type) {} - //////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////// - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } +ScopedMessage::ScopedMessage( MessageBuilder const& builder ) +: m_info( builder.m_info ), m_moved() +{ +m_info.message = builder.m_stream.str(); +getResultCapture().pushScopedMessage( m_info ); +} - ScopedMessage::~ScopedMessage() { - if ( !std::uncaught_exception() ){ - getResultCapture().popScopedMessage(m_info); - } - } +ScopedMessage::ScopedMessage( ScopedMessage&& old ) +: m_info( old.m_info ), m_moved() +{ +old.m_moved = true; +} + +ScopedMessage::~ScopedMessage() { +if ( !uncaught_exceptions() && !m_moved ){ +getResultCapture().popScopedMessage(m_info); +} +} + +Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { +auto trimmed = [&] (size_t start, size_t end) { +while (names[start] == ',' || isspace(names[start])) { +++start; +} +while (names[end] == ',' || isspace(names[end])) { +--end; +} +return names.substr(start, end - start + 1); +}; + +size_t start = 0; +std::stack openings; +for (size_t pos = 0; pos < names.size(); ++pos) { +char c = names[pos]; +switch (c) { +case '[': +case '{': +case '(': +// It is basically impossible to disambiguate between +// comparison and start of template args in this context +// case '<': +openings.push(c); +break; +case ']': +case '}': +case ')': +// case '>': +openings.pop(); +break; +case ',': +if (start != pos && openings.size() == 0) { +m_messages.emplace_back(macroName, lineInfo, resultType); +m_messages.back().message = trimmed(start, pos); +m_messages.back().message += " := "; +start = pos; +} +} +} +assert(openings.size() == 0 && "Mismatched openings"); +m_messages.emplace_back(macroName, lineInfo, resultType); +m_messages.back().message = trimmed(start, names.size() - 1); +m_messages.back().message += " := "; +} +Capturer::~Capturer() { +if ( !uncaught_exceptions() ){ +assert( m_captured == m_messages.size() ); +for( size_t i = 0; i < m_captured; ++i ) +m_resultCapture.popScopedMessage( m_messages[i] ); +} +} + +void Capturer::captureValue( size_t index, std::string const& value ) { +assert( index < m_messages.size() ); +m_messages[index].message += value; +m_resultCapture.pushScopedMessage( m_messages[index] ); +m_captured++; +} } // end namespace Catch // end catch_message.cpp -// start catch_random_number_generator.cpp +// start catch_output_redirect.cpp -// start catch_random_number_generator.h +// start catch_output_redirect.h +#ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H -#include +#include +#include +#include namespace Catch { - struct IConfig; +class RedirectedStream { +std::ostream& m_originalStream; +std::ostream& m_redirectionStream; +std::streambuf* m_prevBuf; - void seedRng( IConfig const& config ); +public: +RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); +~RedirectedStream(); +}; - unsigned int rngSeed(); +class RedirectedStdOut { +ReusableStringStream m_rss; +RedirectedStream m_cout; +public: +RedirectedStdOut(); +auto str() const -> std::string; +}; - struct RandomNumberGenerator { - using result_type = unsigned int; +// StdErr has two constituent streams in C++, std::cerr and std::clog +// This means that we need to redirect 2 streams into 1 to keep proper +// order of writes +class RedirectedStdErr { +ReusableStringStream m_rss; +RedirectedStream m_cerr; +RedirectedStream m_clog; +public: +RedirectedStdErr(); +auto str() const -> std::string; +}; - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return 1000000; } +class RedirectedStreams { +public: +RedirectedStreams(RedirectedStreams const&) = delete; +RedirectedStreams& operator=(RedirectedStreams const&) = delete; +RedirectedStreams(RedirectedStreams&&) = delete; +RedirectedStreams& operator=(RedirectedStreams&&) = delete; - result_type operator()( result_type n ) const; - result_type operator()() const; +RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); +~RedirectedStreams(); +private: +std::string& m_redirectedCout; +std::string& m_redirectedCerr; +RedirectedStdOut m_redirectedStdOut; +RedirectedStdErr m_redirectedStdErr; +}; - template - static void shuffle( V& vector ) { - RandomNumberGenerator rng; - std::shuffle( vector.begin(), vector.end(), rng ); - } - }; +#if defined(CATCH_CONFIG_NEW_CAPTURE) +// Windows's implementation of std::tmpfile is terrible (it tries +// to create a file inside system folder, thus requiring elevated +// privileges for the binary), so we have to use tmpnam(_s) and +// create the file ourselves there. +class TempFile { +public: +TempFile(TempFile const&) = delete; +TempFile& operator=(TempFile const&) = delete; +TempFile(TempFile&&) = delete; +TempFile& operator=(TempFile&&) = delete; + +TempFile(); +~TempFile(); + +std::FILE* getFile(); +std::string getContents(); + +private: +std::FILE* m_file = nullptr; +#if defined(_MSC_VER) +char m_buffer[L_tmpnam] = { 0 }; +#endif +}; + +class OutputRedirect { +public: +OutputRedirect(OutputRedirect const&) = delete; +OutputRedirect& operator=(OutputRedirect const&) = delete; +OutputRedirect(OutputRedirect&&) = delete; +OutputRedirect& operator=(OutputRedirect&&) = delete; + +OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); +~OutputRedirect(); + +private: +int m_originalStdout = -1; +int m_originalStderr = -1; +TempFile m_stdoutFile; +TempFile m_stderrFile; +std::string& m_stdoutDest; +std::string& m_stderrDest; +}; + +#endif + +} // end namespace Catch + +#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H +// end catch_output_redirect.h +#include +#include +#include +#include +#include + +#if defined(CATCH_CONFIG_NEW_CAPTURE) +#if defined(_MSC_VER) +#include //_dup and _dup2 +#define dup _dup +#define dup2 _dup2 +#define fileno _fileno +#else +#include // dup and dup2 +#endif +#endif + +namespace Catch { + +RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) +: m_originalStream( originalStream ), +m_redirectionStream( redirectionStream ), +m_prevBuf( m_originalStream.rdbuf() ) +{ +m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); } -// end catch_random_number_generator.h -#include +RedirectedStream::~RedirectedStream() { +m_originalStream.rdbuf( m_prevBuf ); +} + +RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} +auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } + +RedirectedStdErr::RedirectedStdErr() +: m_cerr( Catch::cerr(), m_rss.get() ), +m_clog( Catch::clog(), m_rss.get() ) +{} +auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } + +RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) +: m_redirectedCout(redirectedCout), +m_redirectedCerr(redirectedCerr) +{} + +RedirectedStreams::~RedirectedStreams() { +m_redirectedCout += m_redirectedStdOut.str(); +m_redirectedCerr += m_redirectedStdErr.str(); +} + +#if defined(CATCH_CONFIG_NEW_CAPTURE) + +#if defined(_MSC_VER) +TempFile::TempFile() { +if (tmpnam_s(m_buffer)) { +CATCH_RUNTIME_ERROR("Could not get a temp filename"); +} +if (fopen_s(&m_file, m_buffer, "w")) { +char buffer[100]; +if (strerror_s(buffer, errno)) { +CATCH_RUNTIME_ERROR("Could not translate errno to a string"); +} +CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); +} +} +#else +TempFile::TempFile() { +m_file = std::tmpfile(); +if (!m_file) { +CATCH_RUNTIME_ERROR("Could not create a temp file."); +} +} + +#endif + +TempFile::~TempFile() { +// TBD: What to do about errors here? +std::fclose(m_file); +// We manually create the file on Windows only, on Linux +// it will be autodeleted +#if defined(_MSC_VER) +std::remove(m_buffer); +#endif +} + +FILE* TempFile::getFile() { +return m_file; +} + +std::string TempFile::getContents() { +std::stringstream sstr; +char buffer[100] = {}; +std::rewind(m_file); +while (std::fgets(buffer, sizeof(buffer), m_file)) { +sstr << buffer; +} +return sstr.str(); +} + +OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : +m_originalStdout(dup(1)), +m_originalStderr(dup(2)), +m_stdoutDest(stdout_dest), +m_stderrDest(stderr_dest) { +dup2(fileno(m_stdoutFile.getFile()), 1); +dup2(fileno(m_stderrFile.getFile()), 2); +} + +OutputRedirect::~OutputRedirect() { +Catch::cout() << std::flush; +fflush(stdout); +// Since we support overriding these streams, we flush cerr +// even though std::cerr is unbuffered +Catch::cerr() << std::flush; +Catch::clog() << std::flush; +fflush(stderr); + +dup2(m_originalStdout, 1); +dup2(m_originalStderr, 2); + +m_stdoutDest += m_stdoutFile.getContents(); +m_stderrDest += m_stderrFile.getContents(); +} + +#endif // CATCH_CONFIG_NEW_CAPTURE + +} // namespace Catch + +#if defined(CATCH_CONFIG_NEW_CAPTURE) +#if defined(_MSC_VER) +#undef dup +#undef dup2 +#undef fileno +#endif +#endif +// end catch_output_redirect.cpp +// start catch_polyfills.cpp + +#include namespace Catch { - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) - std::srand( config.rngSeed() ); - } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } +#if !defined(CATCH_CONFIG_POLYFILL_ISNAN) +bool isnan(float f) { +return std::isnan(f); +} +bool isnan(double d) { +return std::isnan(d); +} +#else +// For now we only use this for embarcadero +bool isnan(float f) { +return std::_isnan(f); +} +bool isnan(double d) { +return std::_isnan(d); +} +#endif - RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { - return std::rand() % n; - } - RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { - return std::rand() % (max)(); - } +} // end namespace Catch +// end catch_polyfills.cpp +// start catch_random_number_generator.cpp +namespace Catch { + +std::mt19937& rng() { +static std::mt19937 s_rng; +return s_rng; +} + +void seedRng( IConfig const& config ) { +if( config.rngSeed() != 0 ) { +std::srand( config.rngSeed() ); +rng().seed( config.rngSeed() ); +} +} + +unsigned int rngSeed() { +return getCurrentContext().getConfig()->rngSeed(); +} } // end catch_random_number_generator.cpp // start catch_registry_hub.cpp @@ -7265,47 +9979,47 @@ namespace Catch { namespace Catch { - class TestCase; - struct IConfig; +class TestCase; +struct IConfig; - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); +std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); +bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - void enforceNoDuplicateTestCases( std::vector const& functions ); +void enforceNoDuplicateTestCases( std::vector const& functions ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); +std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); +std::vector const& getAllTestCasesSorted( IConfig const& config ); - class TestRegistry : public ITestCaseRegistry { - public: - virtual ~TestRegistry() = default; +class TestRegistry : public ITestCaseRegistry { +public: +virtual ~TestRegistry() = default; - virtual void registerTest( TestCase const& testCase ); +virtual void registerTest( TestCase const& testCase ); - std::vector const& getAllTests() const override; - std::vector const& getAllTestsSorted( IConfig const& config ) const override; +std::vector const& getAllTests() const override; +std::vector const& getAllTestsSorted( IConfig const& config ) const override; - private: - std::vector m_functions; - mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; - mutable std::vector m_sortedFunctions; - std::size_t m_unnamedCount = 0; - std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised - }; +private: +std::vector m_functions; +mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; +mutable std::vector m_sortedFunctions; +std::size_t m_unnamedCount = 0; +std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised +}; - /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// - class TestInvokerAsFunction : public ITestInvoker { - void(*m_testAsFunction)(); - public: - TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; +class TestInvokerAsFunction : public ITestInvoker { +void(*m_testAsFunction)(); +public: +TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; - void invoke() const override; - }; +void invoke() const override; +}; - std::string extractClassName( std::string const& classOrQualifiedMethodName ); +std::string extractClassName( StringRef const& classOrQualifiedMethodName ); - /////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// } // end namespace Catch @@ -7316,24 +10030,24 @@ namespace Catch { namespace Catch { - class ReporterRegistry : public IReporterRegistry { +class ReporterRegistry : public IReporterRegistry { - public: +public: - ~ReporterRegistry() override; +~ReporterRegistry() override; - IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; +IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); - void registerListener( IReporterFactoryPtr const& factory ); +void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); +void registerListener( IReporterFactoryPtr const& factory ); - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; +FactoryMap const& getFactories() const override; +Listeners const& getListeners() const override; - private: - FactoryMap m_factories; - Listeners m_listeners; - }; +private: +FactoryMap m_factories; +Listeners m_listeners; +}; } // end catch_reporter_registry.h @@ -7345,12 +10059,12 @@ namespace Catch { namespace Catch { - struct TagAlias { - TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); +struct TagAlias { +TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); - std::string tag; - SourceLineInfo lineInfo; - }; +std::string tag; +SourceLineInfo lineInfo; +}; } // end namespace Catch @@ -7359,16 +10073,16 @@ namespace Catch { namespace Catch { - class TagAliasRegistry : public ITagAliasRegistry { - public: - ~TagAliasRegistry() override; - TagAlias const* find( std::string const& alias ) const override; - std::string expandAliases( std::string const& unexpandedTestSpec ) const override; - void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); +class TagAliasRegistry : public ITagAliasRegistry { +public: +~TagAliasRegistry() override; +TagAlias const* find( std::string const& alias ) const override; +std::string expandAliases( std::string const& unexpandedTestSpec ) const override; +void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); - private: - std::map m_registry; - }; +private: +std::map m_registry; +}; } // end namespace Catch @@ -7380,93 +10094,121 @@ namespace Catch { namespace Catch { - class StartupExceptionRegistry { - public: - void add(std::exception_ptr const& exception) noexcept; - std::vector const& getExceptions() const noexcept; - private: - std::vector m_exceptions; - }; +class StartupExceptionRegistry { +public: +void add(std::exception_ptr const& exception) noexcept; +std::vector const& getExceptions() const noexcept; +private: +std::vector m_exceptions; +}; } // end namespace Catch // end catch_startup_exception_registry.h +// start catch_singletons.hpp + namespace Catch { - namespace { +struct ISingleton { +virtual ~ISingleton(); +}; - class RegistryHub : public IRegistryHub, public IMutableRegistryHub, - private NonCopyable { +void addSingleton( ISingleton* singleton ); +void cleanupSingletons(); - public: // IRegistryHub - RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { - return m_reporterRegistry; - } - ITestCaseRegistry const& getTestCaseRegistry() const override { - return m_testCaseRegistry; - } - IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { - return m_exceptionTranslatorRegistry; - } - ITagAliasRegistry const& getTagAliasRegistry() const override { - return m_tagAliasRegistry; - } - StartupExceptionRegistry const& getStartupExceptionRegistry() const override { - return m_exceptionRegistry; - } +template +class Singleton : SingletonImplT, public ISingleton { - public: // IMutableRegistryHub - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerReporter( name, factory ); - } - void registerListener( IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerListener( factory ); - } - void registerTest( TestCase const& testInfo ) override { - m_testCaseRegistry.registerTest( testInfo ); - } - void registerTranslator( const IExceptionTranslator* translator ) override { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { - m_tagAliasRegistry.add( alias, tag, lineInfo ); - } - void registerStartupException() noexcept override { - m_exceptionRegistry.add(std::current_exception()); - } +static auto getInternal() -> Singleton* { +static Singleton* s_instance = nullptr; +if( !s_instance ) { +s_instance = new Singleton; +addSingleton( s_instance ); +} +return s_instance; +} - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - StartupExceptionRegistry m_exceptionRegistry; - }; +public: +static auto get() -> InterfaceT const& { +return *getInternal(); +} +static auto getMutable() -> MutableInterfaceT& { +return *getInternal(); +} +}; - // Single, global, instance - RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = nullptr; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } +} // namespace Catch - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = nullptr; - cleanUpContext(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } +// end catch_singletons.hpp +namespace Catch { + +namespace { + +class RegistryHub : public IRegistryHub, public IMutableRegistryHub, +private NonCopyable { + +public: // IRegistryHub +RegistryHub() = default; +IReporterRegistry const& getReporterRegistry() const override { +return m_reporterRegistry; +} +ITestCaseRegistry const& getTestCaseRegistry() const override { +return m_testCaseRegistry; +} +IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { +return m_exceptionTranslatorRegistry; +} +ITagAliasRegistry const& getTagAliasRegistry() const override { +return m_tagAliasRegistry; +} +StartupExceptionRegistry const& getStartupExceptionRegistry() const override { +return m_exceptionRegistry; +} + +public: // IMutableRegistryHub +void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { +m_reporterRegistry.registerReporter( name, factory ); +} +void registerListener( IReporterFactoryPtr const& factory ) override { +m_reporterRegistry.registerListener( factory ); +} +void registerTest( TestCase const& testInfo ) override { +m_testCaseRegistry.registerTest( testInfo ); +} +void registerTranslator( const IExceptionTranslator* translator ) override { +m_exceptionTranslatorRegistry.registerTranslator( translator ); +} +void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { +m_tagAliasRegistry.add( alias, tag, lineInfo ); +} +void registerStartupException() noexcept override { +m_exceptionRegistry.add(std::current_exception()); +} + +private: +TestRegistry m_testCaseRegistry; +ReporterRegistry m_reporterRegistry; +ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; +TagAliasRegistry m_tagAliasRegistry; +StartupExceptionRegistry m_exceptionRegistry; +}; +} + +using RegistryHubSingleton = Singleton; + +IRegistryHub const& getRegistryHub() { +return RegistryHubSingleton::get(); +} +IMutableRegistryHub& getMutableRegistryHub() { +return RegistryHubSingleton::getMutable(); +} +void cleanUp() { +cleanupSingletons(); +cleanUpContext(); +} +std::string translateActiveException() { +return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); +} } // end namespace Catch // end catch_registry_hub.cpp @@ -7474,28 +10216,28 @@ namespace Catch { namespace Catch { - ReporterRegistry::~ReporterRegistry() = default; +ReporterRegistry::~ReporterRegistry() = default; - IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( ReporterConfig( config ) ); - } +IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { +auto it = m_factories.find( name ); +if( it == m_factories.end() ) +return nullptr; +return it->second->create( ReporterConfig( config ) ); +} - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { - m_factories.emplace(name, factory); - } - void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { - m_listeners.push_back( factory ); - } +void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { +m_factories.emplace(name, factory); +} +void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { +m_listeners.push_back( factory ); +} - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; - } +IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { +return m_factories; +} +IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { +return m_listeners; +} } // end catch_reporter_registry.cpp @@ -7503,509 +10245,540 @@ namespace Catch { namespace Catch { - bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } +bool isOk( ResultWas::OfType resultType ) { +return ( resultType & ResultWas::FailureBit ) == 0; +} +bool isJustInfo( int flags ) { +return flags == ResultWas::Info; +} - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } +ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { +return static_cast( static_cast( lhs ) | static_cast( rhs ) ); +} - bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } +bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } +bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } } // end namespace Catch // end catch_result_type.cpp // start catch_run_context.cpp -// start catch_run_context.h - -#include - -namespace Catch { - - struct IMutableContext; - - class StreamRedirect { - - public: - StreamRedirect(std::ostream& stream, std::string& targetString); - - ~StreamRedirect(); - - private: - std::ostream& m_stream; - std::streambuf* m_prevBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes and cannot use StreamRedirect on its own - class StdErrRedirect { - public: - StdErrRedirect(std::string& targetString); - ~StdErrRedirect(); - private: - std::streambuf* m_cerrBuf; - std::streambuf* m_clogBuf; - std::ostringstream m_oss; - std::string& m_targetString; - }; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - public: - RunContext( RunContext const& ) = delete; - RunContext& operator =( RunContext const& ) = delete; - - explicit RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter); - - virtual ~RunContext(); - - void testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount); - void testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount); - - Totals runTest(TestCase const& testCase); - - IConfigPtr config() const; - IStreamingReporter& reporter() const; - - private: // IResultCapture - - void assertionStarting(AssertionInfo const& info) override; - void assertionEnded(AssertionResult const& result) override; - - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; - bool testForMissingAssertions(Counts& assertions); - - void sectionEnded(SectionEndInfo const& endInfo) override; - void sectionEndedEarly(SectionEndInfo const& endInfo) override; - - void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; - - void pushScopedMessage(MessageInfo const& message) override; - void popScopedMessage(MessageInfo const& message) override; - - std::string getCurrentTestName() const override; - - const AssertionResult* getLastResult() const override; - - void exceptionEarlyReported() override; - - void handleFatalErrorCondition( StringRef message ) override; - - bool lastAssertionPassed() override; - - void assertionPassed() override; - - void assertionRun() override; - - public: - // !TBD We need to do this another way! - bool aborting() const override; - - private: - - void runCurrentTest(std::string& redirectedCout, std::string& redirectedCerr); - void invokeActiveTestCase(); - - private: - - void handleUnfinishedSections(); - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; - Option m_lastResult; - - IConfigPtr m_config; - Totals m_totals; - IStreamingReporterPtr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - std::size_t m_prevPassed = 0; - bool m_shouldReportUnexpected = true; - }; - - IResultCapture& getResultCapture(); - -} // end namespace Catch - -// end catch_run_context.h #include #include +#include namespace Catch { - StreamRedirect::StreamRedirect(std::ostream& stream, std::string& targetString) - : m_stream(stream), - m_prevBuf(stream.rdbuf()), - m_targetString(targetString) { - stream.rdbuf(m_oss.rdbuf()); - } +namespace Generators { +struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { +GeneratorBasePtr m_generator; - StreamRedirect::~StreamRedirect() { - m_targetString += m_oss.str(); - m_stream.rdbuf(m_prevBuf); - } +GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) +: TrackerBase( nameAndLocation, ctx, parent ) +{} +~GeneratorTracker(); - StdErrRedirect::StdErrRedirect(std::string & targetString) - :m_cerrBuf(cerr().rdbuf()), m_clogBuf(clog().rdbuf()), - m_targetString(targetString) { - cerr().rdbuf(m_oss.rdbuf()); - clog().rdbuf(m_oss.rdbuf()); - } +static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { +std::shared_ptr tracker; - StdErrRedirect::~StdErrRedirect() { - m_targetString += m_oss.str(); - cerr().rdbuf(m_cerrBuf); - clog().rdbuf(m_clogBuf); - } +ITracker& currentTracker = ctx.currentTracker(); +if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { +assert( childTracker ); +assert( childTracker->isGeneratorTracker() ); +tracker = std::static_pointer_cast( childTracker ); +} +else { +tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); +currentTracker.addChild( tracker ); +} - RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) - : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), - m_config(_config), - m_reporter(std::move(reporter)), - m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal } - { - m_context.setRunner(this); - m_context.setConfig(m_config); - m_context.setResultCapture(this); - m_reporter->testRunStarting(m_runInfo); - } +if( !ctx.completedCycle() && !tracker->isComplete() ) { +tracker->open(); +} - RunContext::~RunContext() { - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); - } +return *tracker; +} - void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); - } +// TrackerBase interface +bool isGeneratorTracker() const override { return true; } +auto hasGenerator() const -> bool override { +return !!m_generator; +} +void close() override { +TrackerBase::close(); +// Generator interface only finds out if it has another item on atual move +if (m_runState == CompletedSuccessfully && m_generator->next()) { +m_children.clear(); +m_runState = Executing; +} +} - void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); - } +// IGeneratorTracker interface +auto getGenerator() const -> GeneratorBasePtr const& override { +return m_generator; +} +void setGenerator( GeneratorBasePtr&& generator ) override { +m_generator = std::move( generator ); +} +}; +GeneratorTracker::~GeneratorTracker() {} +} - Totals RunContext::runTest(TestCase const& testCase) { - Totals prevTotals = m_totals; +RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) +: m_runInfo(_config->name()), +m_context(getCurrentMutableContext()), +m_config(_config), +m_reporter(std::move(reporter)), +m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, +m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) +{ +m_context.setRunner(this); +m_context.setConfig(m_config); +m_context.setResultCapture(this); +m_reporter->testRunStarting(m_runInfo); +} - std::string redirectedCout; - std::string redirectedCerr; +RunContext::~RunContext() { +m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); +} - TestCaseInfo testInfo = testCase.getTestCaseInfo(); +void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { +m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); +} - m_reporter->testCaseStarting(testInfo); +void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { +m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); +} - m_activeTestCase = &testCase; +Totals RunContext::runTest(TestCase const& testCase) { +Totals prevTotals = m_totals; - ITracker& rootTracker = m_trackerContext.startRun(); - assert(rootTracker.isSectionTracker()); - static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); - runCurrentTest(redirectedCout, redirectedCerr); - } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); +std::string redirectedCout; +std::string redirectedCerr; - Totals deltaTotals = m_totals.delta(prevTotals); - if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting())); +auto const& testInfo = testCase.getTestCaseInfo(); - m_activeTestCase = nullptr; - m_testCaseTracker = nullptr; +m_reporter->testCaseStarting(testInfo); - return deltaTotals; - } +m_activeTestCase = &testCase; - IConfigPtr RunContext::config() const { - return m_config; - } +ITracker& rootTracker = m_trackerContext.startRun(); +assert(rootTracker.isSectionTracker()); +static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); +do { +m_trackerContext.startCycle(); +m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); +runCurrentTest(redirectedCout, redirectedCerr); +} while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); - IStreamingReporter& RunContext::reporter() const { - return *m_reporter; - } +Totals deltaTotals = m_totals.delta(prevTotals); +if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { +deltaTotals.assertions.failed++; +deltaTotals.testCases.passed--; +deltaTotals.testCases.failed++; +} +m_totals.testCases += deltaTotals.testCases; +m_reporter->testCaseEnded(TestCaseStats(testInfo, +deltaTotals, +redirectedCout, +redirectedCerr, +aborting())); - void RunContext::assertionStarting(AssertionInfo const& info) { - m_reporter->assertionStarting( info ); - } - void RunContext::assertionEnded(AssertionResult const & result) { - if (result.getResultType() == ResultWas::Ok) { - m_totals.assertions.passed++; - } else if (!result.isOk()) { - if( m_activeTestCase->getTestCaseInfo().okToFail() ) - m_totals.assertions.failedButOk++; - else - m_totals.assertions.failed++; - } +m_activeTestCase = nullptr; +m_testCaseTracker = nullptr; - // We have no use for the return value (whether messages should be cleared), because messages were made scoped - // and should be let to clear themselves out. - static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); +return deltaTotals; +} - // Reset working state - m_lastAssertionInfo = { "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}", m_lastAssertionInfo.resultDisposition }; - m_lastResult = result; - } +IConfigPtr RunContext::config() const { +return m_config; +} - bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { - ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); - if (!sectionTracker.isOpen()) - return false; - m_activeSections.push_back(§ionTracker); +IStreamingReporter& RunContext::reporter() const { +return *m_reporter; +} - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; +void RunContext::assertionEnded(AssertionResult const & result) { +if (result.getResultType() == ResultWas::Ok) { +m_totals.assertions.passed++; +m_lastAssertionPassed = true; +} else if (!result.isOk()) { +m_lastAssertionPassed = false; +if( m_activeTestCase->getTestCaseInfo().okToFail() ) +m_totals.assertions.failedButOk++; +else +m_totals.assertions.failed++; +} +else { +m_lastAssertionPassed = true; +} - m_reporter->sectionStarting(sectionInfo); +// We have no use for the return value (whether messages should be cleared), because messages were made scoped +// and should be let to clear themselves out. +static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); - assertions = m_totals.assertions; +if (result.getResultType() != ResultWas::Warning) +m_messageScopes.clear(); - return true; - } +// Reset working state +resetAssertionInfo(); +m_lastResult = result; +} +void RunContext::resetAssertionInfo() { +m_lastAssertionInfo.macroName = StringRef(); +m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; +} - bool RunContext::testForMissingAssertions(Counts& assertions) { - if (assertions.total() != 0) - return false; - if (!m_config->warnAboutMissingAssertions()) - return false; - if (m_trackerContext.currentTracker().hasChildren()) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } +bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { +ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); +if (!sectionTracker.isOpen()) +return false; +m_activeSections.push_back(§ionTracker); - void RunContext::sectionEnded(SectionEndInfo const & endInfo) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); +m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - if (!m_activeSections.empty()) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } +m_reporter->sectionStarting(sectionInfo); - m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); - m_messages.clear(); - } +assertions = m_totals.assertions; - void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { - if (m_unfinishedSections.empty()) - m_activeSections.back()->fail(); - else - m_activeSections.back()->close(); - m_activeSections.pop_back(); +return true; +} +auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { +using namespace Generators; +GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); +assert( tracker.isOpen() ); +m_lastAssertionInfo.lineInfo = lineInfo; +return tracker; +} - m_unfinishedSections.push_back(endInfo); - } - void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { - m_reporter->benchmarkStarting( info ); - } - void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { - m_reporter->benchmarkEnded( stats ); - } +bool RunContext::testForMissingAssertions(Counts& assertions) { +if (assertions.total() != 0) +return false; +if (!m_config->warnAboutMissingAssertions()) +return false; +if (m_trackerContext.currentTracker().hasChildren()) +return false; +m_totals.assertions.failed++; +assertions.failed++; +return true; +} - void RunContext::pushScopedMessage(MessageInfo const & message) { - m_messages.push_back(message); - } +void RunContext::sectionEnded(SectionEndInfo const & endInfo) { +Counts assertions = m_totals.assertions - endInfo.prevAssertions; +bool missingAssertions = testForMissingAssertions(assertions); - void RunContext::popScopedMessage(MessageInfo const & message) { - m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); - } +if (!m_activeSections.empty()) { +m_activeSections.back()->close(); +m_activeSections.pop_back(); +} - std::string RunContext::getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } +m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); +m_messages.clear(); +m_messageScopes.clear(); +} - const AssertionResult * RunContext::getLastResult() const { - return &(*m_lastResult); - } +void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { +if (m_unfinishedSections.empty()) +m_activeSections.back()->fail(); +else +m_activeSections.back()->close(); +m_activeSections.pop_back(); - void RunContext::exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } +m_unfinishedSections.push_back(endInfo); +} +void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { +m_reporter->benchmarkStarting( info ); +} +void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { +m_reporter->benchmarkEnded( stats ); +} - void RunContext::handleFatalErrorCondition( StringRef message ) { - // First notify reporter that bad things happened - m_reporter->fatalErrorEncountered(message); +void RunContext::pushScopedMessage(MessageInfo const & message) { +m_messages.push_back(message); +} - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); - tempResult.message = message; - AssertionResult result(m_lastAssertionInfo, tempResult); +void RunContext::popScopedMessage(MessageInfo const & message) { +m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); +} - getResultCapture().assertionEnded(result); +void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { +m_messageScopes.emplace_back( builder ); +} - handleUnfinishedSections(); +std::string RunContext::getCurrentTestName() const { +return m_activeTestCase +? m_activeTestCase->getTestCaseInfo().name +: std::string(); +} - // Recreate section for test case (as we will lose the one that was in scope) - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); +const AssertionResult * RunContext::getLastResult() const { +return &(*m_lastResult); +} - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); - m_reporter->sectionEnded(testCaseSectionStats); +void RunContext::exceptionEarlyReported() { +m_shouldReportUnexpected = false; +} - auto const& testInfo = m_activeTestCase->getTestCaseInfo(); +void RunContext::handleFatalErrorCondition( StringRef message ) { +// First notify reporter that bad things happened +m_reporter->fatalErrorEncountered(message); - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - std::string(), - std::string(), - false)); - m_totals.testCases.failed++; - testGroupEnded(std::string(), m_totals, 1, 1); - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); - } +// Don't rebuild the result -- the stringification itself can cause more fatal errors +// Instead, fake a result data. +AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); +tempResult.message = message; +AssertionResult result(m_lastAssertionInfo, tempResult); - bool RunContext::lastAssertionPassed() { - return m_totals.assertions.passed == (m_prevPassed + 1); - } +assertionEnded(result); - void RunContext::assertionPassed() { - ++m_totals.assertions.passed; - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"; - m_lastAssertionInfo.macroName = ""; - } +handleUnfinishedSections(); - void RunContext::assertionRun() { - m_prevPassed = m_totals.assertions.passed; - } +// Recreate section for test case (as we will lose the one that was in scope) +auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); +SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); - bool RunContext::aborting() const { - return m_totals.assertions.failed == static_cast(m_config->abortAfter()); - } +Counts assertions; +assertions.failed = 1; +SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); +m_reporter->sectionEnded(testCaseSectionStats); - void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); - m_reporter->sectionStarting(testCaseSection); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - try { - m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal }; +auto const& testInfo = m_activeTestCase->getTestCaseInfo(); - seedRng(*m_config); +Totals deltaTotals; +deltaTotals.testCases.failed = 1; +deltaTotals.assertions.failed = 1; +m_reporter->testCaseEnded(TestCaseStats(testInfo, +deltaTotals, +std::string(), +std::string(), +false)); +m_totals.testCases.failed++; +testGroupEnded(std::string(), m_totals, 1, 1); +m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); +} - Timer timer; - timer.start(); - if (m_reporter->getPreferences().shouldRedirectStdOut) { - StreamRedirect coutRedir(cout(), redirectedCout); - StdErrRedirect errRedir(redirectedCerr); - invokeActiveTestCase(); - } else { - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } catch (TestFailureException&) { - // This just means the test was aborted due to failure - } catch (...) { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if (m_shouldReportUnexpected) { - AssertionHandler - ( m_lastAssertionInfo.macroName, - m_lastAssertionInfo.lineInfo, - m_lastAssertionInfo.capturedExpression, - m_lastAssertionInfo.resultDisposition ).useActiveException(); - } - } - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); +bool RunContext::lastAssertionPassed() { +return m_lastAssertionPassed; +} - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); - m_reporter->sectionEnded(testCaseSectionStats); - } +void RunContext::assertionPassed() { +m_lastAssertionPassed = true; +++m_totals.assertions.passed; +resetAssertionInfo(); +m_messageScopes.clear(); +} - void RunContext::invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } +bool RunContext::aborting() const { +return m_totals.assertions.failed >= static_cast(m_config->abortAfter()); +} - void RunContext::handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for (auto it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it) - sectionEnded(*it); - m_unfinishedSections.clear(); - } +void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { +auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); +SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); +m_reporter->sectionStarting(testCaseSection); +Counts prevAssertions = m_totals.assertions; +double duration = 0; +m_shouldReportUnexpected = true; +m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; - IResultCapture& getResultCapture() { - if (auto* capture = getCurrentContext().getResultCapture()) - return *capture; - else - CATCH_INTERNAL_ERROR("No result capture instance"); - } +seedRng(*m_config); + +Timer timer; +CATCH_TRY { +if (m_reporter->getPreferences().shouldRedirectStdOut) { +#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); + +timer.start(); +invokeActiveTestCase(); +#else +OutputRedirect r(redirectedCout, redirectedCerr); +timer.start(); +invokeActiveTestCase(); +#endif +} else { +timer.start(); +invokeActiveTestCase(); +} +duration = timer.getElapsedSeconds(); +} CATCH_CATCH_ANON (TestFailureException&) { +// This just means the test was aborted due to failure +} CATCH_CATCH_ALL { +// Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions +// are reported without translation at the point of origin. +if( m_shouldReportUnexpected ) { +AssertionReaction dummyReaction; +handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); +} +} +Counts assertions = m_totals.assertions - prevAssertions; +bool missingAssertions = testForMissingAssertions(assertions); + +m_testCaseTracker->close(); +handleUnfinishedSections(); +m_messages.clear(); +m_messageScopes.clear(); + +SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); +m_reporter->sectionEnded(testCaseSectionStats); +} + +void RunContext::invokeActiveTestCase() { +FatalConditionHandler fatalConditionHandler; // Handle signals +m_activeTestCase->invoke(); +fatalConditionHandler.reset(); +} + +void RunContext::handleUnfinishedSections() { +// If sections ended prematurely due to an exception we stored their +// infos here so we can tear them down outside the unwind process. +for (auto it = m_unfinishedSections.rbegin(), +itEnd = m_unfinishedSections.rend(); +it != itEnd; +++it) +sectionEnded(*it); +m_unfinishedSections.clear(); +} + +void RunContext::handleExpr( +AssertionInfo const& info, +ITransientExpression const& expr, +AssertionReaction& reaction +) { +m_reporter->assertionStarting( info ); + +bool negated = isFalseTest( info.resultDisposition ); +bool result = expr.getResult() != negated; + +if( result ) { +if (!m_includeSuccessfulResults) { +assertionPassed(); +} +else { +reportExpr(info, ResultWas::Ok, &expr, negated); +} +} +else { +reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); +populateReaction( reaction ); +} +} +void RunContext::reportExpr( +AssertionInfo const &info, +ResultWas::OfType resultType, +ITransientExpression const *expr, +bool negated ) { + +m_lastAssertionInfo = info; +AssertionResultData data( resultType, LazyExpression( negated ) ); + +AssertionResult assertionResult{ info, data }; +assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; + +assertionEnded( assertionResult ); +} + +void RunContext::handleMessage( +AssertionInfo const& info, +ResultWas::OfType resultType, +StringRef const& message, +AssertionReaction& reaction +) { +m_reporter->assertionStarting( info ); + +m_lastAssertionInfo = info; + +AssertionResultData data( resultType, LazyExpression( false ) ); +data.message = message; +AssertionResult assertionResult{ m_lastAssertionInfo, data }; +assertionEnded( assertionResult ); +if( !assertionResult.isOk() ) +populateReaction( reaction ); +} +void RunContext::handleUnexpectedExceptionNotThrown( +AssertionInfo const& info, +AssertionReaction& reaction +) { +handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); +} + +void RunContext::handleUnexpectedInflightException( +AssertionInfo const& info, +std::string const& message, +AssertionReaction& reaction +) { +m_lastAssertionInfo = info; + +AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); +data.message = message; +AssertionResult assertionResult{ info, data }; +assertionEnded( assertionResult ); +populateReaction( reaction ); +} + +void RunContext::populateReaction( AssertionReaction& reaction ) { +reaction.shouldDebugBreak = m_config->shouldDebugBreak(); +reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); +} + +void RunContext::handleIncomplete( +AssertionInfo const& info +) { +m_lastAssertionInfo = info; + +AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); +data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; +AssertionResult assertionResult{ info, data }; +assertionEnded( assertionResult ); +} +void RunContext::handleNonExpr( +AssertionInfo const &info, +ResultWas::OfType resultType, +AssertionReaction &reaction +) { +m_lastAssertionInfo = info; + +AssertionResultData data( resultType, LazyExpression( false ) ); +AssertionResult assertionResult{ info, data }; +assertionEnded( assertionResult ); + +if( !assertionResult.isOk() ) +populateReaction( reaction ); +} + +IResultCapture& getResultCapture() { +if (auto* capture = getCurrentContext().getResultCapture()) +return *capture; +else +CATCH_INTERNAL_ERROR("No result capture instance"); +} } // end catch_run_context.cpp // start catch_section.cpp namespace Catch { - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } +Section::Section( SectionInfo const& info ) +: m_info( info ), +m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) +{ +m_timer.start(); +} -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4996) // std::uncaught_exception is deprecated in C++17 -#endif - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); - if( std::uncaught_exception() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); - } - } -#if defined(_MSC_VER) -#pragma warning(pop) -#endif +Section::~Section() { +if( m_sectionIncluded ) { +SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; +if( uncaught_exceptions() ) +getResultCapture().sectionEndedEarly( endInfo ); +else +getResultCapture().sectionEnded( endInfo ); +} +} - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } +// This indicates whether the section should be executed or not +Section::operator bool() const { +return m_sectionIncluded; +} } // end namespace Catch // end catch_section.cpp @@ -8013,18 +10786,12 @@ namespace Catch { namespace Catch { - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} - - SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) - : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} +SectionInfo::SectionInfo +( SourceLineInfo const& _lineInfo, +std::string const& _name ) +: name( _name ), +lineInfo( _lineInfo ) +{} } // end namespace Catch // end catch_section_info.cpp @@ -8036,37 +10803,46 @@ namespace Catch { namespace Catch { - class Session : NonCopyable { - public: +class Session : NonCopyable { +public: - Session(); - ~Session() override; +Session(); +~Session() override; - void showHelp() const; - void libIdentify(); +void showHelp() const; +void libIdentify(); - int applyCommandLine( int argc, char* argv[] ); +int applyCommandLine( int argc, char const * const * argv ); +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) +int applyCommandLine( int argc, wchar_t const * const * argv ); +#endif - void useConfigData( ConfigData const& configData ); +void useConfigData( ConfigData const& configData ); - int run( int argc, char* argv[] ); - #if defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t* const argv[] ); - #endif - int run(); +template +int run(int argc, CharT const * const argv[]) { +if (m_startupExceptions) +return 1; +int returnCode = applyCommandLine(argc, argv); +if (returnCode == 0) +returnCode = run(); +return returnCode; +} - clara::Parser const& cli() const; - void cli( clara::Parser const& newParser ); - ConfigData& configData(); - Config& config(); - private: - int runInternal(); +int run(); - clara::Parser m_cli; - ConfigData m_configData; - std::shared_ptr m_config; - bool m_startupExceptions = false; - }; +clara::Parser const& cli() const; +void cli( clara::Parser const& newParser ); +ConfigData& configData(); +Config& config(); +private: +int runInternal(); + +clara::Parser m_cli; +ConfigData m_configData; +std::shared_ptr m_config; +bool m_startupExceptions = false; +}; } // end namespace Catch @@ -8077,406 +10853,513 @@ namespace Catch { namespace Catch { - // Versioning information - struct Version { - Version( Version const& ) = delete; - Version& operator=( Version const& ) = delete; - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ); +// Versioning information +struct Version { +Version( Version const& ) = delete; +Version& operator=( Version const& ) = delete; +Version( unsigned int _majorVersion, +unsigned int _minorVersion, +unsigned int _patchNumber, +char const * const _branchName, +unsigned int _buildNumber ); - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; +unsigned int const majorVersion; +unsigned int const minorVersion; +unsigned int const patchNumber; - // buildNumber is only used if branchName is not null - char const * const branchName; - unsigned int const buildNumber; +// buildNumber is only used if branchName is not null +char const * const branchName; +unsigned int const buildNumber; - friend std::ostream& operator << ( std::ostream& os, Version const& version ); - }; +friend std::ostream& operator << ( std::ostream& os, Version const& version ); +}; - Version const& libraryVersion(); +Version const& libraryVersion(); } // end catch_version.h #include #include -namespace { - const int MaxExitCode = 255; - using Catch::IStreamingReporterPtr; - using Catch::IConfigPtr; - using Catch::Config; - - IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { - auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); - CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); - - return reporter; - } - -#ifndef CATCH_CONFIG_DEFAULT_REPORTER -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif - - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - auto const& reporterNames = config->getReporterNames(); - if (reporterNames.empty()) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); - - IStreamingReporterPtr reporter; - for (auto const& name : reporterNames) - addReporter(reporter, createReporter(name, config)); - return reporter; - } - -#undef CATCH_CONFIG_DEFAULT_REPORTER - - void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) - addReporter(reporters, listener->create(Catch::ReporterConfig(config))); - } - - Catch::Totals runTests(std::shared_ptr const& config) { - using namespace Catch; - IStreamingReporterPtr reporter = makeReporter(config); - addListeners(reporter, config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - if (!testSpec.hasFilters()) - testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); - } - - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } - - void applyFilenamesAsTags(Catch::IConfig const& config) { - using namespace Catch; - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; - - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; - } - - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); - } - - tags.push_back(std::move(filename)); - setTags(testCase, tags); - } - } - -} - namespace Catch { - Session::Session() { - static bool alreadyInstantiated = false; - if( alreadyInstantiated ) { - try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - catch(...) { getMutableRegistryHub().registerStartupException(); } - } +namespace { +const int MaxExitCode = 255; - const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); - if ( !exceptions.empty() ) { - m_startupExceptions = true; - Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occured during startup!" << '\n'; - // iterate over all exceptions and notify user - for ( const auto& ex_ptr : exceptions ) { - try { - std::rethrow_exception(ex_ptr); - } catch ( std::exception const& ex ) { - Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; - } - } - } +IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { +auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); +CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); - alreadyInstantiated = true; - m_cli = makeCommandLineParser( m_configData ); - } - Session::~Session() { - Catch::cleanUp(); - } +return reporter; +} - void Session::showHelp() const { - Catch::cout() - << "\nCatch v" << libraryVersion() << "\n" - << m_cli << std::endl - << "For more detailed usage please see the project docs\n" << std::endl; - } - void Session::libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch Test\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; - } +IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { +if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { +return createReporter(config->getReporterName(), config); +} - int Session::applyCommandLine( int argc, char* argv[] ) { - if( m_startupExceptions ) - return 1; +// On older platforms, returning std::unique_ptr +// when the return type is std::unique_ptr +// doesn't compile without a std::move call. However, this causes +// a warning on newer platforms. Thus, we have to work around +// it a bit and downcast the pointer manually. +auto ret = std::unique_ptr(new ListeningReporter); +auto& multi = static_cast(*ret); +auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); +for (auto const& listener : listeners) { +multi.addListener(listener->create(Catch::ReporterConfig(config))); +} +multi.addReporter(createReporter(config->getReporterName(), config)); +return ret; +} - auto result = m_cli.parse( clara::Args( argc, argv ) ); - if( !result ) { - Catch::cerr() - << Colour( Colour::Red ) - << "\nError(s) in input:\n" - << Column( result.errorMessage() ).indent( 2 ) - << "\n\n"; - Catch::cerr() << "Run with -? for usage\n" << std::endl; - return MaxExitCode; - } +Catch::Totals runTests(std::shared_ptr const& config) { +auto reporter = makeReporter(config); - if( m_configData.showHelp ) - showHelp(); - if( m_configData.libIdentify ) - libIdentify(); - m_config.reset(); - return 0; - } +RunContext context(config, std::move(reporter)); - void Session::useConfigData( ConfigData const& configData ) { - m_configData = configData; - m_config.reset(); - } +Totals totals; - int Session::run( int argc, char* argv[] ) { - if( m_startupExceptions ) - return 1; - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } +context.testGroupStarting(config->name(), 1, 1); -#if defined(WIN32) && defined(UNICODE) - int Session::run( int argc, wchar_t* const argv[] ) { +TestSpec testSpec = config->testSpec(); - char **utf8Argv = new char *[ argc ]; +auto const& allTestCases = getAllTestCasesSorted(*config); +for (auto const& testCase : allTestCases) { +bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) || +(testSpec.hasFilters() && matchTest(testCase, testSpec, *config)); - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); +if (!context.aborting() && matching) +totals += context.runTest(testCase); +else +context.reporter().skipTest(testCase); +} - utf8Argv[ i ] = new char[ bufSize ]; +if (config->warnAboutNoTests() && totals.testCases.total() == 0) { +ReusableStringStream testConfig; - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } +bool first = true; +for (const auto& input : config->getTestsOrTags()) { +if (!first) { testConfig << ' '; } +first = false; +testConfig << input; +} - int returnCode = run( argc, utf8Argv ); +context.reporter().noMatchingTestCases(testConfig.str()); +totals.error = -1; +} - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; +context.testGroupEnded(config->name(), totals, 1, 1); +return totals; +} - delete [] utf8Argv; +void applyFilenamesAsTags(Catch::IConfig const& config) { +auto& tests = const_cast&>(getAllTestCasesSorted(config)); +for (auto& testCase : tests) { +auto tags = testCase.tags; - return returnCode; - } +std::string filename = testCase.lineInfo.file; +auto lastSlash = filename.find_last_of("\\/"); +if (lastSlash != std::string::npos) { +filename.erase(0, lastSlash); +filename[0] = '#'; +} + +auto lastDot = filename.find_last_of('.'); +if (lastDot != std::string::npos) { +filename.erase(lastDot); +} + +tags.push_back(std::move(filename)); +setTags(testCase, tags); +} +} + +} // anon namespace + +Session::Session() { +static bool alreadyInstantiated = false; +if( alreadyInstantiated ) { +CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } +CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } +} + +// There cannot be exceptions at startup in no-exception mode. +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); +if ( !exceptions.empty() ) { +m_startupExceptions = true; +Colour colourGuard( Colour::Red ); +Catch::cerr() << "Errors occurred during startup!" << '\n'; +// iterate over all exceptions and notify user +for ( const auto& ex_ptr : exceptions ) { +try { +std::rethrow_exception(ex_ptr); +} catch ( std::exception const& ex ) { +Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; +} +} +} #endif - int Session::run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting" << std::endl; - static_cast(std::getchar()); - } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; - static_cast(std::getchar()); - } - return exitCode; - } - clara::Parser const& Session::cli() const { - return m_cli; - } - void Session::cli( clara::Parser const& newParser ) { - m_cli = newParser; - } - ConfigData& Session::configData() { - return m_configData; - } - Config& Session::config() { - if( !m_config ) - m_config = std::make_shared( m_configData ); - return *m_config; - } +alreadyInstantiated = true; +m_cli = makeCommandLineParser( m_configData ); +} +Session::~Session() { +Catch::cleanUp(); +} - int Session::runInternal() { - if( m_startupExceptions ) - return 1; +void Session::showHelp() const { +Catch::cout() +<< "\nCatch v" << libraryVersion() << "\n" +<< m_cli << std::endl +<< "For more detailed usage please see the project docs\n" << std::endl; +} +void Session::libIdentify() { +Catch::cout() +<< std::left << std::setw(16) << "description: " << "A Catch test executable\n" +<< std::left << std::setw(16) << "category: " << "testframework\n" +<< std::left << std::setw(16) << "framework: " << "Catch Test\n" +<< std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; +} - if( m_configData.showHelp || m_configData.libIdentify ) - return 0; +int Session::applyCommandLine( int argc, char const * const * argv ) { +if( m_startupExceptions ) +return 1; - try - { - config(); // Force config to be constructed +auto result = m_cli.parse( clara::Args( argc, argv ) ); +if( !result ) { +config(); +getCurrentMutableContext().setConfig(m_config); +Catch::cerr() +<< Colour( Colour::Red ) +<< "\nError(s) in input:\n" +<< Column( result.errorMessage() ).indent( 2 ) +<< "\n\n"; +Catch::cerr() << "Run with -? for usage\n" << std::endl; +return MaxExitCode; +} - seedRng( *m_config ); +if( m_configData.showHelp ) +showHelp(); +if( m_configData.libIdentify ) +libIdentify(); +m_config.reset(); +return 0; +} - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) +int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); +char **utf8Argv = new char *[ argc ]; - return (std::min)( MaxExitCode, static_cast( runTests( m_config ).assertions.failed ) ); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return MaxExitCode; - } - } +for ( int i = 0; i < argc; ++i ) { +int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + +utf8Argv[ i ] = new char[ bufSize ]; + +WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); +} + +int returnCode = applyCommandLine( argc, utf8Argv ); + +for ( int i = 0; i < argc; ++i ) +delete [] utf8Argv[ i ]; + +delete [] utf8Argv; + +return returnCode; +} +#endif + +void Session::useConfigData( ConfigData const& configData ) { +m_configData = configData; +m_config.reset(); +} + +int Session::run() { +if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { +Catch::cout() << "...waiting for enter/ return before starting" << std::endl; +static_cast(std::getchar()); +} +int exitCode = runInternal(); +if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { +Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; +static_cast(std::getchar()); +} +return exitCode; +} + +clara::Parser const& Session::cli() const { +return m_cli; +} +void Session::cli( clara::Parser const& newParser ) { +m_cli = newParser; +} +ConfigData& Session::configData() { +return m_configData; +} +Config& Session::config() { +if( !m_config ) +m_config = std::make_shared( m_configData ); +return *m_config; +} + +int Session::runInternal() { +if( m_startupExceptions ) +return 1; + +if (m_configData.showHelp || m_configData.libIdentify) { +return 0; +} + +CATCH_TRY { +config(); // Force config to be constructed + +seedRng( *m_config ); + +if( m_configData.filenamesAsTags ) +applyFilenamesAsTags( *m_config ); + +// Handle list request +if( Option listed = list( m_config ) ) +return static_cast( *listed ); + +auto totals = runTests( m_config ); +// Note that on unices only the lower 8 bits are usually used, clamping +// the return value to 255 prevents false negative when some multiple +// of 256 tests has failed +return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); +} +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +catch( std::exception& ex ) { +Catch::cerr() << ex.what() << std::endl; +return MaxExitCode; +} +#endif +} } // end namespace Catch // end catch_session.cpp +// start catch_singletons.cpp + +#include + +namespace Catch { + +namespace { +static auto getSingletons() -> std::vector*& { +static std::vector* g_singletons = nullptr; +if( !g_singletons ) +g_singletons = new std::vector(); +return g_singletons; +} +} + +ISingleton::~ISingleton() {} + +void addSingleton(ISingleton* singleton ) { +getSingletons()->push_back( singleton ); +} +void cleanupSingletons() { +auto& singletons = getSingletons(); +for( auto singleton : *singletons ) +delete singleton; +delete singletons; +singletons = nullptr; +} + +} // namespace Catch +// end catch_singletons.cpp // start catch_startup_exception_registry.cpp namespace Catch { - void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - try { - m_exceptions.push_back(exception); - } - catch(...) { - // If we run out of memory during start-up there's really not a lot more we can do about it - std::terminate(); - } - } +void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { +CATCH_TRY { +m_exceptions.push_back(exception); +} CATCH_CATCH_ALL { +// If we run out of memory during start-up there's really not a lot more we can do about it +std::terminate(); +} +} - std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { - return m_exceptions; - } +std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { +return m_exceptions; +} } // end namespace Catch // end catch_startup_exception_registry.cpp // start catch_stream.cpp -#include #include #include +#include +#include +#include +#include namespace Catch { - template - class StreamBufImpl : public StreamBufBase { - char data[bufferSize]; - WriterF m_writer; +Catch::IStream::~IStream() = default; - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } +namespace detail { namespace { +template +class StreamBufImpl : public std::streambuf { +char data[bufferSize]; +WriterF m_writer; - ~StreamBufImpl() noexcept { - StreamBufImpl::sync(); - } +public: +StreamBufImpl() { +setp( data, data + sizeof(data) ); +} - private: - int overflow( int c ) override { - sync(); +~StreamBufImpl() noexcept { +StreamBufImpl::sync(); +} - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } +private: +int overflow( int c ) override { +sync(); - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; +if( c != EOF ) { +if( pbase() == epptr() ) +m_writer( std::string( 1, static_cast( c ) ) ); +else +sputc( static_cast( c ) ); +} +return 0; +} - /////////////////////////////////////////////////////////////////////////// +int sync() override { +if( pbase() != pptr() ) { +m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); +setp( pbase(), epptr() ); +} +return 0; +} +}; - Catch::IStream::~IStream() = default; +/////////////////////////////////////////////////////////////////////////// - FileStream::FileStream( std::string const& filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); - } +struct OutputDebugWriter { - std::ostream& FileStream::stream() const { - return m_ofs; - } +void operator()( std::string const&str ) { +writeToDebugConsole( str ); +} +}; - struct OutputDebugWriter { +/////////////////////////////////////////////////////////////////////////// - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; +class FileStream : public IStream { +mutable std::ofstream m_ofs; +public: +FileStream( StringRef filename ) { +m_ofs.open( filename.c_str() ); +CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); +} +~FileStream() override = default; +public: // IStream +std::ostream& stream() const override { +return m_ofs; +} +}; - DebugOutStream::DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) - {} +/////////////////////////////////////////////////////////////////////////// - std::ostream& DebugOutStream::stream() const { - return m_os; - } +class CoutStream : public IStream { +mutable std::ostream m_os; +public: +// Store the streambuf from cout up-front because +// cout may get redirected when running tests +CoutStream() : m_os( Catch::cout().rdbuf() ) {} +~CoutStream() override = default; - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream::CoutStream() - : m_os( Catch::cout().rdbuf() ) - {} +public: // IStream +std::ostream& stream() const override { return m_os; } +}; - std::ostream& CoutStream::stream() const { - return m_os; - } +/////////////////////////////////////////////////////////////////////////// + +class DebugOutStream : public IStream { +std::unique_ptr> m_streamBuf; +mutable std::ostream m_os; +public: +DebugOutStream() +: m_streamBuf( new StreamBufImpl() ), +m_os( m_streamBuf.get() ) +{} + +~DebugOutStream() override = default; + +public: // IStream +std::ostream& stream() const override { return m_os; } +}; + +}} // namespace anon::detail + +/////////////////////////////////////////////////////////////////////////// + +auto makeStream( StringRef const &filename ) -> IStream const* { +if( filename.empty() ) +return new detail::CoutStream(); +else if( filename[0] == '%' ) { +if( filename == "%debug" ) +return new detail::DebugOutStream(); +else +CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); +} +else +return new detail::FileStream( filename ); +} + +// This class encapsulates the idea of a pool of ostringstreams that can be reused. +struct StringStreams { +std::vector> m_streams; +std::vector m_unused; +std::ostringstream m_referenceStream; // Used for copy state/ flags from + +auto add() -> std::size_t { +if( m_unused.empty() ) { +m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); +return m_streams.size()-1; +} +else { +auto index = m_unused.back(); +m_unused.pop_back(); +return index; +} +} + +void release( std::size_t index ) { +m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state +m_unused.push_back(index); +} +}; + +ReusableStringStream::ReusableStringStream() +: m_index( Singleton::getMutable().add() ), +m_oss( Singleton::getMutable().m_streams[m_index].get() ) +{} + +ReusableStringStream::~ReusableStringStream() { +static_cast( m_oss )->str(""); +m_oss->clear(); +Singleton::getMutable().release( m_index ); +} + +auto ReusableStringStream::str() const -> std::string { +return static_cast( m_oss )->str(); +} + +/////////////////////////////////////////////////////////////////////////// #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions - std::ostream& cout() { - return std::cout; - } - std::ostream& cerr() { - return std::cerr; - } - std::ostream& clog() { - return std::clog; - } +std::ostream& cout() { return std::cout; } +std::ostream& cerr() { return std::cerr; } +std::ostream& clog() { return std::clog; } #endif } // end catch_stream.cpp -// start catch_streambuf.cpp - -namespace Catch { - StreamBufBase::~StreamBufBase() = default; -} -// end catch_streambuf.cpp // start catch_string_manip.cpp #include @@ -8486,65 +11369,68 @@ namespace Catch { namespace Catch { - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( std::string const& s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); +namespace { +char toLowerCh(char c) { +return static_cast( std::tolower( c ) ); +} +} - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } +bool startsWith( std::string const& s, std::string const& prefix ) { +return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); +} +bool startsWith( std::string const& s, char prefix ) { +return !s.empty() && s[0] == prefix; +} +bool endsWith( std::string const& s, std::string const& suffix ) { +return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); +} +bool endsWith( std::string const& s, char suffix ) { +return !s.empty() && s[s.size()-1] == suffix; +} +bool contains( std::string const& s, std::string const& infix ) { +return s.find( infix ) != std::string::npos; +} +void toLowerInPlace( std::string& s ) { +std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); +} +std::string toLower( std::string const& s ) { +std::string lc = s; +toLowerInPlace( lc ); +return lc; +} +std::string trim( std::string const& str ) { +static char const* whitespaceChars = "\n\r\t "; +std::string::size_type start = str.find_first_not_of( whitespaceChars ); +std::string::size_type end = str.find_last_not_of( whitespaceChars ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } +return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); +} - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} +bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { +bool replaced = false; +std::size_t i = str.find( replaceThis ); +while( i != std::string::npos ) { +replaced = true; +str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); +if( i < str.size()-withThis.size() ) +i = str.find( replaceThis, i+withThis.size() ); +else +i = std::string::npos; +} +return replaced; +} - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; - } +pluralise::pluralise( std::size_t count, std::string const& label ) +: m_count( count ), +m_label( label ) +{} + +std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { +os << pluraliser.m_count << ' ' << pluraliser.m_label; +if( pluraliser.m_count != 1 ) +os << 's'; +return os; +} } // end catch_string_manip.cpp @@ -8556,156 +11442,111 @@ namespace Catch { #endif #include -#include #include +#include + +namespace { +const uint32_t byte_2_lead = 0xC0; +const uint32_t byte_3_lead = 0xE0; +const uint32_t byte_4_lead = 0xF0; +} namespace Catch { +StringRef::StringRef( char const* rawChars ) noexcept +: StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) +{} - auto getEmptyStringRef() -> StringRef { - static StringRef s_emptyStringRef(""); - return s_emptyStringRef; - } +StringRef::operator std::string() const { +return std::string( m_start, m_size ); +} - StringRef::StringRef() noexcept - : StringRef( getEmptyStringRef() ) - {} +void StringRef::swap( StringRef& other ) noexcept { +std::swap( m_start, other.m_start ); +std::swap( m_size, other.m_size ); +std::swap( m_data, other.m_data ); +} - StringRef::StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} +auto StringRef::c_str() const -> char const* { +if( isSubstring() ) +const_cast( this )->takeOwnership(); +return m_start; +} +auto StringRef::currentData() const noexcept -> char const* { +return m_start; +} - StringRef::StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } +auto StringRef::isOwned() const noexcept -> bool { +return m_data != nullptr; +} +auto StringRef::isSubstring() const noexcept -> bool { +return m_start[m_size] != '\0'; +} - StringRef::StringRef( char const* rawChars ) noexcept - : m_start( rawChars ), - m_size( static_cast( std::strlen( rawChars ) ) ) - { - assert( rawChars != nullptr ); - } +void StringRef::takeOwnership() { +if( !isOwned() ) { +m_data = new char[m_size+1]; +memcpy( m_data, m_start, m_size ); +m_data[m_size] = '\0'; +m_start = m_data; +} +} +auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { +if( start < m_size ) +return StringRef( m_start+start, size ); +else +return StringRef(); +} +auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { +return +size() == other.size() && +(std::strncmp( m_start, other.m_start, size() ) == 0); +} +auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { +return !operator==( other ); +} - StringRef::StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - { - size_type rawSize = rawChars == nullptr ? 0 : static_cast( std::strlen( rawChars ) ); - if( rawSize < size ) - m_size = rawSize; - } +auto StringRef::operator[](size_type index) const noexcept -> char { +return m_start[index]; +} - StringRef::StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} +auto StringRef::numberOfCharacters() const noexcept -> size_type { +size_type noChars = m_size; +// Make adjustments for uft encodings +for( size_type i=0; i < m_size; ++i ) { +char c = m_start[i]; +if( ( c & byte_2_lead ) == byte_2_lead ) { +noChars--; +if (( c & byte_3_lead ) == byte_3_lead ) +noChars--; +if( ( c & byte_4_lead ) == byte_4_lead ) +noChars--; +} +} +return noChars; +} - StringRef::~StringRef() noexcept { - delete[] m_data; - } +auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { +std::string str; +str.reserve( lhs.size() + rhs.size() ); +str += lhs; +str += rhs; +return str; +} +auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { +return std::string( lhs ) + std::string( rhs ); +} +auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { +return std::string( lhs ) + std::string( rhs ); +} - auto StringRef::operator = ( StringRef other ) noexcept -> StringRef& { - swap( other ); - return *this; - } - StringRef::operator std::string() const { - return std::string( m_start, m_size ); - } +auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { +return os.write(str.currentData(), str.size()); +} - void StringRef::swap( StringRef& other ) noexcept { - std::swap( m_start, other.m_start ); - std::swap( m_size, other.m_size ); - std::swap( m_data, other.m_data ); - } - - auto StringRef::c_str() const -> char const* { - if( isSubstring() ) - const_cast( this )->takeOwnership(); - return m_start; - } - auto StringRef::data() const noexcept -> char const* { - return m_start; - } - - auto StringRef::isOwned() const noexcept -> bool { - return m_data != nullptr; - } - auto StringRef::isSubstring() const noexcept -> bool { - return m_start[m_size] != '\0'; - } - - void StringRef::takeOwnership() { - if( !isOwned() ) { - m_data = new char[m_size+1]; - memcpy( m_data, m_start, m_size ); - m_data[m_size] = '\0'; - m_start = m_data; - } - } - auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { - if( start < m_size ) - return StringRef( m_start+start, size ); - else - return StringRef(); - } - auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { - return - size() == other.size() && - (std::strncmp( m_start, other.m_start, size() ) == 0); - } - auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { - return !operator==( other ); - } - - auto StringRef::operator[](size_type index) const noexcept -> char { - return m_start[index]; - } - - auto StringRef::empty() const noexcept -> bool { - return m_size == 0; - } - - auto StringRef::size() const noexcept -> size_type { - return m_size; - } - auto StringRef::numberOfCharacters() const noexcept -> size_type { - size_type noChars = m_size; - // Make adjustments for uft encodings - for( size_type i=0; i < m_size; ++i ) { - char c = m_start[i]; - if( ( c & 0b11000000 ) == 0b11000000 ) { - if( ( c & 0b11100000 ) == 0b11000000 ) - noChars--; - else if( ( c & 0b11110000 ) == 0b11100000 ) - noChars-=2; - else if( ( c & 0b11111000 ) == 0b11110000 ) - noChars-=3; - } - } - return noChars; - } - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { - std::string str; - str.reserve( lhs.size() + rhs.size() ); - str += lhs; - str += rhs; - return str; - } - auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - - auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os << str.c_str(); - } +auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { +lhs.append(rhs.currentData(), rhs.size()); +return lhs; +} } // namespace Catch @@ -8716,66 +11557,68 @@ namespace Catch { // start catch_tag_alias.cpp namespace Catch { - TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} +TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} } // end catch_tag_alias.cpp // start catch_tag_alias_autoregistrar.cpp namespace Catch { - RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - try { - getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } catch (...) { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } +RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { +CATCH_TRY { +getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); +} CATCH_CATCH_ALL { +// Do not throw when constructing global objects, instead register the exception to be processed later +getMutableRegistryHub().registerStartupException(); +} +} } // end catch_tag_alias_autoregistrar.cpp // start catch_tag_alias_registry.cpp +#include + namespace Catch { - TagAliasRegistry::~TagAliasRegistry() {} +TagAliasRegistry::~TagAliasRegistry() {} - TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { - auto it = m_registry.find( alias ); - if( it != m_registry.end() ) - return &(it->second); - else - return nullptr; - } +TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { +auto it = m_registry.find( alias ); +if( it != m_registry.end() ) +return &(it->second); +else +return nullptr; +} - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( auto const& registryKvp : m_registry ) { - std::size_t pos = expandedTestSpec.find( registryKvp.first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - registryKvp.second.tag + - expandedTestSpec.substr( pos + registryKvp.first.size() ); - } - } - return expandedTestSpec; - } +std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { +std::string expandedTestSpec = unexpandedTestSpec; +for( auto const& registryKvp : m_registry ) { +std::size_t pos = expandedTestSpec.find( registryKvp.first ); +if( pos != std::string::npos ) { +expandedTestSpec = expandedTestSpec.substr( 0, pos ) + +registryKvp.second.tag + +expandedTestSpec.substr( pos + registryKvp.first.size() ); +} +} +return expandedTestSpec; +} - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), - "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); +void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { +CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), +"error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); - CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, - "error: tag alias, '" << alias << "' already registered.\n" - << "\tFirst seen at: " << find(alias)->lineInfo << "\n" - << "\tRedefined at: " << lineInfo ); - } +CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, +"error: tag alias, '" << alias << "' already registered.\n" +<< "\tFirst seen at: " << find(alias)->lineInfo << "\n" +<< "\tRedefined at: " << lineInfo ); +} - ITagAliasRegistry::~ITagAliasRegistry() {} +ITagAliasRegistry::~ITagAliasRegistry() {} - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); - } +ITagAliasRegistry const& ITagAliasRegistry::get() { +return getRegistryHub().getTagAliasRegistry(); +} } // end namespace Catch // end catch_tag_alias_registry.cpp @@ -8784,162 +11627,171 @@ namespace Catch { #include #include #include +#include namespace Catch { - TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else if( tag == "!benchmark" ) - return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); - else - return TestCaseInfo::None; - } - bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); - } - void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - CATCH_ENFORCE( !isReservedTag(tag), - "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << _lineInfo ); - } +namespace { +TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { +if( startsWith( tag, '.' ) || +tag == "!hide" ) +return TestCaseInfo::IsHidden; +else if( tag == "!throws" ) +return TestCaseInfo::Throws; +else if( tag == "!shouldfail" ) +return TestCaseInfo::ShouldFail; +else if( tag == "!mayfail" ) +return TestCaseInfo::MayFail; +else if( tag == "!nonportable" ) +return TestCaseInfo::NonPortable; +else if( tag == "!benchmark" ) +return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); +else +return TestCaseInfo::None; +} +bool isReservedTag( std::string const& tag ) { +return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast(tag[0]) ); +} +void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { +CATCH_ENFORCE( !isReservedTag(tag), +"Tag name: [" << tag << "] is not allowed.\n" +<< "Tag names starting with non alphanumeric characters are reserved\n" +<< _lineInfo ); +} +} - TestCase makeTestCase( ITestInvoker* _testCase, - std::string const& _className, - std::string const& _name, - std::string const& _descOrTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden = false; +TestCase makeTestCase( ITestInvoker* _testCase, +std::string const& _className, +NameAndTags const& nameAndTags, +SourceLineInfo const& _lineInfo ) +{ +bool isHidden = false; - // Parse out tags - std::vector tags; - std::string desc, tag; - bool inTag = false; - for (char c : _descOrTags) { - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; - } - else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( ( prop & TestCaseInfo::IsHidden ) != 0 ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); +// Parse out tags +std::vector tags; +std::string desc, tag; +bool inTag = false; +std::string _descOrTags = nameAndTags.tags; +for (char c : _descOrTags) { +if( !inTag ) { +if( c == '[' ) +inTag = true; +else +desc += c; +} +else { +if( c == ']' ) { +TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); +if( ( prop & TestCaseInfo::IsHidden ) != 0 ) +isHidden = true; +else if( prop == TestCaseInfo::None ) +enforceNotReservedTag( tag, _lineInfo ); - tags.push_back( tag ); - tag.clear(); - inTag = false; - } - else - tag += c; - } - } - if( isHidden ) { - tags.push_back( "." ); - } +// Merged hide tags like `[.approvals]` should be added as +// `[.][approvals]`. The `[.]` is added at later point, so +// we only strip the prefix +if (startsWith(tag, '.') && tag.size() > 1) { +tag.erase(0, 1); +} +tags.push_back( tag ); +tag.clear(); +inTag = false; +} +else +tag += c; +} +} +if( isHidden ) { +tags.push_back( "." ); +} - TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, info ); - } +TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); +return TestCase( _testCase, std::move(info) ); +} - void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { - std::sort(begin(tags), end(tags)); - tags.erase(std::unique(begin(tags), end(tags)), end(tags)); - testCaseInfo.lcaseTags.clear(); +void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { +std::sort(begin(tags), end(tags)); +tags.erase(std::unique(begin(tags), end(tags)), end(tags)); +testCaseInfo.lcaseTags.clear(); - for( auto const& tag : tags ) { - std::string lcaseTag = toLower( tag ); - testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); - testCaseInfo.lcaseTags.push_back( lcaseTag ); - } - testCaseInfo.tags = std::move(tags); - } +for( auto const& tag : tags ) { +std::string lcaseTag = toLower( tag ); +testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); +testCaseInfo.lcaseTags.push_back( lcaseTag ); +} +testCaseInfo.tags = std::move(tags); +} - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - lineInfo( _lineInfo ), - properties( None ) - { - setTags( *this, _tags ); - } +TestCaseInfo::TestCaseInfo( std::string const& _name, +std::string const& _className, +std::string const& _description, +std::vector const& _tags, +SourceLineInfo const& _lineInfo ) +: name( _name ), +className( _className ), +description( _description ), +lineInfo( _lineInfo ), +properties( None ) +{ +setTags( *this, _tags ); +} - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } +bool TestCaseInfo::isHidden() const { +return ( properties & IsHidden ) != 0; +} +bool TestCaseInfo::throws() const { +return ( properties & Throws ) != 0; +} +bool TestCaseInfo::okToFail() const { +return ( properties & (ShouldFail | MayFail ) ) != 0; +} +bool TestCaseInfo::expectedToFail() const { +return ( properties & (ShouldFail ) ) != 0; +} - std::string TestCaseInfo::tagsAsString() const { - std::string ret; - // '[' and ']' per tag - std::size_t full_size = 2 * tags.size(); - for (const auto& tag : tags) { - full_size += tag.size(); - } - ret.reserve(full_size); - for (const auto& tag : tags) { - ret.push_back('['); - ret.append(tag); - ret.push_back(']'); - } +std::string TestCaseInfo::tagsAsString() const { +std::string ret; +// '[' and ']' per tag +std::size_t full_size = 2 * tags.size(); +for (const auto& tag : tags) { +full_size += tag.size(); +} +ret.reserve(full_size); +for (const auto& tag : tags) { +ret.push_back('['); +ret.append(tag); +ret.push_back(']'); +} - return ret; - } +return ret; +} - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} +TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } +TestCase TestCase::withName( std::string const& _newName ) const { +TestCase other( *this ); +other.name = _newName; +return other; +} - void TestCase::invoke() const { - test->invoke(); - } +void TestCase::invoke() const { +test->invoke(); +} - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } +bool TestCase::operator == ( TestCase const& other ) const { +return test.get() == other.test.get() && +name == other.name && +className == other.className; +} - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } +bool TestCase::operator < ( TestCase const& other ) const { +return name < other.name; +} - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } +TestCaseInfo const& TestCase::getTestCaseInfo() const +{ +return *this; +} } // end namespace Catch // end catch_test_case_info.cpp @@ -8949,103 +11801,107 @@ namespace Catch { namespace Catch { - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { +std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { - std::vector sorted = unsortedTestCases; +std::vector sorted = unsortedTestCases; - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - return sorted; - } - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); - } +switch( config.runOrder() ) { +case RunTests::InLexicographicalOrder: +std::sort( sorted.begin(), sorted.end() ); +break; +case RunTests::InRandomOrder: +seedRng( config ); +std::shuffle( sorted.begin(), sorted.end(), rng() ); +break; +case RunTests::InDeclarationOrder: +// already in declaration order +break; +} +return sorted; +} +bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { +return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); +} - void enforceNoDuplicateTestCases( std::vector const& functions ) { - std::set seenFunctions; - for( auto const& function : functions ) { - auto prev = seenFunctions.insert( function ); - CATCH_ENFORCE( prev.second, - "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); - } - } +void enforceNoDuplicateTestCases( std::vector const& functions ) { +std::set seenFunctions; +for( auto const& function : functions ) { +auto prev = seenFunctions.insert( function ); +CATCH_ENFORCE( prev.second, +"error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" +<< "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" +<< "\tRedefined at " << function.getTestCaseInfo().lineInfo ); +} +} - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector filtered; - filtered.reserve( testCases.size() ); - for( auto const& testCase : testCases ) - if( matchTest( testCase, testSpec, config ) ) - filtered.push_back( testCase ); - return filtered; - } - std::vector const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } +std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { +std::vector filtered; +filtered.reserve( testCases.size() ); +for (auto const& testCase : testCases) { +if ((!testSpec.hasFilters() && !testCase.isHidden()) || +(testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { +filtered.push_back(testCase); +} +} +return filtered; +} +std::vector const& getAllTestCasesSorted( IConfig const& config ) { +return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); +} - void TestRegistry::registerTest( TestCase const& testCase ) { - std::string name = testCase.getTestCaseInfo().name; - if( name.empty() ) { - std::ostringstream oss; - oss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( oss.str() ) ); - } - m_functions.push_back( testCase ); - } +void TestRegistry::registerTest( TestCase const& testCase ) { +std::string name = testCase.getTestCaseInfo().name; +if( name.empty() ) { +ReusableStringStream rss; +rss << "Anonymous test case " << ++m_unnamedCount; +return registerTest( testCase.withName( rss.str() ) ); +} +m_functions.push_back( testCase ); +} - std::vector const& TestRegistry::getAllTests() const { - return m_functions; - } - std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_functions ); +std::vector const& TestRegistry::getAllTests() const { +return m_functions; +} +std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { +if( m_sortedFunctions.empty() ) +enforceNoDuplicateTestCases( m_functions ); - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_functions ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } +if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { +m_sortedFunctions = sortTests( config, m_functions ); +m_currentSortOrder = config.runOrder(); +} +return m_sortedFunctions; +} - /////////////////////////////////////////////////////////////////////////// - TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} +/////////////////////////////////////////////////////////////////////////// +TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } +void TestInvokerAsFunction::invoke() const { +m_testAsFunction(); +} - std::string extractClassName( std::string const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, '&' ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } +std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { +std::string className = classOrQualifiedMethodName; +if( startsWith( className, '&' ) ) +{ +std::size_t lastColons = className.rfind( "::" ); +std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); +if( penultimateColons == std::string::npos ) +penultimateColons = 1; +className = className.substr( penultimateColons, lastColons-penultimateColons ); +} +return className; +} } // end namespace Catch // end catch_test_case_registry_impl.cpp // start catch_test_case_tracker.cpp #include -#include +#include #include #include +#include #if defined(__clang__) # pragma clang diagnostic push @@ -9055,257 +11911,217 @@ namespace Catch { namespace Catch { namespace TestCaseTracking { - NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), - location( _location ) - {} +NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) +: name( _name ), +location( _location ) +{} - ITracker::~ITracker() = default; +ITracker::~ITracker() = default; - TrackerContext& TrackerContext::instance() { - static TrackerContext s_instance; - return s_instance; - } +ITracker& TrackerContext::startRun() { +m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); +m_currentTracker = nullptr; +m_runState = Executing; +return *m_rootTracker; +} - ITracker& TrackerContext::startRun() { - m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); - m_currentTracker = nullptr; - m_runState = Executing; - return *m_rootTracker; - } +void TrackerContext::endRun() { +m_rootTracker.reset(); +m_currentTracker = nullptr; +m_runState = NotStarted; +} - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } +void TrackerContext::startCycle() { +m_currentTracker = m_rootTracker.get(); +m_runState = Executing; +} +void TrackerContext::completeCycle() { +m_runState = CompletedCycle; +} - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } - void TrackerContext::completeCycle() { - m_runState = CompletedCycle; - } +bool TrackerContext::completedCycle() const { +return m_runState == CompletedCycle; +} +ITracker& TrackerContext::currentTracker() { +return *m_currentTracker; +} +void TrackerContext::setCurrentTracker( ITracker* tracker ) { +m_currentTracker = tracker; +} - bool TrackerContext::completedCycle() const { - return m_runState == CompletedCycle; - } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } - void TrackerContext::setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } +TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) +: m_nameAndLocation( nameAndLocation ), +m_ctx( ctx ), +m_parent( parent ) +{} - TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} - bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { - return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; - } +NameAndLocation const& TrackerBase::nameAndLocation() const { +return m_nameAndLocation; +} +bool TrackerBase::isComplete() const { +return m_runState == CompletedSuccessfully || m_runState == Failed; +} +bool TrackerBase::isSuccessfullyCompleted() const { +return m_runState == CompletedSuccessfully; +} +bool TrackerBase::isOpen() const { +return m_runState != NotStarted && !isComplete(); +} +bool TrackerBase::hasChildren() const { +return !m_children.empty(); +} - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), - m_ctx( ctx ), - m_parent( parent ) - {} +void TrackerBase::addChild( ITrackerPtr const& child ) { +m_children.push_back( child ); +} - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } - bool TrackerBase::isComplete() const { - return m_runState == CompletedSuccessfully || m_runState == Failed; - } - bool TrackerBase::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool TrackerBase::isOpen() const { - return m_runState != NotStarted && !isComplete(); - } - bool TrackerBase::hasChildren() const { - return !m_children.empty(); - } +ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { +auto it = std::find_if( m_children.begin(), m_children.end(), +[&nameAndLocation]( ITrackerPtr const& tracker ){ +return +tracker->nameAndLocation().location == nameAndLocation.location && +tracker->nameAndLocation().name == nameAndLocation.name; +} ); +return( it != m_children.end() ) +? *it +: nullptr; +} +ITracker& TrackerBase::parent() { +assert( m_parent ); // Should always be non-null except for root +return *m_parent; +} - void TrackerBase::addChild( ITrackerPtr const& child ) { - m_children.push_back( child ); - } +void TrackerBase::openChild() { +if( m_runState != ExecutingChildren ) { +m_runState = ExecutingChildren; +if( m_parent ) +m_parent->openChild(); +} +} - ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { - auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); - return( it != m_children.end() ) - ? *it - : nullptr; - } - ITracker& TrackerBase::parent() { - assert( m_parent ); // Should always be non-null except for root - return *m_parent; - } +bool TrackerBase::isSectionTracker() const { return false; } +bool TrackerBase::isGeneratorTracker() const { return false; } - void TrackerBase::openChild() { - if( m_runState != ExecutingChildren ) { - m_runState = ExecutingChildren; - if( m_parent ) - m_parent->openChild(); - } - } +void TrackerBase::open() { +m_runState = Executing; +moveToThis(); +if( m_parent ) +m_parent->openChild(); +} - bool TrackerBase::isSectionTracker() const { return false; } - bool TrackerBase::isIndexTracker() const { return false; } +void TrackerBase::close() { - void TrackerBase::open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); - } +// Close any still open children (e.g. generators) +while( &m_ctx.currentTracker() != this ) +m_ctx.currentTracker().close(); - void TrackerBase::close() { +switch( m_runState ) { +case NeedsAnotherRun: +break; - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); +case Executing: +m_runState = CompletedSuccessfully; +break; +case ExecutingChildren: +if( m_children.empty() || m_children.back()->isComplete() ) +m_runState = CompletedSuccessfully; +break; - switch( m_runState ) { - case NeedsAnotherRun: - break; +case NotStarted: +case CompletedSuccessfully: +case Failed: +CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) - m_runState = CompletedSuccessfully; - break; +default: +CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); +} +moveToParent(); +m_ctx.completeCycle(); +} +void TrackerBase::fail() { +m_runState = Failed; +if( m_parent ) +m_parent->markAsNeedingAnotherRun(); +moveToParent(); +m_ctx.completeCycle(); +} +void TrackerBase::markAsNeedingAnotherRun() { +m_runState = NeedsAnotherRun; +} - case NotStarted: - case CompletedSuccessfully: - case Failed: - CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); +void TrackerBase::moveToParent() { +assert( m_parent ); +m_ctx.setCurrentTracker( m_parent ); +} +void TrackerBase::moveToThis() { +m_ctx.setCurrentTracker( this ); +} - default: - CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); - } - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::fail() { - m_runState = Failed; - if( m_parent ) - m_parent->markAsNeedingAnotherRun(); - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::markAsNeedingAnotherRun() { - m_runState = NeedsAnotherRun; - } +SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) +: TrackerBase( nameAndLocation, ctx, parent ) +{ +if( parent ) { +while( !parent->isSectionTracker() ) +parent = &parent->parent(); - void TrackerBase::moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void TrackerBase::moveToThis() { - m_ctx.setCurrentTracker( this ); - } +SectionTracker& parentSection = static_cast( *parent ); +addNextFilters( parentSection.m_filters ); +} +} - SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - { - if( parent ) { - while( !parent->isSectionTracker() ) - parent = &parent->parent(); +bool SectionTracker::isComplete() const { +bool complete = true; - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); - } - } +if ((m_filters.empty() || m_filters[0] == "") || +std::find(m_filters.begin(), m_filters.end(), +m_nameAndLocation.name) != m_filters.end()) +complete = TrackerBase::isComplete(); +return complete; - bool SectionTracker::isSectionTracker() const { return true; } +} - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - std::shared_ptr section; +bool SectionTracker::isSectionTracker() const { return true; } - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - section = std::static_pointer_cast( childTracker ); - } - else { - section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( section ); - } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; - } +SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { +std::shared_ptr section; - void SectionTracker::tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) - open(); - } +ITracker& currentTracker = ctx.currentTracker(); +if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { +assert( childTracker ); +assert( childTracker->isSectionTracker() ); +section = std::static_pointer_cast( childTracker ); +} +else { +section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); +currentTracker.addChild( section ); +} +if( !ctx.completedCycle() ) +section->tryOpen(); +return *section; +} - void SectionTracker::addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void SectionTracker::addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); - } +void SectionTracker::tryOpen() { +if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) +open(); +} - IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ) - {} - - bool IndexTracker::isIndexTracker() const { return true; } - - IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - std::shared_ptr tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast( childTracker ); - } - else { - tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - int IndexTracker::index() const { return m_index; } - - void IndexTracker::moveNext() { - m_index++; - m_children.clear(); - } - - void IndexTracker::close() { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; - } +void SectionTracker::addInitialFilters( std::vector const& filters ) { +if( !filters.empty() ) { +m_filters.push_back(""); // Root - should never be consulted +m_filters.push_back(""); // Test Case - not a section filter +m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); +} +} +void SectionTracker::addNextFilters( std::vector const& filters ) { +if( filters.size() > 1 ) +m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); +} } // namespace TestCaseTracking using TestCaseTracking::ITracker; using TestCaseTracking::TrackerContext; using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; } // namespace Catch @@ -9317,29 +12133,28 @@ using TestCaseTracking::IndexTracker; namespace Catch { - auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); - } +auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { +return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); +} - NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {} +NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept { - try { - getMutableRegistryHub() - .registerTest( - makeTestCase( - invoker, - extractClassName( classOrMethod ), - nameAndTags.name, - nameAndTags.tags, - lineInfo)); - } catch (...) { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } +AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { +CATCH_TRY { +getMutableRegistryHub() +.registerTest( +makeTestCase( +invoker, +extractClassName( classOrMethod ), +nameAndTags, +lineInfo)); +} CATCH_CATCH_ALL { +// Do not throw when constructing global objects, instead register the exception to be processed later +getMutableRegistryHub().registerStartupException(); +} +} - AutoReg::~AutoReg() = default; +AutoReg::~AutoReg() = default; } // end catch_test_registry.cpp // start catch_test_spec.cpp @@ -9351,127 +12166,127 @@ namespace Catch { namespace Catch { - TestSpec::Pattern::~Pattern() = default; - TestSpec::NamePattern::~NamePattern() = default; - TestSpec::TagPattern::~TagPattern() = default; - TestSpec::ExcludedPattern::~ExcludedPattern() = default; +TestSpec::Pattern::~Pattern() = default; +TestSpec::NamePattern::~NamePattern() = default; +TestSpec::TagPattern::~TagPattern() = default; +TestSpec::ExcludedPattern::~ExcludedPattern() = default; - TestSpec::NamePattern::NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} - bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); - } +TestSpec::NamePattern::NamePattern( std::string const& name ) +: m_wildcardPattern( toLower( name ), CaseSensitive::No ) +{} +bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { +return m_wildcardPattern.matches( toLower( testCase.name ) ); +} - TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { - return std::find(begin(testCase.lcaseTags), - end(testCase.lcaseTags), - m_tag) != end(testCase.lcaseTags); - } +TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} +bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { +return std::find(begin(testCase.lcaseTags), +end(testCase.lcaseTags), +m_tag) != end(testCase.lcaseTags); +} - TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } +TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} +bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( auto const& pattern : m_patterns ) { - if( !pattern->matches( testCase ) ) - return false; - } - return true; - } +bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { +// All patterns in a filter must match for the filter to be a match +for( auto const& pattern : m_patterns ) { +if( !pattern->matches( testCase ) ) +return false; +} +return true; +} - bool TestSpec::hasFilters() const { - return !m_filters.empty(); - } - bool TestSpec::matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( auto const& filter : m_filters ) - if( filter.matches( testCase ) ) - return true; - return false; - } +bool TestSpec::hasFilters() const { +return !m_filters.empty(); +} +bool TestSpec::matches( TestCaseInfo const& testCase ) const { +// A TestSpec matches if any filter matches +for( auto const& filter : m_filters ) +if( filter.matches( testCase ) ) +return true; +return false; +} } // end catch_test_spec.cpp // start catch_test_spec_parser.cpp namespace Catch { - TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} +TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - TestSpecParser& TestSpecParser::parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec TestSpecParser::testSpec() { - addFilter(); - return m_testSpec; - } +TestSpecParser& TestSpecParser::parse( std::string const& arg ) { +m_mode = None; +m_exclusion = false; +m_start = std::string::npos; +m_arg = m_tagAliases->expandAliases( arg ); +m_escapeChars.clear(); +for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) +visitChar( m_arg[m_pos] ); +if( m_mode == Name ) +addPattern(); +return *this; +} +TestSpec TestSpecParser::testSpec() { +addFilter(); +return m_testSpec; +} - void TestSpecParser::visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); - } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - void TestSpecParser::escape() { - if( m_mode == None ) - m_start = m_pos; - m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); - } - std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } +void TestSpecParser::visitChar( char c ) { +if( m_mode == None ) { +switch( c ) { +case ' ': return; +case '~': m_exclusion = true; return; +case '[': return startNewMode( Tag, ++m_pos ); +case '"': return startNewMode( QuotedName, ++m_pos ); +case '\\': return escape(); +default: startNewMode( Name, m_pos ); break; +} +} +if( m_mode == Name ) { +if( c == ',' ) { +addPattern(); +addFilter(); +} +else if( c == '[' ) { +if( subString() == "exclude:" ) +m_exclusion = true; +else +addPattern(); +startNewMode( Tag, ++m_pos ); +} +else if( c == '\\' ) +escape(); +} +else if( m_mode == EscapedName ) +m_mode = Name; +else if( m_mode == QuotedName && c == '"' ) +addPattern(); +else if( m_mode == Tag && c == ']' ) +addPattern(); +} +void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { +m_mode = mode; +m_start = start; +} +void TestSpecParser::escape() { +if( m_mode == None ) +m_start = m_pos; +m_mode = EscapedName; +m_escapeChars.push_back( m_pos ); +} +std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - void TestSpecParser::addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } +void TestSpecParser::addFilter() { +if( !m_currentFilter.m_patterns.empty() ) { +m_testSpec.m_filters.push_back( m_currentFilter ); +m_currentFilter = TestSpec::Filter(); +} +} - TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } +TestSpec parseTestSpec( std::string const& arg ) { +return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); +} } // namespace Catch // end catch_test_spec_parser.cpp @@ -9479,53 +12294,65 @@ namespace Catch { #include +static const uint64_t nanosecondsInSecond = 1000000000; + namespace Catch { - auto getCurrentNanosecondsSinceEpoch() -> uint64_t { - return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); - } +auto getCurrentNanosecondsSinceEpoch() -> uint64_t { +return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); +} - auto estimateClockResolution() -> uint64_t { - uint64_t sum = 0; - static const uint64_t iterations = 1000000; +namespace { +auto estimateClockResolution() -> uint64_t { +uint64_t sum = 0; +static const uint64_t iterations = 1000000; - for( std::size_t i = 0; i < iterations; ++i ) { +auto startTime = getCurrentNanosecondsSinceEpoch(); - uint64_t ticks; - uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); - do { - ticks = getCurrentNanosecondsSinceEpoch(); - } - while( ticks == baseTicks ); +for( std::size_t i = 0; i < iterations; ++i ) { - auto delta = ticks - baseTicks; - sum += delta; - } +uint64_t ticks; +uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); +do { +ticks = getCurrentNanosecondsSinceEpoch(); +} while( ticks == baseTicks ); - // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers - // - and potentially do more iterations if there's a high variance. - return sum/iterations; - } - auto getEstimatedClockResolution() -> uint64_t { - static auto s_resolution = estimateClockResolution(); - return s_resolution; - } +auto delta = ticks - baseTicks; +sum += delta; - void Timer::start() { - m_nanoseconds = getCurrentNanosecondsSinceEpoch(); - } - auto Timer::getElapsedNanoseconds() const -> unsigned int { - return static_cast(getCurrentNanosecondsSinceEpoch() - m_nanoseconds); - } - auto Timer::getElapsedMicroseconds() const -> unsigned int { - return static_cast(getElapsedNanoseconds()/1000); - } - auto Timer::getElapsedMilliseconds() const -> unsigned int { - return static_cast(getElapsedMicroseconds()/1000); - } - auto Timer::getElapsedSeconds() const -> double { - return getElapsedMicroseconds()/1000000.0; - } +// If we have been calibrating for over 3 seconds -- the clock +// is terrible and we should move on. +// TBD: How to signal that the measured resolution is probably wrong? +if (ticks > startTime + 3 * nanosecondsInSecond) { +return sum / ( i + 1u ); +} +} + +// We're just taking the mean, here. To do better we could take the std. dev and exclude outliers +// - and potentially do more iterations if there's a high variance. +return sum/iterations; +} +} +auto getEstimatedClockResolution() -> uint64_t { +static auto s_resolution = estimateClockResolution(); +return s_resolution; +} + +void Timer::start() { +m_nanoseconds = getCurrentNanosecondsSinceEpoch(); +} +auto Timer::getElapsedNanoseconds() const -> uint64_t { +return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; +} +auto Timer::getElapsedMicroseconds() const -> uint64_t { +return getElapsedNanoseconds()/1000; +} +auto Timer::getElapsedMilliseconds() const -> unsigned int { +return static_cast(getElapsedMicroseconds()/1000); +} +auto Timer::getElapsedSeconds() const -> double { +return getElapsedMicroseconds()/1000000.0; +} } // namespace Catch // end catch_timer.cpp @@ -9537,63 +12364,73 @@ namespace Catch { # pragma clang diagnostic ignored "-Wglobal-constructors" #endif +// Enable specific decls locally +#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +#endif + +#include #include namespace Catch { namespace Detail { - const std::string unprintableString = "{?}"; +const std::string unprintableString = "{?}"; - namespace { - const int hexThreshold = 255; +namespace { +const int hexThreshold = 255; - struct Endianness { - enum Arch { Big, Little }; +struct Endianness { +enum Arch { Big, Little }; - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; +static Arch which() { +union _{ +int asInt; +char asChar[sizeof (int)]; +} u; - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; - } +u.asInt = 1; +return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; +} +}; +} - std::string rawMemoryToString( const void *object, std::size_t size ) { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } +std::string rawMemoryToString( const void *object, std::size_t size ) { +// Reverse order for little endian architectures +int i = 0, end = static_cast( size ), inc = 1; +if( Endianness::which() == Endianness::Little ) { +i = end-1; +end = inc = -1; +} - unsigned char const *bytes = static_cast(object); - std::ostringstream os; - os << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - os << std::setw(2) << static_cast(bytes[i]); - return os.str(); - } +unsigned char const *bytes = static_cast(object); +ReusableStringStream rss; +rss << "0x" << std::setfill('0') << std::hex; +for( ; i != end; i += inc ) +rss << std::setw(2) << static_cast(bytes[i]); +return rss.str(); +} } template std::string fpToString( T value, int precision ) { - std::ostringstream oss; - oss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = oss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; +if (Catch::isnan(value)) { +return "nan"; +} + +ReusableStringStream rss; +rss << std::setprecision( precision ) +<< std::fixed +<< value; +std::string d = rss.str(); +std::size_t i = d.find_last_not_of( '0' ); +if( i != std::string::npos && i != d.size()-1 ) { +if( d[i] == '.' ) +i++; +d = d.substr( 0, i+1 ); +} +return d; } //// ======================================================= //// @@ -9603,135 +12440,157 @@ std::string fpToString( T value, int precision ) { //// ======================================================= //// std::string StringMaker::convert(const std::string& str) { - if (!getCurrentContext().getConfig()->showInvisibles()) { - return '"' + str + '"'; - } - - std::string s("\""); - for (char c : str) { - switch (c) { - case '\n': - s.append("\\n"); - break; - case '\t': - s.append("\\t"); - break; - default: - s.push_back(c); - break; - } - } - s.append("\""); - return s; +if (!getCurrentContext().getConfig()->showInvisibles()) { +return '"' + str + '"'; } -std::string StringMaker::convert(const std::wstring& wstr) { - std::string s; - s.reserve(wstr.size()); - for (auto c : wstr) { - s += (c <= 0xff) ? static_cast(c) : '?'; - } - return ::Catch::Detail::stringify(s); +std::string s("\""); +for (char c : str) { +switch (c) { +case '\n': +s.append("\\n"); +break; +case '\t': +s.append("\\t"); +break; +default: +s.push_back(c); +break; } +} +s.append("\""); +return s; +} + +#ifdef CATCH_CONFIG_CPP17_STRING_VIEW +std::string StringMaker::convert(std::string_view str) { +return ::Catch::Detail::stringify(std::string{ str }); +} +#endif std::string StringMaker::convert(char const* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } +if (str) { +return ::Catch::Detail::stringify(std::string{ str }); +} else { +return{ "{null string}" }; +} } std::string StringMaker::convert(char* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } +if (str) { +return ::Catch::Detail::stringify(std::string{ str }); +} else { +return{ "{null string}" }; } -std::string StringMaker::convert(wchar_t const * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(wchar_t * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } } +#ifdef CATCH_CONFIG_WCHAR +std::string StringMaker::convert(const std::wstring& wstr) { +std::string s; +s.reserve(wstr.size()); +for (auto c : wstr) { +s += (c <= 0xff) ? static_cast(c) : '?'; +} +return ::Catch::Detail::stringify(s); +} + +# ifdef CATCH_CONFIG_CPP17_STRING_VIEW +std::string StringMaker::convert(std::wstring_view str) { +return StringMaker::convert(std::wstring(str)); +} +# endif + +std::string StringMaker::convert(wchar_t const * str) { +if (str) { +return ::Catch::Detail::stringify(std::wstring{ str }); +} else { +return{ "{null string}" }; +} +} +std::string StringMaker::convert(wchar_t * str) { +if (str) { +return ::Catch::Detail::stringify(std::wstring{ str }); +} else { +return{ "{null string}" }; +} +} +#endif + std::string StringMaker::convert(int value) { - return ::Catch::Detail::stringify(static_cast(value)); +return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(long value) { - return ::Catch::Detail::stringify(static_cast(value)); +return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(long long value) { - std::ostringstream oss; - oss << value; - if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; - } - return oss.str(); +ReusableStringStream rss; +rss << value; +if (value > Detail::hexThreshold) { +rss << " (0x" << std::hex << value << ')'; +} +return rss.str(); } std::string StringMaker::convert(unsigned int value) { - return ::Catch::Detail::stringify(static_cast(value)); +return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(unsigned long value) { - return ::Catch::Detail::stringify(static_cast(value)); +return ::Catch::Detail::stringify(static_cast(value)); } std::string StringMaker::convert(unsigned long long value) { - std::ostringstream oss; - oss << value; - if (value > Detail::hexThreshold) { - oss << " (0x" << std::hex << value << ')'; - } - return oss.str(); +ReusableStringStream rss; +rss << value; +if (value > Detail::hexThreshold) { +rss << " (0x" << std::hex << value << ')'; +} +return rss.str(); } std::string StringMaker::convert(bool b) { - return b ? "true" : "false"; +return b ? "true" : "false"; } -std::string StringMaker::convert(char value) { - if (value == '\r') { - return "'\\r'"; - } else if (value == '\f') { - return "'\\f'"; - } else if (value == '\n') { - return "'\\n'"; - } else if (value == '\t') { - return "'\\t'"; - } else if ('\0' <= value && value < ' ') { - return ::Catch::Detail::stringify(static_cast(value)); - } else { - char chstr[] = "' '"; - chstr[1] = value; - return chstr; - } +std::string StringMaker::convert(signed char value) { +if (value == '\r') { +return "'\\r'"; +} else if (value == '\f') { +return "'\\f'"; +} else if (value == '\n') { +return "'\\n'"; +} else if (value == '\t') { +return "'\\t'"; +} else if ('\0' <= value && value < ' ') { +return ::Catch::Detail::stringify(static_cast(value)); +} else { +char chstr[] = "' '"; +chstr[1] = value; +return chstr; } -std::string StringMaker::convert(signed char c) { - return ::Catch::Detail::stringify(static_cast(c)); +} +std::string StringMaker::convert(char c) { +return ::Catch::Detail::stringify(static_cast(c)); } std::string StringMaker::convert(unsigned char c) { - return ::Catch::Detail::stringify(static_cast(c)); +return ::Catch::Detail::stringify(static_cast(c)); } std::string StringMaker::convert(std::nullptr_t) { - return "nullptr"; +return "nullptr"; } std::string StringMaker::convert(float value) { - return fpToString(value, 5) + 'f'; +return fpToString(value, 5) + 'f'; } std::string StringMaker::convert(double value) { - return fpToString(value, 10); +return fpToString(value, 10); } +std::string ratio_string::symbol() { return "a"; } +std::string ratio_string::symbol() { return "f"; } +std::string ratio_string::symbol() { return "p"; } +std::string ratio_string::symbol() { return "n"; } +std::string ratio_string::symbol() { return "u"; } +std::string ratio_string::symbol() { return "m"; } + } // end namespace Catch #if defined(__clang__) @@ -9743,412 +12602,425 @@ std::string StringMaker::convert(double value) { namespace Catch { - Counts Counts::operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } +Counts Counts::operator - ( Counts const& other ) const { +Counts diff; +diff.passed = passed - other.passed; +diff.failed = failed - other.failed; +diff.failedButOk = failedButOk - other.failedButOk; +return diff; +} - Counts& Counts::operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } +Counts& Counts::operator += ( Counts const& other ) { +passed += other.passed; +failed += other.failed; +failedButOk += other.failedButOk; +return *this; +} - std::size_t Counts::total() const { - return passed + failed + failedButOk; - } - bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool Counts::allOk() const { - return failed == 0; - } +std::size_t Counts::total() const { +return passed + failed + failedButOk; +} +bool Counts::allPassed() const { +return failed == 0 && failedButOk == 0; +} +bool Counts::allOk() const { +return failed == 0; +} - Totals Totals::operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } +Totals Totals::operator - ( Totals const& other ) const { +Totals diff; +diff.assertions = assertions - other.assertions; +diff.testCases = testCases - other.testCases; +return diff; +} - Totals& Totals::operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } +Totals& Totals::operator += ( Totals const& other ) { +assertions += other.assertions; +testCases += other.testCases; +return *this; +} - Totals Totals::delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } +Totals Totals::delta( Totals const& prevTotals ) const { +Totals diff = *this - prevTotals; +if( diff.assertions.failed > 0 ) +++diff.testCases.failed; +else if( diff.assertions.failedButOk > 0 ) +++diff.testCases.failedButOk; +else +++diff.testCases.passed; +return diff; +} } // end catch_totals.cpp +// start catch_uncaught_exceptions.cpp + +#include + +namespace Catch { +bool uncaught_exceptions() { +#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +return std::uncaught_exceptions() > 0; +#else +return std::uncaught_exception(); +#endif +} +} // end namespace Catch +// end catch_uncaught_exceptions.cpp // start catch_version.cpp #include namespace Catch { - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} +Version::Version +( unsigned int _majorVersion, +unsigned int _minorVersion, +unsigned int _patchNumber, +char const * const _branchName, +unsigned int _buildNumber ) +: majorVersion( _majorVersion ), +minorVersion( _minorVersion ), +patchNumber( _patchNumber ), +branchName( _branchName ), +buildNumber( _buildNumber ) +{} - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; - } - return os; - } +std::ostream& operator << ( std::ostream& os, Version const& version ) { +os << version.majorVersion << '.' +<< version.minorVersion << '.' +<< version.patchNumber; +// branchName is never null -> 0th char is \0 if it is empty +if (version.branchName[0]) { +os << '-' << version.branchName +<< '.' << version.buildNumber; +} +return os; +} - Version const& libraryVersion() { - static Version version( 2, 0, 1, "", 0 ); - return version; - } +Version const& libraryVersion() { +static Version version( 2, 7, 2, "", 0 ); +return version; +} } // end catch_version.cpp // start catch_wildcard_pattern.cpp +#include + namespace Catch { - WildcardPattern::WildcardPattern( std::string const& pattern, - CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_pattern( adjustCase( pattern ) ) - { - if( startsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } +WildcardPattern::WildcardPattern( std::string const& pattern, +CaseSensitive::Choice caseSensitivity ) +: m_caseSensitivity( caseSensitivity ), +m_pattern( adjustCase( pattern ) ) +{ +if( startsWith( m_pattern, '*' ) ) { +m_pattern = m_pattern.substr( 1 ); +m_wildcard = WildcardAtStart; +} +if( endsWith( m_pattern, '*' ) ) { +m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); +m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); +} +} - bool WildcardPattern::matches( std::string const& str ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_pattern == adjustCase( str ); - case WildcardAtStart: - return endsWith( adjustCase( str ), m_pattern ); - case WildcardAtEnd: - return startsWith( adjustCase( str ), m_pattern ); - case WildcardAtBothEnds: - return contains( adjustCase( str ), m_pattern ); - default: - CATCH_INTERNAL_ERROR( "Unknown enum" ); - } - } +bool WildcardPattern::matches( std::string const& str ) const { +switch( m_wildcard ) { +case NoWildcard: +return m_pattern == adjustCase( str ); +case WildcardAtStart: +return endsWith( adjustCase( str ), m_pattern ); +case WildcardAtEnd: +return startsWith( adjustCase( str ), m_pattern ); +case WildcardAtBothEnds: +return contains( adjustCase( str ), m_pattern ); +default: +CATCH_INTERNAL_ERROR( "Unknown enum" ); +} +} - std::string WildcardPattern::adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; - } +std::string WildcardPattern::adjustCase( std::string const& str ) const { +return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; +} } // end catch_wildcard_pattern.cpp // start catch_xmlwriter.cpp -// start catch_xmlwriter.h - -#include -#include - -namespace Catch { - - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) noexcept; - ScopedElement& operator=( ScopedElement&& other ) noexcept; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = Catch::cout() ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - m_oss.clear(); - m_oss.str(std::string()); - m_oss << attribute; - return writeAttribute( name, m_oss.str() ); - } - - XmlWriter& writeText( std::string const& text, bool indent = true ); - - XmlWriter& writeComment( std::string const& text ); - - void writeStylesheetRef( std::string const& url ); - - XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - std::ostringstream m_oss; - }; - -} - -// end catch_xmlwriter.h #include +using uchar = unsigned char; + namespace Catch { - XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) - : m_str( str ), - m_forWhat( forWhat ) - {} +namespace { - void XmlEncode::encodeTo( std::ostream& os ) const { +size_t trailingBytes(unsigned char c) { +if ((c & 0xE0) == 0xC0) { +return 2; +} +if ((c & 0xF0) == 0xE0) { +return 3; +} +if ((c & 0xF8) == 0xF0) { +return 4; +} +CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); +} - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: http://www.w3.org/TR/xml/#syntax) +uint32_t headerValue(unsigned char c) { +if ((c & 0xE0) == 0xC0) { +return c & 0x1F; +} +if ((c & 0xF0) == 0xE0) { +return c & 0x0F; +} +if ((c & 0xF8) == 0xF0) { +return c & 0x07; +} +CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); +} - for( std::size_t i = 0; i < m_str.size(); ++ i ) { - char c = m_str[i]; - switch( c ) { - case '<': os << "<"; break; - case '&': os << "&"; break; +void hexEscapeChar(std::ostream& os, unsigned char c) { +std::ios_base::fmtflags f(os.flags()); +os << "\\x" +<< std::uppercase << std::hex << std::setfill('0') << std::setw(2) +<< static_cast(c); +os.flags(f); +} - case '>': - // See: http://www.w3.org/TR/xml/#syntax - if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) - os << ">"; - else - os << c; - break; +} // anonymous namespace - case '\"': - if( m_forWhat == ForAttributes ) - os << """; - else - os << c; - break; +XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) +: m_str( str ), +m_forWhat( forWhat ) +{} - default: - // Escape control chars - based on contribution by @espenalb in PR #465 and - // by @mrpi PR #588 - if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast( c ); - } - else - os << c; - } - } - } +void XmlEncode::encodeTo( std::ostream& os ) const { +// Apostrophe escaping not necessary if we always use " to write attributes +// (see: http://www.w3.org/TR/xml/#syntax) - std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } +for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { +uchar c = m_str[idx]; +switch (c) { +case '<': os << "<"; break; +case '&': os << "&"; break; - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} +case '>': +// See: http://www.w3.org/TR/xml/#syntax +if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') +os << ">"; +else +os << c; +break; - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - return *this; - } +case '\"': +if (m_forWhat == ForAttributes) +os << """; +else +os << c; +break; - XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } +default: +// Check for control characters and invalid utf-8 - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); - return *this; - } +// Escape control characters in standard ascii +// see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 +if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { +hexEscapeChar(os, c); +break; +} - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } +// Plain ASCII: Write it to stream +if (c < 0x7F) { +os << c; +break; +} - XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } +// UTF-8 territory +// Check if the encoding is valid and if it is not, hex escape bytes. +// Important: We do not check the exact decoded values for validity, only the encoding format +// First check that this bytes is a valid lead byte: +// This means that it is not encoded as 1111 1XXX +// Or as 10XX XXXX +if (c < 0xC0 || +c >= 0xF8) { +hexEscapeChar(os, c); +break; +} - XmlWriter& XmlWriter::startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } +auto encBytes = trailingBytes(c); +// Are there enough bytes left to avoid accessing out-of-bounds memory? +if (idx + encBytes - 1 >= m_str.size()) { +hexEscapeChar(os, c); +break; +} +// The header is valid, check data +// The next encBytes bytes must together be a valid utf-8 +// This means: bitpattern 10XX XXXX and the extracted value is sane (ish) +bool valid = true; +uint32_t value = headerValue(c); +for (std::size_t n = 1; n < encBytes; ++n) { +uchar nc = m_str[idx + n]; +valid &= ((nc & 0xC0) == 0x80); +value = (value << 6) | (nc & 0x3F); +} - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } +if ( +// Wrong bit pattern of following bytes +(!valid) || +// Overlong encodings +(value < 0x80) || +(0x80 <= value && value < 0x800 && encBytes > 2) || +(0x800 < value && value < 0x10000 && encBytes > 3) || +// Encoded value out of range +(value >= 0x110000) +) { +hexEscapeChar(os, c); +break; +} - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } +// If we got here, this is in fact a valid(ish) utf-8 sequence +for (std::size_t n = 0; n < encBytes; ++n) { +os << m_str[idx + n]; +} +idx += encBytes - 1; +break; +} +} +} - XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } +std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { +xmlEncode.encodeTo( os ); +return os; +} - XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } +XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) +: m_writer( writer ) +{} - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } +XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept +: m_writer( other.m_writer ){ +other.m_writer = nullptr; +} +XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { +if ( m_writer ) { +m_writer->endElement(); +} +m_writer = other.m_writer; +other.m_writer = nullptr; +return *this; +} - XmlWriter& XmlWriter::writeComment( std::string const& text ) { - ensureTagClosed(); - m_os << m_indent << ""; - m_needsNewline = true; - return *this; - } +XmlWriter::ScopedElement::~ScopedElement() { +if( m_writer ) +m_writer->endElement(); +} - void XmlWriter::writeStylesheetRef( std::string const& url ) { - m_os << "\n"; - } +XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { +m_writer->writeText( text, indent ); +return *this; +} - XmlWriter& XmlWriter::writeBlankLine() { - ensureTagClosed(); - m_os << '\n'; - return *this; - } +XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) +{ +writeDeclaration(); +} - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } +XmlWriter::~XmlWriter() { +while( !m_tags.empty() ) +endElement(); +} - void XmlWriter::writeDeclaration() { - m_os << "\n"; - } +XmlWriter& XmlWriter::startElement( std::string const& name ) { +ensureTagClosed(); +newlineIfNecessary(); +m_os << m_indent << '<' << name; +m_tags.push_back( name ); +m_indent += " "; +m_tagIsOpen = true; +return *this; +} - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } +XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { +ScopedElement scoped( this ); +startElement( name ); +return scoped; +} + +XmlWriter& XmlWriter::endElement() { +newlineIfNecessary(); +m_indent = m_indent.substr( 0, m_indent.size()-2 ); +if( m_tagIsOpen ) { +m_os << "/>"; +m_tagIsOpen = false; +} +else { +m_os << m_indent << ""; +} +m_os << std::endl; +m_tags.pop_back(); +return *this; +} + +XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { +if( !name.empty() && !attribute.empty() ) +m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; +return *this; +} + +XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { +m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; +return *this; +} + +XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { +if( !text.empty() ){ +bool tagWasOpen = m_tagIsOpen; +ensureTagClosed(); +if( tagWasOpen && indent ) +m_os << m_indent; +m_os << XmlEncode( text ); +m_needsNewline = true; +} +return *this; +} + +XmlWriter& XmlWriter::writeComment( std::string const& text ) { +ensureTagClosed(); +m_os << m_indent << ""; +m_needsNewline = true; +return *this; +} + +void XmlWriter::writeStylesheetRef( std::string const& url ) { +m_os << "\n"; +} + +XmlWriter& XmlWriter::writeBlankLine() { +ensureTagClosed(); +m_os << '\n'; +return *this; +} + +void XmlWriter::ensureTagClosed() { +if( m_tagIsOpen ) { +m_os << ">" << std::endl; +m_tagIsOpen = false; +} +} + +void XmlWriter::writeDeclaration() { +m_os << "\n"; +} + +void XmlWriter::newlineIfNecessary() { +if( m_needsNewline ) { +m_os << std::endl; +m_needsNewline = false; +} +} } // end catch_xmlwriter.cpp // start catch_reporter_bases.cpp @@ -10156,42 +13028,61 @@ namespace Catch { #include #include #include -#include +#include #include namespace Catch { - void prepareExpandedExpression(AssertionResult& result) { - result.getExpandedExpression(); - } +void prepareExpandedExpression(AssertionResult& result) { +result.getExpandedExpression(); +} - // Because formatting using c++ streams is stateful, drop down to C is required - // Alternatively we could use stringstream, but its performance is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; +// Because formatting using c++ streams is stateful, drop down to C is required +// Alternatively we could use stringstream, but its performance is... not good. +std::string getFormattedDuration( double duration ) { +// Max exponent + 1 is required to represent the whole part +// + 1 for decimal point +// + 3 for the 3 decimal places +// + 1 for null terminator +const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; +char buffer[maxDoubleSize]; - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; +// Save previous errno, to prevent sprintf from overwriting it +ErrnoGuard guard; #ifdef _MSC_VER - sprintf_s(buffer, "%.3f", duration); +sprintf_s(buffer, "%.3f", duration); #else - sprintf(buffer, "%.3f", duration); +std::sprintf(buffer, "%.3f", duration); #endif - return std::string(buffer); - } +return std::string(buffer); +} - TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) - :StreamingReporterBase(_config) {} +std::string serializeFilters( std::vector const& container ) { +ReusableStringStream oss; +bool first = true; +for (auto&& filter : container) +{ +if (!first) +oss << ' '; +else +first = false; - void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} +oss << filter; +} +return oss.str(); +} - bool TestEventListenerBase::assertionEnded(AssertionStats const &) { - return false; - } +TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) +:StreamingReporterBase(_config) {} + +std::set TestEventListenerBase::getSupportedVerbosities() { +return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High }; +} + +void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} + +bool TestEventListenerBase::assertionEnded(AssertionStats const &) { +return false; +} } // end namespace Catch // end catch_reporter_bases.cpp @@ -10200,292 +13091,280 @@ namespace Catch { namespace { #ifdef CATCH_PLATFORM_MAC - const char* failedString() { return "FAILED"; } - const char* passedString() { return "PASSED"; } +const char* failedString() { return "FAILED"; } +const char* passedString() { return "PASSED"; } #else - const char* failedString() { return "failed"; } - const char* passedString() { return "passed"; } +const char* failedString() { return "failed"; } +const char* passedString() { return "passed"; } #endif - // Colour::LightGrey - Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } +// Colour::LightGrey +Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } - std::string bothOrAll( std::size_t count ) { - return count == 1 ? std::string() : - count == 2 ? "both " : "all " ; - } +std::string bothOrAll( std::size_t count ) { +return count == 1 ? std::string() : +count == 2 ? "both " : "all " ; } +} // anon namespace + namespace Catch { +namespace { +// Colour, message variants: +// - white: No tests ran. +// - red: Failed [both/all] N test cases, failed [both/all] M assertions. +// - white: Passed [both/all] N test cases (no assertions). +// - red: Failed N tests cases, failed M assertions. +// - green: Passed [both/all] N tests cases with M assertions. +void printTotals(std::ostream& out, const Totals& totals) { +if (totals.testCases.total() == 0) { +out << "No tests ran."; +} else if (totals.testCases.failed == totals.testCases.total()) { +Colour colour(Colour::ResultError); +const std::string qualify_assertions_failed = +totals.assertions.failed == totals.assertions.total() ? +bothOrAll(totals.assertions.failed) : std::string(); +out << +"Failed " << bothOrAll(totals.testCases.failed) +<< pluralise(totals.testCases.failed, "test case") << ", " +"failed " << qualify_assertions_failed << +pluralise(totals.assertions.failed, "assertion") << '.'; +} else if (totals.assertions.total() == 0) { +out << +"Passed " << bothOrAll(totals.testCases.total()) +<< pluralise(totals.testCases.total(), "test case") +<< " (no assertions)."; +} else if (totals.assertions.failed) { +Colour colour(Colour::ResultError); +out << +"Failed " << pluralise(totals.testCases.failed, "test case") << ", " +"failed " << pluralise(totals.assertions.failed, "assertion") << '.'; +} else { +Colour colour(Colour::ResultSuccess); +out << +"Passed " << bothOrAll(totals.testCases.passed) +<< pluralise(totals.testCases.passed, "test case") << +" with " << pluralise(totals.assertions.passed, "assertion") << '.'; +} +} - struct CompactReporter : StreamingReporterBase { +// Implementation of CompactReporter formatting +class AssertionPrinter { +public: +AssertionPrinter& operator= (AssertionPrinter const&) = delete; +AssertionPrinter(AssertionPrinter const&) = delete; +AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) +: stream(_stream) +, result(_stats.assertionResult) +, messages(_stats.infoMessages) +, itMessage(_stats.infoMessages.begin()) +, printInfoMessages(_printInfoMessages) {} - using StreamingReporterBase::StreamingReporterBase; +void print() { +printSourceInfo(); - ~CompactReporter() override; +itMessage = messages.begin(); - static std::string getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } +switch (result.getResultType()) { +case ResultWas::Ok: +printResultType(Colour::ResultSuccess, passedString()); +printOriginalExpression(); +printReconstructedExpression(); +if (!result.hasExpression()) +printRemainingMessages(Colour::None); +else +printRemainingMessages(); +break; +case ResultWas::ExpressionFailed: +if (result.isOk()) +printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); +else +printResultType(Colour::Error, failedString()); +printOriginalExpression(); +printReconstructedExpression(); +printRemainingMessages(); +break; +case ResultWas::ThrewException: +printResultType(Colour::Error, failedString()); +printIssue("unexpected exception with message:"); +printMessage(); +printExpressionWas(); +printRemainingMessages(); +break; +case ResultWas::FatalErrorCondition: +printResultType(Colour::Error, failedString()); +printIssue("fatal error condition with message:"); +printMessage(); +printExpressionWas(); +printRemainingMessages(); +break; +case ResultWas::DidntThrowException: +printResultType(Colour::Error, failedString()); +printIssue("expected exception, got none"); +printExpressionWas(); +printRemainingMessages(); +break; +case ResultWas::Info: +printResultType(Colour::None, "info"); +printMessage(); +printRemainingMessages(); +break; +case ResultWas::Warning: +printResultType(Colour::None, "warning"); +printMessage(); +printRemainingMessages(); +break; +case ResultWas::ExplicitFailure: +printResultType(Colour::Error, failedString()); +printIssue("explicitly"); +printRemainingMessages(Colour::None); +break; +// These cases are here to prevent compiler warnings +case ResultWas::Unknown: +case ResultWas::FailureBit: +case ResultWas::Exception: +printResultType(Colour::Error, "** internal error **"); +break; +} +} - ReporterPreferences getPreferences() const override { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } +private: +void printSourceInfo() const { +Colour colourGuard(Colour::FileName); +stream << result.getSourceInfo() << ':'; +} - void noMatchingTestCases( std::string const& spec ) override { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } +void printResultType(Colour::Code colour, std::string const& passOrFail) const { +if (!passOrFail.empty()) { +{ +Colour colourGuard(colour); +stream << ' ' << passOrFail; +} +stream << ':'; +} +} - void assertionStarting( AssertionInfo const& ) override {} +void printIssue(std::string const& issue) const { +stream << ' ' << issue; +} - bool assertionEnded( AssertionStats const& _assertionStats ) override { - AssertionResult const& result = _assertionStats.assertionResult; +void printExpressionWas() { +if (result.hasExpression()) { +stream << ';'; +{ +Colour colour(dimColour()); +stream << " expression was:"; +} +printOriginalExpression(); +} +} - bool printInfoMessages = true; +void printOriginalExpression() const { +if (result.hasExpression()) { +stream << ' ' << result.getExpression(); +} +} - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } +void printReconstructedExpression() const { +if (result.hasExpandedExpression()) { +{ +Colour colour(dimColour()); +stream << " for: "; +} +stream << result.getExpandedExpression(); +} +} - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); +void printMessage() { +if (itMessage != messages.end()) { +stream << " '" << itMessage->message << '\''; +++itMessage; +} +} - stream << std::endl; - return true; - } +void printRemainingMessages(Colour::Code colour = dimColour()) { +if (itMessage == messages.end()) +return; - void sectionEnded(SectionStats const& _sectionStats) override { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - } +// using messages.end() directly yields (or auto) compilation error: +std::vector::const_iterator itEnd = messages.end(); +const std::size_t N = static_cast(std::distance(itMessage, itEnd)); - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotals( _testRunStats.totals ); - stream << '\n' << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } +{ +Colour colourGuard(colour); +stream << " with " << pluralise(N, "message") << ':'; +} - private: - class AssertionPrinter { - public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ) - , result( _stats.assertionResult ) - , messages( _stats.infoMessages ) - , itMessage( _stats.infoMessages.begin() ) - , printInfoMessages( _printInfoMessages ) - {} +for (; itMessage != itEnd; ) { +// If this assertion is a warning ignore any INFO messages +if (printInfoMessages || itMessage->type != ResultWas::Info) { +stream << " '" << itMessage->message << '\''; +if (++itMessage != itEnd) { +Colour colourGuard(dimColour()); +stream << " and"; +} +} +} +} - void print() { - printSourceInfo(); +private: +std::ostream& stream; +AssertionResult const& result; +std::vector messages; +std::vector::const_iterator itMessage; +bool printInfoMessages; +}; - itMessage = messages.begin(); +} // anon namespace - switch( result.getResultType() ) { - case ResultWas::Ok: - printResultType( Colour::ResultSuccess, passedString() ); - printOriginalExpression(); - printReconstructedExpression(); - if ( ! result.hasExpression() ) - printRemainingMessages( Colour::None ); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) - printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); - else - printResultType( Colour::Error, failedString() ); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType( Colour::Error, failedString() ); - printIssue( "unexpected exception with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType( Colour::Error, failedString() ); - printIssue( "fatal error condition with message:" ); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType( Colour::Error, failedString() ); - printIssue( "expected exception, got none" ); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType( Colour::None, "info" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType( Colour::None, "warning" ); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType( Colour::Error, failedString() ); - printIssue( "explicitly" ); - printRemainingMessages( Colour::None ); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType( Colour::Error, "** internal error **" ); - break; - } - } +std::string CompactReporter::getDescription() { +return "Reports test results on a single line, suitable for IDEs"; +} - private: - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ':'; - } +ReporterPreferences CompactReporter::getPreferences() const { +return m_reporterPrefs; +} - void printResultType( Colour::Code colour, std::string const& passOrFail ) const { - if( !passOrFail.empty() ) { - { - Colour colourGuard( colour ); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } +void CompactReporter::noMatchingTestCases( std::string const& spec ) { +stream << "No test cases matched '" << spec << '\'' << std::endl; +} - void printIssue( std::string const& issue ) const { - stream << ' ' << issue; - } +void CompactReporter::assertionStarting( AssertionInfo const& ) {} - void printExpressionWas() { - if( result.hasExpression() ) { - stream << ';'; - { - Colour colour( dimColour() ); - stream << " expression was:"; - } - printOriginalExpression(); - } - } +bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { +AssertionResult const& result = _assertionStats.assertionResult; - void printOriginalExpression() const { - if( result.hasExpression() ) { - stream << ' ' << result.getExpression(); - } - } +bool printInfoMessages = true; - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - { - Colour colour( dimColour() ); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } +// Drop out if result was successful and we're not printing those +if( !m_config->includeSuccessfulResults() && result.isOk() ) { +if( result.getResultType() != ResultWas::Warning ) +return false; +printInfoMessages = false; +} - void printMessage() { - if ( itMessage != messages.end() ) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } +AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); +printer.print(); - void printRemainingMessages( Colour::Code colour = dimColour() ) { - if ( itMessage == messages.end() ) - return; +stream << std::endl; +return true; +} - // using messages.end() directly yields (or auto) compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast( std::distance( itMessage, itEnd ) ); +void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { +if (m_config->showDurations() == ShowDurations::Always) { +stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; +} +} - { - Colour colourGuard( colour ); - stream << " with " << pluralise( N, "message" ) << ':'; - } +void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { +printTotals( stream, _testRunStats.totals ); +stream << '\n' << std::endl; +StreamingReporterBase::testRunEnded( _testRunStats ); +} - for(; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || itMessage->type != ResultWas::Info ) { - stream << " '" << itMessage->message << '\''; - if ( ++itMessage != itEnd ) { - Colour colourGuard( dimColour() ); - stream << " and"; - } - } - } - } +CompactReporter::~CompactReporter() {} - private: - std::ostream& stream; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; - }; - - // Colour, message variants: - // - white: No tests ran. - // - red: Failed [both/all] N test cases, failed [both/all] M assertions. - // - white: Passed [both/all] N test cases (no assertions). - // - red: Failed N tests cases, failed M assertions. - // - green: Passed [both/all] N tests cases with M assertions. - - void printTotals( const Totals& totals ) const { - if( totals.testCases.total() == 0 ) { - stream << "No tests ran."; - } - else if( totals.testCases.failed == totals.testCases.total() ) { - Colour colour( Colour::ResultError ); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll( totals.assertions.failed ) : std::string(); - stream << - "Failed " << bothOrAll( totals.testCases.failed ) - << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << qualify_assertions_failed << - pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else if( totals.assertions.total() == 0 ) { - stream << - "Passed " << bothOrAll( totals.testCases.total() ) - << pluralise( totals.testCases.total(), "test case" ) - << " (no assertions)."; - } - else if( totals.assertions.failed ) { - Colour colour( Colour::ResultError ); - stream << - "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " - "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; - } - else { - Colour colour( Colour::ResultSuccess ); - stream << - "Passed " << bothOrAll( totals.testCases.passed ) - << pluralise( totals.testCases.passed, "test case" ) << - " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; - } - } - }; - - CompactReporter::~CompactReporter() {} - - CATCH_REGISTER_REPORTER( "compact", CompactReporter ) +CATCH_REGISTER_REPORTER( "compact", CompactReporter ) } // end namespace Catch // end catch_reporter_compact.cpp @@ -10497,629 +13376,616 @@ namespace Catch { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled +// Note that 4062 (not all labels are handled +// and default is missing) is enabled #endif namespace Catch { - namespace { - std::size_t makeRatio( std::size_t number, std::size_t total ) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; - return ( ratio == 0 && number > 0 ) ? 1 : ratio; - } +namespace { - std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { - if( i > j && i > k ) - return i; - else if( j > k ) - return j; - else - return k; - } +// Formatter impl for ConsoleReporter +class ConsoleAssertionPrinter { +public: +ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; +ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; +ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) +: stream(_stream), +stats(_stats), +result(_stats.assertionResult), +colour(Colour::None), +message(result.getMessage()), +messages(_stats.infoMessages), +printInfoMessages(_printInfoMessages) { +switch (result.getResultType()) { +case ResultWas::Ok: +colour = Colour::Success; +passOrFail = "PASSED"; +//if( result.hasMessage() ) +if (_stats.infoMessages.size() == 1) +messageLabel = "with message"; +if (_stats.infoMessages.size() > 1) +messageLabel = "with messages"; +break; +case ResultWas::ExpressionFailed: +if (result.isOk()) { +colour = Colour::Success; +passOrFail = "FAILED - but was ok"; +} else { +colour = Colour::Error; +passOrFail = "FAILED"; +} +if (_stats.infoMessages.size() == 1) +messageLabel = "with message"; +if (_stats.infoMessages.size() > 1) +messageLabel = "with messages"; +break; +case ResultWas::ThrewException: +colour = Colour::Error; +passOrFail = "FAILED"; +messageLabel = "due to unexpected exception with "; +if (_stats.infoMessages.size() == 1) +messageLabel += "message"; +if (_stats.infoMessages.size() > 1) +messageLabel += "messages"; +break; +case ResultWas::FatalErrorCondition: +colour = Colour::Error; +passOrFail = "FAILED"; +messageLabel = "due to a fatal error condition"; +break; +case ResultWas::DidntThrowException: +colour = Colour::Error; +passOrFail = "FAILED"; +messageLabel = "because no exception was thrown where one was expected"; +break; +case ResultWas::Info: +messageLabel = "info"; +break; +case ResultWas::Warning: +messageLabel = "warning"; +break; +case ResultWas::ExplicitFailure: +passOrFail = "FAILED"; +colour = Colour::Error; +if (_stats.infoMessages.size() == 1) +messageLabel = "explicitly with message"; +if (_stats.infoMessages.size() > 1) +messageLabel = "explicitly with messages"; +break; +// These cases are here to prevent compiler warnings +case ResultWas::Unknown: +case ResultWas::FailureBit: +case ResultWas::Exception: +passOrFail = "** internal error **"; +colour = Colour::Error; +break; +} +} - struct ColumnInfo { - enum Justification { Left, Right }; - std::string name; - int width; - Justification justification; - }; - struct ColumnBreak {}; - struct RowBreak {}; +void print() const { +printSourceInfo(); +if (stats.totals.assertions.total() > 0) { +printResultType(); +printOriginalExpression(); +printReconstructedExpression(); +} else { +stream << '\n'; +} +printMessage(); +} - class TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - std::ostringstream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; +private: +void printResultType() const { +if (!passOrFail.empty()) { +Colour colourGuard(colour); +stream << passOrFail << ":\n"; +} +} +void printOriginalExpression() const { +if (result.hasExpression()) { +Colour colourGuard(Colour::OriginalExpression); +stream << " "; +stream << result.getExpressionInMacro(); +stream << '\n'; +} +} +void printReconstructedExpression() const { +if (result.hasExpandedExpression()) { +stream << "with expansion:\n"; +Colour colourGuard(Colour::ReconstructedExpression); +stream << Column(result.getExpandedExpression()).indent(2) << '\n'; +} +} +void printMessage() const { +if (!messageLabel.empty()) +stream << messageLabel << ':' << '\n'; +for (auto const& msg : messages) { +// If this assertion is a warning ignore any INFO messages +if (printInfoMessages || msg.type != ResultWas::Info) +stream << Column(msg.message).indent(2) << '\n'; +} +} +void printSourceInfo() const { +Colour colourGuard(Colour::FileName); +stream << result.getSourceInfo() << ": "; +} - public: - TablePrinter( std::ostream& os, std::vector const& columnInfos ) - : m_os( os ), - m_columnInfos( columnInfos ) - {} +std::ostream& stream; +AssertionStats const& stats; +AssertionResult const& result; +Colour::Code colour; +std::string passOrFail; +std::string messageLabel; +std::string message; +std::vector messages; +bool printInfoMessages; +}; - auto columnInfos() const -> std::vector const& { - return m_columnInfos; - } +std::size_t makeRatio(std::size_t number, std::size_t total) { +std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; +return (ratio == 0 && number > 0) ? 1 : ratio; +} - void open() { - if( !m_isOpen ) { - m_isOpen = true; - *this << RowBreak(); - for( auto const& info : m_columnInfos ) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; - } - } - void close() { - if( m_isOpen ) { - *this << RowBreak(); - m_os << std::endl; - m_isOpen = false; - } - } +std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { +if (i > j && i > k) +return i; +else if (j > k) +return j; +else +return k; +} - template - friend TablePrinter& operator << ( TablePrinter& tp, T const& value ) { - tp.m_oss << value; - return tp; - } +struct ColumnInfo { +enum Justification { Left, Right }; +std::string name; +int width; +Justification justification; +}; +struct ColumnBreak {}; +struct RowBreak {}; - friend TablePrinter& operator << ( TablePrinter& tp, ColumnBreak ) { - auto colStr = tp.m_oss.str(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef( colStr ).numberOfCharacters(); - tp.m_oss.str(""); - tp.open(); - if( tp.m_currentColumn == static_cast(tp.m_columnInfos.size()-1) ) { - tp.m_currentColumn = -1; - tp.m_os << "\n"; - } - tp.m_currentColumn++; +class Duration { +enum class Unit { +Auto, +Nanoseconds, +Microseconds, +Milliseconds, +Seconds, +Minutes +}; +static const uint64_t s_nanosecondsInAMicrosecond = 1000; +static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; +static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; +static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = ( strSize+2 < static_cast( colInfo.width ) ) - ? std::string( colInfo.width-(strSize+2), ' ' ) - : std::string(); - if( colInfo.justification == ColumnInfo::Left ) - tp.m_os << colStr << padding << " "; - else - tp.m_os << padding << colStr << " "; - return tp; - } +uint64_t m_inNanoseconds; +Unit m_units; - friend TablePrinter& operator << ( TablePrinter& tp, RowBreak ) { - if( tp.m_currentColumn > 0 ) { - tp.m_os << "\n"; - tp.m_currentColumn = -1; - } - return tp; - } - }; +public: +explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) +: m_inNanoseconds(inNanoseconds), +m_units(units) { +if (m_units == Unit::Auto) { +if (m_inNanoseconds < s_nanosecondsInAMicrosecond) +m_units = Unit::Nanoseconds; +else if (m_inNanoseconds < s_nanosecondsInAMillisecond) +m_units = Unit::Microseconds; +else if (m_inNanoseconds < s_nanosecondsInASecond) +m_units = Unit::Milliseconds; +else if (m_inNanoseconds < s_nanosecondsInAMinute) +m_units = Unit::Seconds; +else +m_units = Unit::Minutes; +} - class Duration { - enum class Unit { - Auto, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes - }; - static const uint64_t s_nanosecondsInAMicrosecond = 1000; - static const uint64_t s_nanosecondsInAMillisecond = 1000*s_nanosecondsInAMicrosecond; - static const uint64_t s_nanosecondsInASecond = 1000*s_nanosecondsInAMillisecond; - static const uint64_t s_nanosecondsInAMinute = 60*s_nanosecondsInASecond; +} - uint64_t m_inNanoseconds; - Unit m_units; +auto value() const -> double { +switch (m_units) { +case Unit::Microseconds: +return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); +case Unit::Milliseconds: +return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); +case Unit::Seconds: +return m_inNanoseconds / static_cast(s_nanosecondsInASecond); +case Unit::Minutes: +return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); +default: +return static_cast(m_inNanoseconds); +} +} +auto unitsAsString() const -> std::string { +switch (m_units) { +case Unit::Nanoseconds: +return "ns"; +case Unit::Microseconds: +return "us"; +case Unit::Milliseconds: +return "ms"; +case Unit::Seconds: +return "s"; +case Unit::Minutes: +return "m"; +default: +return "** internal error **"; +} - public: - Duration( uint64_t inNanoseconds, Unit units = Unit::Auto ) - : m_inNanoseconds( inNanoseconds ), - m_units( units ) - { - if( m_units == Unit::Auto ) { - if( m_inNanoseconds < s_nanosecondsInAMicrosecond ) - m_units = Unit::Nanoseconds; - else if( m_inNanoseconds < s_nanosecondsInAMillisecond ) - m_units = Unit::Microseconds; - else if( m_inNanoseconds < s_nanosecondsInASecond ) - m_units = Unit::Milliseconds; - else if( m_inNanoseconds < s_nanosecondsInAMinute ) - m_units = Unit::Seconds; - else - m_units = Unit::Minutes; - } +} +friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { +return os << duration.value() << " " << duration.unitsAsString(); +} +}; +} // end anon namespace - } +class TablePrinter { +std::ostream& m_os; +std::vector m_columnInfos; +std::ostringstream m_oss; +int m_currentColumn = -1; +bool m_isOpen = false; - auto value() const -> double { - switch( m_units ) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMicrosecond ); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast( s_nanosecondsInAMillisecond ); - case Unit::Seconds: - return m_inNanoseconds / static_cast( s_nanosecondsInASecond ); - case Unit::Minutes: - return m_inNanoseconds / static_cast( s_nanosecondsInAMinute ); - default: - return static_cast( m_inNanoseconds ); - } - } - auto unitsAsString() const -> std::string { - switch( m_units ) { - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: - return "µs"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: - return "s"; - case Unit::Minutes: - return "m"; - default: - return "** internal error **"; - } +public: +TablePrinter( std::ostream& os, std::vector columnInfos ) +: m_os( os ), +m_columnInfos( std::move( columnInfos ) ) {} - } - friend auto operator << ( std::ostream& os, Duration const& duration ) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); - } - }; - } // end anon namespace +auto columnInfos() const -> std::vector const& { +return m_columnInfos; +} - struct ConsoleReporter : StreamingReporterBase { - TablePrinter m_tablePrinter; +void open() { +if (!m_isOpen) { +m_isOpen = true; +*this << RowBreak(); +for (auto const& info : m_columnInfos) +*this << info.name << ColumnBreak(); +*this << RowBreak(); +m_os << Catch::getLineOfChars<'-'>() << "\n"; +} +} +void close() { +if (m_isOpen) { +*this << RowBreak(); +m_os << std::endl; +m_isOpen = false; +} +} - ConsoleReporter( ReporterConfig const& config ) - : StreamingReporterBase( config ), - m_tablePrinter( config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH-32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - } ) - {} - ~ConsoleReporter() override; - static std::string getDescription() { - return "Reports test results as plain lines of text"; - } +template +friend TablePrinter& operator << (TablePrinter& tp, T const& value) { +tp.m_oss << value; +return tp; +} - void noMatchingTestCases( std::string const& spec ) override { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } +friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { +auto colStr = tp.m_oss.str(); +// This takes account of utf8 encodings +auto strSize = Catch::StringRef(colStr).numberOfCharacters(); +tp.m_oss.str(""); +tp.open(); +if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { +tp.m_currentColumn = -1; +tp.m_os << "\n"; +} +tp.m_currentColumn++; - void assertionStarting( AssertionInfo const& ) override { - } +auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; +auto padding = (strSize + 2 < static_cast(colInfo.width)) +? std::string(colInfo.width - (strSize + 2), ' ') +: std::string(); +if (colInfo.justification == ColumnInfo::Left) +tp.m_os << colStr << padding << " "; +else +tp.m_os << padding << colStr << " "; +return tp; +} - bool assertionEnded( AssertionStats const& _assertionStats ) override { - AssertionResult const& result = _assertionStats.assertionResult; +friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { +if (tp.m_currentColumn > 0) { +tp.m_os << "\n"; +tp.m_currentColumn = -1; +} +return tp; +} +}; - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); +ConsoleReporter::ConsoleReporter(ReporterConfig const& config) +: StreamingReporterBase(config), +m_tablePrinter(new TablePrinter(config.stream(), +{ +{ "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, +{ "iters", 8, ColumnInfo::Right }, +{ "elapsed ns", 14, ColumnInfo::Right }, +{ "average", 14, ColumnInfo::Right } +})) {} +ConsoleReporter::~ConsoleReporter() = default; - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return false; +std::string ConsoleReporter::getDescription() { +return "Reports test results as plain lines of text"; +} - lazyPrint(); +void ConsoleReporter::noMatchingTestCases(std::string const& spec) { +stream << "No test cases matched '" << spec << '\'' << std::endl; +} - AssertionPrinter printer( stream, _assertionStats, includeResults ); - printer.print(); - stream << std::endl; - return true; - } +void ConsoleReporter::assertionStarting(AssertionInfo const&) {} - void sectionStarting( SectionInfo const& _sectionInfo ) override { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting( _sectionInfo ); - } - void sectionEnded( SectionStats const& _sectionStats ) override { - m_tablePrinter.close(); - if( _sectionStats.missingAssertions ) { - lazyPrint(); - Colour colour( Colour::ResultError ); - if( m_sectionStack.size() > 1 ) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; - } - if( m_config->showDurations() == ShowDurations::Always ) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - if( m_headerPrinted ) { - m_headerPrinted = false; - } - StreamingReporterBase::sectionEnded( _sectionStats ); - } +bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { +AssertionResult const& result = _assertionStats.assertionResult; - void benchmarkStarting( BenchmarkInfo const& info ) override { - lazyPrintWithoutClosingBenchmarkTable(); +bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - auto nameCol = Column( info.name ).width( m_tablePrinter.columnInfos()[0].width-2 ); +// Drop out if result was successful but we're not printing them. +if (!includeResults && result.getResultType() != ResultWas::Warning) +return false; - bool firstLine = true; - for( auto line : nameCol ) { - if( !firstLine ) - m_tablePrinter << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; +lazyPrint(); - m_tablePrinter << line << ColumnBreak(); - } - } - void benchmarkEnded( BenchmarkStats const& stats ) override { - Duration average( stats.elapsedTimeInNanoseconds/stats.iterations ); - m_tablePrinter - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); - } +ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); +printer.print(); +stream << std::endl; +return true; +} - void testCaseEnded( TestCaseStats const& _testCaseStats ) override { - m_tablePrinter.close(); - StreamingReporterBase::testCaseEnded( _testCaseStats ); - m_headerPrinted = false; - } - void testGroupEnded( TestGroupStats const& _testGroupStats ) override { - if( currentGroupInfo.used ) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals( _testGroupStats.totals ); - stream << '\n' << std::endl; - } - StreamingReporterBase::testGroupEnded( _testGroupStats ); - } - void testRunEnded( TestRunStats const& _testRunStats ) override { - printTotalsDivider( _testRunStats.totals ); - printTotals( _testRunStats.totals ); - stream << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } +void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { +m_headerPrinted = false; +StreamingReporterBase::sectionStarting(_sectionInfo); +} +void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { +m_tablePrinter->close(); +if (_sectionStats.missingAssertions) { +lazyPrint(); +Colour colour(Colour::ResultError); +if (m_sectionStack.size() > 1) +stream << "\nNo assertions in section"; +else +stream << "\nNo assertions in test case"; +stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; +} +if (m_config->showDurations() == ShowDurations::Always) { +stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; +} +if (m_headerPrinted) { +m_headerPrinted = false; +} +StreamingReporterBase::sectionEnded(_sectionStats); +} - private: +void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { +lazyPrintWithoutClosingBenchmarkTable(); - class AssertionPrinter { - public: - AssertionPrinter& operator= ( AssertionPrinter const& ) = delete; - AssertionPrinter( AssertionPrinter const& ) = delete; - AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) - : stream( _stream ), - stats( _stats ), - result( _stats.assertionResult ), - colour( Colour::None ), - message( result.getMessage() ), - messages( _stats.infoMessages ), - printInfoMessages( _printInfoMessages ) - { - switch( result.getResultType() ) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if( result.isOk() ) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } - else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if( _stats.infoMessages.size() == 1 ) - messageLabel = "with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if( _stats.infoMessages.size() == 1 ) - messageLabel = "explicitly with message"; - if( _stats.infoMessages.size() > 1 ) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } +auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); - void print() const { - printSourceInfo(); - if( stats.totals.assertions.total() > 0 ) { - if( result.isOk() ) - stream << '\n'; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } - else { - stream << '\n'; - } - printMessage(); - } +bool firstLine = true; +for (auto line : nameCol) { +if (!firstLine) +(*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); +else +firstLine = false; - private: - void printResultType() const { - if( !passOrFail.empty() ) { - Colour colourGuard( colour ); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if( result.hasExpression() ) { - Colour colourGuard( Colour::OriginalExpression ); - stream << " "; - stream << result.getExpressionInMacro(); - stream << '\n'; - } - } - void printReconstructedExpression() const { - if( result.hasExpandedExpression() ) { - stream << "with expansion:\n"; - Colour colourGuard( Colour::ReconstructedExpression ); - stream << Column( result.getExpandedExpression() ).indent(2) << '\n'; - } - } - void printMessage() const { - if( !messageLabel.empty() ) - stream << messageLabel << ':' << '\n'; - for( auto const& msg : messages ) { - // If this assertion is a warning ignore any INFO messages - if( printInfoMessages || msg.type != ResultWas::Info ) - stream << Column( msg.message ).indent(2) << '\n'; - } - } - void printSourceInfo() const { - Colour colourGuard( Colour::FileName ); - stream << result.getSourceInfo() << ": "; - } +(*m_tablePrinter) << line << ColumnBreak(); +} +} +void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { +Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); +(*m_tablePrinter) +<< stats.iterations << ColumnBreak() +<< stats.elapsedTimeInNanoseconds << ColumnBreak() +<< average << ColumnBreak(); +} - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; - }; +void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { +m_tablePrinter->close(); +StreamingReporterBase::testCaseEnded(_testCaseStats); +m_headerPrinted = false; +} +void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { +if (currentGroupInfo.used) { +printSummaryDivider(); +stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; +printTotals(_testGroupStats.totals); +stream << '\n' << std::endl; +} +StreamingReporterBase::testGroupEnded(_testGroupStats); +} +void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { +printTotalsDivider(_testRunStats.totals); +printTotals(_testRunStats.totals); +stream << std::endl; +StreamingReporterBase::testRunEnded(_testRunStats); +} +void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { +StreamingReporterBase::testRunStarting(_testInfo); +printTestFilters(); +} - void lazyPrint() { +void ConsoleReporter::lazyPrint() { - m_tablePrinter.close(); - lazyPrintWithoutClosingBenchmarkTable(); - } +m_tablePrinter->close(); +lazyPrintWithoutClosingBenchmarkTable(); +} - void lazyPrintWithoutClosingBenchmarkTable() { +void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { - if( !currentTestRunInfo.used ) - lazyPrintRunInfo(); - if( !currentGroupInfo.used ) - lazyPrintGroupInfo(); +if (!currentTestRunInfo.used) +lazyPrintRunInfo(); +if (!currentGroupInfo.used) +lazyPrintGroupInfo(); - if( !m_headerPrinted ) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } - } - void lazyPrintRunInfo() { - stream << '\n' << getLineOfChars<'~'>() << '\n'; - Colour colour( Colour::SecondaryText ); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion() << " host application.\n" - << "Run with -? for options\n\n"; +if (!m_headerPrinted) { +printTestCaseAndSectionHeader(); +m_headerPrinted = true; +} +} +void ConsoleReporter::lazyPrintRunInfo() { +stream << '\n' << getLineOfChars<'~'>() << '\n'; +Colour colour(Colour::SecondaryText); +stream << currentTestRunInfo->name +<< " is a Catch v" << libraryVersion() << " host application.\n" +<< "Run with -? for options\n\n"; - if( m_config->rngSeed() != 0 ) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; +if (m_config->rngSeed() != 0) +stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - currentTestRunInfo.used = true; - } - void lazyPrintGroupInfo() { - if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { - printClosedHeader( "Group: " + currentGroupInfo->name ); - currentGroupInfo.used = true; - } - } - void printTestCaseAndSectionHeader() { - assert( !m_sectionStack.empty() ); - printOpenHeader( currentTestCaseInfo->name ); +currentTestRunInfo.used = true; +} +void ConsoleReporter::lazyPrintGroupInfo() { +if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { +printClosedHeader("Group: " + currentGroupInfo->name); +currentGroupInfo.used = true; +} +} +void ConsoleReporter::printTestCaseAndSectionHeader() { +assert(!m_sectionStack.empty()); +printOpenHeader(currentTestCaseInfo->name); - if( m_sectionStack.size() > 1 ) { - Colour colourGuard( Colour::Headers ); +if (m_sectionStack.size() > 1) { +Colour colourGuard(Colour::Headers); - auto - it = m_sectionStack.begin()+1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for( ; it != itEnd; ++it ) - printHeaderString( it->name, 2 ); - } +auto +it = m_sectionStack.begin() + 1, // Skip first section (test case) +itEnd = m_sectionStack.end(); +for (; it != itEnd; ++it) +printHeaderString(it->name, 2); +} - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; +SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - if( !lineInfo.empty() ){ - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard( Colour::FileName ); - stream << lineInfo << '\n'; - } - stream << getLineOfChars<'.'>() << '\n' << std::endl; - } +if (!lineInfo.empty()) { +stream << getLineOfChars<'-'>() << '\n'; +Colour colourGuard(Colour::FileName); +stream << lineInfo << '\n'; +} +stream << getLineOfChars<'.'>() << '\n' << std::endl; +} - void printClosedHeader( std::string const& _name ) { - printOpenHeader( _name ); - stream << getLineOfChars<'.'>() << '\n'; - } - void printOpenHeader( std::string const& _name ) { - stream << getLineOfChars<'-'>() << '\n'; - { - Colour colourGuard( Colour::Headers ); - printHeaderString( _name ); - } - } +void ConsoleReporter::printClosedHeader(std::string const& _name) { +printOpenHeader(_name); +stream << getLineOfChars<'.'>() << '\n'; +} +void ConsoleReporter::printOpenHeader(std::string const& _name) { +stream << getLineOfChars<'-'>() << '\n'; +{ +Colour colourGuard(Colour::Headers); +printHeaderString(_name); +} +} - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { - std::size_t i = _string.find( ": " ); - if( i != std::string::npos ) - i+=2; - else - i = 0; - stream << Column( _string ).indent( indent+i ).initialIndent( indent ) << '\n'; - } +// if string has a : in first line will set indent to follow it on +// subsequent lines +void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { +std::size_t i = _string.find(": "); +if (i != std::string::npos) +i += 2; +else +i = 0; +stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; +} - struct SummaryColumn { +struct SummaryColumn { - SummaryColumn( std::string const& _label, Colour::Code _colour ) - : label( _label ), - colour( _colour ) - {} - SummaryColumn addRow( std::size_t count ) { - std::ostringstream oss; - oss << count; - std::string row = oss.str(); - for( auto& oldRow : rows ) { - while( oldRow.size() < row.size() ) - oldRow = ' ' + oldRow; - while( oldRow.size() > row.size() ) - row = ' ' + row; - } - rows.push_back( row ); - return *this; - } +SummaryColumn( std::string _label, Colour::Code _colour ) +: label( std::move( _label ) ), +colour( _colour ) {} +SummaryColumn addRow( std::size_t count ) { +ReusableStringStream rss; +rss << count; +std::string row = rss.str(); +for (auto& oldRow : rows) { +while (oldRow.size() < row.size()) +oldRow = ' ' + oldRow; +while (oldRow.size() > row.size()) +row = ' ' + row; +} +rows.push_back(row); +return *this; +} - std::string label; - Colour::Code colour; - std::vector rows; +std::string label; +Colour::Code colour; +std::vector rows; - }; +}; - void printTotals( Totals const& totals ) { - if( totals.testCases.total() == 0 ) { - stream << Colour( Colour::Warning ) << "No tests ran\n"; - } - else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { - stream << Colour( Colour::ResultSuccess ) << "All tests passed"; - stream << " (" - << pluralise( totals.assertions.passed, "assertion" ) << " in " - << pluralise( totals.testCases.passed, "test case" ) << ')' - << '\n'; - } - else { +void ConsoleReporter::printTotals( Totals const& totals ) { +if (totals.testCases.total() == 0) { +stream << Colour(Colour::Warning) << "No tests ran\n"; +} else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { +stream << Colour(Colour::ResultSuccess) << "All tests passed"; +stream << " (" +<< pluralise(totals.assertions.passed, "assertion") << " in " +<< pluralise(totals.testCases.passed, "test case") << ')' +<< '\n'; +} else { - std::vector columns; - columns.push_back( SummaryColumn( "", Colour::None ) - .addRow( totals.testCases.total() ) - .addRow( totals.assertions.total() ) ); - columns.push_back( SummaryColumn( "passed", Colour::Success ) - .addRow( totals.testCases.passed ) - .addRow( totals.assertions.passed ) ); - columns.push_back( SummaryColumn( "failed", Colour::ResultError ) - .addRow( totals.testCases.failed ) - .addRow( totals.assertions.failed ) ); - columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) - .addRow( totals.testCases.failedButOk ) - .addRow( totals.assertions.failedButOk ) ); +std::vector columns; +columns.push_back(SummaryColumn("", Colour::None) +.addRow(totals.testCases.total()) +.addRow(totals.assertions.total())); +columns.push_back(SummaryColumn("passed", Colour::Success) +.addRow(totals.testCases.passed) +.addRow(totals.assertions.passed)); +columns.push_back(SummaryColumn("failed", Colour::ResultError) +.addRow(totals.testCases.failed) +.addRow(totals.assertions.failed)); +columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) +.addRow(totals.testCases.failedButOk) +.addRow(totals.assertions.failedButOk)); - printSummaryRow( "test cases", columns, 0 ); - printSummaryRow( "assertions", columns, 1 ); - } - } - void printSummaryRow( std::string const& label, std::vector const& cols, std::size_t row ) { - for( auto col : cols ) { - std::string value = col.rows[row]; - if( col.label.empty() ) { - stream << label << ": "; - if( value != "0" ) - stream << value; - else - stream << Colour( Colour::Warning ) << "- none -"; - } - else if( value != "0" ) { - stream << Colour( Colour::LightGrey ) << " | "; - stream << Colour( col.colour ) - << value << ' ' << col.label; - } - } - stream << '\n'; - } +printSummaryRow("test cases", columns, 0); +printSummaryRow("assertions", columns, 1); +} +} +void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { +for (auto col : cols) { +std::string value = col.rows[row]; +if (col.label.empty()) { +stream << label << ": "; +if (value != "0") +stream << value; +else +stream << Colour(Colour::Warning) << "- none -"; +} else if (value != "0") { +stream << Colour(Colour::LightGrey) << " | "; +stream << Colour(col.colour) +<< value << ' ' << col.label; +} +} +stream << '\n'; +} - void printTotalsDivider( Totals const& totals ) { - if( totals.testCases.total() > 0 ) { - std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); - std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); - std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); - while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )++; - while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) - findMax( failedRatio, failedButOkRatio, passedRatio )--; +void ConsoleReporter::printTotalsDivider(Totals const& totals) { +if (totals.testCases.total() > 0) { +std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); +std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); +std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); +while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) +findMax(failedRatio, failedButOkRatio, passedRatio)++; +while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) +findMax(failedRatio, failedButOkRatio, passedRatio)--; - stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); - stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); - if( totals.testCases.allPassed() ) - stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); - else - stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); - } - else { - stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); - } - stream << '\n'; - } - void printSummaryDivider() { - stream << getLineOfChars<'-'>() << '\n'; - } +stream << Colour(Colour::Error) << std::string(failedRatio, '='); +stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); +if (totals.testCases.allPassed()) +stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); +else +stream << Colour(Colour::Success) << std::string(passedRatio, '='); +} else { +stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); +} +stream << '\n'; +} +void ConsoleReporter::printSummaryDivider() { +stream << getLineOfChars<'-'>() << '\n'; +} - private: - bool m_headerPrinted = false; - }; +void ConsoleReporter::printTestFilters() { +if (m_config->testSpec().hasFilters()) +stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n'; +} - CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) - - ConsoleReporter::~ConsoleReporter() {} +CATCH_REGISTER_REPORTER("console", ConsoleReporter) } // end namespace Catch @@ -11129,558 +13995,599 @@ namespace Catch { // end catch_reporter_console.cpp // start catch_reporter_junit.cpp -#include - +#include +#include #include #include namespace Catch { - namespace { - std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); +namespace { +std::string getCurrentTimestamp() { +// Beware, this is not reentrant because of backward compatibility issues +// Also, UTC only, again because of backward compatibility (%z is C++11) +time_t rawtime; +std::time(&rawtime); +auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); #ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &rawtime); +std::tm timeInfo = {}; +gmtime_s(&timeInfo, &rawtime); #else - std::tm* timeInfo; - timeInfo = std::gmtime(&rawtime); +std::tm* timeInfo; +timeInfo = std::gmtime(&rawtime); #endif - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; +char timeStamp[timeStampSize]; +const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; #ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); +std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); #else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); +std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif - return std::string(timeStamp); - } +return std::string(timeStamp); +} - std::string fileNameTag(const std::vector &tags) { - auto it = std::find_if(begin(tags), - end(tags), - [] (std::string const& tag) {return tag.front() == '#'; }); - if (it != tags.end()) - return it->substr(1); - return std::string(); - } - } +std::string fileNameTag(const std::vector &tags) { +auto it = std::find_if(begin(tags), +end(tags), +[] (std::string const& tag) {return tag.front() == '#'; }); +if (it != tags.end()) +return it->substr(1); +return std::string(); +} +} // anonymous namespace - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } +JunitReporter::JunitReporter( ReporterConfig const& _config ) +: CumulativeReporterBase( _config ), +xml( _config.stream() ) +{ +m_reporterPrefs.shouldRedirectStdOut = true; +m_reporterPrefs.shouldReportAllAssertions = true; +} - ~JunitReporter() override; +JunitReporter::~JunitReporter() {} - static std::string getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } +std::string JunitReporter::getDescription() { +return "Reports test results in an XML format that looks like Ant's junitreport target"; +} - void noMatchingTestCases( std::string const& /*spec*/ ) override {} +void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} - void testRunStarting( TestRunInfo const& runInfo ) override { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } +void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { +CumulativeReporterBase::testRunStarting( runInfo ); +xml.startElement( "testsuites" ); +} - void testGroupStarting( GroupInfo const& groupInfo ) override { - suiteTimer.start(); - stdOutForSuite.str(""); - stdErrForSuite.str(""); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } +void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { +suiteTimer.start(); +stdOutForSuite.clear(); +stdErrForSuite.clear(); +unexpectedExceptions = 0; +CumulativeReporterBase::testGroupStarting( groupInfo ); +} - void testCaseStarting( TestCaseInfo const& testCaseInfo ) override { - m_okToFail = testCaseInfo.okToFail(); - } - bool assertionEnded( AssertionStats const& assertionStats ) override { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } +void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { +m_okToFail = testCaseInfo.okToFail(); +} - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - stdOutForSuite << testCaseStats.stdOut; - stdErrForSuite << testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } +bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { +if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) +unexpectedExceptions++; +return CumulativeReporterBase::assertionEnded( assertionStats ); +} - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } +void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { +stdOutForSuite += testCaseStats.stdOut; +stdErrForSuite += testCaseStats.stdErr; +CumulativeReporterBase::testCaseEnded( testCaseStats ); +} - void testRunEndedCumulative() override { - xml.endElement(); - } +void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { +double suiteTime = suiteTimer.getElapsedSeconds(); +CumulativeReporterBase::testGroupEnded( testGroupStats ); +writeGroup( *m_testGroups.back(), suiteTime ); +} - void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); +void JunitReporter::testRunEndedCumulative() { +xml.endElement(); +} - // Write test cases - for( auto const& child : groupNode.children ) - writeTestCase( *child ); +void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { +XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); - } +TestGroupStats const& stats = groupNode.value; +xml.writeAttribute( "name", stats.groupInfo.name ); +xml.writeAttribute( "errors", unexpectedExceptions ); +xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); +xml.writeAttribute( "tests", stats.totals.assertions.total() ); +xml.writeAttribute( "hostname", "tbd" ); // !TBD +if( m_config->showDurations() == ShowDurations::Never ) +xml.writeAttribute( "time", "" ); +else +xml.writeAttribute( "time", suiteTime ); +xml.writeAttribute( "timestamp", getCurrentTimestamp() ); - void writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; +// Write properties if there are any +if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { +auto properties = xml.scopedElement("properties"); +if (m_config->hasTestFilters()) { +xml.scopedElement("property") +.writeAttribute("name", "filters") +.writeAttribute("value", serializeFilters(m_config->getTestsOrTags())); +} +if (m_config->rngSeed() != 0) { +xml.scopedElement("property") +.writeAttribute("name", "random-seed") +.writeAttribute("value", m_config->rngSeed()); +} +} - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); +// Write test cases +for( auto const& child : groupNode.children ) +writeTestCase( *child ); - std::string className = stats.testInfo.className; +xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); +xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); +} - if( className.empty() ) { - className = fileNameTag(stats.testInfo.tags); - if ( className.empty() ) - className = "global"; - } +void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { +TestCaseStats const& stats = testCaseNode.value; - if ( !m_config->name().empty() ) - className = m_config->name() + "." + className; +// All test cases have exactly one section - which represents the +// test case itself. That section may have 0-n nested sections +assert( testCaseNode.children.size() == 1 ); +SectionNode const& rootSection = *testCaseNode.children.front(); - writeSection( className, "", rootSection ); - } +std::string className = stats.testInfo.className; - void writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; +if( className.empty() ) { +className = fileNameTag(stats.testInfo.tags); +if ( className.empty() ) +className = "global"; +} - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); +if ( !m_config->name().empty() ) +className = m_config->name() + "." + className; - writeAssertions( sectionNode ); +writeSection( className, "", rootSection ); +} - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode ); - else - writeSection( className, name, *childNode ); - } +void JunitReporter::writeSection( std::string const& className, +std::string const& rootName, +SectionNode const& sectionNode ) { +std::string name = trim( sectionNode.stats.sectionInfo.name ); +if( !rootName.empty() ) +name = rootName + '/' + name; - void writeAssertions( SectionNode const& sectionNode ) { - for( auto const& assertion : sectionNode.assertions ) - writeAssertion( assertion ); - } - void writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; +if( !sectionNode.assertions.empty() || +!sectionNode.stdOut.empty() || +!sectionNode.stdErr.empty() ) { +XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); +if( className.empty() ) { +xml.writeAttribute( "classname", name ); +xml.writeAttribute( "name", "root" ); +} +else { +xml.writeAttribute( "classname", className ); +xml.writeAttribute( "name", name ); +} +xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } +writeAssertions( sectionNode ); - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); +if( !sectionNode.stdOut.empty() ) +xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); +if( !sectionNode.stdErr.empty() ) +xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); +} +for( auto const& childNode : sectionNode.childSections ) +if( className.empty() ) +writeSection( name, "", *childNode ); +else +writeSection( className, name, *childNode ); +} - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); +void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { +for( auto const& assertion : sectionNode.assertions ) +writeAssertion( assertion ); +} - std::ostringstream oss; - if( !result.getMessage().empty() ) - oss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - oss << msg.message << '\n'; +void JunitReporter::writeAssertion( AssertionStats const& stats ) { +AssertionResult const& result = stats.assertionResult; +if( !result.isOk() ) { +std::string elementName; +switch( result.getResultType() ) { +case ResultWas::ThrewException: +case ResultWas::FatalErrorCondition: +elementName = "error"; +break; +case ResultWas::ExplicitFailure: +elementName = "failure"; +break; +case ResultWas::ExpressionFailed: +elementName = "failure"; +break; +case ResultWas::DidntThrowException: +elementName = "failure"; +break; - oss << "at " << result.getSourceInfo(); - xml.writeText( oss.str(), false ); - } - } +// We should never see these here: +case ResultWas::Info: +case ResultWas::Warning: +case ResultWas::Ok: +case ResultWas::Unknown: +case ResultWas::FailureBit: +case ResultWas::Exception: +elementName = "internalError"; +break; +} - XmlWriter xml; - Timer suiteTimer; - std::ostringstream stdOutForSuite; - std::ostringstream stdErrForSuite; - unsigned int unexpectedExceptions = 0; - bool m_okToFail = false; - }; +XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - JunitReporter::~JunitReporter() {} - CATCH_REGISTER_REPORTER( "junit", JunitReporter ) +xml.writeAttribute( "message", result.getExpandedExpression() ); +xml.writeAttribute( "type", result.getTestMacroName() ); + +ReusableStringStream rss; +if( !result.getMessage().empty() ) +rss << result.getMessage() << '\n'; +for( auto const& msg : stats.infoMessages ) +if( msg.type == ResultWas::Info ) +rss << msg.message << '\n'; + +rss << "at " << result.getSourceInfo(); +xml.writeText( rss.str(), false ); +} +} + +CATCH_REGISTER_REPORTER( "junit", JunitReporter ) } // end namespace Catch // end catch_reporter_junit.cpp -// start catch_reporter_multi.cpp +// start catch_reporter_listening.cpp + +#include namespace Catch { - void MultipleReporters::add( IStreamingReporterPtr&& reporter ) { - m_reporters.push_back( std::move( reporter ) ); - } +ListeningReporter::ListeningReporter() { +// We will assume that listeners will always want all assertions +m_preferences.shouldReportAllAssertions = true; +} - ReporterPreferences MultipleReporters::getPreferences() const { - return m_reporters[0]->getPreferences(); - } +void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { +m_listeners.push_back( std::move( listener ) ); +} - std::set MultipleReporters::getSupportedVerbosities() { - return std::set{ }; - } +void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { +assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); +m_reporter = std::move( reporter ); +m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; +} - void MultipleReporters::noMatchingTestCases( std::string const& spec ) { - for( auto const& reporter : m_reporters ) - reporter->noMatchingTestCases( spec ); - } +ReporterPreferences ListeningReporter::getPreferences() const { +return m_preferences; +} - void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkStarting( benchmarkInfo ); - } - void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkEnded( benchmarkStats ); - } +std::set ListeningReporter::getSupportedVerbosities() { +return std::set{ }; +} - void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testRunStarting( testRunInfo ); - } +void ListeningReporter::noMatchingTestCases( std::string const& spec ) { +for ( auto const& listener : m_listeners ) { +listener->noMatchingTestCases( spec ); +} +m_reporter->noMatchingTestCases( spec ); +} - void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupStarting( groupInfo ); - } +void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { +for ( auto const& listener : m_listeners ) { +listener->benchmarkStarting( benchmarkInfo ); +} +m_reporter->benchmarkStarting( benchmarkInfo ); +} +void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { +for ( auto const& listener : m_listeners ) { +listener->benchmarkEnded( benchmarkStats ); +} +m_reporter->benchmarkEnded( benchmarkStats ); +} - void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseStarting( testInfo ); - } +void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { +for ( auto const& listener : m_listeners ) { +listener->testRunStarting( testRunInfo ); +} +m_reporter->testRunStarting( testRunInfo ); +} - void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->sectionStarting( sectionInfo ); - } +void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { +for ( auto const& listener : m_listeners ) { +listener->testGroupStarting( groupInfo ); +} +m_reporter->testGroupStarting( groupInfo ); +} - void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->assertionStarting( assertionInfo ); - } +void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { +for ( auto const& listener : m_listeners ) { +listener->testCaseStarting( testInfo ); +} +m_reporter->testCaseStarting( testInfo ); +} - // The return value indicates if the messages buffer should be cleared: - bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) { - bool clearBuffer = false; - for( auto const& reporter : m_reporters ) - clearBuffer |= reporter->assertionEnded( assertionStats ); - return clearBuffer; - } +void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { +for ( auto const& listener : m_listeners ) { +listener->sectionStarting( sectionInfo ); +} +m_reporter->sectionStarting( sectionInfo ); +} - void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) { - for( auto const& reporter : m_reporters ) - reporter->sectionEnded( sectionStats ); - } +void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { +for ( auto const& listener : m_listeners ) { +listener->assertionStarting( assertionInfo ); +} +m_reporter->assertionStarting( assertionInfo ); +} - void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseEnded( testCaseStats ); - } +// The return value indicates if the messages buffer should be cleared: +bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { +for( auto const& listener : m_listeners ) { +static_cast( listener->assertionEnded( assertionStats ) ); +} +return m_reporter->assertionEnded( assertionStats ); +} - void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupEnded( testGroupStats ); - } +void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { +for ( auto const& listener : m_listeners ) { +listener->sectionEnded( sectionStats ); +} +m_reporter->sectionEnded( sectionStats ); +} - void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) { - for( auto const& reporter : m_reporters ) - reporter->testRunEnded( testRunStats ); - } +void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { +for ( auto const& listener : m_listeners ) { +listener->testCaseEnded( testCaseStats ); +} +m_reporter->testCaseEnded( testCaseStats ); +} - void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->skipTest( testInfo ); - } +void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { +for ( auto const& listener : m_listeners ) { +listener->testGroupEnded( testGroupStats ); +} +m_reporter->testGroupEnded( testGroupStats ); +} - bool MultipleReporters::isMulti() const { - return true; - } +void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { +for ( auto const& listener : m_listeners ) { +listener->testRunEnded( testRunStats ); +} +m_reporter->testRunEnded( testRunStats ); +} + +void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { +for ( auto const& listener : m_listeners ) { +listener->skipTest( testInfo ); +} +m_reporter->skipTest( testInfo ); +} + +bool ListeningReporter::isMulti() const { +return true; +} } // end namespace Catch -// end catch_reporter_multi.cpp +// end catch_reporter_listening.cpp // start catch_reporter_xml.cpp #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled +// Note that 4062 (not all labels are handled +// and default is missing) is enabled #endif namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } +XmlReporter::XmlReporter( ReporterConfig const& _config ) +: StreamingReporterBase( _config ), +m_xml(_config.stream()) +{ +m_reporterPrefs.shouldRedirectStdOut = true; +m_reporterPrefs.shouldReportAllAssertions = true; +} - ~XmlReporter() override; +XmlReporter::~XmlReporter() = default; - static std::string getDescription() { - return "Reports test results as an XML document"; - } +std::string XmlReporter::getDescription() { +return "Reports test results as an XML document"; +} - virtual std::string getStylesheetRef() const { - return std::string(); - } +std::string XmlReporter::getStylesheetRef() const { +return std::string(); +} - void writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } +void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { +m_xml +.writeAttribute( "filename", sourceInfo.file ) +.writeAttribute( "line", sourceInfo.line ); +} - public: // StreamingReporterBase +void XmlReporter::noMatchingTestCases( std::string const& s ) { +StreamingReporterBase::noMatchingTestCases( s ); +} - void noMatchingTestCases( std::string const& s ) override { - StreamingReporterBase::noMatchingTestCases( s ); - } +void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { +StreamingReporterBase::testRunStarting( testInfo ); +std::string stylesheetRef = getStylesheetRef(); +if( !stylesheetRef.empty() ) +m_xml.writeStylesheetRef( stylesheetRef ); +m_xml.startElement( "Catch" ); +if( !m_config->name().empty() ) +m_xml.writeAttribute( "name", m_config->name() ); +if (m_config->testSpec().hasFilters()) +m_xml.writeAttribute( "filters", serializeFilters( m_config->getTestsOrTags() ) ); +if( m_config->rngSeed() != 0 ) +m_xml.scopedElement( "Randomness" ) +.writeAttribute( "seed", m_config->rngSeed() ); +} - void testRunStarting( TestRunInfo const& testInfo ) override { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } +void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { +StreamingReporterBase::testGroupStarting( groupInfo ); +m_xml.startElement( "Group" ) +.writeAttribute( "name", groupInfo.name ); +} - void testGroupStarting( GroupInfo const& groupInfo ) override { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } +void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { +StreamingReporterBase::testCaseStarting(testInfo); +m_xml.startElement( "TestCase" ) +.writeAttribute( "name", trim( testInfo.name ) ) +.writeAttribute( "description", testInfo.description ) +.writeAttribute( "tags", testInfo.tagsAsString() ); - void testCaseStarting( TestCaseInfo const& testInfo ) override { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString() ); +writeSourceInfo( testInfo.lineInfo ); - writeSourceInfo( testInfo.lineInfo ); +if ( m_config->showDurations() == ShowDurations::Always ) +m_testCaseTimer.start(); +m_xml.ensureTagClosed(); +} - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } +void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { +StreamingReporterBase::sectionStarting( sectionInfo ); +if( m_sectionDepth++ > 0 ) { +m_xml.startElement( "Section" ) +.writeAttribute( "name", trim( sectionInfo.name ) ); +writeSourceInfo( sectionInfo.lineInfo ); +m_xml.ensureTagClosed(); +} +} - void sectionStarting( SectionInfo const& sectionInfo ) override { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); - } - } +void XmlReporter::assertionStarting( AssertionInfo const& ) { } - void assertionStarting( AssertionInfo const& ) override { } +bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { - bool assertionEnded( AssertionStats const& assertionStats ) override { +AssertionResult const& result = assertionStats.assertionResult; - AssertionResult const& result = assertionStats.assertionResult; +bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); +if( includeResults || result.getResultType() == ResultWas::Warning ) { +// Print any info messages in tags. +for( auto const& msg : assertionStats.infoMessages ) { +if( msg.type == ResultWas::Info && includeResults ) { +m_xml.scopedElement( "Info" ) +.writeText( msg.message ); +} else if ( msg.type == ResultWas::Warning ) { +m_xml.scopedElement( "Warning" ) +.writeText( msg.message ); +} +} +} - if( includeResults ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); - } - } - } +// Drop out if result was successful but we're not printing them. +if( !includeResults && result.getResultType() != ResultWas::Warning ) +return true; - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; +// Print the expression if there is one. +if( result.hasExpression() ) { +m_xml.startElement( "Expression" ) +.writeAttribute( "success", result.succeeded() ) +.writeAttribute( "type", result.getTestMacroName() ); - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); +writeSourceInfo( result.getSourceInfo() ); - writeSourceInfo( result.getSourceInfo() ); +m_xml.scopedElement( "Original" ) +.writeText( result.getExpression() ); +m_xml.scopedElement( "Expanded" ) +.writeText( result.getExpandedExpression() ); +} - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } +// And... Print a result applicable to each result type. +switch( result.getResultType() ) { +case ResultWas::ThrewException: +m_xml.startElement( "Exception" ); +writeSourceInfo( result.getSourceInfo() ); +m_xml.writeText( result.getMessage() ); +m_xml.endElement(); +break; +case ResultWas::FatalErrorCondition: +m_xml.startElement( "FatalErrorCondition" ); +writeSourceInfo( result.getSourceInfo() ); +m_xml.writeText( result.getMessage() ); +m_xml.endElement(); +break; +case ResultWas::Info: +m_xml.scopedElement( "Info" ) +.writeText( result.getMessage() ); +break; +case ResultWas::Warning: +// Warning will already have been written +break; +case ResultWas::ExplicitFailure: +m_xml.startElement( "Failure" ); +writeSourceInfo( result.getSourceInfo() ); +m_xml.writeText( result.getMessage() ); +m_xml.endElement(); +break; +default: +break; +} - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } +if( result.hasExpression() ) +m_xml.endElement(); - if( result.hasExpression() ) - m_xml.endElement(); +return true; +} - return true; - } +void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { +StreamingReporterBase::sectionEnded( sectionStats ); +if( --m_sectionDepth > 0 ) { +XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); +e.writeAttribute( "successes", sectionStats.assertions.passed ); +e.writeAttribute( "failures", sectionStats.assertions.failed ); +e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - void sectionEnded( SectionStats const& sectionStats ) override { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); +if ( m_config->showDurations() == ShowDurations::Always ) +e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); +m_xml.endElement(); +} +} - m_xml.endElement(); - } - } +void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { +StreamingReporterBase::testCaseEnded( testCaseStats ); +XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); +e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - void testCaseEnded( TestCaseStats const& testCaseStats ) override { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); +if ( m_config->showDurations() == ShowDurations::Always ) +e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); +if( !testCaseStats.stdOut.empty() ) +m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); +if( !testCaseStats.stdErr.empty() ) +m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); +m_xml.endElement(); +} - m_xml.endElement(); - } +void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { +StreamingReporterBase::testGroupEnded( testGroupStats ); +// TODO: Check testGroupStats.aborting and act accordingly. +m_xml.scopedElement( "OverallResults" ) +.writeAttribute( "successes", testGroupStats.totals.assertions.passed ) +.writeAttribute( "failures", testGroupStats.totals.assertions.failed ) +.writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); +m_xml.endElement(); +} - void testGroupEnded( TestGroupStats const& testGroupStats ) override { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } +void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { +StreamingReporterBase::testRunEnded( testRunStats ); +m_xml.scopedElement( "OverallResults" ) +.writeAttribute( "successes", testRunStats.totals.assertions.passed ) +.writeAttribute( "failures", testRunStats.totals.assertions.failed ) +.writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); +m_xml.endElement(); +} - void testRunEnded( TestRunStats const& testRunStats ) override { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth = 0; - }; - - XmlReporter::~XmlReporter() {} - CATCH_REGISTER_REPORTER( "xml", XmlReporter ) +CATCH_REGISTER_REPORTER( "xml", XmlReporter ) } // end namespace Catch @@ -11690,7 +14597,7 @@ namespace Catch { // end catch_reporter_xml.cpp namespace Catch { - LeakDetector leakDetector; +LeakDetector leakDetector; } #ifdef __clang__ @@ -11705,7 +14612,7 @@ namespace Catch { #ifndef __OBJC__ -#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else @@ -11713,7 +14620,7 @@ extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { int main (int argc, char * argv[]) { #endif - return Catch::Session().run( argc, argv ); +return Catch::Session().run( argc, argv ); } #else // __OBJC__ @@ -11721,17 +14628,17 @@ int main (int argc, char * argv[]) { // Objective-C entry point int main (int argc, char * const argv[]) { #if !CATCH_ARC_ENABLED - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; #endif - Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char**)argv ); +Catch::registerTestMethods(); +int result = Catch::Session().run( argc, (char**)argv ); #if !CATCH_ARC_ENABLED - [pool drain]; +[pool drain]; #endif - return result; +return result; } #endif // __OBJC__ @@ -11739,6 +14646,8 @@ int main (int argc, char * const argv[]) { // end catch_default_main.hpp #endif +#if !defined(CATCH_CONFIG_IMPL_ONLY) + #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED # undef CLARA_CONFIG_MAIN #endif @@ -11751,7 +14660,7 @@ int main (int argc, char * const argv[]) { #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) +#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) @@ -11765,7 +14674,7 @@ int main (int argc, char * const argv[]) { #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) -#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) +#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) @@ -11781,27 +14690,49 @@ int main (int argc, char * const argv[]) { #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) +#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#else +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#endif + +#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) +#define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) +#else +#define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) +#endif + // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) -#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) -#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) +#define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) +#define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) +#define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -11838,19 +14769,41 @@ int main (int argc, char * const argv[]) { #endif // CATCH_CONFIG_DISABLE_MATCHERS #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) +#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) +#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) +#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#else +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) +#endif + +#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) +#define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) +#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) +#else +#define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) +#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) +#endif + #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) @@ -11859,15 +14812,17 @@ int main (int argc, char * const argv[]) { #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) -#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) -#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) -#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) -#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) +#define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) +#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) +#define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) +#define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) +#define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) +#define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) using Catch::Detail::Approx; -#else +#else // CATCH_CONFIG_DISABLE + ////// // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ #ifdef CATCH_CONFIG_PREFIX_ALL @@ -11912,21 +14867,38 @@ using Catch::Detail::Approx; #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) +#define CATCH_DYNAMIC_SECTION( ... ) #define CATCH_FAIL( ... ) (void)(0) #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#else +#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) ) +#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#endif + // "BDD-style" convenience wrappers #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) #define CATCH_GIVEN( desc ) +#define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) #define CATCH_AND_WHEN( desc ) #define CATCH_THEN( desc ) #define CATCH_AND_THEN( desc ) +#define CATCH_STATIC_REQUIRE( ... ) (void)(0) +#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) + // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -11970,11 +14942,27 @@ using Catch::Detail::Approx; #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) +#define DYNAMIC_SECTION( ... ) #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#else +#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) ) +#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) ) +#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) +#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) +#endif + +#define STATIC_REQUIRE( ... ) (void)(0) +#define STATIC_REQUIRE_FALSE( ... ) (void)(0) + #endif #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) @@ -11984,6 +14972,7 @@ using Catch::Detail::Approx; #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) #define GIVEN( desc ) +#define AND_GIVEN( desc ) #define WHEN( desc ) #define AND_WHEN( desc ) #define THEN( desc ) @@ -11993,6 +14982,8 @@ using Catch::Detail::Approx; #endif +#endif // ! CATCH_CONFIG_IMPL_ONLY + // start catch_reenable_warnings.h diff --git a/FlippR-Driver/tests/catch_bak.hpp b/FlippR-Driver/tests/catch_bak.hpp deleted file mode 100644 index ecd8907..0000000 --- a/FlippR-Driver/tests/catch_bak.hpp +++ /dev/null @@ -1,13050 +0,0 @@ -/* - * Catch v2.2.2 - * Generated: 2018-04-06 12:05:03.186665 - * ---------------------------------------------------------- - * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. - * - * Distributed under the Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - */ -#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED -// start catch.hpp - - -#define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 2 -#define CATCH_VERSION_PATCH 2 - -#ifdef __clang__ -# pragma clang system_header -#elif defined __GNUC__ -# pragma GCC system_header -#endif - -// start catch_suppress_warnings.h - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(push) -# pragma warning(disable: 161 1682) -# else // __ICC -# pragma clang diagnostic ignored "-Wunused-variable" -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wpadded" -# pragma clang diagnostic ignored "-Wswitch-enum" -# pragma clang diagnostic ignored "-Wcovered-switch-default" -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic ignored "-Wparentheses" -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-variable" -# pragma GCC diagnostic ignored "-Wpadded" -#endif -// end catch_suppress_warnings.h -#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) -# define CATCH_IMPL -# define CATCH_CONFIG_ALL_PARTS -#endif - -// In the impl file, we want to have access to all parts of the headers -// Can also be used to sanely support PCHs -#if defined(CATCH_CONFIG_ALL_PARTS) -# define CATCH_CONFIG_EXTERNAL_INTERFACES -# if defined(CATCH_CONFIG_DISABLE_MATCHERS) -# undef CATCH_CONFIG_DISABLE_MATCHERS -# endif -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) -// start catch_platform.h - -#ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif - -#elif defined(linux) || defined(__linux) || defined(__linux__) -# define CATCH_PLATFORM_LINUX - -#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) -# define CATCH_PLATFORM_WINDOWS -#endif - -// end catch_platform.h - -#ifdef CATCH_IMPL -# ifndef CLARA_CONFIG_MAIN -# define CLARA_CONFIG_MAIN_NOT_DEFINED -# define CLARA_CONFIG_MAIN -# endif -#endif - -// start catch_user_interfaces.h - -namespace Catch { - unsigned int rngSeed(); -} - -// end catch_user_interfaces.h -// start catch_tag_alias_autoregistrar.h - -// start catch_common.h - -// start catch_compiler_capabilities.h - -// Detect a number of compiler features - by compiler -// The following features are defined: -// -// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? -// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? -// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? -// **************** -// Note to maintainers: if new toggles are added please document them -// in configuration.md, too -// **************** - -// In general each macro has a _NO_ form -// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. -// Many features, at point of detection, define an _INTERNAL_ macro, so they -// can be combined, en-mass, with the _NO_ forms later. - -#ifdef __cplusplus - -# if __cplusplus >= 201402L -# define CATCH_CPP14_OR_GREATER -# endif - -# if __cplusplus >= 201703L -# define CATCH_CPP17_OR_GREATER -# endif - -#endif - -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#ifdef __clang__ - -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ - _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic push" ) \ - _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - _Pragma( "clang diagnostic pop" ) - -#endif // __clang__ - -//////////////////////////////////////////////////////////////////////////////// -// Assume that non-Windows platforms support posix signals by default -#if !defined(CATCH_PLATFORM_WINDOWS) - #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS -#endif - -//////////////////////////////////////////////////////////////////////////////// -// We know some environments not to support full POSIX signals -#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) - #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -#endif - -#ifdef __OS400__ -# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS -# define CATCH_CONFIG_COLOUR_NONE -#endif - -//////////////////////////////////////////////////////////////////////////////// -// Cygwin -#ifdef __CYGWIN__ - -// Required for some versions of Cygwin to declare gettimeofday -// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin -# define _BSD_SOURCE - -#endif // __CYGWIN__ - -//////////////////////////////////////////////////////////////////////////////// -// Visual C++ -#ifdef _MSC_VER - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif - -// Universal Windows platform does not support SEH -// Or console colours (or console at all...) -# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) -# define CATCH_CONFIG_COLOUR_NONE -# else -# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH -# endif - -#endif // _MSC_VER - -//////////////////////////////////////////////////////////////////////////////// - -// DJGPP -#ifdef __DJGPP__ -# define CATCH_INTERNAL_CONFIG_NO_WCHAR -#endif // __DJGPP__ - -//////////////////////////////////////////////////////////////////////////////// - -// Use of __COUNTER__ is suppressed during code analysis in -// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly -// handled by it. -// Otherwise all supported compilers support COUNTER macro, -// but user still might want to turn it off -#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) - #define CATCH_INTERNAL_CONFIG_COUNTER -#endif - -#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) -# define CATCH_CONFIG_COUNTER -#endif -#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) -# define CATCH_CONFIG_WINDOWS_SEH -#endif -// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. -#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) -# define CATCH_CONFIG_POSIX_SIGNALS -#endif -// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. -#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) -# define CATCH_CONFIG_WCHAR -#endif - -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS -#endif -#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) -# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -# define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS -#endif - -// end catch_compiler_capabilities.h -#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line -#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) -#ifdef CATCH_CONFIG_COUNTER -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) -#else -# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) -#endif - -#include -#include -#include - -namespace Catch { - - struct CaseSensitive { enum Choice { - Yes, - No - }; }; - - class NonCopyable { - NonCopyable( NonCopyable const& ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable& operator = ( NonCopyable const& ) = delete; - NonCopyable& operator = ( NonCopyable && ) = delete; - - protected: - NonCopyable(); - virtual ~NonCopyable(); - }; - - struct SourceLineInfo { - - SourceLineInfo() = delete; - SourceLineInfo( char const* _file, std::size_t _line ) noexcept - : file( _file ), - line( _line ) - {} - - SourceLineInfo( SourceLineInfo const& other ) = default; - SourceLineInfo( SourceLineInfo && ) = default; - SourceLineInfo& operator = ( SourceLineInfo const& ) = default; - SourceLineInfo& operator = ( SourceLineInfo && ) = default; - - bool empty() const noexcept; - bool operator == ( SourceLineInfo const& other ) const noexcept; - bool operator < ( SourceLineInfo const& other ) const noexcept; - - char const* file; - std::size_t line; - }; - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); - - // Use this in variadic streaming macros to allow - // >> +StreamEndStop - // as well as - // >> stuff +StreamEndStop - struct StreamEndStop { - std::string operator+() const; - }; - template - T const& operator + ( T const& value, StreamEndStop ) { - return value; - } -} - -#define CATCH_INTERNAL_LINEINFO \ - ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) - -// end catch_common.h -namespace Catch { - - struct RegistrarForTagAliases { - RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); - }; - -} // end namespace Catch - -#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -// end catch_tag_alias_autoregistrar.h -// start catch_test_registry.h - -// start catch_interfaces_testcase.h - -#include -#include - -namespace Catch { - - class TestSpec; - - struct ITestInvoker { - virtual void invoke () const = 0; - virtual ~ITestInvoker(); - }; - - using ITestCasePtr = std::shared_ptr; - - class TestCase; - struct IConfig; - - struct ITestCaseRegistry { - virtual ~ITestCaseRegistry(); - virtual std::vector const& getAllTests() const = 0; - virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; - }; - - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - -} - -// end catch_interfaces_testcase.h -// start catch_stringref.h - -#include -#include -#include - -namespace Catch { - - class StringData; - - /// A non-owning string class (similar to the forthcoming std::string_view) - /// Note that, because a StringRef may be a substring of another string, - /// it may not be null terminated. c_str() must return a null terminated - /// string, however, and so the StringRef will internally take ownership - /// (taking a copy), if necessary. In theory this ownership is not externally - /// visible - but it does mean (substring) StringRefs should not be shared between - /// threads. - class StringRef { - public: - using size_type = std::size_t; - - private: - friend struct StringRefTestAccess; - - char const* m_start; - size_type m_size; - - char* m_data = nullptr; - - void takeOwnership(); - - static constexpr char const* const s_empty = ""; - - public: // construction/ assignment - StringRef() noexcept - : StringRef( s_empty, 0 ) - {} - - StringRef( StringRef const& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ) - {} - - StringRef( StringRef&& other ) noexcept - : m_start( other.m_start ), - m_size( other.m_size ), - m_data( other.m_data ) - { - other.m_data = nullptr; - } - - StringRef( char const* rawChars ) noexcept; - - StringRef( char const* rawChars, size_type size ) noexcept - : m_start( rawChars ), - m_size( size ) - {} - - StringRef( std::string const& stdString ) noexcept - : m_start( stdString.c_str() ), - m_size( stdString.size() ) - {} - - ~StringRef() noexcept { - delete[] m_data; - } - - auto operator = ( StringRef const &other ) noexcept -> StringRef& { - delete[] m_data; - m_data = nullptr; - m_start = other.m_start; - m_size = other.m_size; - return *this; - } - - operator std::string() const; - - void swap( StringRef& other ) noexcept; - - public: // operators - auto operator == ( StringRef const& other ) const noexcept -> bool; - auto operator != ( StringRef const& other ) const noexcept -> bool; - - auto operator[] ( size_type index ) const noexcept -> char; - - public: // named queries - auto empty() const noexcept -> bool { - return m_size == 0; - } - auto size() const noexcept -> size_type { - return m_size; - } - - auto numberOfCharacters() const noexcept -> size_type; - auto c_str() const -> char const*; - - public: // substrings and searches - auto substr( size_type start, size_type size ) const noexcept -> StringRef; - - // Returns the current start pointer. - // Note that the pointer can change when if the StringRef is a substring - auto currentData() const noexcept -> char const*; - - private: // ownership queries - may not be consistent between calls - auto isOwned() const noexcept -> bool; - auto isSubstring() const noexcept -> bool; - }; - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; - auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; - - auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; - auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; - - inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { - return StringRef( rawChars, size ); - } - -} // namespace Catch - -// end catch_stringref.h -namespace Catch { - -template -class TestInvokerAsMethod : public ITestInvoker { - void (C::*m_testAsMethod)(); -public: - TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} - - void invoke() const override { - C obj; - (obj.*m_testAsMethod)(); - } -}; - -auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; - -template -auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsMethod( testAsMethod ); -} - -struct NameAndTags { - NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; - StringRef name; - StringRef tags; -}; - -struct AutoReg : NonCopyable { - AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; - ~AutoReg(); -}; - -} // end namespace Catch - -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ - namespace{ \ - struct TestName : ClassName { \ - void test(); \ - }; \ - } \ - void TestName::test() - -#endif - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ - static void TestName(); \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - static void TestName() - #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ \ - struct TestName : ClassName{ \ - void test(); \ - }; \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - void TestName::test() - #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) - - /////////////////////////////////////////////////////////////////////////////// - #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -// end catch_test_registry.h -// start catch_capture.hpp - -// start catch_assertionhandler.h - -// start catch_assertioninfo.h - -// start catch_result_type.h - -namespace Catch { - - // ResultWas::OfType enum - struct ResultWas { enum OfType { - Unknown = -1, - Ok = 0, - Info = 1, - Warning = 2, - - FailureBit = 0x10, - - ExpressionFailed = FailureBit | 1, - ExplicitFailure = FailureBit | 2, - - Exception = 0x100 | FailureBit, - - ThrewException = Exception | 1, - DidntThrowException = Exception | 2, - - FatalErrorCondition = 0x200 | FailureBit - - }; }; - - bool isOk( ResultWas::OfType resultType ); - bool isJustInfo( int flags ); - - // ResultDisposition::Flags enum - struct ResultDisposition { enum Flags { - Normal = 0x01, - - ContinueOnFailure = 0x02, // Failures fail test, but execution continues - FalseTest = 0x04, // Prefix expression with ! - SuppressFail = 0x08 // Failures are reported but do not fail the test - }; }; - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); - - bool shouldContinueOnFailure( int flags ); - inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } - bool shouldSuppressFailure( int flags ); - -} // end namespace Catch - -// end catch_result_type.h -namespace Catch { - - struct AssertionInfo - { - StringRef macroName; - SourceLineInfo lineInfo; - StringRef capturedExpression; - ResultDisposition::Flags resultDisposition; - - // We want to delete this constructor but a compiler bug in 4.8 means - // the struct is then treated as non-aggregate - //AssertionInfo() = delete; - }; - -} // end namespace Catch - -// end catch_assertioninfo.h -// start catch_decomposer.h - -// start catch_tostring.h - -#include -#include -#include -#include -// start catch_stream.h - -#include -#include -#include - -namespace Catch { - - std::ostream& cout(); - std::ostream& cerr(); - std::ostream& clog(); - - class StringRef; - - struct IStream { - virtual ~IStream(); - virtual std::ostream& stream() const = 0; - }; - - auto makeStream( StringRef const &filename ) -> IStream const*; - - class ReusableStringStream { - std::size_t m_index; - std::ostream* m_oss; - public: - ReusableStringStream(); - ~ReusableStringStream(); - - auto str() const -> std::string; - - template - auto operator << ( T const& value ) -> ReusableStringStream& { - *m_oss << value; - return *this; - } - auto get() -> std::ostream& { return *m_oss; } - - static void cleanup(); - }; -} - -// end catch_stream.h - -#ifdef __OBJC__ -// start catch_objc_arc.hpp - -#import - -#ifdef __has_feature -#define CATCH_ARC_ENABLED __has_feature(objc_arc) -#else -#define CATCH_ARC_ENABLED 0 -#endif - -void arcSafeRelease( NSObject* obj ); -id performOptionalSelector( id obj, SEL sel ); - -#if !CATCH_ARC_ENABLED -inline void arcSafeRelease( NSObject* obj ) { - [obj release]; -} -inline id performOptionalSelector( id obj, SEL sel ) { - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; - return nil; -} -#define CATCH_UNSAFE_UNRETAINED -#define CATCH_ARC_STRONG -#else -inline void arcSafeRelease( NSObject* ){} -inline id performOptionalSelector( id obj, SEL sel ) { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" -#endif - if( [obj respondsToSelector: sel] ) - return [obj performSelector: sel]; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - return nil; -} -#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained -#define CATCH_ARC_STRONG __strong -#endif - -// end catch_objc_arc.hpp -#endif - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless -#endif - -// We need a dummy global operator<< so we can bring it into Catch namespace later -struct Catch_global_namespace_dummy {}; -std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); - -namespace Catch { - // Bring in operator<< from global namespace into Catch namespace - using ::operator<<; - - namespace Detail { - - extern const std::string unprintableString; - - std::string rawMemoryToString( const void *object, std::size_t size ); - - template - std::string rawMemoryToString( const T& object ) { - return rawMemoryToString( &object, sizeof(object) ); - } - - template - class IsStreamInsertable { - template - static auto test(int) - -> decltype(std::declval() << std::declval(), std::true_type()); - - template - static auto test(...)->std::false_type; - - public: - static const bool value = decltype(test(0))::value; - }; - - template - std::string convertUnknownEnumToString( E e ); - - template - typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) { -#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) - (void)value; - return Detail::unprintableString; -#else - return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); -#endif - } - template - typename std::enable_if::value, std::string>::type convertUnstreamable( T const& value ) { - return convertUnknownEnumToString( value ); - } - -#if defined(_MANAGED) - //! Convert a CLR string to a utf8 std::string - template - std::string clrReferenceToString( T^ ref ) { - if (ref == nullptr) - return std::string("null"); - auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); - cli::pin_ptr p = &bytes[0]; - return std::string(reinterpret_cast(p), bytes->Length); - } -#endif - - } // namespace Detail - - // If we decide for C++14, change these to enable_if_ts - template - struct StringMaker { - template - static - typename std::enable_if<::Catch::Detail::IsStreamInsertable::value, std::string>::type - convert(const Fake& value) { - ReusableStringStream rss; - rss << value; - return rss.str(); - } - - template - static - typename std::enable_if::value, std::string>::type - convert( const Fake& value ) { - return Detail::convertUnstreamable( value ); - } - }; - - namespace Detail { - - // This function dispatches all stringification requests inside of Catch. - // Should be preferably called fully qualified, like ::Catch::Detail::stringify - template - std::string stringify(const T& e) { - return ::Catch::StringMaker::type>::type>::convert(e); - } - - template - std::string convertUnknownEnumToString( E e ) { - return ::Catch::Detail::stringify(static_cast::type>(e)); - } - -#if defined(_MANAGED) - template - std::string stringify( T^ e ) { - return ::Catch::StringMaker::convert(e); - } -#endif - - } // namespace Detail - - // Some predefined specializations - - template<> - struct StringMaker { - static std::string convert(const std::string& str); - }; -#ifdef CATCH_CONFIG_WCHAR - template<> - struct StringMaker { - static std::string convert(const std::wstring& wstr); - }; -#endif - - template<> - struct StringMaker { - static std::string convert(char const * str); - }; - template<> - struct StringMaker { - static std::string convert(char * str); - }; - -#ifdef CATCH_CONFIG_WCHAR - template<> - struct StringMaker { - static std::string convert(wchar_t const * str); - }; - template<> - struct StringMaker { - static std::string convert(wchar_t * str); - }; -#endif - - // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, - // while keeping string semantics? - template - struct StringMaker { - static std::string convert(char const* str) { - return ::Catch::Detail::stringify(std::string{ str }); - } - }; - template - struct StringMaker { - static std::string convert(signed char const* str) { - return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); - } - }; - template - struct StringMaker { - static std::string convert(unsigned char const* str) { - return ::Catch::Detail::stringify(std::string{ reinterpret_cast(str) }); - } - }; - - template<> - struct StringMaker { - static std::string convert(int value); - }; - template<> - struct StringMaker { - static std::string convert(long value); - }; - template<> - struct StringMaker { - static std::string convert(long long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned int value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long value); - }; - template<> - struct StringMaker { - static std::string convert(unsigned long long value); - }; - - template<> - struct StringMaker { - static std::string convert(bool b); - }; - - template<> - struct StringMaker { - static std::string convert(char c); - }; - template<> - struct StringMaker { - static std::string convert(signed char c); - }; - template<> - struct StringMaker { - static std::string convert(unsigned char c); - }; - - template<> - struct StringMaker { - static std::string convert(std::nullptr_t); - }; - - template<> - struct StringMaker { - static std::string convert(float value); - }; - template<> - struct StringMaker { - static std::string convert(double value); - }; - - template - struct StringMaker { - template - static std::string convert(U* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - - template - struct StringMaker { - static std::string convert(R C::* p) { - if (p) { - return ::Catch::Detail::rawMemoryToString(p); - } else { - return "nullptr"; - } - } - }; - -#if defined(_MANAGED) - template - struct StringMaker { - static std::string convert( T^ ref ) { - return ::Catch::Detail::clrReferenceToString(ref); - } - }; -#endif - - namespace Detail { - template - std::string rangeToString(InputIterator first, InputIterator last) { - ReusableStringStream rss; - rss << "{ "; - if (first != last) { - rss << ::Catch::Detail::stringify(*first); - for (++first; first != last; ++first) - rss << ", " << ::Catch::Detail::stringify(*first); - } - rss << " }"; - return rss.str(); - } - } - -#ifdef __OBJC__ - template<> - struct StringMaker { - static std::string convert(NSString * nsstring) { - if (!nsstring) - return "nil"; - return std::string("@") + [nsstring UTF8String]; - } - }; - template<> - struct StringMaker { - static std::string convert(NSObject* nsObject) { - return ::Catch::Detail::stringify([nsObject description]); - } - - }; - namespace Detail { - inline std::string stringify( NSString* nsstring ) { - return StringMaker::convert( nsstring ); - } - - } // namespace Detail -#endif // __OBJC__ - -} // namespace Catch - -////////////////////////////////////////////////////// -// Separate std-lib types stringification, so it can be selectively enabled -// This means that we do not bring in - -#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) -# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER -# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER -# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -#endif - -// Separate std::pair specialization -#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) -#include -namespace Catch { - template - struct StringMaker > { - static std::string convert(const std::pair& pair) { - ReusableStringStream rss; - rss << "{ " - << ::Catch::Detail::stringify(pair.first) - << ", " - << ::Catch::Detail::stringify(pair.second) - << " }"; - return rss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER - -// Separate std::tuple specialization -#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) -#include -namespace Catch { - namespace Detail { - template< - typename Tuple, - std::size_t N = 0, - bool = (N < std::tuple_size::value) - > - struct TupleElementPrinter { - static void print(const Tuple& tuple, std::ostream& os) { - os << (N ? ", " : " ") - << ::Catch::Detail::stringify(std::get(tuple)); - TupleElementPrinter::print(tuple, os); - } - }; - - template< - typename Tuple, - std::size_t N - > - struct TupleElementPrinter { - static void print(const Tuple&, std::ostream&) {} - }; - - } - - template - struct StringMaker> { - static std::string convert(const std::tuple& tuple) { - ReusableStringStream rss; - rss << '{'; - Detail::TupleElementPrinter>::print(tuple, rss.get()); - rss << " }"; - return rss.str(); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER - -namespace Catch { - struct not_this_one {}; // Tag type for detecting which begin/ end are being selected - - // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace - using std::begin; - using std::end; - - not_this_one begin( ... ); - not_this_one end( ... ); - - template - struct is_range { - static const bool value = - !std::is_same())), not_this_one>::value && - !std::is_same())), not_this_one>::value; - }; - -#if defined(_MANAGED) // Managed types are never ranges - template - struct is_range { - static const bool value = false; - }; -#endif - - template - std::string rangeToString( Range const& range ) { - return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); - } - - // Handle vector specially - template - std::string rangeToString( std::vector const& v ) { - ReusableStringStream rss; - rss << "{ "; - bool first = true; - for( bool b : v ) { - if( first ) - first = false; - else - rss << ", "; - rss << ::Catch::Detail::stringify( b ); - } - rss << " }"; - return rss.str(); - } - - template - struct StringMaker::value && !::Catch::Detail::IsStreamInsertable::value>::type> { - static std::string convert( R const& range ) { - return rangeToString( range ); - } - }; - - template - struct StringMaker { - static std::string convert(T const(&arr)[SZ]) { - return rangeToString(arr); - } - }; - -} // namespace Catch - -// Separate std::chrono::duration specialization -#if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -#include -#include -#include - -namespace Catch { - -template -struct ratio_string { - static std::string symbol(); -}; - -template -std::string ratio_string::symbol() { - Catch::ReusableStringStream rss; - rss << '[' << Ratio::num << '/' - << Ratio::den << ']'; - return rss.str(); -} -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; -template <> -struct ratio_string { - static std::string symbol(); -}; - - //////////// - // std::chrono::duration specializations - template - struct StringMaker> { - static std::string convert(std::chrono::duration const& duration) { - ReusableStringStream rss; - rss << duration.count() << ' ' << ratio_string::symbol() << 's'; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " s"; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " m"; - return rss.str(); - } - }; - template - struct StringMaker>> { - static std::string convert(std::chrono::duration> const& duration) { - ReusableStringStream rss; - rss << duration.count() << " h"; - return rss.str(); - } - }; - - //////////// - // std::chrono::time_point specialization - // Generic time_point cannot be specialized, only std::chrono::time_point - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; - } - }; - // std::chrono::time_point specialization - template - struct StringMaker> { - static std::string convert(std::chrono::time_point const& time_point) { - auto converted = std::chrono::system_clock::to_time_t(time_point); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &converted); -#else - std::tm* timeInfo = std::gmtime(&converted); -#endif - - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - }; -} -#endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// end catch_tostring.h -#include - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4389) // '==' : signed/unsigned mismatch -#pragma warning(disable:4018) // more "signed/unsigned mismatch" -#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) -#pragma warning(disable:4180) // qualifier applied to function type has no meaning -#endif - -namespace Catch { - - struct ITransientExpression { - auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } - auto getResult() const -> bool { return m_result; } - virtual void streamReconstructedExpression( std::ostream &os ) const = 0; - - ITransientExpression( bool isBinaryExpression, bool result ) - : m_isBinaryExpression( isBinaryExpression ), - m_result( result ) - {} - - // We don't actually need a virtual destructor, but many static analysers - // complain if it's not here :-( - virtual ~ITransientExpression(); - - bool m_isBinaryExpression; - bool m_result; - - }; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); - - template - class BinaryExpr : public ITransientExpression { - LhsT m_lhs; - StringRef m_op; - RhsT m_rhs; - - void streamReconstructedExpression( std::ostream &os ) const override { - formatReconstructedExpression - ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); - } - - public: - BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) - : ITransientExpression{ true, comparisonResult }, - m_lhs( lhs ), - m_op( op ), - m_rhs( rhs ) - {} - }; - - template - class UnaryExpr : public ITransientExpression { - LhsT m_lhs; - - void streamReconstructedExpression( std::ostream &os ) const override { - os << Catch::Detail::stringify( m_lhs ); - } - - public: - explicit UnaryExpr( LhsT lhs ) - : ITransientExpression{ false, lhs ? true : false }, - m_lhs( lhs ) - {} - }; - - // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) - template - auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast(lhs == rhs); } - template - auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast( rhs ); } - template - auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - template - auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) == rhs; } - - template - auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast(lhs != rhs); } - template - auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast( rhs ); } - template - auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - template - auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast( lhs ) != rhs; } - - template - class ExprLhs { - LhsT m_lhs; - public: - explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} - - template - auto operator == ( RhsT const& rhs ) -> BinaryExpr const { - return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; - } - auto operator == ( bool rhs ) -> BinaryExpr const { - return { m_lhs == rhs, m_lhs, "==", rhs }; - } - - template - auto operator != ( RhsT const& rhs ) -> BinaryExpr const { - return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; - } - auto operator != ( bool rhs ) -> BinaryExpr const { - return { m_lhs != rhs, m_lhs, "!=", rhs }; - } - - template - auto operator > ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs > rhs), m_lhs, ">", rhs }; - } - template - auto operator < ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs < rhs), m_lhs, "<", rhs }; - } - template - auto operator >= ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs >= rhs), m_lhs, ">=", rhs }; - } - template - auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { - return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; - } - - auto makeUnaryExpr() const -> UnaryExpr { - return UnaryExpr{ m_lhs }; - } - }; - - void handleExpression( ITransientExpression const& expr ); - - template - void handleExpression( ExprLhs const& expr ) { - handleExpression( expr.makeUnaryExpr() ); - } - - struct Decomposer { - template - auto operator <= ( T const& lhs ) -> ExprLhs { - return ExprLhs{ lhs }; - } - - auto operator <=( bool value ) -> ExprLhs { - return ExprLhs{ value }; - } - }; - -} // end namespace Catch - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -// end catch_decomposer.h -// start catch_interfaces_capture.h - -#include - -namespace Catch { - - class AssertionResult; - struct AssertionInfo; - struct SectionInfo; - struct SectionEndInfo; - struct MessageInfo; - struct Counts; - struct BenchmarkInfo; - struct BenchmarkStats; - struct AssertionReaction; - - struct ITransientExpression; - - struct IResultCapture { - - virtual ~IResultCapture(); - - virtual bool sectionStarted( SectionInfo const& sectionInfo, - Counts& assertions ) = 0; - virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; - virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - - virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; - virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; - - virtual void pushScopedMessage( MessageInfo const& message ) = 0; - virtual void popScopedMessage( MessageInfo const& message ) = 0; - - virtual void handleFatalErrorCondition( StringRef message ) = 0; - - virtual void handleExpr - ( AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction ) = 0; - virtual void handleMessage - ( AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef const& message, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedExceptionNotThrown - ( AssertionInfo const& info, - AssertionReaction& reaction ) = 0; - virtual void handleUnexpectedInflightException - ( AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction ) = 0; - virtual void handleIncomplete - ( AssertionInfo const& info ) = 0; - virtual void handleNonExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction ) = 0; - - virtual bool lastAssertionPassed() = 0; - virtual void assertionPassed() = 0; - - // Deprecated, do not use: - virtual std::string getCurrentTestName() const = 0; - virtual const AssertionResult* getLastResult() const = 0; - virtual void exceptionEarlyReported() = 0; - }; - - IResultCapture& getResultCapture(); -} - -// end catch_interfaces_capture.h -namespace Catch { - - struct TestFailureException{}; - struct AssertionResultData; - struct IResultCapture; - class RunContext; - - class LazyExpression { - friend class AssertionHandler; - friend struct AssertionStats; - friend class RunContext; - - ITransientExpression const* m_transientExpression = nullptr; - bool m_isNegated; - public: - LazyExpression( bool isNegated ); - LazyExpression( LazyExpression const& other ); - LazyExpression& operator = ( LazyExpression const& ) = delete; - - explicit operator bool() const; - - friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; - }; - - struct AssertionReaction { - bool shouldDebugBreak = false; - bool shouldThrow = false; - }; - - class AssertionHandler { - AssertionInfo m_assertionInfo; - AssertionReaction m_reaction; - bool m_completed = false; - IResultCapture& m_resultCapture; - - public: - AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ); - ~AssertionHandler() { - if ( !m_completed ) { - m_resultCapture.handleIncomplete( m_assertionInfo ); - } - } - - template - void handleExpr( ExprLhs const& expr ) { - handleExpr( expr.makeUnaryExpr() ); - } - void handleExpr( ITransientExpression const& expr ); - - void handleMessage(ResultWas::OfType resultType, StringRef const& message); - - void handleExceptionThrownAsExpected(); - void handleUnexpectedExceptionNotThrown(); - void handleExceptionNotThrownAsExpected(); - void handleThrowingCallSkipped(); - void handleUnexpectedInflightException(); - - void complete(); - void setCompleted(); - - // query - auto allowThrows() const -> bool; - }; - - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ); - -} // namespace Catch - -// end catch_assertionhandler.h -// start catch_message.h - -#include - -namespace Catch { - - struct MessageInfo { - MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ); - - std::string macroName; - std::string message; - SourceLineInfo lineInfo; - ResultWas::OfType type; - unsigned int sequence; - - bool operator == ( MessageInfo const& other ) const; - bool operator < ( MessageInfo const& other ) const; - private: - static unsigned int globalCount; - }; - - struct MessageStream { - - template - MessageStream& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - ReusableStringStream m_stream; - }; - - struct MessageBuilder : MessageStream { - MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ); - - template - MessageBuilder& operator << ( T const& value ) { - m_stream << value; - return *this; - } - - MessageInfo m_info; - }; - - class ScopedMessage { - public: - explicit ScopedMessage( MessageBuilder const& builder ); - ~ScopedMessage(); - - MessageInfo m_info; - }; - -} // end namespace Catch - -// end catch_message.h -#if !defined(CATCH_CONFIG_DISABLE) - -#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) - #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ -#else - #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" -#endif - -#if defined(CATCH_CONFIG_FAST_COMPILE) - -/////////////////////////////////////////////////////////////////////////////// -// Another way to speed-up compilation is to omit local try-catch for REQUIRE* -// macros. -#define INTERNAL_CATCH_TRY -#define INTERNAL_CATCH_CATCH( capturer ) - -#else // CATCH_CONFIG_FAST_COMPILE - -#define INTERNAL_CATCH_TRY try -#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } - -#endif - -#define INTERNAL_CATCH_REACT( handler ) handler.complete(); - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - INTERNAL_CATCH_TRY { \ - CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ - CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( (void)0, false && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( Catch::getResultCapture().lastAssertionPassed() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ - INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ - if( !Catch::getResultCapture().lastAssertionPassed() ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleExceptionThrownAsExpected(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(expr); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( exceptionType const& ) { \ - catchAssertionHandler.handleExceptionThrownAsExpected(); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ - catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_INFO( macroName, log ) \ - Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); - -/////////////////////////////////////////////////////////////////////////////// -// Although this is matcher-based, it can be used with just a string -#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( ... ) { \ - Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -#endif // CATCH_CONFIG_DISABLE - -// end catch_capture.hpp -// start catch_section.h - -// start catch_section_info.h - -// start catch_totals.h - -#include - -namespace Catch { - - struct Counts { - Counts operator - ( Counts const& other ) const; - Counts& operator += ( Counts const& other ); - - std::size_t total() const; - bool allPassed() const; - bool allOk() const; - - std::size_t passed = 0; - std::size_t failed = 0; - std::size_t failedButOk = 0; - }; - - struct Totals { - - Totals operator - ( Totals const& other ) const; - Totals& operator += ( Totals const& other ); - - Totals delta( Totals const& prevTotals ) const; - - int error = 0; - Counts assertions; - Counts testCases; - }; -} - -// end catch_totals.h -#include - -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); - - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; - - struct SectionEndInfo { - SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ); - - SectionInfo sectionInfo; - Counts prevAssertions; - double durationInSeconds; - }; - -} // end namespace Catch - -// end catch_section_info.h -// start catch_timer.h - -#include - -namespace Catch { - - auto getCurrentNanosecondsSinceEpoch() -> uint64_t; - auto getEstimatedClockResolution() -> uint64_t; - - class Timer { - uint64_t m_nanoseconds = 0; - public: - void start(); - auto getElapsedNanoseconds() const -> uint64_t; - auto getElapsedMicroseconds() const -> uint64_t; - auto getElapsedMilliseconds() const -> unsigned int; - auto getElapsedSeconds() const -> double; - }; - -} // namespace Catch - -// end catch_timer.h -#include - -namespace Catch { - - class Section : NonCopyable { - public: - Section( SectionInfo const& info ); - ~Section(); - - // This indicates whether the section should be executed or not - explicit operator bool() const; - - private: - SectionInfo m_info; - - std::string m_name; - Counts m_assertions; - bool m_sectionIncluded; - Timer m_timer; - }; - -} // end namespace Catch - - #define INTERNAL_CATCH_SECTION( ... ) \ - if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) - -// end catch_section.h -// start catch_benchmark.h - -#include -#include - -namespace Catch { - - class BenchmarkLooper { - - std::string m_name; - std::size_t m_count = 0; - std::size_t m_iterationsToRun = 1; - uint64_t m_resolution; - Timer m_timer; - - static auto getResolution() -> uint64_t; - public: - // Keep most of this inline as it's on the code path that is being timed - BenchmarkLooper( StringRef name ) - : m_name( name ), - m_resolution( getResolution() ) - { - reportStart(); - m_timer.start(); - } - - explicit operator bool() { - if( m_count < m_iterationsToRun ) - return true; - return needsMoreIterations(); - } - - void increment() { - ++m_count; - } - - void reportStart(); - auto needsMoreIterations() -> bool; - }; - -} // end namespace Catch - -#define BENCHMARK( name ) \ - for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) - -// end catch_benchmark.h -// start catch_interfaces_exception.h - -// start catch_interfaces_registry_hub.h - -#include -#include - -namespace Catch { - - class TestCase; - struct ITestCaseRegistry; - struct IExceptionTranslatorRegistry; - struct IExceptionTranslator; - struct IReporterRegistry; - struct IReporterFactory; - struct ITagAliasRegistry; - class StartupExceptionRegistry; - - using IReporterFactoryPtr = std::shared_ptr; - - struct IRegistryHub { - virtual ~IRegistryHub(); - - virtual IReporterRegistry const& getReporterRegistry() const = 0; - virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; - virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; - - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; - - virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; - }; - - struct IMutableRegistryHub { - virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; - virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; - virtual void registerTest( TestCase const& testInfo ) = 0; - virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; - virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; - virtual void registerStartupException() noexcept = 0; - }; - - IRegistryHub& getRegistryHub(); - IMutableRegistryHub& getMutableRegistryHub(); - void cleanUp(); - std::string translateActiveException(); - -} - -// end catch_interfaces_registry_hub.h -#if defined(CATCH_CONFIG_DISABLE) - #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ - static std::string translatorName( signature ) -#endif - -#include -#include -#include - -namespace Catch { - using exceptionTranslateFunction = std::string(*)(); - - struct IExceptionTranslator; - using ExceptionTranslators = std::vector>; - - struct IExceptionTranslator { - virtual ~IExceptionTranslator(); - virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; - }; - - struct IExceptionTranslatorRegistry { - virtual ~IExceptionTranslatorRegistry(); - - virtual std::string translateActiveException() const = 0; - }; - - class ExceptionTranslatorRegistrar { - template - class ExceptionTranslator : public IExceptionTranslator { - public: - - ExceptionTranslator( std::string(*translateFunction)( T& ) ) - : m_translateFunction( translateFunction ) - {} - - std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { - try { - if( it == itEnd ) - std::rethrow_exception(std::current_exception()); - else - return (*it)->translate( it+1, itEnd ); - } - catch( T& ex ) { - return m_translateFunction( ex ); - } - } - - protected: - std::string(*m_translateFunction)( T& ); - }; - - public: - template - ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { - getMutableRegistryHub().registerTranslator - ( new ExceptionTranslator( translateFunction ) ); - } - }; -} - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ - static std::string translatorName( signature ); \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ - static std::string translatorName( signature ) - -#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) - -// end catch_interfaces_exception.h -// start catch_approx.h - -#include -#include - -namespace Catch { -namespace Detail { - - class Approx { - private: - bool equalityComparisonImpl(double other) const; - - public: - explicit Approx ( double value ); - - static Approx custom(); - - template ::value>::type> - Approx operator()( T const& value ) { - Approx approx( static_cast(value) ); - approx.epsilon( m_epsilon ); - approx.margin( m_margin ); - approx.scale( m_scale ); - return approx; - } - - template ::value>::type> - explicit Approx( T const& value ): Approx(static_cast(value)) - {} - - template ::value>::type> - friend bool operator == ( const T& lhs, Approx const& rhs ) { - auto lhs_v = static_cast(lhs); - return rhs.equalityComparisonImpl(lhs_v); - } - - template ::value>::type> - friend bool operator == ( Approx const& lhs, const T& rhs ) { - return operator==( rhs, lhs ); - } - - template ::value>::type> - friend bool operator != ( T const& lhs, Approx const& rhs ) { - return !operator==( lhs, rhs ); - } - - template ::value>::type> - friend bool operator != ( Approx const& lhs, T const& rhs ) { - return !operator==( rhs, lhs ); - } - - template ::value>::type> - friend bool operator <= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) < rhs.m_value || lhs == rhs; - } - - template ::value>::type> - friend bool operator <= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value < static_cast(rhs) || lhs == rhs; - } - - template ::value>::type> - friend bool operator >= ( T const& lhs, Approx const& rhs ) { - return static_cast(lhs) > rhs.m_value || lhs == rhs; - } - - template ::value>::type> - friend bool operator >= ( Approx const& lhs, T const& rhs ) { - return lhs.m_value > static_cast(rhs) || lhs == rhs; - } - - template ::value>::type> - Approx& epsilon( T const& newEpsilon ) { - double epsilonAsDouble = static_cast(newEpsilon); - if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) { - throw std::domain_error - ( "Invalid Approx::epsilon: " + - Catch::Detail::stringify( epsilonAsDouble ) + - ", Approx::epsilon has to be between 0 and 1" ); - } - m_epsilon = epsilonAsDouble; - return *this; - } - - template ::value>::type> - Approx& margin( T const& newMargin ) { - double marginAsDouble = static_cast(newMargin); - if( marginAsDouble < 0 ) { - throw std::domain_error - ( "Invalid Approx::margin: " + - Catch::Detail::stringify( marginAsDouble ) + - ", Approx::Margin has to be non-negative." ); - - } - m_margin = marginAsDouble; - return *this; - } - - template ::value>::type> - Approx& scale( T const& newScale ) { - m_scale = static_cast(newScale); - return *this; - } - - std::string toString() const; - - private: - double m_epsilon; - double m_margin; - double m_scale; - double m_value; - }; -} - -template<> -struct StringMaker { - static std::string convert(Catch::Detail::Approx const& value); -}; - -} // end namespace Catch - -// end catch_approx.h -// start catch_string_manip.h - -#include -#include - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ); - bool startsWith( std::string const& s, char prefix ); - bool endsWith( std::string const& s, std::string const& suffix ); - bool endsWith( std::string const& s, char suffix ); - bool contains( std::string const& s, std::string const& infix ); - void toLowerInPlace( std::string& s ); - std::string toLower( std::string const& s ); - std::string trim( std::string const& str ); - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); - - struct pluralise { - pluralise( std::size_t count, std::string const& label ); - - friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); - - std::size_t m_count; - std::string m_label; - }; -} - -// end catch_string_manip.h -#ifndef CATCH_CONFIG_DISABLE_MATCHERS -// start catch_capture_matchers.h - -// start catch_matchers.h - -#include -#include - -namespace Catch { -namespace Matchers { - namespace Impl { - - template struct MatchAllOf; - template struct MatchAnyOf; - template struct MatchNotOf; - - class MatcherUntypedBase { - public: - MatcherUntypedBase() = default; - MatcherUntypedBase ( MatcherUntypedBase const& ) = default; - MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; - std::string toString() const; - - protected: - virtual ~MatcherUntypedBase(); - virtual std::string describe() const = 0; - mutable std::string m_cachedToString; - }; - - template - struct MatcherMethod { - virtual bool match( ObjectT const& arg ) const = 0; - }; - template - struct MatcherMethod { - virtual bool match( PtrT* arg ) const = 0; - }; - - template - struct MatcherBase : MatcherUntypedBase, MatcherMethod { - - MatchAllOf operator && ( MatcherBase const& other ) const; - MatchAnyOf operator || ( MatcherBase const& other ) const; - MatchNotOf operator ! () const; - }; - - template - struct MatchAllOf : MatcherBase { - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (!matcher->match(arg)) - return false; - } - return true; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " and "; - description += matcher->toString(); - } - description += " )"; - return description; - } - - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - template - struct MatchAnyOf : MatcherBase { - - bool match( ArgT const& arg ) const override { - for( auto matcher : m_matchers ) { - if (matcher->match(arg)) - return true; - } - return false; - } - std::string describe() const override { - std::string description; - description.reserve( 4 + m_matchers.size()*32 ); - description += "( "; - bool first = true; - for( auto matcher : m_matchers ) { - if( first ) - first = false; - else - description += " or "; - description += matcher->toString(); - } - description += " )"; - return description; - } - - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; - } - - std::vector const*> m_matchers; - }; - - template - struct MatchNotOf : MatcherBase { - - MatchNotOf( MatcherBase const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} - - bool match( ArgT const& arg ) const override { - return !m_underlyingMatcher.match( arg ); - } - - std::string describe() const override { - return "not " + m_underlyingMatcher.toString(); - } - MatcherBase const& m_underlyingMatcher; - }; - - template - MatchAllOf MatcherBase::operator && ( MatcherBase const& other ) const { - return MatchAllOf() && *this && other; - } - template - MatchAnyOf MatcherBase::operator || ( MatcherBase const& other ) const { - return MatchAnyOf() || *this || other; - } - template - MatchNotOf MatcherBase::operator ! () const { - return MatchNotOf( *this ); - } - - } // namespace Impl - -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch - -// end catch_matchers.h -// start catch_matchers_floating.h - -#include -#include - -namespace Catch { -namespace Matchers { - - namespace Floating { - - enum class FloatingPointKind : uint8_t; - - struct WithinAbsMatcher : MatcherBase { - WithinAbsMatcher(double target, double margin); - bool match(double const& matchee) const override; - std::string describe() const override; - private: - double m_target; - double m_margin; - }; - - struct WithinUlpsMatcher : MatcherBase { - WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); - bool match(double const& matchee) const override; - std::string describe() const override; - private: - double m_target; - int m_ulps; - FloatingPointKind m_type; - }; - - } // namespace Floating - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); - Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); - Floating::WithinAbsMatcher WithinAbs(double target, double margin); - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_floating.h -// start catch_matchers_generic.hpp - -#include -#include - -namespace Catch { -namespace Matchers { -namespace Generic { - -namespace Detail { - std::string finalizeDescription(const std::string& desc); -} - -template -class PredicateMatcher : public MatcherBase { - std::function m_predicate; - std::string m_description; -public: - - PredicateMatcher(std::function const& elem, std::string const& descr) - :m_predicate(std::move(elem)), - m_description(Detail::finalizeDescription(descr)) - {} - - bool match( T const& item ) const override { - return m_predicate(item); - } - - std::string describe() const override { - return m_description; - } -}; - -} // namespace Generic - - // The following functions create the actual matcher objects. - // The user has to explicitly specify type to the function, because - // infering std::function is hard (but possible) and - // requires a lot of TMP. - template - Generic::PredicateMatcher Predicate(std::function const& predicate, std::string const& description = "") { - return Generic::PredicateMatcher(predicate, description); - } - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_generic.hpp -// start catch_matchers_string.h - -#include - -namespace Catch { -namespace Matchers { - - namespace StdString { - - struct CasedString - { - CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); - std::string adjustString( std::string const& str ) const; - std::string caseSensitivitySuffix() const; - - CaseSensitive::Choice m_caseSensitivity; - std::string m_str; - }; - - struct StringMatcherBase : MatcherBase { - StringMatcherBase( std::string const& operation, CasedString const& comparator ); - std::string describe() const override; - - CasedString m_comparator; - std::string m_operation; - }; - - struct EqualsMatcher : StringMatcherBase { - EqualsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct ContainsMatcher : StringMatcherBase { - ContainsMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct StartsWithMatcher : StringMatcherBase { - StartsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - struct EndsWithMatcher : StringMatcherBase { - EndsWithMatcher( CasedString const& comparator ); - bool match( std::string const& source ) const override; - }; - - struct RegexMatcher : MatcherBase { - RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); - bool match( std::string const& matchee ) const override; - std::string describe() const override; - - private: - std::string m_regex; - CaseSensitive::Choice m_caseSensitivity; - }; - - } // namespace StdString - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_string.h -// start catch_matchers_vector.h - -#include - -namespace Catch { -namespace Matchers { - - namespace Vector { - namespace Detail { - template - size_t count(InputIterator first, InputIterator last, T const& item) { - size_t cnt = 0; - for (; first != last; ++first) { - if (*first == item) { - ++cnt; - } - } - return cnt; - } - template - bool contains(InputIterator first, InputIterator last, T const& item) { - for (; first != last; ++first) { - if (*first == item) { - return true; - } - } - return false; - } - } - - template - struct ContainsElementMatcher : MatcherBase> { - - ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - - bool match(std::vector const &v) const override { - for (auto const& el : v) { - if (el == m_comparator) { - return true; - } - } - return false; - } - - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } - - T const& m_comparator; - }; - - template - struct ContainsMatcher : MatcherBase> { - - ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - // !TBD: see note in EqualsMatcher - if (m_comparator.size() > v.size()) - return false; - for (auto const& comparator : m_comparator) { - auto present = false; - for (const auto& el : v) { - if (el == comparator) { - present = true; - break; - } - } - if (!present) { - return false; - } - } - return true; - } - std::string describe() const override { - return "Contains: " + ::Catch::Detail::stringify( m_comparator ); - } - - std::vector const& m_comparator; - }; - - template - struct EqualsMatcher : MatcherBase> { - - EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - - bool match(std::vector const &v) const override { - // !TBD: This currently works if all elements can be compared using != - // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector etc - // - then just call that directly - if (m_comparator.size() != v.size()) - return false; - for (std::size_t i = 0; i < v.size(); ++i) - if (m_comparator[i] != v[i]) - return false; - return true; - } - std::string describe() const override { - return "Equals: " + ::Catch::Detail::stringify( m_comparator ); - } - std::vector const& m_comparator; - }; - - template - struct UnorderedEqualsMatcher : MatcherBase> { - UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} - bool match(std::vector const& vec) const override { - // Note: This is a reimplementation of std::is_permutation, - // because I don't want to include inside the common path - if (m_target.size() != vec.size()) { - return false; - } - auto lfirst = m_target.begin(), llast = m_target.end(); - auto rfirst = vec.begin(), rlast = vec.end(); - // Cut common prefix to optimize checking of permuted parts - while (lfirst != llast && *lfirst != *rfirst) { - ++lfirst; ++rfirst; - } - if (lfirst == llast) { - return true; - } - - for (auto mid = lfirst; mid != llast; ++mid) { - // Skip already counted items - if (Detail::contains(lfirst, mid, *mid)) { - continue; - } - size_t num_vec = Detail::count(rfirst, rlast, *mid); - if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { - return false; - } - } - - return true; - } - - std::string describe() const override { - return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); - } - private: - std::vector const& m_target; - }; - - } // namespace Vector - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - - template - Vector::ContainsMatcher Contains( std::vector const& comparator ) { - return Vector::ContainsMatcher( comparator ); - } - - template - Vector::ContainsElementMatcher VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher( comparator ); - } - - template - Vector::EqualsMatcher Equals( std::vector const& comparator ) { - return Vector::EqualsMatcher( comparator ); - } - - template - Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { - return Vector::UnorderedEqualsMatcher(target); - } - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_vector.h -namespace Catch { - - template - class MatchExpr : public ITransientExpression { - ArgT const& m_arg; - MatcherT m_matcher; - StringRef m_matcherString; - public: - MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) - : ITransientExpression{ true, matcher.match( arg ) }, - m_arg( arg ), - m_matcher( matcher ), - m_matcherString( matcherString ) - {} - - void streamReconstructedExpression( std::ostream &os ) const override { - auto matcherAsString = m_matcher.toString(); - os << Catch::Detail::stringify( m_arg ) << ' '; - if( matcherAsString == Detail::unprintableString ) - os << m_matcherString; - else - os << matcherAsString; - } - }; - - using StringMatcher = Matchers::Impl::MatcherBase; - - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ); - - template - auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString ) -> MatchExpr { - return MatchExpr( arg, matcher, matcherString ); - } - -} // namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - INTERNAL_CATCH_TRY { \ - catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -/////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ - do { \ - Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ - if( catchAssertionHandler.allowThrows() ) \ - try { \ - static_cast(__VA_ARGS__ ); \ - catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ - } \ - catch( exceptionType const& ex ) { \ - catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \ - } \ - catch( ... ) { \ - catchAssertionHandler.handleUnexpectedInflightException(); \ - } \ - else \ - catchAssertionHandler.handleThrowingCallSkipped(); \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( false ) - -// end catch_capture_matchers.h -#endif - -// These files are included here so the single_include script doesn't put them -// in the conditionally compiled sections -// start catch_test_case_info.h - -#include -#include -#include - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -namespace Catch { - - struct ITestInvoker; - - struct TestCaseInfo { - enum SpecialProperties{ - None = 0, - IsHidden = 1 << 1, - ShouldFail = 1 << 2, - MayFail = 1 << 3, - Throws = 1 << 4, - NonPortable = 1 << 5, - Benchmark = 1 << 6 - }; - - TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ); - - friend void setTags( TestCaseInfo& testCaseInfo, std::vector tags ); - - bool isHidden() const; - bool throws() const; - bool okToFail() const; - bool expectedToFail() const; - - std::string tagsAsString() const; - - std::string name; - std::string className; - std::string description; - std::vector tags; - std::vector lcaseTags; - SourceLineInfo lineInfo; - SpecialProperties properties; - }; - - class TestCase : public TestCaseInfo { - public: - - TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); - - TestCase withName( std::string const& _newName ) const; - - void invoke() const; - - TestCaseInfo const& getTestCaseInfo() const; - - bool operator == ( TestCase const& other ) const; - bool operator < ( TestCase const& other ) const; - - private: - std::shared_ptr test; - }; - - TestCase makeTestCase( ITestInvoker* testCase, - std::string const& className, - NameAndTags const& nameAndTags, - SourceLineInfo const& lineInfo ); -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_test_case_info.h -// start catch_interfaces_runner.h - -namespace Catch { - - struct IRunner { - virtual ~IRunner(); - virtual bool aborting() const = 0; - }; -} - -// end catch_interfaces_runner.h - -#ifdef __OBJC__ -// start catch_objc.hpp - -#import - -#include - -// NB. Any general catch headers included here must be included -// in catch.hpp first to make sure they are included by the single -// header for non obj-usage - -/////////////////////////////////////////////////////////////////////////////// -// This protocol is really only here for (self) documenting purposes, since -// all its methods are optional. -@protocol OcFixture - -@optional - --(void) setUp; --(void) tearDown; - -@end - -namespace Catch { - - class OcMethod : public ITestInvoker { - - public: - OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} - - virtual void invoke() const { - id obj = [[m_cls alloc] init]; - - performOptionalSelector( obj, @selector(setUp) ); - performOptionalSelector( obj, m_sel ); - performOptionalSelector( obj, @selector(tearDown) ); - - arcSafeRelease( obj ); - } - private: - virtual ~OcMethod() {} - - Class m_cls; - SEL m_sel; - }; - - namespace Detail{ - - inline std::string getAnnotation( Class cls, - std::string const& annotationName, - std::string const& testCaseName ) { - NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; - SEL sel = NSSelectorFromString( selStr ); - arcSafeRelease( selStr ); - id value = performOptionalSelector( cls, sel ); - if( value ) - return [(NSString*)value UTF8String]; - return ""; - } - } - - inline std::size_t registerTestMethods() { - std::size_t noTestMethods = 0; - int noClasses = objc_getClassList( nullptr, 0 ); - - Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); - objc_getClassList( classes, noClasses ); - - for( int c = 0; c < noClasses; c++ ) { - Class cls = classes[c]; - { - u_int count; - Method* methods = class_copyMethodList( cls, &count ); - for( u_int m = 0; m < count ; m++ ) { - SEL selector = method_getName(methods[m]); - std::string methodName = sel_getName(selector); - if( startsWith( methodName, "Catch_TestCase_" ) ) { - std::string testCaseName = methodName.substr( 15 ); - std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); - std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); - const char* className = class_getName( cls ); - - getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo("",0) ) ); - noTestMethods++; - } - } - free(methods); - } - } - return noTestMethods; - } - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) - - namespace Matchers { - namespace Impl { - namespace NSStringMatchers { - - struct StringHolder : MatcherBase{ - StringHolder( NSString* substr ) : m_substr( [substr copy] ){} - StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} - StringHolder() { - arcSafeRelease( m_substr ); - } - - bool match( NSString* arg ) const override { - return false; - } - - NSString* CATCH_ARC_STRONG m_substr; - }; - - struct Equals : StringHolder { - Equals( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str isEqualToString:m_substr]; - } - - std::string describe() const override { - return "equals string: " + Catch::Detail::stringify( m_substr ); - } - }; - - struct Contains : StringHolder { - Contains( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location != NSNotFound; - } - - std::string describe() const override { - return "contains string: " + Catch::Detail::stringify( m_substr ); - } - }; - - struct StartsWith : StringHolder { - StartsWith( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == 0; - } - - std::string describe() const override { - return "starts with: " + Catch::Detail::stringify( m_substr ); - } - }; - struct EndsWith : StringHolder { - EndsWith( NSString* substr ) : StringHolder( substr ){} - - bool match( NSString* str ) const override { - return (str != nil || m_substr == nil ) && - [str rangeOfString:m_substr].location == [str length] - [m_substr length]; - } - - std::string describe() const override { - return "ends with: " + Catch::Detail::stringify( m_substr ); - } - }; - - } // namespace NSStringMatchers - } // namespace Impl - - inline Impl::NSStringMatchers::Equals - Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } - - inline Impl::NSStringMatchers::Contains - Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } - - inline Impl::NSStringMatchers::StartsWith - StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } - - inline Impl::NSStringMatchers::EndsWith - EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } - - } // namespace Matchers - - using namespace Matchers; - -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -} // namespace Catch - -/////////////////////////////////////////////////////////////////////////////// -#define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix -#define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ -+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ -{ \ -return @ name; \ -} \ -+(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ -{ \ -return @ desc; \ -} \ --(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) - -#define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) - -// end catch_objc.hpp -#endif - -#ifdef CATCH_CONFIG_EXTERNAL_INTERFACES -// start catch_external_interfaces.h - -// start catch_reporter_bases.hpp - -// start catch_interfaces_reporter.h - -// start catch_config.hpp - -// start catch_test_spec_parser.h - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -// start catch_test_spec.h - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wpadded" -#endif - -// start catch_wildcard_pattern.h - -namespace Catch -{ - class WildcardPattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - - public: - - WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); - virtual ~WildcardPattern() = default; - virtual bool matches( std::string const& str ) const; - - private: - std::string adjustCase( std::string const& str ) const; - CaseSensitive::Choice m_caseSensitivity; - WildcardPosition m_wildcard = NoWildcard; - std::string m_pattern; - }; -} - -// end catch_wildcard_pattern.h -#include -#include -#include - -namespace Catch { - - class TestSpec { - struct Pattern { - virtual ~Pattern(); - virtual bool matches( TestCaseInfo const& testCase ) const = 0; - }; - using PatternPtr = std::shared_ptr; - - class NamePattern : public Pattern { - public: - NamePattern( std::string const& name ); - virtual ~NamePattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - WildcardPattern m_wildcardPattern; - }; - - class TagPattern : public Pattern { - public: - TagPattern( std::string const& tag ); - virtual ~TagPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - std::string m_tag; - }; - - class ExcludedPattern : public Pattern { - public: - ExcludedPattern( PatternPtr const& underlyingPattern ); - virtual ~ExcludedPattern(); - virtual bool matches( TestCaseInfo const& testCase ) const override; - private: - PatternPtr m_underlyingPattern; - }; - - struct Filter { - std::vector m_patterns; - - bool matches( TestCaseInfo const& testCase ) const; - }; - - public: - bool hasFilters() const; - bool matches( TestCaseInfo const& testCase ) const; - - private: - std::vector m_filters; - - friend class TestSpecParser; - }; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_test_spec.h -// start catch_interfaces_tag_alias_registry.h - -#include - -namespace Catch { - - struct TagAlias; - - struct ITagAliasRegistry { - virtual ~ITagAliasRegistry(); - // Nullptr if not present - virtual TagAlias const* find( std::string const& alias ) const = 0; - virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; - - static ITagAliasRegistry const& get(); - }; - -} // end namespace Catch - -// end catch_interfaces_tag_alias_registry.h -namespace Catch { - - class TestSpecParser { - enum Mode{ None, Name, QuotedName, Tag, EscapedName }; - Mode m_mode = None; - bool m_exclusion = false; - std::size_t m_start = std::string::npos, m_pos = 0; - std::string m_arg; - std::vector m_escapeChars; - TestSpec::Filter m_currentFilter; - TestSpec m_testSpec; - ITagAliasRegistry const* m_tagAliases = nullptr; - - public: - TestSpecParser( ITagAliasRegistry const& tagAliases ); - - TestSpecParser& parse( std::string const& arg ); - TestSpec testSpec(); - - private: - void visitChar( char c ); - void startNewMode( Mode mode, std::size_t start ); - void escape(); - std::string subString() const; - - template - void addPattern() { - std::string token = subString(); - for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) - token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); - m_escapeChars.clear(); - if( startsWith( token, "exclude:" ) ) { - m_exclusion = true; - token = token.substr( 8 ); - } - if( !token.empty() ) { - TestSpec::PatternPtr pattern = std::make_shared( token ); - if( m_exclusion ) - pattern = std::make_shared( pattern ); - m_currentFilter.m_patterns.push_back( pattern ); - } - m_exclusion = false; - m_mode = None; - } - - void addFilter(); - }; - TestSpec parseTestSpec( std::string const& arg ); - -} // namespace Catch - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_test_spec_parser.h -// start catch_interfaces_config.h - -#include -#include -#include -#include - -namespace Catch { - - enum class Verbosity { - Quiet = 0, - Normal, - High - }; - - struct WarnAbout { enum What { - Nothing = 0x00, - NoAssertions = 0x01, - NoTests = 0x02 - }; }; - - struct ShowDurations { enum OrNot { - DefaultForReporter, - Always, - Never - }; }; - struct RunTests { enum InWhatOrder { - InDeclarationOrder, - InLexicographicalOrder, - InRandomOrder - }; }; - struct UseColour { enum YesOrNo { - Auto, - Yes, - No - }; }; - struct WaitForKeypress { enum When { - Never, - BeforeStart = 1, - BeforeExit = 2, - BeforeStartAndExit = BeforeStart | BeforeExit - }; }; - - class TestSpec; - - struct IConfig : NonCopyable { - - virtual ~IConfig(); - - virtual bool allowThrows() const = 0; - virtual std::ostream& stream() const = 0; - virtual std::string name() const = 0; - virtual bool includeSuccessfulResults() const = 0; - virtual bool shouldDebugBreak() const = 0; - virtual bool warnAboutMissingAssertions() const = 0; - virtual bool warnAboutNoTests() const = 0; - virtual int abortAfter() const = 0; - virtual bool showInvisibles() const = 0; - virtual ShowDurations::OrNot showDurations() const = 0; - virtual TestSpec const& testSpec() const = 0; - virtual bool hasTestFilters() const = 0; - virtual RunTests::InWhatOrder runOrder() const = 0; - virtual unsigned int rngSeed() const = 0; - virtual int benchmarkResolutionMultiple() const = 0; - virtual UseColour::YesOrNo useColour() const = 0; - virtual std::vector const& getSectionsToRun() const = 0; - virtual Verbosity verbosity() const = 0; - }; - - using IConfigPtr = std::shared_ptr; -} - -// end catch_interfaces_config.h -// Libstdc++ doesn't like incomplete classes for unique_ptr - -#include -#include -#include - -#ifndef CATCH_CONFIG_CONSOLE_WIDTH -#define CATCH_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { - - struct IStream; - - struct ConfigData { - bool listTests = false; - bool listTags = false; - bool listReporters = false; - bool listTestNamesOnly = false; - - bool showSuccessfulTests = false; - bool shouldDebugBreak = false; - bool noThrow = false; - bool showHelp = false; - bool showInvisibles = false; - bool filenamesAsTags = false; - bool libIdentify = false; - - int abortAfter = -1; - unsigned int rngSeed = 0; - int benchmarkResolutionMultiple = 100; - - Verbosity verbosity = Verbosity::Normal; - WarnAbout::What warnings = WarnAbout::Nothing; - ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; - RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; - UseColour::YesOrNo useColour = UseColour::Auto; - WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; - - std::string outputFilename; - std::string name; - std::string processName; - - std::vector reporterNames; - std::vector testsOrTags; - std::vector sectionsToRun; - }; - - class Config : public IConfig { - public: - - Config() = default; - Config( ConfigData const& data ); - virtual ~Config() = default; - - std::string const& getFilename() const; - - bool listTests() const; - bool listTestNamesOnly() const; - bool listTags() const; - bool listReporters() const; - - std::string getProcessName() const; - - std::vector const& getReporterNames() const; - std::vector const& getTestsOrTags() const; - std::vector const& getSectionsToRun() const override; - - virtual TestSpec const& testSpec() const override; - bool hasTestFilters() const override; - - bool showHelp() const; - - // IConfig interface - bool allowThrows() const override; - std::ostream& stream() const override; - std::string name() const override; - bool includeSuccessfulResults() const override; - bool warnAboutMissingAssertions() const override; - bool warnAboutNoTests() const override; - ShowDurations::OrNot showDurations() const override; - RunTests::InWhatOrder runOrder() const override; - unsigned int rngSeed() const override; - int benchmarkResolutionMultiple() const override; - UseColour::YesOrNo useColour() const override; - bool shouldDebugBreak() const override; - int abortAfter() const override; - bool showInvisibles() const override; - Verbosity verbosity() const override; - - private: - - IStream const* openStream(); - ConfigData m_data; - - std::unique_ptr m_stream; - TestSpec m_testSpec; - bool m_hasTestFilters = false; - }; - -} // end namespace Catch - -// end catch_config.hpp -// start catch_assertionresult.h - -#include - -namespace Catch { - - struct AssertionResultData - { - AssertionResultData() = delete; - - AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); - - std::string message; - mutable std::string reconstructedExpression; - LazyExpression lazyExpression; - ResultWas::OfType resultType; - - std::string reconstructExpression() const; - }; - - class AssertionResult { - public: - AssertionResult() = delete; - AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); - - bool isOk() const; - bool succeeded() const; - ResultWas::OfType getResultType() const; - bool hasExpression() const; - bool hasMessage() const; - std::string getExpression() const; - std::string getExpressionInMacro() const; - bool hasExpandedExpression() const; - std::string getExpandedExpression() const; - std::string getMessage() const; - SourceLineInfo getSourceInfo() const; - StringRef getTestMacroName() const; - - //protected: - AssertionInfo m_info; - AssertionResultData m_resultData; - }; - -} // end namespace Catch - -// end catch_assertionresult.h -// start catch_option.hpp - -namespace Catch { - - // An optional type - template - class Option { - public: - Option() : nullableValue( nullptr ) {} - Option( T const& _value ) - : nullableValue( new( storage ) T( _value ) ) - {} - Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) - {} - - ~Option() { - reset(); - } - - Option& operator= ( Option const& _other ) { - if( &_other != this ) { - reset(); - if( _other ) - nullableValue = new( storage ) T( *_other ); - } - return *this; - } - Option& operator = ( T const& _value ) { - reset(); - nullableValue = new( storage ) T( _value ); - return *this; - } - - void reset() { - if( nullableValue ) - nullableValue->~T(); - nullableValue = nullptr; - } - - T& operator*() { return *nullableValue; } - T const& operator*() const { return *nullableValue; } - T* operator->() { return nullableValue; } - const T* operator->() const { return nullableValue; } - - T valueOr( T const& defaultValue ) const { - return nullableValue ? *nullableValue : defaultValue; - } - - bool some() const { return nullableValue != nullptr; } - bool none() const { return nullableValue == nullptr; } - - bool operator !() const { return nullableValue == nullptr; } - explicit operator bool() const { - return some(); - } - - private: - T *nullableValue; - alignas(alignof(T)) char storage[sizeof(T)]; - }; - -} // end namespace Catch - -// end catch_option.hpp -#include -#include -#include -#include -#include - -namespace Catch { - - struct ReporterConfig { - explicit ReporterConfig( IConfigPtr const& _fullConfig ); - - ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); - - std::ostream& stream() const; - IConfigPtr fullConfig() const; - - private: - std::ostream* m_stream; - IConfigPtr m_fullConfig; - }; - - struct ReporterPreferences { - bool shouldRedirectStdOut = false; - }; - - template - struct LazyStat : Option { - LazyStat& operator=( T const& _value ) { - Option::operator=( _value ); - used = false; - return *this; - } - void reset() { - Option::reset(); - used = false; - } - bool used = false; - }; - - struct TestRunInfo { - TestRunInfo( std::string const& _name ); - std::string name; - }; - struct GroupInfo { - GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ); - - std::string name; - std::size_t groupIndex; - std::size_t groupsCounts; - }; - - struct AssertionStats { - AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ); - - AssertionStats( AssertionStats const& ) = default; - AssertionStats( AssertionStats && ) = default; - AssertionStats& operator = ( AssertionStats const& ) = default; - AssertionStats& operator = ( AssertionStats && ) = default; - virtual ~AssertionStats(); - - AssertionResult assertionResult; - std::vector infoMessages; - Totals totals; - }; - - struct SectionStats { - SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ); - SectionStats( SectionStats const& ) = default; - SectionStats( SectionStats && ) = default; - SectionStats& operator = ( SectionStats const& ) = default; - SectionStats& operator = ( SectionStats && ) = default; - virtual ~SectionStats(); - - SectionInfo sectionInfo; - Counts assertions; - double durationInSeconds; - bool missingAssertions; - }; - - struct TestCaseStats { - TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ); - - TestCaseStats( TestCaseStats const& ) = default; - TestCaseStats( TestCaseStats && ) = default; - TestCaseStats& operator = ( TestCaseStats const& ) = default; - TestCaseStats& operator = ( TestCaseStats && ) = default; - virtual ~TestCaseStats(); - - TestCaseInfo testInfo; - Totals totals; - std::string stdOut; - std::string stdErr; - bool aborting; - }; - - struct TestGroupStats { - TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ); - TestGroupStats( GroupInfo const& _groupInfo ); - - TestGroupStats( TestGroupStats const& ) = default; - TestGroupStats( TestGroupStats && ) = default; - TestGroupStats& operator = ( TestGroupStats const& ) = default; - TestGroupStats& operator = ( TestGroupStats && ) = default; - virtual ~TestGroupStats(); - - GroupInfo groupInfo; - Totals totals; - bool aborting; - }; - - struct TestRunStats { - TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ); - - TestRunStats( TestRunStats const& ) = default; - TestRunStats( TestRunStats && ) = default; - TestRunStats& operator = ( TestRunStats const& ) = default; - TestRunStats& operator = ( TestRunStats && ) = default; - virtual ~TestRunStats(); - - TestRunInfo runInfo; - Totals totals; - bool aborting; - }; - - struct BenchmarkInfo { - std::string name; - }; - struct BenchmarkStats { - BenchmarkInfo info; - std::size_t iterations; - uint64_t elapsedTimeInNanoseconds; - }; - - struct IStreamingReporter { - virtual ~IStreamingReporter() = default; - - // Implementing class must also provide the following static methods: - // static std::string getDescription(); - // static std::set getSupportedVerbosities() - - virtual ReporterPreferences getPreferences() const = 0; - - virtual void noMatchingTestCases( std::string const& spec ) = 0; - - virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; - virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; - - virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; - virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; - - // *** experimental *** - virtual void benchmarkStarting( BenchmarkInfo const& ) {} - - virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; - - // The return value indicates if the messages buffer should be cleared: - virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; - - // *** experimental *** - virtual void benchmarkEnded( BenchmarkStats const& ) {} - - virtual void sectionEnded( SectionStats const& sectionStats ) = 0; - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; - virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; - - virtual void skipTest( TestCaseInfo const& testInfo ) = 0; - - // Default empty implementation provided - virtual void fatalErrorEncountered( StringRef name ); - - virtual bool isMulti() const; - }; - using IStreamingReporterPtr = std::unique_ptr; - - struct IReporterFactory { - virtual ~IReporterFactory(); - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; - virtual std::string getDescription() const = 0; - }; - using IReporterFactoryPtr = std::shared_ptr; - - struct IReporterRegistry { - using FactoryMap = std::map; - using Listeners = std::vector; - - virtual ~IReporterRegistry(); - virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; - virtual FactoryMap const& getFactories() const = 0; - virtual Listeners const& getListeners() const = 0; - }; - - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ); - -} // end namespace Catch - -// end catch_interfaces_reporter.h -#include -#include -#include -#include -#include -#include -#include - -namespace Catch { - void prepareExpandedExpression(AssertionResult& result); - - // Returns double formatted as %.3f (format expected on output) - std::string getFormattedDuration( double duration ); - - template - struct StreamingReporterBase : IStreamingReporter { - - StreamingReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) - throw std::domain_error( "Verbosity level not supported by this reporter" ); - } - - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } - - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } - - ~StreamingReporterBase() override = default; - - void noMatchingTestCases(std::string const&) override {} - - void testRunStarting(TestRunInfo const& _testRunInfo) override { - currentTestRunInfo = _testRunInfo; - } - void testGroupStarting(GroupInfo const& _groupInfo) override { - currentGroupInfo = _groupInfo; - } - - void testCaseStarting(TestCaseInfo const& _testInfo) override { - currentTestCaseInfo = _testInfo; - } - void sectionStarting(SectionInfo const& _sectionInfo) override { - m_sectionStack.push_back(_sectionInfo); - } - - void sectionEnded(SectionStats const& /* _sectionStats */) override { - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { - currentTestCaseInfo.reset(); - } - void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { - currentGroupInfo.reset(); - } - void testRunEnded(TestRunStats const& /* _testRunStats */) override { - currentTestCaseInfo.reset(); - currentGroupInfo.reset(); - currentTestRunInfo.reset(); - } - - void skipTest(TestCaseInfo const&) override { - // Don't do anything with this by default. - // It can optionally be overridden in the derived class. - } - - IConfigPtr m_config; - std::ostream& stream; - - LazyStat currentTestRunInfo; - LazyStat currentGroupInfo; - LazyStat currentTestCaseInfo; - - std::vector m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - template - struct CumulativeReporterBase : IStreamingReporter { - template - struct Node { - explicit Node( T const& _value ) : value( _value ) {} - virtual ~Node() {} - - using ChildNodes = std::vector>; - T value; - ChildNodes children; - }; - struct SectionNode { - explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} - virtual ~SectionNode() = default; - - bool operator == (SectionNode const& other) const { - return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; - } - bool operator == (std::shared_ptr const& other) const { - return operator==(*other); - } - - SectionStats stats; - using ChildSections = std::vector>; - using Assertions = std::vector; - ChildSections childSections; - Assertions assertions; - std::string stdOut; - std::string stdErr; - }; - - struct BySectionInfo { - BySectionInfo( SectionInfo const& other ) : m_other( other ) {} - BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} - bool operator() (std::shared_ptr const& node) const { - return ((node->stats.sectionInfo.name == m_other.name) && - (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); - } - void operator=(BySectionInfo const&) = delete; - - private: - SectionInfo const& m_other; - }; - - using TestCaseNode = Node; - using TestGroupNode = Node; - using TestRunNode = Node; - - CumulativeReporterBase( ReporterConfig const& _config ) - : m_config( _config.fullConfig() ), - stream( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = false; - if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) - throw std::domain_error( "Verbosity level not supported by this reporter" ); - } - ~CumulativeReporterBase() override = default; - - ReporterPreferences getPreferences() const override { - return m_reporterPrefs; - } - - static std::set getSupportedVerbosities() { - return { Verbosity::Normal }; - } - - void testRunStarting( TestRunInfo const& ) override {} - void testGroupStarting( GroupInfo const& ) override {} - - void testCaseStarting( TestCaseInfo const& ) override {} - - void sectionStarting( SectionInfo const& sectionInfo ) override { - SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); - std::shared_ptr node; - if( m_sectionStack.empty() ) { - if( !m_rootSection ) - m_rootSection = std::make_shared( incompleteStats ); - node = m_rootSection; - } - else { - SectionNode& parentNode = *m_sectionStack.back(); - auto it = - std::find_if( parentNode.childSections.begin(), - parentNode.childSections.end(), - BySectionInfo( sectionInfo ) ); - if( it == parentNode.childSections.end() ) { - node = std::make_shared( incompleteStats ); - parentNode.childSections.push_back( node ); - } - else - node = *it; - } - m_sectionStack.push_back( node ); - m_deepestSection = std::move(node); - } - - void assertionStarting(AssertionInfo const&) override {} - - bool assertionEnded(AssertionStats const& assertionStats) override { - assert(!m_sectionStack.empty()); - // AssertionResult holds a pointer to a temporary DecomposedExpression, - // which getExpandedExpression() calls to build the expression string. - // Our section stack copy of the assertionResult will likely outlive the - // temporary, so it must be expanded or discarded now to avoid calling - // a destroyed object later. - prepareExpandedExpression(const_cast( assertionStats.assertionResult ) ); - SectionNode& sectionNode = *m_sectionStack.back(); - sectionNode.assertions.push_back(assertionStats); - return true; - } - void sectionEnded(SectionStats const& sectionStats) override { - assert(!m_sectionStack.empty()); - SectionNode& node = *m_sectionStack.back(); - node.stats = sectionStats; - m_sectionStack.pop_back(); - } - void testCaseEnded(TestCaseStats const& testCaseStats) override { - auto node = std::make_shared(testCaseStats); - assert(m_sectionStack.size() == 0); - node->children.push_back(m_rootSection); - m_testCases.push_back(node); - m_rootSection.reset(); - - assert(m_deepestSection); - m_deepestSection->stdOut = testCaseStats.stdOut; - m_deepestSection->stdErr = testCaseStats.stdErr; - } - void testGroupEnded(TestGroupStats const& testGroupStats) override { - auto node = std::make_shared(testGroupStats); - node->children.swap(m_testCases); - m_testGroups.push_back(node); - } - void testRunEnded(TestRunStats const& testRunStats) override { - auto node = std::make_shared(testRunStats); - node->children.swap(m_testGroups); - m_testRuns.push_back(node); - testRunEndedCumulative(); - } - virtual void testRunEndedCumulative() = 0; - - void skipTest(TestCaseInfo const&) override {} - - IConfigPtr m_config; - std::ostream& stream; - std::vector m_assertions; - std::vector>> m_sections; - std::vector> m_testCases; - std::vector> m_testGroups; - - std::vector> m_testRuns; - - std::shared_ptr m_rootSection; - std::shared_ptr m_deepestSection; - std::vector> m_sectionStack; - ReporterPreferences m_reporterPrefs; - }; - - template - char const* getLineOfChars() { - static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; - if( !*line ) { - std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); - line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; - } - return line; - } - - struct TestEventListenerBase : StreamingReporterBase { - TestEventListenerBase( ReporterConfig const& _config ); - - void assertionStarting(AssertionInfo const&) override; - bool assertionEnded(AssertionStats const&) override; - }; - -} // end namespace Catch - -// end catch_reporter_bases.hpp -// start catch_console_colour.h - -namespace Catch { - - struct Colour { - enum Code { - None = 0, - - White, - Red, - Green, - Blue, - Cyan, - Yellow, - Grey, - - Bright = 0x10, - - BrightRed = Bright | Red, - BrightGreen = Bright | Green, - LightGrey = Bright | Grey, - BrightWhite = Bright | White, - BrightYellow = Bright | Yellow, - - // By intention - FileName = LightGrey, - Warning = BrightYellow, - ResultError = BrightRed, - ResultSuccess = BrightGreen, - ResultExpectedFailure = Warning, - - Error = BrightRed, - Success = Green, - - OriginalExpression = Cyan, - ReconstructedExpression = BrightYellow, - - SecondaryText = LightGrey, - Headers = White - }; - - // Use constructed object for RAII guard - Colour( Code _colourCode ); - Colour( Colour&& other ) noexcept; - Colour& operator=( Colour&& other ) noexcept; - ~Colour(); - - // Use static method for one-shot changes - static void use( Code _colourCode ); - - private: - bool m_moved = false; - }; - - std::ostream& operator << ( std::ostream& os, Colour const& ); - -} // end namespace Catch - -// end catch_console_colour.h -// start catch_reporter_registrars.hpp - - -namespace Catch { - - template - class ReporterRegistrar { - - class ReporterFactory : public IReporterFactory { - - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - - virtual std::string getDescription() const override { - return T::getDescription(); - } - }; - - public: - - explicit ReporterRegistrar( std::string const& name ) { - getMutableRegistryHub().registerReporter( name, std::make_shared() ); - } - }; - - template - class ListenerRegistrar { - - class ListenerFactory : public IReporterFactory { - - virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { - return std::unique_ptr( new T( config ) ); - } - virtual std::string getDescription() const override { - return std::string(); - } - }; - - public: - - ListenerRegistrar() { - getMutableRegistryHub().registerListener( std::make_shared() ); - } - }; -} - -#if !defined(CATCH_CONFIG_DISABLE) - -#define CATCH_REGISTER_REPORTER( name, reporterType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } \ - CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS - -#define CATCH_REGISTER_LISTENER( listenerType ) \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ - namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } \ - CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS -#else // CATCH_CONFIG_DISABLE - -#define CATCH_REGISTER_REPORTER(name, reporterType) -#define CATCH_REGISTER_LISTENER(listenerType) - -#endif // CATCH_CONFIG_DISABLE - -// end catch_reporter_registrars.hpp -// Allow users to base their work off existing reporters -// start catch_reporter_compact.h - -namespace Catch { - - struct CompactReporter : StreamingReporterBase { - - using StreamingReporterBase::StreamingReporterBase; - - ~CompactReporter() override; - - static std::string getDescription(); - - ReporterPreferences getPreferences() const override; - - void noMatchingTestCases(std::string const& spec) override; - - void assertionStarting(AssertionInfo const&) override; - - bool assertionEnded(AssertionStats const& _assertionStats) override; - - void sectionEnded(SectionStats const& _sectionStats) override; - - void testRunEnded(TestRunStats const& _testRunStats) override; - - }; - -} // end namespace Catch - -// end catch_reporter_compact.h -// start catch_reporter_console.h - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - // Fwd decls - struct SummaryColumn; - class TablePrinter; - - struct ConsoleReporter : StreamingReporterBase { - std::unique_ptr m_tablePrinter; - - ConsoleReporter(ReporterConfig const& config); - ~ConsoleReporter() override; - static std::string getDescription(); - - void noMatchingTestCases(std::string const& spec) override; - - void assertionStarting(AssertionInfo const&) override; - - bool assertionEnded(AssertionStats const& _assertionStats) override; - - void sectionStarting(SectionInfo const& _sectionInfo) override; - void sectionEnded(SectionStats const& _sectionStats) override; - - void benchmarkStarting(BenchmarkInfo const& info) override; - void benchmarkEnded(BenchmarkStats const& stats) override; - - void testCaseEnded(TestCaseStats const& _testCaseStats) override; - void testGroupEnded(TestGroupStats const& _testGroupStats) override; - void testRunEnded(TestRunStats const& _testRunStats) override; - - private: - - void lazyPrint(); - - void lazyPrintWithoutClosingBenchmarkTable(); - void lazyPrintRunInfo(); - void lazyPrintGroupInfo(); - void printTestCaseAndSectionHeader(); - - void printClosedHeader(std::string const& _name); - void printOpenHeader(std::string const& _name); - - // if string has a : in first line will set indent to follow it on - // subsequent lines - void printHeaderString(std::string const& _string, std::size_t indent = 0); - - void printTotals(Totals const& totals); - void printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row); - - void printTotalsDivider(Totals const& totals); - void printSummaryDivider(); - - private: - bool m_headerPrinted = false; - }; - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -// end catch_reporter_console.h -// start catch_reporter_junit.h - -// start catch_xmlwriter.h - -#include - -namespace Catch { - - class XmlEncode { - public: - enum ForWhat { ForTextNodes, ForAttributes }; - - XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); - - void encodeTo( std::ostream& os ) const; - - friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); - - private: - std::string m_str; - ForWhat m_forWhat; - }; - - class XmlWriter { - public: - - class ScopedElement { - public: - ScopedElement( XmlWriter* writer ); - - ScopedElement( ScopedElement&& other ) noexcept; - ScopedElement& operator=( ScopedElement&& other ) noexcept; - - ~ScopedElement(); - - ScopedElement& writeText( std::string const& text, bool indent = true ); - - template - ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { - m_writer->writeAttribute( name, attribute ); - return *this; - } - - private: - mutable XmlWriter* m_writer = nullptr; - }; - - XmlWriter( std::ostream& os = Catch::cout() ); - ~XmlWriter(); - - XmlWriter( XmlWriter const& ) = delete; - XmlWriter& operator=( XmlWriter const& ) = delete; - - XmlWriter& startElement( std::string const& name ); - - ScopedElement scopedElement( std::string const& name ); - - XmlWriter& endElement(); - - XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); - - XmlWriter& writeAttribute( std::string const& name, bool attribute ); - - template - XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - ReusableStringStream rss; - rss << attribute; - return writeAttribute( name, rss.str() ); - } - - XmlWriter& writeText( std::string const& text, bool indent = true ); - - XmlWriter& writeComment( std::string const& text ); - - void writeStylesheetRef( std::string const& url ); - - XmlWriter& writeBlankLine(); - - void ensureTagClosed(); - - private: - - void writeDeclaration(); - - void newlineIfNecessary(); - - bool m_tagIsOpen = false; - bool m_needsNewline = false; - std::vector m_tags; - std::string m_indent; - std::ostream& m_os; - }; - -} - -// end catch_xmlwriter.h -namespace Catch { - - class JunitReporter : public CumulativeReporterBase { - public: - JunitReporter(ReporterConfig const& _config); - - ~JunitReporter() override; - - static std::string getDescription(); - - void noMatchingTestCases(std::string const& /*spec*/) override; - - void testRunStarting(TestRunInfo const& runInfo) override; - - void testGroupStarting(GroupInfo const& groupInfo) override; - - void testCaseStarting(TestCaseInfo const& testCaseInfo) override; - bool assertionEnded(AssertionStats const& assertionStats) override; - - void testCaseEnded(TestCaseStats const& testCaseStats) override; - - void testGroupEnded(TestGroupStats const& testGroupStats) override; - - void testRunEndedCumulative() override; - - void writeGroup(TestGroupNode const& groupNode, double suiteTime); - - void writeTestCase(TestCaseNode const& testCaseNode); - - void writeSection(std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode); - - void writeAssertions(SectionNode const& sectionNode); - void writeAssertion(AssertionStats const& stats); - - XmlWriter xml; - Timer suiteTimer; - std::string stdOutForSuite; - std::string stdErrForSuite; - unsigned int unexpectedExceptions = 0; - bool m_okToFail = false; - }; - -} // end namespace Catch - -// end catch_reporter_junit.h -// start catch_reporter_xml.h - -namespace Catch { - class XmlReporter : public StreamingReporterBase { - public: - XmlReporter(ReporterConfig const& _config); - - ~XmlReporter() override; - - static std::string getDescription(); - - virtual std::string getStylesheetRef() const; - - void writeSourceInfo(SourceLineInfo const& sourceInfo); - - public: // StreamingReporterBase - - void noMatchingTestCases(std::string const& s) override; - - void testRunStarting(TestRunInfo const& testInfo) override; - - void testGroupStarting(GroupInfo const& groupInfo) override; - - void testCaseStarting(TestCaseInfo const& testInfo) override; - - void sectionStarting(SectionInfo const& sectionInfo) override; - - void assertionStarting(AssertionInfo const&) override; - - bool assertionEnded(AssertionStats const& assertionStats) override; - - void sectionEnded(SectionStats const& sectionStats) override; - - void testCaseEnded(TestCaseStats const& testCaseStats) override; - - void testGroupEnded(TestGroupStats const& testGroupStats) override; - - void testRunEnded(TestRunStats const& testRunStats) override; - - private: - Timer m_testCaseTimer; - XmlWriter m_xml; - int m_sectionDepth = 0; - }; - -} // end namespace Catch - -// end catch_reporter_xml.h - -// end catch_external_interfaces.h -#endif - -#endif // ! CATCH_CONFIG_IMPL_ONLY - -#ifdef CATCH_IMPL -// start catch_impl.hpp - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -// Keep these here for external reporters -// start catch_test_case_tracker.h - -#include -#include -#include - -namespace Catch { -namespace TestCaseTracking { - - struct NameAndLocation { - std::string name; - SourceLineInfo location; - - NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); - }; - - struct ITracker; - - using ITrackerPtr = std::shared_ptr; - - struct ITracker { - virtual ~ITracker(); - - // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; - - // dynamic queries - virtual bool isComplete() const = 0; // Successfully completed or failed - virtual bool isSuccessfullyCompleted() const = 0; - virtual bool isOpen() const = 0; // Started but not complete - virtual bool hasChildren() const = 0; - - virtual ITracker& parent() = 0; - - // actions - virtual void close() = 0; // Successfully complete - virtual void fail() = 0; - virtual void markAsNeedingAnotherRun() = 0; - - virtual void addChild( ITrackerPtr const& child ) = 0; - virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; - virtual void openChild() = 0; - - // Debug/ checking - virtual bool isSectionTracker() const = 0; - virtual bool isIndexTracker() const = 0; - }; - - class TrackerContext { - - enum RunState { - NotStarted, - Executing, - CompletedCycle - }; - - ITrackerPtr m_rootTracker; - ITracker* m_currentTracker = nullptr; - RunState m_runState = NotStarted; - - public: - - static TrackerContext& instance(); - - ITracker& startRun(); - void endRun(); - - void startCycle(); - void completeCycle(); - - bool completedCycle() const; - ITracker& currentTracker(); - void setCurrentTracker( ITracker* tracker ); - }; - - class TrackerBase : public ITracker { - protected: - enum CycleState { - NotStarted, - Executing, - ExecutingChildren, - NeedsAnotherRun, - CompletedSuccessfully, - Failed - }; - - class TrackerHasName { - NameAndLocation m_nameAndLocation; - public: - TrackerHasName( NameAndLocation const& nameAndLocation ); - bool operator ()( ITrackerPtr const& tracker ) const; - }; - - using Children = std::vector; - NameAndLocation m_nameAndLocation; - TrackerContext& m_ctx; - ITracker* m_parent; - Children m_children; - CycleState m_runState = NotStarted; - - public: - TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - - NameAndLocation const& nameAndLocation() const override; - bool isComplete() const override; - bool isSuccessfullyCompleted() const override; - bool isOpen() const override; - bool hasChildren() const override; - - void addChild( ITrackerPtr const& child ) override; - - ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; - ITracker& parent() override; - - void openChild() override; - - bool isSectionTracker() const override; - bool isIndexTracker() const override; - - void open(); - - void close() override; - void fail() override; - void markAsNeedingAnotherRun() override; - - private: - void moveToParent(); - void moveToThis(); - }; - - class SectionTracker : public TrackerBase { - std::vector m_filters; - public: - SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - - bool isSectionTracker() const override; - - static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); - - void tryOpen(); - - void addInitialFilters( std::vector const& filters ); - void addNextFilters( std::vector const& filters ); - }; - - class IndexTracker : public TrackerBase { - int m_size; - int m_index = -1; - public: - IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); - - bool isIndexTracker() const override; - void close() override; - - static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); - - int index() const; - - void moveNext(); - }; - -} // namespace TestCaseTracking - -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; - -} // namespace Catch - -// end catch_test_case_tracker.h - -// start catch_leak_detector.h - -namespace Catch { - - struct LeakDetector { - LeakDetector(); - }; - -} -// end catch_leak_detector.h -// Cpp files will be included in the single-header file here -// start catch_approx.cpp - -#include -#include - -namespace { - -// Performs equivalent check of std::fabs(lhs - rhs) <= margin -// But without the subtraction to allow for INFINITY in comparison -bool marginComparison(double lhs, double rhs, double margin) { - return (lhs + margin >= rhs) && (rhs + margin >= lhs); -} - -} - -namespace Catch { -namespace Detail { - - Approx::Approx ( double value ) - : m_epsilon( std::numeric_limits::epsilon()*100 ), - m_margin( 0.0 ), - m_scale( 0.0 ), - m_value( value ) - {} - - Approx Approx::custom() { - return Approx( 0 ); - } - - std::string Approx::toString() const { - ReusableStringStream rss; - rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; - return rss.str(); - } - - bool Approx::equalityComparisonImpl(const double other) const { - // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value - // Thanks to Richard Harris for his help refining the scaled margin value - return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); - } - -} // end namespace Detail - -std::string StringMaker::convert(Catch::Detail::Approx const& value) { - return value.toString(); -} - -} // end namespace Catch -// end catch_approx.cpp -// start catch_assertionhandler.cpp - -// start catch_context.h - -#include - -namespace Catch { - - struct IResultCapture; - struct IRunner; - struct IConfig; - struct IMutableContext; - - using IConfigPtr = std::shared_ptr; - - struct IContext - { - virtual ~IContext(); - - virtual IResultCapture* getResultCapture() = 0; - virtual IRunner* getRunner() = 0; - virtual IConfigPtr const& getConfig() const = 0; - }; - - struct IMutableContext : IContext - { - virtual ~IMutableContext(); - virtual void setResultCapture( IResultCapture* resultCapture ) = 0; - virtual void setRunner( IRunner* runner ) = 0; - virtual void setConfig( IConfigPtr const& config ) = 0; - - private: - static IMutableContext *currentContext; - friend IMutableContext& getCurrentMutableContext(); - friend void cleanUpContext(); - static void createContext(); - }; - - inline IMutableContext& getCurrentMutableContext() - { - if( !IMutableContext::currentContext ) - IMutableContext::createContext(); - return *IMutableContext::currentContext; - } - - inline IContext& getCurrentContext() - { - return getCurrentMutableContext(); - } - - void cleanUpContext(); -} - -// end catch_context.h -// start catch_debugger.h - -namespace Catch { - bool isDebuggerActive(); -} - -#ifdef CATCH_PLATFORM_MAC - - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ - -#elif defined(CATCH_PLATFORM_LINUX) - // If we can use inline assembler, do it because this allows us to break - // directly at the location of the failing check instead of breaking inside - // raise() called from it, i.e. one stack frame below. - #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) - #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ - #else // Fall back to the generic way. - #include - - #define CATCH_TRAP() raise(SIGTRAP) - #endif -#elif defined(_MSC_VER) - #define CATCH_TRAP() __debugbreak() -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) void __stdcall DebugBreak(); - #define CATCH_TRAP() DebugBreak() -#endif - -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } -#else - namespace Catch { - inline void doNothing() {} - } - #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() -#endif - -// end catch_debugger.h -// start catch_run_context.h - -// start catch_fatal_condition.h - -// start catch_windows_h_proxy.h - - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -#ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif - -#endif // defined(CATCH_PLATFORM_WINDOWS) - -// end catch_windows_h_proxy.h -#if defined( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); - FatalConditionHandler(); - static void reset(); - ~FatalConditionHandler(); - - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); - - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); - }; - -} // namespace Catch - -#else - -namespace Catch { - struct FatalConditionHandler { - void reset(); - }; -} - -#endif - -// end catch_fatal_condition.h -#include - -namespace Catch { - - struct IMutableContext; - - /////////////////////////////////////////////////////////////////////////// - - class RunContext : public IResultCapture, public IRunner { - - public: - RunContext( RunContext const& ) = delete; - RunContext& operator =( RunContext const& ) = delete; - - explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); - - ~RunContext() override; - - void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); - void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); - - Totals runTest(TestCase const& testCase); - - IConfigPtr config() const; - IStreamingReporter& reporter() const; - - public: // IResultCapture - - // Assertion handlers - void handleExpr - ( AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction ) override; - void handleMessage - ( AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef const& message, - AssertionReaction& reaction ) override; - void handleUnexpectedExceptionNotThrown - ( AssertionInfo const& info, - AssertionReaction& reaction ) override; - void handleUnexpectedInflightException - ( AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction ) override; - void handleIncomplete - ( AssertionInfo const& info ) override; - void handleNonExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction ) override; - - bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; - - void sectionEnded( SectionEndInfo const& endInfo ) override; - void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - - void benchmarkStarting( BenchmarkInfo const& info ) override; - void benchmarkEnded( BenchmarkStats const& stats ) override; - - void pushScopedMessage( MessageInfo const& message ) override; - void popScopedMessage( MessageInfo const& message ) override; - - std::string getCurrentTestName() const override; - - const AssertionResult* getLastResult() const override; - - void exceptionEarlyReported() override; - - void handleFatalErrorCondition( StringRef message ) override; - - bool lastAssertionPassed() override; - - void assertionPassed() override; - - public: - // !TBD We need to do this another way! - bool aborting() const final; - - private: - - void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); - void invokeActiveTestCase(); - - void resetAssertionInfo(); - bool testForMissingAssertions( Counts& assertions ); - - void assertionEnded( AssertionResult const& result ); - void reportExpr - ( AssertionInfo const &info, - ResultWas::OfType resultType, - ITransientExpression const *expr, - bool negated ); - - void populateReaction( AssertionReaction& reaction ); - - private: - - void handleUnfinishedSections(); - - TestRunInfo m_runInfo; - IMutableContext& m_context; - TestCase const* m_activeTestCase = nullptr; - ITracker* m_testCaseTracker; - Option m_lastResult; - - IConfigPtr m_config; - Totals m_totals; - IStreamingReporterPtr m_reporter; - std::vector m_messages; - AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; - std::vector m_activeSections; - TrackerContext m_trackerContext; - bool m_lastAssertionPassed = false; - bool m_shouldReportUnexpected = true; - bool m_includeSuccessfulResults; - }; - -} // end namespace Catch - -// end catch_run_context.h -namespace Catch { - - auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { - expr.streamReconstructedExpression( os ); - return os; - } - - LazyExpression::LazyExpression( bool isNegated ) - : m_isNegated( isNegated ) - {} - - LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} - - LazyExpression::operator bool() const { - return m_transientExpression != nullptr; - } - - auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { - if( lazyExpr.m_isNegated ) - os << "!"; - - if( lazyExpr ) { - if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) - os << "(" << *lazyExpr.m_transientExpression << ")"; - else - os << *lazyExpr.m_transientExpression; - } - else { - os << "{** error - unchecked empty expression requested **}"; - } - return os; - } - - AssertionHandler::AssertionHandler - ( StringRef macroName, - SourceLineInfo const& lineInfo, - StringRef capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, - m_resultCapture( getResultCapture() ) - {} - - void AssertionHandler::handleExpr( ITransientExpression const& expr ) { - m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); - } - void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { - m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); - } - - auto AssertionHandler::allowThrows() const -> bool { - return getCurrentContext().getConfig()->allowThrows(); - } - - void AssertionHandler::complete() { - setCompleted(); - if( m_reaction.shouldDebugBreak ) { - - // If you find your debugger stopping you here then go one level up on the - // call-stack for the code that caused it (typically a failed assertion) - - // (To go back to the test and change execution, jump over the throw, next) - CATCH_BREAK_INTO_DEBUGGER(); - } - if( m_reaction.shouldThrow ) - throw Catch::TestFailureException(); - } - void AssertionHandler::setCompleted() { - m_completed = true; - } - - void AssertionHandler::handleUnexpectedInflightException() { - m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); - } - - void AssertionHandler::handleExceptionThrownAsExpected() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - void AssertionHandler::handleExceptionNotThrownAsExpected() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - - void AssertionHandler::handleUnexpectedExceptionNotThrown() { - m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); - } - - void AssertionHandler::handleThrowingCallSkipped() { - m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); - } - - // This is the overload that takes a string and infers the Equals matcher from it - // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp - void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString ) { - handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); - } - -} // namespace Catch -// end catch_assertionhandler.cpp -// start catch_assertionresult.cpp - -namespace Catch { - AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): - lazyExpression(_lazyExpression), - resultType(_resultType) {} - - std::string AssertionResultData::reconstructExpression() const { - - if( reconstructedExpression.empty() ) { - if( lazyExpression ) { - ReusableStringStream rss; - rss << lazyExpression; - reconstructedExpression = rss.str(); - } - } - return reconstructedExpression; - } - - AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) - : m_info( info ), - m_resultData( data ) - {} - - // Result was a success - bool AssertionResult::succeeded() const { - return Catch::isOk( m_resultData.resultType ); - } - - // Result was a success, or failure is suppressed - bool AssertionResult::isOk() const { - return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); - } - - ResultWas::OfType AssertionResult::getResultType() const { - return m_resultData.resultType; - } - - bool AssertionResult::hasExpression() const { - return m_info.capturedExpression[0] != 0; - } - - bool AssertionResult::hasMessage() const { - return !m_resultData.message.empty(); - } - - std::string AssertionResult::getExpression() const { - if( isFalseTest( m_info.resultDisposition ) ) - return "!(" + m_info.capturedExpression + ")"; - else - return m_info.capturedExpression; - } - - std::string AssertionResult::getExpressionInMacro() const { - std::string expr; - if( m_info.macroName[0] == 0 ) - expr = m_info.capturedExpression; - else { - expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); - expr += m_info.macroName; - expr += "( "; - expr += m_info.capturedExpression; - expr += " )"; - } - return expr; - } - - bool AssertionResult::hasExpandedExpression() const { - return hasExpression() && getExpandedExpression() != getExpression(); - } - - std::string AssertionResult::getExpandedExpression() const { - std::string expr = m_resultData.reconstructExpression(); - return expr.empty() - ? getExpression() - : expr; - } - - std::string AssertionResult::getMessage() const { - return m_resultData.message; - } - SourceLineInfo AssertionResult::getSourceInfo() const { - return m_info.lineInfo; - } - - StringRef AssertionResult::getTestMacroName() const { - return m_info.macroName; - } - -} // end namespace Catch -// end catch_assertionresult.cpp -// start catch_benchmark.cpp - -namespace Catch { - - auto BenchmarkLooper::getResolution() -> uint64_t { - return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); - } - - void BenchmarkLooper::reportStart() { - getResultCapture().benchmarkStarting( { m_name } ); - } - auto BenchmarkLooper::needsMoreIterations() -> bool { - auto elapsed = m_timer.getElapsedNanoseconds(); - - // Exponentially increasing iterations until we're confident in our timer resolution - if( elapsed < m_resolution ) { - m_iterationsToRun *= 10; - return true; - } - - getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); - return false; - } - -} // end namespace Catch -// end catch_benchmark.cpp -// start catch_capture_matchers.cpp - -namespace Catch { - - using StringMatcher = Matchers::Impl::MatcherBase; - - // This is the general overload that takes a any string matcher - // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers - // the Equals matcher (so the header does not mention matchers) - void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString ) { - std::string exceptionMessage = Catch::translateActiveException(); - MatchExpr expr( exceptionMessage, matcher, matcherString ); - handler.handleExpr( expr ); - } - -} // namespace Catch -// end catch_capture_matchers.cpp -// start catch_commandline.cpp - -// start catch_commandline.h - -// start catch_clara.h - -// Use Catch's value for console width (store Clara's off to the side, if present) -#ifdef CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#endif -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wweak-vtables" -#pragma clang diagnostic ignored "-Wexit-time-destructors" -#pragma clang diagnostic ignored "-Wshadow" -#endif - -// start clara.hpp -// Copyright 2017 Two Blue Cubes Ltd. All rights reserved. -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// See https://github.com/philsquared/Clara for more details - -// Clara v1.1.4 - - -#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 -#endif - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -#ifndef CLARA_CONFIG_OPTIONAL_TYPE -#ifdef __has_include -#if __has_include() && __cplusplus >= 201703L -#include -#define CLARA_CONFIG_OPTIONAL_TYPE std::optional -#endif -#endif -#endif - -// ----------- #included from clara_textflow.hpp ----------- - -// TextFlowCpp -// -// A single-header library for wrapping and laying out basic text, by Phil Nash -// -// This work is licensed under the BSD 2-Clause license. -// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause -// -// This project is hosted at https://github.com/philsquared/textflowcpp - - -#include -#include -#include -#include - -#ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 -#endif - -namespace Catch { namespace clara { namespace TextFlow { - - inline auto isWhitespace( char c ) -> bool { - static std::string chars = " \t\n\r"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableBefore( char c ) -> bool { - static std::string chars = "[({<|"; - return chars.find( c ) != std::string::npos; - } - inline auto isBreakableAfter( char c ) -> bool { - static std::string chars = "])}>.,:;*+-=&/\\"; - return chars.find( c ) != std::string::npos; - } - - class Columns; - - class Column { - std::vector m_strings; - size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; - size_t m_indent = 0; - size_t m_initialIndent = std::string::npos; - - public: - class iterator { - friend Column; - - Column const& m_column; - size_t m_stringIndex = 0; - size_t m_pos = 0; - - size_t m_len = 0; - size_t m_end = 0; - bool m_suffix = false; - - iterator( Column const& column, size_t stringIndex ) - : m_column( column ), - m_stringIndex( stringIndex ) - {} - - auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } - - auto isBoundary( size_t at ) const -> bool { - assert( at > 0 ); - assert( at <= line().size() ); - - return at == line().size() || - ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || - isBreakableBefore( line()[at] ) || - isBreakableAfter( line()[at-1] ); - } - - void calcLength() { - assert( m_stringIndex < m_column.m_strings.size() ); - - m_suffix = false; - auto width = m_column.m_width-indent(); - m_end = m_pos; - while( m_end < line().size() && line()[m_end] != '\n' ) - ++m_end; - - if( m_end < m_pos + width ) { - m_len = m_end - m_pos; - } - else { - size_t len = width; - while (len > 0 && !isBoundary(m_pos + len)) - --len; - while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) - --len; - - if (len > 0) { - m_len = len; - } else { - m_suffix = true; - m_len = width - 1; - } - } - } - - auto indent() const -> size_t { - auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; - return initial == std::string::npos ? m_column.m_indent : initial; - } - - auto addIndentAndSuffix(std::string const &plain) const -> std::string { - return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); - } - - public: - explicit iterator( Column const& column ) : m_column( column ) { - assert( m_column.m_width > m_column.m_indent ); - assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); - calcLength(); - if( m_len == 0 ) - m_stringIndex++; // Empty string - } - - auto operator *() const -> std::string { - assert( m_stringIndex < m_column.m_strings.size() ); - assert( m_pos <= m_end ); - if( m_pos + m_column.m_width < m_end ) - return addIndentAndSuffix(line().substr(m_pos, m_len)); - else - return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); - } - - auto operator ++() -> iterator& { - m_pos += m_len; - if( m_pos < line().size() && line()[m_pos] == '\n' ) - m_pos += 1; - else - while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) - ++m_pos; - - if( m_pos == line().size() ) { - m_pos = 0; - ++m_stringIndex; - } - if( m_stringIndex < m_column.m_strings.size() ) - calcLength(); - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - - auto operator ==( iterator const& other ) const -> bool { - return - m_pos == other.m_pos && - m_stringIndex == other.m_stringIndex && - &m_column == &other.m_column; - } - auto operator !=( iterator const& other ) const -> bool { - return !operator==( other ); - } - }; - using const_iterator = iterator; - - explicit Column( std::string const& text ) { m_strings.push_back( text ); } - - auto width( size_t newWidth ) -> Column& { - assert( newWidth > 0 ); - m_width = newWidth; - return *this; - } - auto indent( size_t newIndent ) -> Column& { - m_indent = newIndent; - return *this; - } - auto initialIndent( size_t newIndent ) -> Column& { - m_initialIndent = newIndent; - return *this; - } - - auto width() const -> size_t { return m_width; } - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, m_strings.size() }; } - - inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { - bool first = true; - for( auto line : col ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto operator + ( Column const& other ) -> Columns; - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; - - class Spacer : public Column { - - public: - explicit Spacer( size_t spaceWidth ) : Column( "" ) { - width( spaceWidth ); - } - }; - - class Columns { - std::vector m_columns; - - public: - - class iterator { - friend Columns; - struct EndTag {}; - - std::vector const& m_columns; - std::vector m_iterators; - size_t m_activeIterators; - - iterator( Columns const& columns, EndTag ) - : m_columns( columns.m_columns ), - m_activeIterators( 0 ) - { - m_iterators.reserve( m_columns.size() ); - - for( auto const& col : m_columns ) - m_iterators.push_back( col.end() ); - } - - public: - explicit iterator( Columns const& columns ) - : m_columns( columns.m_columns ), - m_activeIterators( m_columns.size() ) - { - m_iterators.reserve( m_columns.size() ); - - for( auto const& col : m_columns ) - m_iterators.push_back( col.begin() ); - } - - auto operator ==( iterator const& other ) const -> bool { - return m_iterators == other.m_iterators; - } - auto operator !=( iterator const& other ) const -> bool { - return m_iterators != other.m_iterators; - } - auto operator *() const -> std::string { - std::string row, padding; - - for( size_t i = 0; i < m_columns.size(); ++i ) { - auto width = m_columns[i].width(); - if( m_iterators[i] != m_columns[i].end() ) { - std::string col = *m_iterators[i]; - row += padding + col; - if( col.size() < width ) - padding = std::string( width - col.size(), ' ' ); - else - padding = ""; - } - else { - padding += std::string( width, ' ' ); - } - } - return row; - } - auto operator ++() -> iterator& { - for( size_t i = 0; i < m_columns.size(); ++i ) { - if (m_iterators[i] != m_columns[i].end()) - ++m_iterators[i]; - } - return *this; - } - auto operator ++(int) -> iterator { - iterator prev( *this ); - operator++(); - return prev; - } - }; - using const_iterator = iterator; - - auto begin() const -> iterator { return iterator( *this ); } - auto end() const -> iterator { return { *this, iterator::EndTag() }; } - - auto operator += ( Column const& col ) -> Columns& { - m_columns.push_back( col ); - return *this; - } - auto operator + ( Column const& col ) -> Columns { - Columns combined = *this; - combined += col; - return combined; - } - - inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { - - bool first = true; - for( auto line : cols ) { - if( first ) - first = false; - else - os << "\n"; - os << line; - } - return os; - } - - auto toString() const -> std::string { - std::ostringstream oss; - oss << *this; - return oss.str(); - } - }; - - inline auto Column::operator + ( Column const& other ) -> Columns { - Columns cols; - cols += *this; - cols += other; - return cols; - } -}}} // namespace Catch::clara::TextFlow - -// ----------- end of #include from clara_textflow.hpp ----------- -// ........... back in clara.hpp - -#include -#include -#include - -#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) -#define CATCH_PLATFORM_WINDOWS -#endif - -namespace Catch { namespace clara { -namespace detail { - - // Traits for extracting arg and return type of lambdas (for single argument lambdas) - template - struct UnaryLambdaTraits : UnaryLambdaTraits {}; - - template - struct UnaryLambdaTraits { - static const bool isValid = false; - }; - - template - struct UnaryLambdaTraits { - static const bool isValid = true; - using ArgType = typename std::remove_const::type>::type; - using ReturnType = ReturnT; - }; - - class TokenStream; - - // Transport for raw args (copied from main args, or supplied via init list for testing) - class Args { - friend TokenStream; - std::string m_exeName; - std::vector m_args; - - public: - Args( int argc, char const* const* argv ) - : m_exeName(argv[0]), - m_args(argv + 1, argv + argc) {} - - Args( std::initializer_list args ) - : m_exeName( *args.begin() ), - m_args( args.begin()+1, args.end() ) - {} - - auto exeName() const -> std::string { - return m_exeName; - } - }; - - // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string - // may encode an option + its argument if the : or = form is used - enum class TokenType { - Option, Argument - }; - struct Token { - TokenType type; - std::string token; - }; - - inline auto isOptPrefix( char c ) -> bool { - return c == '-' -#ifdef CATCH_PLATFORM_WINDOWS - || c == '/' -#endif - ; - } - - // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled - class TokenStream { - using Iterator = std::vector::const_iterator; - Iterator it; - Iterator itEnd; - std::vector m_tokenBuffer; - - void loadBuffer() { - m_tokenBuffer.resize( 0 ); - - // Skip any empty strings - while( it != itEnd && it->empty() ) - ++it; - - if( it != itEnd ) { - auto const &next = *it; - if( isOptPrefix( next[0] ) ) { - auto delimiterPos = next.find_first_of( " :=" ); - if( delimiterPos != std::string::npos ) { - m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); - m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); - } else { - if( next[1] != '-' && next.size() > 2 ) { - std::string opt = "- "; - for( size_t i = 1; i < next.size(); ++i ) { - opt[1] = next[i]; - m_tokenBuffer.push_back( { TokenType::Option, opt } ); - } - } else { - m_tokenBuffer.push_back( { TokenType::Option, next } ); - } - } - } else { - m_tokenBuffer.push_back( { TokenType::Argument, next } ); - } - } - } - - public: - explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} - - TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { - loadBuffer(); - } - - explicit operator bool() const { - return !m_tokenBuffer.empty() || it != itEnd; - } - - auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } - - auto operator*() const -> Token { - assert( !m_tokenBuffer.empty() ); - return m_tokenBuffer.front(); - } - - auto operator->() const -> Token const * { - assert( !m_tokenBuffer.empty() ); - return &m_tokenBuffer.front(); - } - - auto operator++() -> TokenStream & { - if( m_tokenBuffer.size() >= 2 ) { - m_tokenBuffer.erase( m_tokenBuffer.begin() ); - } else { - if( it != itEnd ) - ++it; - loadBuffer(); - } - return *this; - } - }; - - class ResultBase { - public: - enum Type { - Ok, LogicError, RuntimeError - }; - - protected: - ResultBase( Type type ) : m_type( type ) {} - virtual ~ResultBase() = default; - - virtual void enforceOk() const = 0; - - Type m_type; - }; - - template - class ResultValueBase : public ResultBase { - public: - auto value() const -> T const & { - enforceOk(); - return m_value; - } - - protected: - ResultValueBase( Type type ) : ResultBase( type ) {} - - ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - } - - ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { - new( &m_value ) T( value ); - } - - auto operator=( ResultValueBase const &other ) -> ResultValueBase & { - if( m_type == ResultBase::Ok ) - m_value.~T(); - ResultBase::operator=(other); - if( m_type == ResultBase::Ok ) - new( &m_value ) T( other.m_value ); - return *this; - } - - ~ResultValueBase() override { - if( m_type == Ok ) - m_value.~T(); - } - - union { - T m_value; - }; - }; - - template<> - class ResultValueBase : public ResultBase { - protected: - using ResultBase::ResultBase; - }; - - template - class BasicResult : public ResultValueBase { - public: - template - explicit BasicResult( BasicResult const &other ) - : ResultValueBase( other.type() ), - m_errorMessage( other.errorMessage() ) - { - assert( type() != ResultBase::Ok ); - } - - template - static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } - static auto ok() -> BasicResult { return { ResultBase::Ok }; } - static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } - static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } - - explicit operator bool() const { return m_type == ResultBase::Ok; } - auto type() const -> ResultBase::Type { return m_type; } - auto errorMessage() const -> std::string { return m_errorMessage; } - - protected: - void enforceOk() const override { - - // Errors shouldn't reach this point, but if they do - // the actual error message will be in m_errorMessage - assert( m_type != ResultBase::LogicError ); - assert( m_type != ResultBase::RuntimeError ); - if( m_type != ResultBase::Ok ) - std::abort(); - } - - std::string m_errorMessage; // Only populated if resultType is an error - - BasicResult( ResultBase::Type type, std::string const &message ) - : ResultValueBase(type), - m_errorMessage(message) - { - assert( m_type != ResultBase::Ok ); - } - - using ResultValueBase::ResultValueBase; - using ResultBase::m_type; - }; - - enum class ParseResultType { - Matched, NoMatch, ShortCircuitAll, ShortCircuitSame - }; - - class ParseState { - public: - - ParseState( ParseResultType type, TokenStream const &remainingTokens ) - : m_type(type), - m_remainingTokens( remainingTokens ) - {} - - auto type() const -> ParseResultType { return m_type; } - auto remainingTokens() const -> TokenStream { return m_remainingTokens; } - - private: - ParseResultType m_type; - TokenStream m_remainingTokens; - }; - - using Result = BasicResult; - using ParserResult = BasicResult; - using InternalParseResult = BasicResult; - - struct HelpColumns { - std::string left; - std::string right; - }; - - template - inline auto convertInto( std::string const &source, T& target ) -> ParserResult { - std::stringstream ss; - ss << source; - ss >> target; - if( ss.fail() ) - return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { - target = source; - return ParserResult::ok( ParseResultType::Matched ); - } - inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { - std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( ::tolower(c) ); } ); - if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") - target = true; - else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") - target = false; - else - return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - } -#ifdef CLARA_CONFIG_OPTIONAL_TYPE - template - inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE& target ) -> ParserResult { - T temp; - auto result = convertInto( source, temp ); - if( result ) - target = std::move(temp); - return result; - } -#endif // CLARA_CONFIG_OPTIONAL_TYPE - - struct NonCopyable { - NonCopyable() = default; - NonCopyable( NonCopyable const & ) = delete; - NonCopyable( NonCopyable && ) = delete; - NonCopyable &operator=( NonCopyable const & ) = delete; - NonCopyable &operator=( NonCopyable && ) = delete; - }; - - struct BoundRef : NonCopyable { - virtual ~BoundRef() = default; - virtual auto isContainer() const -> bool { return false; } - virtual auto isFlag() const -> bool { return false; } - }; - struct BoundValueRefBase : BoundRef { - virtual auto setValue( std::string const &arg ) -> ParserResult = 0; - }; - struct BoundFlagRefBase : BoundRef { - virtual auto setFlag( bool flag ) -> ParserResult = 0; - virtual auto isFlag() const -> bool { return true; } - }; - - template - struct BoundValueRef : BoundValueRefBase { - T &m_ref; - - explicit BoundValueRef( T &ref ) : m_ref( ref ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return convertInto( arg, m_ref ); - } - }; - - template - struct BoundValueRef> : BoundValueRefBase { - std::vector &m_ref; - - explicit BoundValueRef( std::vector &ref ) : m_ref( ref ) {} - - auto isContainer() const -> bool override { return true; } - - auto setValue( std::string const &arg ) -> ParserResult override { - T temp; - auto result = convertInto( arg, temp ); - if( result ) - m_ref.push_back( temp ); - return result; - } - }; - - struct BoundFlagRef : BoundFlagRefBase { - bool &m_ref; - - explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} - - auto setFlag( bool flag ) -> ParserResult override { - m_ref = flag; - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - struct LambdaInvoker { - static_assert( std::is_same::value, "Lambda must return void or clara::ParserResult" ); - - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - return lambda( arg ); - } - }; - - template<> - struct LambdaInvoker { - template - static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { - lambda( arg ); - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - template - inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { - ArgType temp{}; - auto result = convertInto( arg, temp ); - return !result - ? result - : LambdaInvoker::ReturnType>::invoke( lambda, temp ); - } - - template - struct BoundLambda : BoundValueRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setValue( std::string const &arg ) -> ParserResult override { - return invokeLambda::ArgType>( m_lambda, arg ); - } - }; - - template - struct BoundFlagLambda : BoundFlagRefBase { - L m_lambda; - - static_assert( UnaryLambdaTraits::isValid, "Supplied lambda must take exactly one argument" ); - static_assert( std::is_same::ArgType, bool>::value, "flags must be boolean" ); - - explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} - - auto setFlag( bool flag ) -> ParserResult override { - return LambdaInvoker::ReturnType>::invoke( m_lambda, flag ); - } - }; - - enum class Optionality { Optional, Required }; - - struct Parser; - - class ParserBase { - public: - virtual ~ParserBase() = default; - virtual auto validate() const -> Result { return Result::ok(); } - virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; - virtual auto cardinality() const -> size_t { return 1; } - - auto parse( Args const &args ) const -> InternalParseResult { - return parse( args.exeName(), TokenStream( args ) ); - } - }; - - template - class ComposableParserImpl : public ParserBase { - public: - template - auto operator|( T const &other ) const -> Parser; - - template - auto operator+( T const &other ) const -> Parser; - }; - - // Common code and state for Args and Opts - template - class ParserRefImpl : public ComposableParserImpl { - protected: - Optionality m_optionality = Optionality::Optional; - std::shared_ptr m_ref; - std::string m_hint; - std::string m_description; - - explicit ParserRefImpl( std::shared_ptr const &ref ) : m_ref( ref ) {} - - public: - template - ParserRefImpl( T &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint( hint ) - {} - - template - ParserRefImpl( LambdaT const &ref, std::string const &hint ) - : m_ref( std::make_shared>( ref ) ), - m_hint(hint) - {} - - auto operator()( std::string const &description ) -> DerivedT & { - m_description = description; - return static_cast( *this ); - } - - auto optional() -> DerivedT & { - m_optionality = Optionality::Optional; - return static_cast( *this ); - }; - - auto required() -> DerivedT & { - m_optionality = Optionality::Required; - return static_cast( *this ); - }; - - auto isOptional() const -> bool { - return m_optionality == Optionality::Optional; - } - - auto cardinality() const -> size_t override { - if( m_ref->isContainer() ) - return 0; - else - return 1; - } - - auto hint() const -> std::string { return m_hint; } - }; - - class ExeName : public ComposableParserImpl { - std::shared_ptr m_name; - std::shared_ptr m_ref; - - template - static auto makeRef(LambdaT const &lambda) -> std::shared_ptr { - return std::make_shared>( lambda) ; - } - - public: - ExeName() : m_name( std::make_shared( "" ) ) {} - - explicit ExeName( std::string &ref ) : ExeName() { - m_ref = std::make_shared>( ref ); - } - - template - explicit ExeName( LambdaT const& lambda ) : ExeName() { - m_ref = std::make_shared>( lambda ); - } - - // The exe name is not parsed out of the normal tokens, but is handled specially - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - } - - auto name() const -> std::string { return *m_name; } - auto set( std::string const& newName ) -> ParserResult { - - auto lastSlash = newName.find_last_of( "\\/" ); - auto filename = ( lastSlash == std::string::npos ) - ? newName - : newName.substr( lastSlash+1 ); - - *m_name = filename; - if( m_ref ) - return m_ref->setValue( filename ); - else - return ParserResult::ok( ParseResultType::Matched ); - } - }; - - class Arg : public ParserRefImpl { - public: - using ParserRefImpl::ParserRefImpl; - - auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - auto const &token = *remainingTokens; - if( token.type != TokenType::Argument ) - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - - assert( !m_ref->isFlag() ); - auto valueRef = static_cast( m_ref.get() ); - - auto result = valueRef->setValue( remainingTokens->token ); - if( !result ) - return InternalParseResult( result ); - else - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - }; - - inline auto normaliseOpt( std::string const &optName ) -> std::string { -#ifdef CATCH_PLATFORM_WINDOWS - if( optName[0] == '/' ) - return "-" + optName.substr( 1 ); - else -#endif - return optName; - } - - class Opt : public ParserRefImpl { - protected: - std::vector m_optNames; - - public: - template - explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared>( ref ) ) {} - - explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared( ref ) ) {} - - template - Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - - template - Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} - - auto operator[]( std::string const &optName ) -> Opt & { - m_optNames.push_back( optName ); - return *this; - } - - auto getHelpColumns() const -> std::vector { - std::ostringstream oss; - bool first = true; - for( auto const &opt : m_optNames ) { - if (first) - first = false; - else - oss << ", "; - oss << opt; - } - if( !m_hint.empty() ) - oss << " <" << m_hint << ">"; - return { { oss.str(), m_description } }; - } - - auto isMatch( std::string const &optToken ) const -> bool { - auto normalisedToken = normaliseOpt( optToken ); - for( auto const &name : m_optNames ) { - if( normaliseOpt( name ) == normalisedToken ) - return true; - } - return false; - } - - using ParserBase::parse; - - auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { - auto validationResult = validate(); - if( !validationResult ) - return InternalParseResult( validationResult ); - - auto remainingTokens = tokens; - if( remainingTokens && remainingTokens->type == TokenType::Option ) { - auto const &token = *remainingTokens; - if( isMatch(token.token ) ) { - if( m_ref->isFlag() ) { - auto flagRef = static_cast( m_ref.get() ); - auto result = flagRef->setFlag( true ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } else { - auto valueRef = static_cast( m_ref.get() ); - ++remainingTokens; - if( !remainingTokens ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto const &argToken = *remainingTokens; - if( argToken.type != TokenType::Argument ) - return InternalParseResult::runtimeError( "Expected argument following " + token.token ); - auto result = valueRef->setValue( argToken.token ); - if( !result ) - return InternalParseResult( result ); - if( result.value() == ParseResultType::ShortCircuitAll ) - return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); - } - return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); - } - } - return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); - } - - auto validate() const -> Result override { - if( m_optNames.empty() ) - return Result::logicError( "No options supplied to Opt" ); - for( auto const &name : m_optNames ) { - if( name.empty() ) - return Result::logicError( "Option name cannot be empty" ); -#ifdef CATCH_PLATFORM_WINDOWS - if( name[0] != '-' && name[0] != '/' ) - return Result::logicError( "Option name must begin with '-' or '/'" ); -#else - if( name[0] != '-' ) - return Result::logicError( "Option name must begin with '-'" ); -#endif - } - return ParserRefImpl::validate(); - } - }; - - struct Help : Opt { - Help( bool &showHelpFlag ) - : Opt([&]( bool flag ) { - showHelpFlag = flag; - return ParserResult::ok( ParseResultType::ShortCircuitAll ); - }) - { - static_cast( *this ) - ("display usage information") - ["-?"]["-h"]["--help"] - .optional(); - } - }; - - struct Parser : ParserBase { - - mutable ExeName m_exeName; - std::vector m_options; - std::vector m_args; - - auto operator|=( ExeName const &exeName ) -> Parser & { - m_exeName = exeName; - return *this; - } - - auto operator|=( Arg const &arg ) -> Parser & { - m_args.push_back(arg); - return *this; - } - - auto operator|=( Opt const &opt ) -> Parser & { - m_options.push_back(opt); - return *this; - } - - auto operator|=( Parser const &other ) -> Parser & { - m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); - m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); - return *this; - } - - template - auto operator|( T const &other ) const -> Parser { - return Parser( *this ) |= other; - } - - // Forward deprecated interface with '+' instead of '|' - template - auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } - template - auto operator+( T const &other ) const -> Parser { return operator|( other ); } - - auto getHelpColumns() const -> std::vector { - std::vector cols; - for (auto const &o : m_options) { - auto childCols = o.getHelpColumns(); - cols.insert( cols.end(), childCols.begin(), childCols.end() ); - } - return cols; - } - - void writeToStream( std::ostream &os ) const { - if (!m_exeName.name().empty()) { - os << "usage:\n" << " " << m_exeName.name() << " "; - bool required = true, first = true; - for( auto const &arg : m_args ) { - if (first) - first = false; - else - os << " "; - if( arg.isOptional() && required ) { - os << "["; - required = false; - } - os << "<" << arg.hint() << ">"; - if( arg.cardinality() == 0 ) - os << " ... "; - } - if( !required ) - os << "]"; - if( !m_options.empty() ) - os << " options"; - os << "\n\nwhere options are:" << std::endl; - } - - auto rows = getHelpColumns(); - size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; - size_t optWidth = 0; - for( auto const &cols : rows ) - optWidth = (std::max)(optWidth, cols.left.size() + 2); - - optWidth = (std::min)(optWidth, consoleWidth/2); - - for( auto const &cols : rows ) { - auto row = - TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + - TextFlow::Spacer(4) + - TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); - os << row << std::endl; - } - } - - friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { - parser.writeToStream( os ); - return os; - } - - auto validate() const -> Result override { - for( auto const &opt : m_options ) { - auto result = opt.validate(); - if( !result ) - return result; - } - for( auto const &arg : m_args ) { - auto result = arg.validate(); - if( !result ) - return result; - } - return Result::ok(); - } - - using ParserBase::parse; - - auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { - - struct ParserInfo { - ParserBase const* parser = nullptr; - size_t count = 0; - }; - const size_t totalParsers = m_options.size() + m_args.size(); - assert( totalParsers < 512 ); - // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do - ParserInfo parseInfos[512]; - - { - size_t i = 0; - for (auto const &opt : m_options) parseInfos[i++].parser = &opt; - for (auto const &arg : m_args) parseInfos[i++].parser = &arg; - } - - m_exeName.set( exeName ); - - auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); - while( result.value().remainingTokens() ) { - bool tokenParsed = false; - - for( size_t i = 0; i < totalParsers; ++i ) { - auto& parseInfo = parseInfos[i]; - if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { - result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); - if (!result) - return result; - if (result.value().type() != ParseResultType::NoMatch) { - tokenParsed = true; - ++parseInfo.count; - break; - } - } - } - - if( result.value().type() == ParseResultType::ShortCircuitAll ) - return result; - if( !tokenParsed ) - return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); - } - // !TBD Check missing required options - return result; - } - }; - - template - template - auto ComposableParserImpl::operator|( T const &other ) const -> Parser { - return Parser() | static_cast( *this ) | other; - } -} // namespace detail - -// A Combined parser -using detail::Parser; - -// A parser for options -using detail::Opt; - -// A parser for arguments -using detail::Arg; - -// Wrapper for argc, argv from main() -using detail::Args; - -// Specifies the name of the executable -using detail::ExeName; - -// Convenience wrapper for option parser that specifies the help option -using detail::Help; - -// enum of result types from a parse -using detail::ParseResultType; - -// Result type for parser operation -using detail::ParserResult; - -}} // namespace Catch::clara - -// end clara.hpp -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// Restore Clara's value for console width, if present -#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH -#endif - -// end catch_clara.h -namespace Catch { - - clara::Parser makeCommandLineParser( ConfigData& config ); - -} // end namespace Catch - -// end catch_commandline.h -#include -#include - -namespace Catch { - - clara::Parser makeCommandLineParser( ConfigData& config ) { - - using namespace clara; - - auto const setWarning = [&]( std::string const& warning ) { - auto warningSet = [&]() { - if( warning == "NoAssertions" ) - return WarnAbout::NoAssertions; - - if ( warning == "NoTests" ) - return WarnAbout::NoTests; - - return WarnAbout::Nothing; - }(); - - if (warningSet == WarnAbout::Nothing) - return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); - config.warnings = static_cast( config.warnings | warningSet ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const loadTestNamesFromFile = [&]( std::string const& filename ) { - std::ifstream f( filename.c_str() ); - if( !f.is_open() ) - return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); - - std::string line; - while( std::getline( f, line ) ) { - line = trim(line); - if( !line.empty() && !startsWith( line, '#' ) ) { - if( !startsWith( line, '"' ) ) - line = '"' + line + '"'; - config.testsOrTags.push_back( line + ',' ); - } - } - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setTestOrder = [&]( std::string const& order ) { - if( startsWith( "declared", order ) ) - config.runOrder = RunTests::InDeclarationOrder; - else if( startsWith( "lexical", order ) ) - config.runOrder = RunTests::InLexicographicalOrder; - else if( startsWith( "random", order ) ) - config.runOrder = RunTests::InRandomOrder; - else - return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setRngSeed = [&]( std::string const& seed ) { - if( seed != "time" ) - return clara::detail::convertInto( seed, config.rngSeed ); - config.rngSeed = static_cast( std::time(nullptr) ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setColourUsage = [&]( std::string const& useColour ) { - auto mode = toLower( useColour ); - - if( mode == "yes" ) - config.useColour = UseColour::Yes; - else if( mode == "no" ) - config.useColour = UseColour::No; - else if( mode == "auto" ) - config.useColour = UseColour::Auto; - else - return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setWaitForKeypress = [&]( std::string const& keypress ) { - auto keypressLc = toLower( keypress ); - if( keypressLc == "start" ) - config.waitForKeypress = WaitForKeypress::BeforeStart; - else if( keypressLc == "exit" ) - config.waitForKeypress = WaitForKeypress::BeforeExit; - else if( keypressLc == "both" ) - config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; - else - return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - auto const setVerbosity = [&]( std::string const& verbosity ) { - auto lcVerbosity = toLower( verbosity ); - if( lcVerbosity == "quiet" ) - config.verbosity = Verbosity::Quiet; - else if( lcVerbosity == "normal" ) - config.verbosity = Verbosity::Normal; - else if( lcVerbosity == "high" ) - config.verbosity = Verbosity::High; - else - return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); - return ParserResult::ok( ParseResultType::Matched ); - }; - - auto cli - = ExeName( config.processName ) - | Help( config.showHelp ) - | Opt( config.listTests ) - ["-l"]["--list-tests"] - ( "list all/matching test cases" ) - | Opt( config.listTags ) - ["-t"]["--list-tags"] - ( "list all/matching tags" ) - | Opt( config.showSuccessfulTests ) - ["-s"]["--success"] - ( "include successful tests in output" ) - | Opt( config.shouldDebugBreak ) - ["-b"]["--break"] - ( "break into debugger on failure" ) - | Opt( config.noThrow ) - ["-e"]["--nothrow"] - ( "skip exception tests" ) - | Opt( config.showInvisibles ) - ["-i"]["--invisibles"] - ( "show invisibles (tabs, newlines)" ) - | Opt( config.outputFilename, "filename" ) - ["-o"]["--out"] - ( "output filename" ) - | Opt( config.reporterNames, "name" ) - ["-r"]["--reporter"] - ( "reporter to use (defaults to console)" ) - | Opt( config.name, "name" ) - ["-n"]["--name"] - ( "suite name" ) - | Opt( [&]( bool ){ config.abortAfter = 1; } ) - ["-a"]["--abort"] - ( "abort at first failure" ) - | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) - ["-x"]["--abortx"] - ( "abort after x failures" ) - | Opt( setWarning, "warning name" ) - ["-w"]["--warn"] - ( "enable warnings" ) - | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) - ["-d"]["--durations"] - ( "show test durations" ) - | Opt( loadTestNamesFromFile, "filename" ) - ["-f"]["--input-file"] - ( "load test names to run from a file" ) - | Opt( config.filenamesAsTags ) - ["-#"]["--filenames-as-tags"] - ( "adds a tag for the filename" ) - | Opt( config.sectionsToRun, "section name" ) - ["-c"]["--section"] - ( "specify section to run" ) - | Opt( setVerbosity, "quiet|normal|high" ) - ["-v"]["--verbosity"] - ( "set output verbosity" ) - | Opt( config.listTestNamesOnly ) - ["--list-test-names-only"] - ( "list all/matching test cases names only" ) - | Opt( config.listReporters ) - ["--list-reporters"] - ( "list all reporters" ) - | Opt( setTestOrder, "decl|lex|rand" ) - ["--order"] - ( "test case order (defaults to decl)" ) - | Opt( setRngSeed, "'time'|number" ) - ["--rng-seed"] - ( "set a specific seed for random numbers" ) - | Opt( setColourUsage, "yes|no" ) - ["--use-colour"] - ( "should output be colourised" ) - | Opt( config.libIdentify ) - ["--libidentify"] - ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "start|exit|both" ) - ["--wait-for-keypress"] - ( "waits for a keypress before exiting" ) - | Opt( config.benchmarkResolutionMultiple, "multiplier" ) - ["--benchmark-resolution-multiple"] - ( "multiple of clock resolution to run benchmarks" ) - - | Arg( config.testsOrTags, "test name|pattern|tags" ) - ( "which test or tests to use" ); - - return cli; - } - -} // end namespace Catch -// end catch_commandline.cpp -// start catch_common.cpp - -#include -#include - -namespace Catch { - - bool SourceLineInfo::empty() const noexcept { - return file[0] == '\0'; - } - bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { - return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); - } - bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { - return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); - } - - std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { -#ifndef __GNUG__ - os << info.file << '(' << info.line << ')'; -#else - os << info.file << ':' << info.line; -#endif - return os; - } - - std::string StreamEndStop::operator+() const { - return std::string(); - } - - NonCopyable::NonCopyable() = default; - NonCopyable::~NonCopyable() = default; - -} -// end catch_common.cpp -// start catch_config.cpp - -// start catch_enforce.h - -#include - -#define CATCH_PREPARE_EXCEPTION( type, msg ) \ - type( ( Catch::ReusableStringStream() << msg ).str() ) -#define CATCH_INTERNAL_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg); -#define CATCH_ERROR( msg ) \ - throw CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) -#define CATCH_ENFORCE( condition, msg ) \ - do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) - -// end catch_enforce.h -namespace Catch { - - Config::Config( ConfigData const& data ) - : m_data( data ), - m_stream( openStream() ) - { - TestSpecParser parser(ITagAliasRegistry::get()); - if (data.testsOrTags.empty()) { - parser.parse("~[.]"); // All not hidden tests - } - else { - m_hasTestFilters = true; - for( auto const& testOrTags : data.testsOrTags ) - parser.parse( testOrTags ); - } - m_testSpec = parser.testSpec(); - } - - std::string const& Config::getFilename() const { - return m_data.outputFilename ; - } - - bool Config::listTests() const { return m_data.listTests; } - bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } - bool Config::listTags() const { return m_data.listTags; } - bool Config::listReporters() const { return m_data.listReporters; } - - std::string Config::getProcessName() const { return m_data.processName; } - - std::vector const& Config::getReporterNames() const { return m_data.reporterNames; } - std::vector const& Config::getTestsOrTags() const { return m_data.testsOrTags; } - std::vector const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } - - TestSpec const& Config::testSpec() const { return m_testSpec; } - bool Config::hasTestFilters() const { return m_hasTestFilters; } - - bool Config::showHelp() const { return m_data.showHelp; } - - // IConfig interface - bool Config::allowThrows() const { return !m_data.noThrow; } - std::ostream& Config::stream() const { return m_stream->stream(); } - std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } - bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } - bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } - bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } - ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } - RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } - unsigned int Config::rngSeed() const { return m_data.rngSeed; } - int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } - UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } - bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } - int Config::abortAfter() const { return m_data.abortAfter; } - bool Config::showInvisibles() const { return m_data.showInvisibles; } - Verbosity Config::verbosity() const { return m_data.verbosity; } - - IStream const* Config::openStream() { - return Catch::makeStream(m_data.outputFilename); - } - -} // end namespace Catch -// end catch_config.cpp -// start catch_console_colour.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -// start catch_errno_guard.h - -namespace Catch { - - class ErrnoGuard { - public: - ErrnoGuard(); - ~ErrnoGuard(); - private: - int m_oldErrno; - }; - -} - -// end catch_errno_guard.h -#include - -namespace Catch { - namespace { - - struct IColourImpl { - virtual ~IColourImpl() = default; - virtual void use( Colour::Code _colourCode ) = 0; - }; - - struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} - - static IColourImpl* instance() { - static NoColourImpl s_instance; - return &s_instance; - } - }; - - } // anon namespace -} // namespace Catch - -#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) -# ifdef CATCH_PLATFORM_WINDOWS -# define CATCH_CONFIG_COLOUR_WINDOWS -# else -# define CATCH_CONFIG_COLOUR_ANSI -# endif -#endif - -#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// - -namespace Catch { -namespace { - - class Win32ColourImpl : public IColourImpl { - public: - Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) - { - CONSOLE_SCREEN_BUFFER_INFO csbiInfo; - GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); - originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); - } - - virtual void use( Colour::Code _colourCode ) override { - switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalForegroundAttributes ); - case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::Red: return setTextAttribute( FOREGROUND_RED ); - case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); - case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); - case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); - case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); - case Colour::Grey: return setTextAttribute( 0 ); - - case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); - case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); - case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); - case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); - case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); - - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - - default: - CATCH_ERROR( "Unknown colour requested" ); - } - } - - private: - void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); - } - HANDLE stdoutHandle; - WORD originalForegroundAttributes; - WORD originalBackgroundAttributes; - }; - - IColourImpl* platformColourInstance() { - static Win32ColourImpl s_instance; - - IConfigPtr config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = UseColour::Yes; - return colourMode == UseColour::Yes - ? &s_instance - : NoColourImpl::instance(); - } - -} // end anon namespace -} // end namespace Catch - -#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// - -#include - -namespace Catch { -namespace { - - // use POSIX/ ANSI console terminal codes - // Thanks to Adam Strzelecki for original contribution - // (http://github.com/nanoant) - // https://github.com/philsquared/Catch/pull/131 - class PosixColourImpl : public IColourImpl { - public: - virtual void use( Colour::Code _colourCode ) override { - switch( _colourCode ) { - case Colour::None: - case Colour::White: return setColour( "[0m" ); - case Colour::Red: return setColour( "[0;31m" ); - case Colour::Green: return setColour( "[0;32m" ); - case Colour::Blue: return setColour( "[0;34m" ); - case Colour::Cyan: return setColour( "[0;36m" ); - case Colour::Yellow: return setColour( "[0;33m" ); - case Colour::Grey: return setColour( "[1;30m" ); - - case Colour::LightGrey: return setColour( "[0;37m" ); - case Colour::BrightRed: return setColour( "[1;31m" ); - case Colour::BrightGreen: return setColour( "[1;32m" ); - case Colour::BrightWhite: return setColour( "[1;37m" ); - case Colour::BrightYellow: return setColour( "[1;33m" ); - - case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); - default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); - } - } - static IColourImpl* instance() { - static PosixColourImpl s_instance; - return &s_instance; - } - - private: - void setColour( const char* _escapeCode ) { - Catch::cout() << '\033' << _escapeCode; - } - }; - - bool useColourOnPlatform() { - return -#ifdef CATCH_PLATFORM_MAC - !isDebuggerActive() && -#endif -#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) - isatty(STDOUT_FILENO) -#else - false -#endif - ; - } - IColourImpl* platformColourInstance() { - ErrnoGuard guard; - IConfigPtr config = getCurrentContext().getConfig(); - UseColour::YesOrNo colourMode = config - ? config->useColour() - : UseColour::Auto; - if( colourMode == UseColour::Auto ) - colourMode = useColourOnPlatform() - ? UseColour::Yes - : UseColour::No; - return colourMode == UseColour::Yes - ? PosixColourImpl::instance() - : NoColourImpl::instance(); - } - -} // end anon namespace -} // end namespace Catch - -#else // not Windows or ANSI /////////////////////////////////////////////// - -namespace Catch { - - static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } - -} // end namespace Catch - -#endif // Windows/ ANSI/ None - -namespace Catch { - - Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - } - Colour& Colour::operator=( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; - return *this; - } - - Colour::~Colour(){ if( !m_moved ) use( None ); } - - void Colour::use( Code _colourCode ) { - static IColourImpl* impl = platformColourInstance(); - impl->use( _colourCode ); - } - - std::ostream& operator << ( std::ostream& os, Colour const& ) { - return os; - } - -} // end namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// end catch_console_colour.cpp -// start catch_context.cpp - -namespace Catch { - - class Context : public IMutableContext, NonCopyable { - - public: // IContext - virtual IResultCapture* getResultCapture() override { - return m_resultCapture; - } - virtual IRunner* getRunner() override { - return m_runner; - } - - virtual IConfigPtr const& getConfig() const override { - return m_config; - } - - virtual ~Context() override; - - public: // IMutableContext - virtual void setResultCapture( IResultCapture* resultCapture ) override { - m_resultCapture = resultCapture; - } - virtual void setRunner( IRunner* runner ) override { - m_runner = runner; - } - virtual void setConfig( IConfigPtr const& config ) override { - m_config = config; - } - - friend IMutableContext& getCurrentMutableContext(); - - private: - IConfigPtr m_config; - IRunner* m_runner = nullptr; - IResultCapture* m_resultCapture = nullptr; - }; - - IMutableContext *IMutableContext::currentContext = nullptr; - - void IMutableContext::createContext() - { - currentContext = new Context(); - } - - void cleanUpContext() { - delete IMutableContext::currentContext; - IMutableContext::currentContext = nullptr; - } - IContext::~IContext() = default; - IMutableContext::~IMutableContext() = default; - Context::~Context() = default; -} -// end catch_context.cpp -// start catch_debug_console.cpp - -// start catch_debug_console.h - -#include - -namespace Catch { - void writeToDebugConsole( std::string const& text ); -} - -// end catch_debug_console.h -#ifdef CATCH_PLATFORM_WINDOWS - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - ::OutputDebugStringA( text.c_str() ); - } - } - -#else - - namespace Catch { - void writeToDebugConsole( std::string const& text ) { - // !TBD: Need a version for Mac/ XCode and other IDEs - Catch::cout() << text; - } - } - -#endif // Platform -// end catch_debug_console.cpp -// start catch_debugger.cpp - -#ifdef CATCH_PLATFORM_MAC - -# include -# include -# include -# include -# include -# include -# include - -namespace Catch { - - // The following function is taken directly from the following technical note: - // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html - - // Returns true if the current process is being debugged (either - // running under the debugger or has a debugger attached post facto). - bool isDebuggerActive(){ - - int mib[4]; - struct kinfo_proc info; - std::size_t size; - - // Initialize the flags so that, if sysctl fails for some bizarre - // reason, we get a predictable result. - - info.kp_proc.p_flag = 0; - - // Initialize mib, which tells sysctl the info we want, in this case - // we're looking for information about a specific process ID. - - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - // Call sysctl. - - size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { - Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; - return false; - } - - // We're being debugged if the P_TRACED flag is set. - - return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); - } - } // namespace Catch - -#elif defined(CATCH_PLATFORM_LINUX) - #include - #include - - namespace Catch{ - // The standard POSIX way of detecting a debugger is to attempt to - // ptrace() the process, but this needs to be done from a child and not - // this process itself to still allow attaching to this process later - // if wanted, so is rather heavy. Under Linux we have the PID of the - // "debugger" (which doesn't need to be gdb, of course, it could also - // be strace, for example) in /proc/$PID/status, so just get it from - // there instead. - bool isDebuggerActive(){ - // Libstdc++ has a bug, where std::ifstream sets errno to 0 - // This way our users can properly assert over errno values - ErrnoGuard guard; - std::ifstream in("/proc/self/status"); - for( std::string line; std::getline(in, line); ) { - static const int PREFIX_LEN = 11; - if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { - // We're traced if the PID is not 0 and no other PID starts - // with 0 digit, so it's enough to check for just a single - // character. - return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; - } - } - - return false; - } - } // namespace Catch -#elif defined(_MSC_VER) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#elif defined(__MINGW32__) - extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); - namespace Catch { - bool isDebuggerActive() { - return IsDebuggerPresent() != 0; - } - } -#else - namespace Catch { - bool isDebuggerActive() { return false; } - } -#endif // Platform -// end catch_debugger.cpp -// start catch_decomposer.cpp - -namespace Catch { - - ITransientExpression::~ITransientExpression() = default; - - void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { - if( lhs.size() + rhs.size() < 40 && - lhs.find('\n') == std::string::npos && - rhs.find('\n') == std::string::npos ) - os << lhs << " " << op << " " << rhs; - else - os << lhs << "\n" << op << "\n" << rhs; - } -} -// end catch_decomposer.cpp -// start catch_errno_guard.cpp - -#include - -namespace Catch { - ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} - ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } -} -// end catch_errno_guard.cpp -// start catch_exception_translator_registry.cpp - -// start catch_exception_translator_registry.h - -#include -#include -#include - -namespace Catch { - - class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { - public: - ~ExceptionTranslatorRegistry(); - virtual void registerTranslator( const IExceptionTranslator* translator ); - virtual std::string translateActiveException() const override; - std::string tryTranslators() const; - - private: - std::vector> m_translators; - }; -} - -// end catch_exception_translator_registry.h -#ifdef __OBJC__ -#import "Foundation/Foundation.h" -#endif - -namespace Catch { - - ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { - } - - void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { - m_translators.push_back( std::unique_ptr( translator ) ); - } - - std::string ExceptionTranslatorRegistry::translateActiveException() const { - try { -#ifdef __OBJC__ - // In Objective-C try objective-c exceptions first - @try { - return tryTranslators(); - } - @catch (NSException *exception) { - return Catch::Detail::stringify( [exception description] ); - } -#else - // Compiling a mixed mode project with MSVC means that CLR - // exceptions will be caught in (...) as well. However, these - // do not fill-in std::current_exception and thus lead to crash - // when attempting rethrow. - // /EHa switch also causes structured exceptions to be caught - // here, but they fill-in current_exception properly, so - // at worst the output should be a little weird, instead of - // causing a crash. - if (std::current_exception() == nullptr) { - return "Non C++ exception. Possibly a CLR exception."; - } - return tryTranslators(); -#endif - } - catch( TestFailureException& ) { - std::rethrow_exception(std::current_exception()); - } - catch( std::exception& ex ) { - return ex.what(); - } - catch( std::string& msg ) { - return msg; - } - catch( const char* msg ) { - return msg; - } - catch(...) { - return "Unknown exception"; - } - } - - std::string ExceptionTranslatorRegistry::tryTranslators() const { - if( m_translators.empty() ) - std::rethrow_exception(std::current_exception()); - else - return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); - } -} -// end catch_exception_translator_registry.cpp -// start catch_fatal_condition.cpp - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) - -namespace { - // Report the error condition - void reportFatal( char const * const message ) { - Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); - } -} - -#endif // signals/SEH handling - -#if defined( CATCH_CONFIG_WINDOWS_SEH ) - -namespace Catch { - struct SignalDefs { DWORD id; const char* name; }; - - // There is no 1-1 mapping between signals and windows exceptions. - // Windows can easily distinguish between SO and SigSegV, - // but SigInt, SigTerm, etc are handled differently. - static SignalDefs signalDefs[] = { - { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, - { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, - { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, - { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, - }; - - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { - for (auto const& def : signalDefs) { - if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { - reportFatal(def.name); - } - } - // If its not an exception we care about, pass it along. - // This stops us from eating debugger breaks etc. - return EXCEPTION_CONTINUE_SEARCH; - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = nullptr; - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); - } - - void FatalConditionHandler::reset() { - if (isSet) { - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = nullptr; - isSet = false; - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - -bool FatalConditionHandler::isSet = false; -ULONG FatalConditionHandler::guaranteeSize = 0; -PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; - -} // namespace Catch - -#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) - -namespace Catch { - - struct SignalDefs { - int id; - const char* name; - }; - static SignalDefs signalDefs[] = { - { SIGINT, "SIGINT - Terminal interrupt signal" }, - { SIGILL, "SIGILL - Illegal instruction signal" }, - { SIGFPE, "SIGFPE - Floating point error signal" }, - { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, - { SIGTERM, "SIGTERM - Termination request signal" }, - { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } - }; - - void FatalConditionHandler::handleSignal( int sig ) { - char const * name = ""; - for (auto const& def : signalDefs) { - if (sig == def.id) { - name = def.name; - break; - } - } - reset(); - reportFatal(name); - raise( sig ); - } - - FatalConditionHandler::FatalConditionHandler() { - isSet = true; - stack_t sigStack; - sigStack.ss_sp = altStackMem; - sigStack.ss_size = SIGSTKSZ; - sigStack.ss_flags = 0; - sigaltstack(&sigStack, &oldSigStack); - struct sigaction sa = { }; - - sa.sa_handler = handleSignal; - sa.sa_flags = SA_ONSTACK; - for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { - sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); - } - } - - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } - - void FatalConditionHandler::reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } - } - - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; - -} // namespace Catch - -#else - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -#endif // signals/SEH handling - -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif -// end catch_fatal_condition.cpp -// start catch_interfaces_capture.cpp - -namespace Catch { - IResultCapture::~IResultCapture() = default; -} -// end catch_interfaces_capture.cpp -// start catch_interfaces_config.cpp - -namespace Catch { - IConfig::~IConfig() = default; -} -// end catch_interfaces_config.cpp -// start catch_interfaces_exception.cpp - -namespace Catch { - IExceptionTranslator::~IExceptionTranslator() = default; - IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; -} -// end catch_interfaces_exception.cpp -// start catch_interfaces_registry_hub.cpp - -namespace Catch { - IRegistryHub::~IRegistryHub() = default; - IMutableRegistryHub::~IMutableRegistryHub() = default; -} -// end catch_interfaces_registry_hub.cpp -// start catch_interfaces_reporter.cpp - -// start catch_reporter_multi.h - -namespace Catch { - - class MultipleReporters : public IStreamingReporter { - using Reporters = std::vector; - Reporters m_reporters; - - public: - void add( IStreamingReporterPtr&& reporter ); - - public: // IStreamingReporter - - ReporterPreferences getPreferences() const override; - - void noMatchingTestCases( std::string const& spec ) override; - - static std::set getSupportedVerbosities(); - - void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; - void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; - - void testRunStarting( TestRunInfo const& testRunInfo ) override; - void testGroupStarting( GroupInfo const& groupInfo ) override; - void testCaseStarting( TestCaseInfo const& testInfo ) override; - void sectionStarting( SectionInfo const& sectionInfo ) override; - void assertionStarting( AssertionInfo const& assertionInfo ) override; - - // The return value indicates if the messages buffer should be cleared: - bool assertionEnded( AssertionStats const& assertionStats ) override; - void sectionEnded( SectionStats const& sectionStats ) override; - void testCaseEnded( TestCaseStats const& testCaseStats ) override; - void testGroupEnded( TestGroupStats const& testGroupStats ) override; - void testRunEnded( TestRunStats const& testRunStats ) override; - - void skipTest( TestCaseInfo const& testInfo ) override; - bool isMulti() const override; - - }; - -} // end namespace Catch - -// end catch_reporter_multi.h -namespace Catch { - - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) - : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - - ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) - : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} - - std::ostream& ReporterConfig::stream() const { return *m_stream; } - IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } - - TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} - - GroupInfo::GroupInfo( std::string const& _name, - std::size_t _groupIndex, - std::size_t _groupsCount ) - : name( _name ), - groupIndex( _groupIndex ), - groupsCounts( _groupsCount ) - {} - - AssertionStats::AssertionStats( AssertionResult const& _assertionResult, - std::vector const& _infoMessages, - Totals const& _totals ) - : assertionResult( _assertionResult ), - infoMessages( _infoMessages ), - totals( _totals ) - { - assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; - - if( assertionResult.hasMessage() ) { - // Copy message into messages list. - // !TBD This should have been done earlier, somewhere - MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); - builder << assertionResult.getMessage(); - builder.m_info.message = builder.m_stream.str(); - - infoMessages.push_back( builder.m_info ); - } - } - - AssertionStats::~AssertionStats() = default; - - SectionStats::SectionStats( SectionInfo const& _sectionInfo, - Counts const& _assertions, - double _durationInSeconds, - bool _missingAssertions ) - : sectionInfo( _sectionInfo ), - assertions( _assertions ), - durationInSeconds( _durationInSeconds ), - missingAssertions( _missingAssertions ) - {} - - SectionStats::~SectionStats() = default; - - TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, - Totals const& _totals, - std::string const& _stdOut, - std::string const& _stdErr, - bool _aborting ) - : testInfo( _testInfo ), - totals( _totals ), - stdOut( _stdOut ), - stdErr( _stdErr ), - aborting( _aborting ) - {} - - TestCaseStats::~TestCaseStats() = default; - - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, - Totals const& _totals, - bool _aborting ) - : groupInfo( _groupInfo ), - totals( _totals ), - aborting( _aborting ) - {} - - TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) - : groupInfo( _groupInfo ), - aborting( false ) - {} - - TestGroupStats::~TestGroupStats() = default; - - TestRunStats::TestRunStats( TestRunInfo const& _runInfo, - Totals const& _totals, - bool _aborting ) - : runInfo( _runInfo ), - totals( _totals ), - aborting( _aborting ) - {} - - TestRunStats::~TestRunStats() = default; - - void IStreamingReporter::fatalErrorEncountered( StringRef ) {} - bool IStreamingReporter::isMulti() const { return false; } - - IReporterFactory::~IReporterFactory() = default; - IReporterRegistry::~IReporterRegistry() = default; - - void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) { - - if( !existingReporter ) { - existingReporter = std::move( additionalReporter ); - return; - } - - MultipleReporters* multi = nullptr; - - if( existingReporter->isMulti() ) { - multi = static_cast( existingReporter.get() ); - } - else { - auto newMulti = std::unique_ptr( new MultipleReporters ); - newMulti->add( std::move( existingReporter ) ); - multi = newMulti.get(); - existingReporter = std::move( newMulti ); - } - multi->add( std::move( additionalReporter ) ); - } - -} // end namespace Catch -// end catch_interfaces_reporter.cpp -// start catch_interfaces_runner.cpp - -namespace Catch { - IRunner::~IRunner() = default; -} -// end catch_interfaces_runner.cpp -// start catch_interfaces_testcase.cpp - -namespace Catch { - ITestInvoker::~ITestInvoker() = default; - ITestCaseRegistry::~ITestCaseRegistry() = default; -} -// end catch_interfaces_testcase.cpp -// start catch_leak_detector.cpp - -#ifdef CATCH_CONFIG_WINDOWS_CRTDBG -#include - -namespace Catch { - - LeakDetector::LeakDetector() { - int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - flag |= _CRTDBG_LEAK_CHECK_DF; - flag |= _CRTDBG_ALLOC_MEM_DF; - _CrtSetDbgFlag(flag); - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); - _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); - // Change this to leaking allocation's number to break there - _CrtSetBreakAlloc(-1); - } -} - -#else - - Catch::LeakDetector::LeakDetector() {} - -#endif -// end catch_leak_detector.cpp -// start catch_list.cpp - -// start catch_list.h - -#include - -namespace Catch { - - std::size_t listTests( Config const& config ); - - std::size_t listTestsNamesOnly( Config const& config ); - - struct TagInfo { - void add( std::string const& spelling ); - std::string all() const; - - std::set spellings; - std::size_t count = 0; - }; - - std::size_t listTags( Config const& config ); - - std::size_t listReporters( Config const& /*config*/ ); - - Option list( Config const& config ); - -} // end namespace Catch - -// end catch_list.h -// start catch_text.h - -namespace Catch { - using namespace clara::TextFlow; -} - -// end catch_text.h -#include -#include -#include - -namespace Catch { - - std::size_t listTests( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.hasTestFilters() ) - Catch::cout() << "Matching test cases:\n"; - else { - Catch::cout() << "All available test cases:\n"; - } - - auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - Colour::Code colour = testCaseInfo.isHidden() - ? Colour::SecondaryText - : Colour::None; - Colour colourGuard( colour ); - - Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; - if( config.verbosity() >= Verbosity::High ) { - Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; - std::string description = testCaseInfo.description; - if( description.empty() ) - description = "(NO DESCRIPTION)"; - Catch::cout() << Column( description ).indent(4) << std::endl; - } - if( !testCaseInfo.tags.empty() ) - Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; - } - - if( !config.hasTestFilters() ) - Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; - else - Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; - return matchedTestCases.size(); - } - - std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); - std::size_t matchedTests = 0; - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCaseInfo : matchedTestCases ) { - matchedTests++; - if( startsWith( testCaseInfo.name, '#' ) ) - Catch::cout() << '"' << testCaseInfo.name << '"'; - else - Catch::cout() << testCaseInfo.name; - if ( config.verbosity() >= Verbosity::High ) - Catch::cout() << "\t@" << testCaseInfo.lineInfo; - Catch::cout() << std::endl; - } - return matchedTests; - } - - void TagInfo::add( std::string const& spelling ) { - ++count; - spellings.insert( spelling ); - } - - std::string TagInfo::all() const { - std::string out; - for( auto const& spelling : spellings ) - out += "[" + spelling + "]"; - return out; - } - - std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); - if( config.hasTestFilters() ) - Catch::cout() << "Tags for matching test cases:\n"; - else { - Catch::cout() << "All available tags:\n"; - } - - std::map tagCounts; - - std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); - for( auto const& testCase : matchedTestCases ) { - for( auto const& tagName : testCase.getTestCaseInfo().tags ) { - std::string lcaseTagName = toLower( tagName ); - auto countIt = tagCounts.find( lcaseTagName ); - if( countIt == tagCounts.end() ) - countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; - countIt->second.add( tagName ); - } - } - - for( auto const& tagCount : tagCounts ) { - ReusableStringStream rss; - rss << " " << std::setw(2) << tagCount.second.count << " "; - auto str = rss.str(); - auto wrapper = Column( tagCount.second.all() ) - .initialIndent( 0 ) - .indent( str.size() ) - .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); - Catch::cout() << str << wrapper << '\n'; - } - Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; - return tagCounts.size(); - } - - std::size_t listReporters( Config const& /*config*/ ) { - Catch::cout() << "Available reporters:\n"; - IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); - std::size_t maxNameLen = 0; - for( auto const& factoryKvp : factories ) - maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); - - for( auto const& factoryKvp : factories ) { - Catch::cout() - << Column( factoryKvp.first + ":" ) - .indent(2) - .width( 5+maxNameLen ) - + Column( factoryKvp.second->getDescription() ) - .initialIndent(0) - .indent(2) - .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) - << "\n"; - } - Catch::cout() << std::endl; - return factories.size(); - } - - Option list( Config const& config ) { - Option listedCount; - if( config.listTests() ) - listedCount = listedCount.valueOr(0) + listTests( config ); - if( config.listTestNamesOnly() ) - listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); - if( config.listTags() ) - listedCount = listedCount.valueOr(0) + listTags( config ); - if( config.listReporters() ) - listedCount = listedCount.valueOr(0) + listReporters( config ); - return listedCount; - } - -} // end namespace Catch -// end catch_list.cpp -// start catch_matchers.cpp - -namespace Catch { -namespace Matchers { - namespace Impl { - - std::string MatcherUntypedBase::toString() const { - if( m_cachedToString.empty() ) - m_cachedToString = describe(); - return m_cachedToString; - } - - MatcherUntypedBase::~MatcherUntypedBase() = default; - - } // namespace Impl -} // namespace Matchers - -using namespace Matchers; -using Matchers::Impl::MatcherBase; - -} // namespace Catch -// end catch_matchers.cpp -// start catch_matchers_floating.cpp - -#include -#include -#include -#include - -namespace Catch { -namespace Matchers { -namespace Floating { -enum class FloatingPointKind : uint8_t { - Float, - Double -}; -} -} -} - -namespace { - -template -struct Converter; - -template <> -struct Converter { - static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); - Converter(float f) { - std::memcpy(&i, &f, sizeof(f)); - } - int32_t i; -}; - -template <> -struct Converter { - static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); - Converter(double d) { - std::memcpy(&i, &d, sizeof(d)); - } - int64_t i; -}; - -template -auto convert(T t) -> Converter { - return Converter(t); -} - -template -bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { - // Comparison with NaN should always be false. - // This way we can rule it out before getting into the ugly details - if (std::isnan(lhs) || std::isnan(rhs)) { - return false; - } - - auto lc = convert(lhs); - auto rc = convert(rhs); - - if ((lc.i < 0) != (rc.i < 0)) { - // Potentially we can have +0 and -0 - return lhs == rhs; - } - - auto ulpDiff = std::abs(lc.i - rc.i); - return ulpDiff <= maxUlpDiff; -} - -} - -namespace Catch { -namespace Matchers { -namespace Floating { - WithinAbsMatcher::WithinAbsMatcher(double target, double margin) - :m_target{ target }, m_margin{ margin } { - if (m_margin < 0) { - throw std::domain_error("Allowed margin difference has to be >= 0"); - } - } - - // Performs equivalent check of std::fabs(lhs - rhs) <= margin - // But without the subtraction to allow for INFINITY in comparison - bool WithinAbsMatcher::match(double const& matchee) const { - return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); - } - - std::string WithinAbsMatcher::describe() const { - return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); - } - - WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) - :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { - if (m_ulps < 0) { - throw std::domain_error("Allowed ulp difference has to be >= 0"); - } - } - - bool WithinUlpsMatcher::match(double const& matchee) const { - switch (m_type) { - case FloatingPointKind::Float: - return almostEqualUlps(static_cast(matchee), static_cast(m_target), m_ulps); - case FloatingPointKind::Double: - return almostEqualUlps(matchee, m_target, m_ulps); - default: - throw std::domain_error("Unknown FloatingPointKind value"); - } - } - - std::string WithinUlpsMatcher::describe() const { - return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); - } - -}// namespace Floating - -Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { - return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); -} - -Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { - return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); -} - -Floating::WithinAbsMatcher WithinAbs(double target, double margin) { - return Floating::WithinAbsMatcher(target, margin); -} - -} // namespace Matchers -} // namespace Catch - -// end catch_matchers_floating.cpp -// start catch_matchers_generic.cpp - -std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { - if (desc.empty()) { - return "matches undescribed predicate"; - } else { - return "matches predicate: \"" + desc + '"'; - } -} -// end catch_matchers_generic.cpp -// start catch_matchers_string.cpp - -#include - -namespace Catch { -namespace Matchers { - - namespace StdString { - - CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_str( adjustString( str ) ) - {} - std::string CasedString::adjustString( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No - ? toLower( str ) - : str; - } - std::string CasedString::caseSensitivitySuffix() const { - return m_caseSensitivity == CaseSensitive::No - ? " (case insensitive)" - : std::string(); - } - - StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) - : m_comparator( comparator ), - m_operation( operation ) { - } - - std::string StringMatcherBase::describe() const { - std::string description; - description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + - m_comparator.caseSensitivitySuffix().size()); - description += m_operation; - description += ": \""; - description += m_comparator.m_str; - description += "\""; - description += m_comparator.caseSensitivitySuffix(); - return description; - } - - EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} - - bool EqualsMatcher::match( std::string const& source ) const { - return m_comparator.adjustString( source ) == m_comparator.m_str; - } - - ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} - - bool ContainsMatcher::match( std::string const& source ) const { - return contains( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} - - bool StartsWithMatcher::match( std::string const& source ) const { - return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} - - bool EndsWithMatcher::match( std::string const& source ) const { - return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); - } - - RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} - - bool RegexMatcher::match(std::string const& matchee) const { - auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway - if (m_caseSensitivity == CaseSensitive::Choice::No) { - flags |= std::regex::icase; - } - auto reg = std::regex(m_regex, flags); - return std::regex_match(matchee, reg); - } - - std::string RegexMatcher::describe() const { - return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); - } - - } // namespace StdString - - StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } - StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { - return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); - } - - StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { - return StdString::RegexMatcher(regex, caseSensitivity); - } - -} // namespace Matchers -} // namespace Catch -// end catch_matchers_string.cpp -// start catch_message.cpp - -// start catch_uncaught_exceptions.h - -namespace Catch { - bool uncaught_exceptions(); -} // end namespace Catch - -// end catch_uncaught_exceptions.h -namespace Catch { - - MessageInfo::MessageInfo( std::string const& _macroName, - SourceLineInfo const& _lineInfo, - ResultWas::OfType _type ) - : macroName( _macroName ), - lineInfo( _lineInfo ), - type( _type ), - sequence( ++globalCount ) - {} - - bool MessageInfo::operator==( MessageInfo const& other ) const { - return sequence == other.sequence; - } - - bool MessageInfo::operator<( MessageInfo const& other ) const { - return sequence < other.sequence; - } - - // This may need protecting if threading support is added - unsigned int MessageInfo::globalCount = 0; - - //////////////////////////////////////////////////////////////////////////// - - Catch::MessageBuilder::MessageBuilder( std::string const& macroName, - SourceLineInfo const& lineInfo, - ResultWas::OfType type ) - :m_info(macroName, lineInfo, type) {} - - //////////////////////////////////////////////////////////////////////////// - - ScopedMessage::ScopedMessage( MessageBuilder const& builder ) - : m_info( builder.m_info ) - { - m_info.message = builder.m_stream.str(); - getResultCapture().pushScopedMessage( m_info ); - } - - ScopedMessage::~ScopedMessage() { - if ( !uncaught_exceptions() ){ - getResultCapture().popScopedMessage(m_info); - } - } -} // end namespace Catch -// end catch_message.cpp -// start catch_random_number_generator.cpp - -// start catch_random_number_generator.h - -#include - -namespace Catch { - - struct IConfig; - - void seedRng( IConfig const& config ); - - unsigned int rngSeed(); - - struct RandomNumberGenerator { - using result_type = unsigned int; - - static constexpr result_type (min)() { return 0; } - static constexpr result_type (max)() { return 1000000; } - - result_type operator()( result_type n ) const; - result_type operator()() const; - - template - static void shuffle( V& vector ) { - RandomNumberGenerator rng; - std::shuffle( vector.begin(), vector.end(), rng ); - } - }; - -} - -// end catch_random_number_generator.h -#include - -namespace Catch { - - void seedRng( IConfig const& config ) { - if( config.rngSeed() != 0 ) - std::srand( config.rngSeed() ); - } - unsigned int rngSeed() { - return getCurrentContext().getConfig()->rngSeed(); - } - - RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const { - return std::rand() % n; - } - RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const { - return std::rand() % (max)(); - } - -} -// end catch_random_number_generator.cpp -// start catch_registry_hub.cpp - -// start catch_test_case_registry_impl.h - -#include -#include -#include -#include - -namespace Catch { - - class TestCase; - struct IConfig; - - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ); - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); - - void enforceNoDuplicateTestCases( std::vector const& functions ); - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); - std::vector const& getAllTestCasesSorted( IConfig const& config ); - - class TestRegistry : public ITestCaseRegistry { - public: - virtual ~TestRegistry() = default; - - virtual void registerTest( TestCase const& testCase ); - - std::vector const& getAllTests() const override; - std::vector const& getAllTestsSorted( IConfig const& config ) const override; - - private: - std::vector m_functions; - mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; - mutable std::vector m_sortedFunctions; - std::size_t m_unnamedCount = 0; - std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised - }; - - /////////////////////////////////////////////////////////////////////////// - - class TestInvokerAsFunction : public ITestInvoker { - void(*m_testAsFunction)(); - public: - TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; - - void invoke() const override; - }; - - std::string extractClassName( StringRef const& classOrQualifiedMethodName ); - - /////////////////////////////////////////////////////////////////////////// - -} // end namespace Catch - -// end catch_test_case_registry_impl.h -// start catch_reporter_registry.h - -#include - -namespace Catch { - - class ReporterRegistry : public IReporterRegistry { - - public: - - ~ReporterRegistry() override; - - IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; - - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); - void registerListener( IReporterFactoryPtr const& factory ); - - FactoryMap const& getFactories() const override; - Listeners const& getListeners() const override; - - private: - FactoryMap m_factories; - Listeners m_listeners; - }; -} - -// end catch_reporter_registry.h -// start catch_tag_alias_registry.h - -// start catch_tag_alias.h - -#include - -namespace Catch { - - struct TagAlias { - TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); - - std::string tag; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - -// end catch_tag_alias.h -#include - -namespace Catch { - - class TagAliasRegistry : public ITagAliasRegistry { - public: - ~TagAliasRegistry() override; - TagAlias const* find( std::string const& alias ) const override; - std::string expandAliases( std::string const& unexpandedTestSpec ) const override; - void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); - - private: - std::map m_registry; - }; - -} // end namespace Catch - -// end catch_tag_alias_registry.h -// start catch_startup_exception_registry.h - -#include -#include - -namespace Catch { - - class StartupExceptionRegistry { - public: - void add(std::exception_ptr const& exception) noexcept; - std::vector const& getExceptions() const noexcept; - private: - std::vector m_exceptions; - }; - -} // end namespace Catch - -// end catch_startup_exception_registry.h -namespace Catch { - - namespace { - - class RegistryHub : public IRegistryHub, public IMutableRegistryHub, - private NonCopyable { - - public: // IRegistryHub - RegistryHub() = default; - IReporterRegistry const& getReporterRegistry() const override { - return m_reporterRegistry; - } - ITestCaseRegistry const& getTestCaseRegistry() const override { - return m_testCaseRegistry; - } - IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override { - return m_exceptionTranslatorRegistry; - } - ITagAliasRegistry const& getTagAliasRegistry() const override { - return m_tagAliasRegistry; - } - StartupExceptionRegistry const& getStartupExceptionRegistry() const override { - return m_exceptionRegistry; - } - - public: // IMutableRegistryHub - void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerReporter( name, factory ); - } - void registerListener( IReporterFactoryPtr const& factory ) override { - m_reporterRegistry.registerListener( factory ); - } - void registerTest( TestCase const& testInfo ) override { - m_testCaseRegistry.registerTest( testInfo ); - } - void registerTranslator( const IExceptionTranslator* translator ) override { - m_exceptionTranslatorRegistry.registerTranslator( translator ); - } - void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { - m_tagAliasRegistry.add( alias, tag, lineInfo ); - } - void registerStartupException() noexcept override { - m_exceptionRegistry.add(std::current_exception()); - } - - private: - TestRegistry m_testCaseRegistry; - ReporterRegistry m_reporterRegistry; - ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; - TagAliasRegistry m_tagAliasRegistry; - StartupExceptionRegistry m_exceptionRegistry; - }; - - // Single, global, instance - RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = nullptr; - if( !theRegistryHub ) - theRegistryHub = new RegistryHub(); - return theRegistryHub; - } - } - - IRegistryHub& getRegistryHub() { - return *getTheRegistryHub(); - } - IMutableRegistryHub& getMutableRegistryHub() { - return *getTheRegistryHub(); - } - void cleanUp() { - delete getTheRegistryHub(); - getTheRegistryHub() = nullptr; - cleanUpContext(); - ReusableStringStream::cleanup(); - } - std::string translateActiveException() { - return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); - } - -} // end namespace Catch -// end catch_registry_hub.cpp -// start catch_reporter_registry.cpp - -namespace Catch { - - ReporterRegistry::~ReporterRegistry() = default; - - IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { - auto it = m_factories.find( name ); - if( it == m_factories.end() ) - return nullptr; - return it->second->create( ReporterConfig( config ) ); - } - - void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { - m_factories.emplace(name, factory); - } - void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { - m_listeners.push_back( factory ); - } - - IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { - return m_factories; - } - IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { - return m_listeners; - } - -} -// end catch_reporter_registry.cpp -// start catch_result_type.cpp - -namespace Catch { - - bool isOk( ResultWas::OfType resultType ) { - return ( resultType & ResultWas::FailureBit ) == 0; - } - bool isJustInfo( int flags ) { - return flags == ResultWas::Info; - } - - ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { - return static_cast( static_cast( lhs ) | static_cast( rhs ) ); - } - - bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } - bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } - -} // end namespace Catch -// end catch_result_type.cpp -// start catch_run_context.cpp - -#include -#include -#include - -namespace Catch { - - class RedirectedStream { - std::ostream& m_originalStream; - std::ostream& m_redirectionStream; - std::streambuf* m_prevBuf; - - public: - RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) - : m_originalStream( originalStream ), - m_redirectionStream( redirectionStream ), - m_prevBuf( m_originalStream.rdbuf() ) - { - m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); - } - ~RedirectedStream() { - m_originalStream.rdbuf( m_prevBuf ); - } - }; - - class RedirectedStdOut { - ReusableStringStream m_rss; - RedirectedStream m_cout; - public: - RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} - auto str() const -> std::string { return m_rss.str(); } - }; - - // StdErr has two constituent streams in C++, std::cerr and std::clog - // This means that we need to redirect 2 streams into 1 to keep proper - // order of writes - class RedirectedStdErr { - ReusableStringStream m_rss; - RedirectedStream m_cerr; - RedirectedStream m_clog; - public: - RedirectedStdErr() - : m_cerr( Catch::cerr(), m_rss.get() ), - m_clog( Catch::clog(), m_rss.get() ) - {} - auto str() const -> std::string { return m_rss.str(); } - }; - - RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) - : m_runInfo(_config->name()), - m_context(getCurrentMutableContext()), - m_config(_config), - m_reporter(std::move(reporter)), - m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, - m_includeSuccessfulResults( m_config->includeSuccessfulResults() ) - { - m_context.setRunner(this); - m_context.setConfig(m_config); - m_context.setResultCapture(this); - m_reporter->testRunStarting(m_runInfo); - } - - RunContext::~RunContext() { - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); - } - - void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); - } - - void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { - m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); - } - - Totals RunContext::runTest(TestCase const& testCase) { - Totals prevTotals = m_totals; - - std::string redirectedCout; - std::string redirectedCerr; - - auto const& testInfo = testCase.getTestCaseInfo(); - - m_reporter->testCaseStarting(testInfo); - - m_activeTestCase = &testCase; - - ITracker& rootTracker = m_trackerContext.startRun(); - assert(rootTracker.isSectionTracker()); - static_cast(rootTracker).addInitialFilters(m_config->getSectionsToRun()); - do { - m_trackerContext.startCycle(); - m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); - runCurrentTest(redirectedCout, redirectedCerr); - } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); - - Totals deltaTotals = m_totals.delta(prevTotals); - if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { - deltaTotals.assertions.failed++; - deltaTotals.testCases.passed--; - deltaTotals.testCases.failed++; - } - m_totals.testCases += deltaTotals.testCases; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - redirectedCout, - redirectedCerr, - aborting())); - - m_activeTestCase = nullptr; - m_testCaseTracker = nullptr; - - return deltaTotals; - } - - IConfigPtr RunContext::config() const { - return m_config; - } - - IStreamingReporter& RunContext::reporter() const { - return *m_reporter; - } - - void RunContext::assertionEnded(AssertionResult const & result) { - if (result.getResultType() == ResultWas::Ok) { - m_totals.assertions.passed++; - m_lastAssertionPassed = true; - } else if (!result.isOk()) { - m_lastAssertionPassed = false; - if( m_activeTestCase->getTestCaseInfo().okToFail() ) - m_totals.assertions.failedButOk++; - else - m_totals.assertions.failed++; - } - else { - m_lastAssertionPassed = true; - } - - // We have no use for the return value (whether messages should be cleared), because messages were made scoped - // and should be let to clear themselves out. - static_cast(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); - - // Reset working state - resetAssertionInfo(); - m_lastResult = result; - } - void RunContext::resetAssertionInfo() { - m_lastAssertionInfo.macroName = StringRef(); - m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; - } - - bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { - ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); - if (!sectionTracker.isOpen()) - return false; - m_activeSections.push_back(§ionTracker); - - m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; - - m_reporter->sectionStarting(sectionInfo); - - assertions = m_totals.assertions; - - return true; - } - - bool RunContext::testForMissingAssertions(Counts& assertions) { - if (assertions.total() != 0) - return false; - if (!m_config->warnAboutMissingAssertions()) - return false; - if (m_trackerContext.currentTracker().hasChildren()) - return false; - m_totals.assertions.failed++; - assertions.failed++; - return true; - } - - void RunContext::sectionEnded(SectionEndInfo const & endInfo) { - Counts assertions = m_totals.assertions - endInfo.prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - if (!m_activeSections.empty()) { - m_activeSections.back()->close(); - m_activeSections.pop_back(); - } - - m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); - m_messages.clear(); - } - - void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { - if (m_unfinishedSections.empty()) - m_activeSections.back()->fail(); - else - m_activeSections.back()->close(); - m_activeSections.pop_back(); - - m_unfinishedSections.push_back(endInfo); - } - void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { - m_reporter->benchmarkStarting( info ); - } - void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { - m_reporter->benchmarkEnded( stats ); - } - - void RunContext::pushScopedMessage(MessageInfo const & message) { - m_messages.push_back(message); - } - - void RunContext::popScopedMessage(MessageInfo const & message) { - m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); - } - - std::string RunContext::getCurrentTestName() const { - return m_activeTestCase - ? m_activeTestCase->getTestCaseInfo().name - : std::string(); - } - - const AssertionResult * RunContext::getLastResult() const { - return &(*m_lastResult); - } - - void RunContext::exceptionEarlyReported() { - m_shouldReportUnexpected = false; - } - - void RunContext::handleFatalErrorCondition( StringRef message ) { - // First notify reporter that bad things happened - m_reporter->fatalErrorEncountered(message); - - // Don't rebuild the result -- the stringification itself can cause more fatal errors - // Instead, fake a result data. - AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); - tempResult.message = message; - AssertionResult result(m_lastAssertionInfo, tempResult); - - assertionEnded(result); - - handleUnfinishedSections(); - - // Recreate section for test case (as we will lose the one that was in scope) - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); - - Counts assertions; - assertions.failed = 1; - SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); - m_reporter->sectionEnded(testCaseSectionStats); - - auto const& testInfo = m_activeTestCase->getTestCaseInfo(); - - Totals deltaTotals; - deltaTotals.testCases.failed = 1; - deltaTotals.assertions.failed = 1; - m_reporter->testCaseEnded(TestCaseStats(testInfo, - deltaTotals, - std::string(), - std::string(), - false)); - m_totals.testCases.failed++; - testGroupEnded(std::string(), m_totals, 1, 1); - m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); - } - - bool RunContext::lastAssertionPassed() { - return m_lastAssertionPassed; - } - - void RunContext::assertionPassed() { - m_lastAssertionPassed = true; - ++m_totals.assertions.passed; - resetAssertionInfo(); - } - - bool RunContext::aborting() const { - return m_totals.assertions.failed == static_cast(m_config->abortAfter()); - } - - void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { - auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); - SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description); - m_reporter->sectionStarting(testCaseSection); - Counts prevAssertions = m_totals.assertions; - double duration = 0; - m_shouldReportUnexpected = true; - m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; - - seedRng(*m_config); - - Timer timer; - try { - if (m_reporter->getPreferences().shouldRedirectStdOut) { - RedirectedStdOut redirectedStdOut; - RedirectedStdErr redirectedStdErr; - timer.start(); - invokeActiveTestCase(); - redirectedCout += redirectedStdOut.str(); - redirectedCerr += redirectedStdErr.str(); - - } else { - timer.start(); - invokeActiveTestCase(); - } - duration = timer.getElapsedSeconds(); - } catch (TestFailureException&) { - // This just means the test was aborted due to failure - } catch (...) { - // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions - // are reported without translation at the point of origin. - if( m_shouldReportUnexpected ) { - AssertionReaction dummyReaction; - handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); - } - } - Counts assertions = m_totals.assertions - prevAssertions; - bool missingAssertions = testForMissingAssertions(assertions); - - m_testCaseTracker->close(); - handleUnfinishedSections(); - m_messages.clear(); - - SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); - m_reporter->sectionEnded(testCaseSectionStats); - } - - void RunContext::invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals - m_activeTestCase->invoke(); - fatalConditionHandler.reset(); - } - - void RunContext::handleUnfinishedSections() { - // If sections ended prematurely due to an exception we stored their - // infos here so we can tear them down outside the unwind process. - for (auto it = m_unfinishedSections.rbegin(), - itEnd = m_unfinishedSections.rend(); - it != itEnd; - ++it) - sectionEnded(*it); - m_unfinishedSections.clear(); - } - - void RunContext::handleExpr( - AssertionInfo const& info, - ITransientExpression const& expr, - AssertionReaction& reaction - ) { - m_reporter->assertionStarting( info ); - - bool negated = isFalseTest( info.resultDisposition ); - bool result = expr.getResult() != negated; - - if( result ) { - if (!m_includeSuccessfulResults) { - assertionPassed(); - } - else { - reportExpr(info, ResultWas::Ok, &expr, negated); - } - } - else { - reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); - populateReaction( reaction ); - } - } - void RunContext::reportExpr( - AssertionInfo const &info, - ResultWas::OfType resultType, - ITransientExpression const *expr, - bool negated ) { - - m_lastAssertionInfo = info; - AssertionResultData data( resultType, LazyExpression( negated ) ); - - AssertionResult assertionResult{ info, data }; - assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; - - assertionEnded( assertionResult ); - } - - void RunContext::handleMessage( - AssertionInfo const& info, - ResultWas::OfType resultType, - StringRef const& message, - AssertionReaction& reaction - ) { - m_reporter->assertionStarting( info ); - - m_lastAssertionInfo = info; - - AssertionResultData data( resultType, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ m_lastAssertionInfo, data }; - assertionEnded( assertionResult ); - if( !assertionResult.isOk() ) - populateReaction( reaction ); - } - void RunContext::handleUnexpectedExceptionNotThrown( - AssertionInfo const& info, - AssertionReaction& reaction - ) { - handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); - } - - void RunContext::handleUnexpectedInflightException( - AssertionInfo const& info, - std::string const& message, - AssertionReaction& reaction - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = message; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); - populateReaction( reaction ); - } - - void RunContext::populateReaction( AssertionReaction& reaction ) { - reaction.shouldDebugBreak = m_config->shouldDebugBreak(); - reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); - } - - void RunContext::handleIncomplete( - AssertionInfo const& info - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); - data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); - } - void RunContext::handleNonExpr( - AssertionInfo const &info, - ResultWas::OfType resultType, - AssertionReaction &reaction - ) { - m_lastAssertionInfo = info; - - AssertionResultData data( resultType, LazyExpression( false ) ); - AssertionResult assertionResult{ info, data }; - assertionEnded( assertionResult ); - - if( !assertionResult.isOk() ) - populateReaction( reaction ); - } - - IResultCapture& getResultCapture() { - if (auto* capture = getCurrentContext().getResultCapture()) - return *capture; - else - CATCH_INTERNAL_ERROR("No result capture instance"); - } -} -// end catch_run_context.cpp -// start catch_section.cpp - -namespace Catch { - - Section::Section( SectionInfo const& info ) - : m_info( info ), - m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) - { - m_timer.start(); - } - - Section::~Section() { - if( m_sectionIncluded ) { - SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); - if( uncaught_exceptions() ) - getResultCapture().sectionEndedEarly( endInfo ); - else - getResultCapture().sectionEnded( endInfo ); - } - } - - // This indicates whether the section should be executed or not - Section::operator bool() const { - return m_sectionIncluded; - } - -} // end namespace Catch -// end catch_section.cpp -// start catch_section_info.cpp - -namespace Catch { - - SectionInfo::SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description ) - : name( _name ), - description( _description ), - lineInfo( _lineInfo ) - {} - - SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) - : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - -} // end namespace Catch -// end catch_section_info.cpp -// start catch_session.cpp - -// start catch_session.h - -#include - -namespace Catch { - - class Session : NonCopyable { - public: - - Session(); - ~Session() override; - - void showHelp() const; - void libIdentify(); - - int applyCommandLine( int argc, char const * const * argv ); - - void useConfigData( ConfigData const& configData ); - - int run( int argc, char* argv[] ); - #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) - int run( int argc, wchar_t* const argv[] ); - #endif - int run(); - - clara::Parser const& cli() const; - void cli( clara::Parser const& newParser ); - ConfigData& configData(); - Config& config(); - private: - int runInternal(); - - clara::Parser m_cli; - ConfigData m_configData; - std::shared_ptr m_config; - bool m_startupExceptions = false; - }; - -} // end namespace Catch - -// end catch_session.h -// start catch_version.h - -#include - -namespace Catch { - - // Versioning information - struct Version { - Version( Version const& ) = delete; - Version& operator=( Version const& ) = delete; - Version( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ); - - unsigned int const majorVersion; - unsigned int const minorVersion; - unsigned int const patchNumber; - - // buildNumber is only used if branchName is not null - char const * const branchName; - unsigned int const buildNumber; - - friend std::ostream& operator << ( std::ostream& os, Version const& version ); - }; - - Version const& libraryVersion(); -} - -// end catch_version.h -#include -#include - -namespace Catch { - - namespace { - const int MaxExitCode = 255; - - IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { - auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); - CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); - - return reporter; - } - -#ifndef CATCH_CONFIG_DEFAULT_REPORTER -#define CATCH_CONFIG_DEFAULT_REPORTER "console" -#endif - - IStreamingReporterPtr makeReporter(std::shared_ptr const& config) { - auto const& reporterNames = config->getReporterNames(); - if (reporterNames.empty()) - return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config); - - IStreamingReporterPtr reporter; - for (auto const& name : reporterNames) - addReporter(reporter, createReporter(name, config)); - return reporter; - } - -#undef CATCH_CONFIG_DEFAULT_REPORTER - - void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) { - auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); - for (auto const& listener : listeners) - addReporter(reporters, listener->create(Catch::ReporterConfig(config))); - } - - Catch::Totals runTests(std::shared_ptr const& config) { - IStreamingReporterPtr reporter = makeReporter(config); - addListeners(reporter, config); - - RunContext context(config, std::move(reporter)); - - Totals totals; - - context.testGroupStarting(config->name(), 1, 1); - - TestSpec testSpec = config->testSpec(); - - auto const& allTestCases = getAllTestCasesSorted(*config); - for (auto const& testCase : allTestCases) { - if (!context.aborting() && matchTest(testCase, testSpec, *config)) - totals += context.runTest(testCase); - else - context.reporter().skipTest(testCase); - } - - if (config->warnAboutNoTests() && totals.testCases.total() == 0) { - ReusableStringStream testConfig; - - bool first = true; - for (const auto& input : config->getTestsOrTags()) { - if (!first) { testConfig << ' '; } - first = false; - testConfig << input; - } - - context.reporter().noMatchingTestCases(testConfig.str()); - totals.error = -1; - } - - context.testGroupEnded(config->name(), totals, 1, 1); - return totals; - } - - void applyFilenamesAsTags(Catch::IConfig const& config) { - auto& tests = const_cast&>(getAllTestCasesSorted(config)); - for (auto& testCase : tests) { - auto tags = testCase.tags; - - std::string filename = testCase.lineInfo.file; - auto lastSlash = filename.find_last_of("\\/"); - if (lastSlash != std::string::npos) { - filename.erase(0, lastSlash); - filename[0] = '#'; - } - - auto lastDot = filename.find_last_of('.'); - if (lastDot != std::string::npos) { - filename.erase(lastDot); - } - - tags.push_back(std::move(filename)); - setTags(testCase, tags); - } - } - - } // anon namespace - - Session::Session() { - static bool alreadyInstantiated = false; - if( alreadyInstantiated ) { - try { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } - catch(...) { getMutableRegistryHub().registerStartupException(); } - } - - const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); - if ( !exceptions.empty() ) { - m_startupExceptions = true; - Colour colourGuard( Colour::Red ); - Catch::cerr() << "Errors occurred during startup!" << '\n'; - // iterate over all exceptions and notify user - for ( const auto& ex_ptr : exceptions ) { - try { - std::rethrow_exception(ex_ptr); - } catch ( std::exception const& ex ) { - Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; - } - } - } - - alreadyInstantiated = true; - m_cli = makeCommandLineParser( m_configData ); - } - Session::~Session() { - Catch::cleanUp(); - } - - void Session::showHelp() const { - Catch::cout() - << "\nCatch v" << libraryVersion() << "\n" - << m_cli << std::endl - << "For more detailed usage please see the project docs\n" << std::endl; - } - void Session::libIdentify() { - Catch::cout() - << std::left << std::setw(16) << "description: " << "A Catch test executable\n" - << std::left << std::setw(16) << "category: " << "testframework\n" - << std::left << std::setw(16) << "framework: " << "Catch Test\n" - << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; - } - - int Session::applyCommandLine( int argc, char const * const * argv ) { - if( m_startupExceptions ) - return 1; - - auto result = m_cli.parse( clara::Args( argc, argv ) ); - if( !result ) { - Catch::cerr() - << Colour( Colour::Red ) - << "\nError(s) in input:\n" - << Column( result.errorMessage() ).indent( 2 ) - << "\n\n"; - Catch::cerr() << "Run with -? for usage\n" << std::endl; - return MaxExitCode; - } - - if( m_configData.showHelp ) - showHelp(); - if( m_configData.libIdentify ) - libIdentify(); - m_config.reset(); - return 0; - } - - void Session::useConfigData( ConfigData const& configData ) { - m_configData = configData; - m_config.reset(); - } - - int Session::run( int argc, char* argv[] ) { - if( m_startupExceptions ) - return 1; - int returnCode = applyCommandLine( argc, argv ); - if( returnCode == 0 ) - returnCode = run(); - return returnCode; - } - -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) - int Session::run( int argc, wchar_t* const argv[] ) { - - char **utf8Argv = new char *[ argc ]; - - for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); - - utf8Argv[ i ] = new char[ bufSize ]; - - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); - } - - int returnCode = run( argc, utf8Argv ); - - for ( int i = 0; i < argc; ++i ) - delete [] utf8Argv[ i ]; - - delete [] utf8Argv; - - return returnCode; - } -#endif - int Session::run() { - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before starting" << std::endl; - static_cast(std::getchar()); - } - int exitCode = runInternal(); - if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { - Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; - static_cast(std::getchar()); - } - return exitCode; - } - - clara::Parser const& Session::cli() const { - return m_cli; - } - void Session::cli( clara::Parser const& newParser ) { - m_cli = newParser; - } - ConfigData& Session::configData() { - return m_configData; - } - Config& Session::config() { - if( !m_config ) - m_config = std::make_shared( m_configData ); - return *m_config; - } - - int Session::runInternal() { - if( m_startupExceptions ) - return 1; - - if( m_configData.showHelp || m_configData.libIdentify ) - return 0; - - try - { - config(); // Force config to be constructed - - seedRng( *m_config ); - - if( m_configData.filenamesAsTags ) - applyFilenamesAsTags( *m_config ); - - // Handle list request - if( Option listed = list( config() ) ) - return static_cast( *listed ); - - auto totals = runTests( m_config ); - // Note that on unices only the lower 8 bits are usually used, clamping - // the return value to 255 prevents false negative when some multiple - // of 256 tests has failed - return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast(totals.assertions.failed))); - } - catch( std::exception& ex ) { - Catch::cerr() << ex.what() << std::endl; - return MaxExitCode; - } - } - -} // end namespace Catch -// end catch_session.cpp -// start catch_startup_exception_registry.cpp - -namespace Catch { - void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { - try { - m_exceptions.push_back(exception); - } - catch(...) { - // If we run out of memory during start-up there's really not a lot more we can do about it - std::terminate(); - } - } - - std::vector const& StartupExceptionRegistry::getExceptions() const noexcept { - return m_exceptions; - } - -} // end namespace Catch -// end catch_startup_exception_registry.cpp -// start catch_stream.cpp - -#include -#include -#include -#include -#include -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -namespace Catch { - - Catch::IStream::~IStream() = default; - - namespace detail { namespace { - template - class StreamBufImpl : public std::streambuf { - char data[bufferSize]; - WriterF m_writer; - - public: - StreamBufImpl() { - setp( data, data + sizeof(data) ); - } - - ~StreamBufImpl() noexcept { - StreamBufImpl::sync(); - } - - private: - int overflow( int c ) override { - sync(); - - if( c != EOF ) { - if( pbase() == epptr() ) - m_writer( std::string( 1, static_cast( c ) ) ); - else - sputc( static_cast( c ) ); - } - return 0; - } - - int sync() override { - if( pbase() != pptr() ) { - m_writer( std::string( pbase(), static_cast( pptr() - pbase() ) ) ); - setp( pbase(), epptr() ); - } - return 0; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - struct OutputDebugWriter { - - void operator()( std::string const&str ) { - writeToDebugConsole( str ); - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class FileStream : public IStream { - mutable std::ofstream m_ofs; - public: - FileStream( StringRef filename ) { - m_ofs.open( filename.c_str() ); - CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); - } - ~FileStream() override = default; - public: // IStream - std::ostream& stream() const override { - return m_ofs; - } - }; - - /////////////////////////////////////////////////////////////////////////// - - class CoutStream : public IStream { - mutable std::ostream m_os; - public: - // Store the streambuf from cout up-front because - // cout may get redirected when running tests - CoutStream() : m_os( Catch::cout().rdbuf() ) {} - ~CoutStream() override = default; - - public: // IStream - std::ostream& stream() const override { return m_os; } - }; - - /////////////////////////////////////////////////////////////////////////// - - class DebugOutStream : public IStream { - std::unique_ptr> m_streamBuf; - mutable std::ostream m_os; - public: - DebugOutStream() - : m_streamBuf( new StreamBufImpl() ), - m_os( m_streamBuf.get() ) - {} - - ~DebugOutStream() override = default; - - public: // IStream - std::ostream& stream() const override { return m_os; } - }; - - }} // namespace anon::detail - - /////////////////////////////////////////////////////////////////////////// - - auto makeStream( StringRef const &filename ) -> IStream const* { - if( filename.empty() ) - return new detail::CoutStream(); - else if( filename[0] == '%' ) { - if( filename == "%debug" ) - return new detail::DebugOutStream(); - else - CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); - } - else - return new detail::FileStream( filename ); - } - - // This class encapsulates the idea of a pool of ostringstreams that can be reused. - struct StringStreams { - std::vector> m_streams; - std::vector m_unused; - std::ostringstream m_referenceStream; // Used for copy state/ flags from - static StringStreams* s_instance; - - auto add() -> std::size_t { - if( m_unused.empty() ) { - m_streams.push_back( std::unique_ptr( new std::ostringstream ) ); - return m_streams.size()-1; - } - else { - auto index = m_unused.back(); - m_unused.pop_back(); - return index; - } - } - - void release( std::size_t index ) { - m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state - m_unused.push_back(index); - } - - // !TBD: put in TLS - static auto instance() -> StringStreams& { - if( !s_instance ) - s_instance = new StringStreams(); - return *s_instance; - } - static void cleanup() { - delete s_instance; - s_instance = nullptr; - } - }; - - StringStreams* StringStreams::s_instance = nullptr; - - void ReusableStringStream::cleanup() { - StringStreams::cleanup(); - } - - ReusableStringStream::ReusableStringStream() - : m_index( StringStreams::instance().add() ), - m_oss( StringStreams::instance().m_streams[m_index].get() ) - {} - - ReusableStringStream::~ReusableStringStream() { - static_cast( m_oss )->str(""); - m_oss->clear(); - StringStreams::instance().release( m_index ); - } - - auto ReusableStringStream::str() const -> std::string { - return static_cast( m_oss )->str(); - } - - /////////////////////////////////////////////////////////////////////////// - -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions - std::ostream& cout() { return std::cout; } - std::ostream& cerr() { return std::cerr; } - std::ostream& clog() { return std::clog; } -#endif -} - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_stream.cpp -// start catch_string_manip.cpp - -#include -#include -#include -#include - -namespace Catch { - - bool startsWith( std::string const& s, std::string const& prefix ) { - return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); - } - bool startsWith( std::string const& s, char prefix ) { - return !s.empty() && s[0] == prefix; - } - bool endsWith( std::string const& s, std::string const& suffix ) { - return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); - } - bool endsWith( std::string const& s, char suffix ) { - return !s.empty() && s[s.size()-1] == suffix; - } - bool contains( std::string const& s, std::string const& infix ) { - return s.find( infix ) != std::string::npos; - } - char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); - } - void toLowerInPlace( std::string& s ) { - std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); - } - std::string toLower( std::string const& s ) { - std::string lc = s; - toLowerInPlace( lc ); - return lc; - } - std::string trim( std::string const& str ) { - static char const* whitespaceChars = "\n\r\t "; - std::string::size_type start = str.find_first_not_of( whitespaceChars ); - std::string::size_type end = str.find_last_not_of( whitespaceChars ); - - return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); - } - - bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { - bool replaced = false; - std::size_t i = str.find( replaceThis ); - while( i != std::string::npos ) { - replaced = true; - str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); - if( i < str.size()-withThis.size() ) - i = str.find( replaceThis, i+withThis.size() ); - else - i = std::string::npos; - } - return replaced; - } - - pluralise::pluralise( std::size_t count, std::string const& label ) - : m_count( count ), - m_label( label ) - {} - - std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { - os << pluraliser.m_count << ' ' << pluraliser.m_label; - if( pluraliser.m_count != 1 ) - os << 's'; - return os; - } - -} -// end catch_string_manip.cpp -// start catch_stringref.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -#include -#include -#include - -namespace { - const uint32_t byte_2_lead = 0xC0; - const uint32_t byte_3_lead = 0xE0; - const uint32_t byte_4_lead = 0xF0; -} - -namespace Catch { - StringRef::StringRef( char const* rawChars ) noexcept - : StringRef( rawChars, static_cast(std::strlen(rawChars) ) ) - {} - - StringRef::operator std::string() const { - return std::string( m_start, m_size ); - } - - void StringRef::swap( StringRef& other ) noexcept { - std::swap( m_start, other.m_start ); - std::swap( m_size, other.m_size ); - std::swap( m_data, other.m_data ); - } - - auto StringRef::c_str() const -> char const* { - if( isSubstring() ) - const_cast( this )->takeOwnership(); - return m_start; - } - auto StringRef::currentData() const noexcept -> char const* { - return m_start; - } - - auto StringRef::isOwned() const noexcept -> bool { - return m_data != nullptr; - } - auto StringRef::isSubstring() const noexcept -> bool { - return m_start[m_size] != '\0'; - } - - void StringRef::takeOwnership() { - if( !isOwned() ) { - m_data = new char[m_size+1]; - memcpy( m_data, m_start, m_size ); - m_data[m_size] = '\0'; - m_start = m_data; - } - } - auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { - if( start < m_size ) - return StringRef( m_start+start, size ); - else - return StringRef(); - } - auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { - return - size() == other.size() && - (std::strncmp( m_start, other.m_start, size() ) == 0); - } - auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { - return !operator==( other ); - } - - auto StringRef::operator[](size_type index) const noexcept -> char { - return m_start[index]; - } - - auto StringRef::numberOfCharacters() const noexcept -> size_type { - size_type noChars = m_size; - // Make adjustments for uft encodings - for( size_type i=0; i < m_size; ++i ) { - char c = m_start[i]; - if( ( c & byte_2_lead ) == byte_2_lead ) { - noChars--; - if (( c & byte_3_lead ) == byte_3_lead ) - noChars--; - if( ( c & byte_4_lead ) == byte_4_lead ) - noChars--; - } - } - return noChars; - } - - auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { - std::string str; - str.reserve( lhs.size() + rhs.size() ); - str += lhs; - str += rhs; - return str; - } - auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { - return std::string( lhs ) + std::string( rhs ); - } - - auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { - return os.write(str.currentData(), str.size()); - } - - auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { - lhs.append(rhs.currentData(), rhs.size()); - return lhs; - } - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_stringref.cpp -// start catch_tag_alias.cpp - -namespace Catch { - TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} -} -// end catch_tag_alias.cpp -// start catch_tag_alias_autoregistrar.cpp - -namespace Catch { - - RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { - try { - getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); - } catch (...) { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - -} -// end catch_tag_alias_autoregistrar.cpp -// start catch_tag_alias_registry.cpp - -#include - -namespace Catch { - - TagAliasRegistry::~TagAliasRegistry() {} - - TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { - auto it = m_registry.find( alias ); - if( it != m_registry.end() ) - return &(it->second); - else - return nullptr; - } - - std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { - std::string expandedTestSpec = unexpandedTestSpec; - for( auto const& registryKvp : m_registry ) { - std::size_t pos = expandedTestSpec.find( registryKvp.first ); - if( pos != std::string::npos ) { - expandedTestSpec = expandedTestSpec.substr( 0, pos ) + - registryKvp.second.tag + - expandedTestSpec.substr( pos + registryKvp.first.size() ); - } - } - return expandedTestSpec; - } - - void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { - CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), - "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); - - CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, - "error: tag alias, '" << alias << "' already registered.\n" - << "\tFirst seen at: " << find(alias)->lineInfo << "\n" - << "\tRedefined at: " << lineInfo ); - } - - ITagAliasRegistry::~ITagAliasRegistry() {} - - ITagAliasRegistry const& ITagAliasRegistry::get() { - return getRegistryHub().getTagAliasRegistry(); - } - -} // end namespace Catch -// end catch_tag_alias_registry.cpp -// start catch_test_case_info.cpp - -#include -#include -#include -#include - -namespace Catch { - - TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { - if( startsWith( tag, '.' ) || - tag == "!hide" ) - return TestCaseInfo::IsHidden; - else if( tag == "!throws" ) - return TestCaseInfo::Throws; - else if( tag == "!shouldfail" ) - return TestCaseInfo::ShouldFail; - else if( tag == "!mayfail" ) - return TestCaseInfo::MayFail; - else if( tag == "!nonportable" ) - return TestCaseInfo::NonPortable; - else if( tag == "!benchmark" ) - return static_cast( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); - else - return TestCaseInfo::None; - } - bool isReservedTag( std::string const& tag ) { - return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); - } - void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { - CATCH_ENFORCE( !isReservedTag(tag), - "Tag name: [" << tag << "] is not allowed.\n" - << "Tag names starting with non alpha-numeric characters are reserved\n" - << _lineInfo ); - } - - TestCase makeTestCase( ITestInvoker* _testCase, - std::string const& _className, - NameAndTags const& nameAndTags, - SourceLineInfo const& _lineInfo ) - { - bool isHidden = false; - - // Parse out tags - std::vector tags; - std::string desc, tag; - bool inTag = false; - std::string _descOrTags = nameAndTags.tags; - for (char c : _descOrTags) { - if( !inTag ) { - if( c == '[' ) - inTag = true; - else - desc += c; - } - else { - if( c == ']' ) { - TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); - if( ( prop & TestCaseInfo::IsHidden ) != 0 ) - isHidden = true; - else if( prop == TestCaseInfo::None ) - enforceNotReservedTag( tag, _lineInfo ); - - tags.push_back( tag ); - tag.clear(); - inTag = false; - } - else - tag += c; - } - } - if( isHidden ) { - tags.push_back( "." ); - } - - TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); - return TestCase( _testCase, std::move(info) ); - } - - void setTags( TestCaseInfo& testCaseInfo, std::vector tags ) { - std::sort(begin(tags), end(tags)); - tags.erase(std::unique(begin(tags), end(tags)), end(tags)); - testCaseInfo.lcaseTags.clear(); - - for( auto const& tag : tags ) { - std::string lcaseTag = toLower( tag ); - testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); - testCaseInfo.lcaseTags.push_back( lcaseTag ); - } - testCaseInfo.tags = std::move(tags); - } - - TestCaseInfo::TestCaseInfo( std::string const& _name, - std::string const& _className, - std::string const& _description, - std::vector const& _tags, - SourceLineInfo const& _lineInfo ) - : name( _name ), - className( _className ), - description( _description ), - lineInfo( _lineInfo ), - properties( None ) - { - setTags( *this, _tags ); - } - - bool TestCaseInfo::isHidden() const { - return ( properties & IsHidden ) != 0; - } - bool TestCaseInfo::throws() const { - return ( properties & Throws ) != 0; - } - bool TestCaseInfo::okToFail() const { - return ( properties & (ShouldFail | MayFail ) ) != 0; - } - bool TestCaseInfo::expectedToFail() const { - return ( properties & (ShouldFail ) ) != 0; - } - - std::string TestCaseInfo::tagsAsString() const { - std::string ret; - // '[' and ']' per tag - std::size_t full_size = 2 * tags.size(); - for (const auto& tag : tags) { - full_size += tag.size(); - } - ret.reserve(full_size); - for (const auto& tag : tags) { - ret.push_back('['); - ret.append(tag); - ret.push_back(']'); - } - - return ret; - } - - TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} - - TestCase TestCase::withName( std::string const& _newName ) const { - TestCase other( *this ); - other.name = _newName; - return other; - } - - void TestCase::invoke() const { - test->invoke(); - } - - bool TestCase::operator == ( TestCase const& other ) const { - return test.get() == other.test.get() && - name == other.name && - className == other.className; - } - - bool TestCase::operator < ( TestCase const& other ) const { - return name < other.name; - } - - TestCaseInfo const& TestCase::getTestCaseInfo() const - { - return *this; - } - -} // end namespace Catch -// end catch_test_case_info.cpp -// start catch_test_case_registry_impl.cpp - -#include - -namespace Catch { - - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { - - std::vector sorted = unsortedTestCases; - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - seedRng( config ); - RandomNumberGenerator::shuffle( sorted ); - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - return sorted; - } - bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { - return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); - } - - void enforceNoDuplicateTestCases( std::vector const& functions ) { - std::set seenFunctions; - for( auto const& function : functions ) { - auto prev = seenFunctions.insert( function ); - CATCH_ENFORCE( prev.second, - "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); - } - } - - std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { - std::vector filtered; - filtered.reserve( testCases.size() ); - for( auto const& testCase : testCases ) - if( matchTest( testCase, testSpec, config ) ) - filtered.push_back( testCase ); - return filtered; - } - std::vector const& getAllTestCasesSorted( IConfig const& config ) { - return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); - } - - void TestRegistry::registerTest( TestCase const& testCase ) { - std::string name = testCase.getTestCaseInfo().name; - if( name.empty() ) { - ReusableStringStream rss; - rss << "Anonymous test case " << ++m_unnamedCount; - return registerTest( testCase.withName( rss.str() ) ); - } - m_functions.push_back( testCase ); - } - - std::vector const& TestRegistry::getAllTests() const { - return m_functions; - } - std::vector const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { - if( m_sortedFunctions.empty() ) - enforceNoDuplicateTestCases( m_functions ); - - if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { - m_sortedFunctions = sortTests( config, m_functions ); - m_currentSortOrder = config.runOrder(); - } - return m_sortedFunctions; - } - - /////////////////////////////////////////////////////////////////////////// - TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} - - void TestInvokerAsFunction::invoke() const { - m_testAsFunction(); - } - - std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { - std::string className = classOrQualifiedMethodName; - if( startsWith( className, '&' ) ) - { - std::size_t lastColons = className.rfind( "::" ); - std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); - if( penultimateColons == std::string::npos ) - penultimateColons = 1; - className = className.substr( penultimateColons, lastColons-penultimateColons ); - } - return className; - } - -} // end namespace Catch -// end catch_test_case_registry_impl.cpp -// start catch_test_case_tracker.cpp - -#include -#include -#include -#include -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -#endif - -namespace Catch { -namespace TestCaseTracking { - - NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) - : name( _name ), - location( _location ) - {} - - ITracker::~ITracker() = default; - - TrackerContext& TrackerContext::instance() { - static TrackerContext s_instance; - return s_instance; - } - - ITracker& TrackerContext::startRun() { - m_rootTracker = std::make_shared( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); - m_currentTracker = nullptr; - m_runState = Executing; - return *m_rootTracker; - } - - void TrackerContext::endRun() { - m_rootTracker.reset(); - m_currentTracker = nullptr; - m_runState = NotStarted; - } - - void TrackerContext::startCycle() { - m_currentTracker = m_rootTracker.get(); - m_runState = Executing; - } - void TrackerContext::completeCycle() { - m_runState = CompletedCycle; - } - - bool TrackerContext::completedCycle() const { - return m_runState == CompletedCycle; - } - ITracker& TrackerContext::currentTracker() { - return *m_currentTracker; - } - void TrackerContext::setCurrentTracker( ITracker* tracker ) { - m_currentTracker = tracker; - } - - TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} - bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const { - return - tracker->nameAndLocation().name == m_nameAndLocation.name && - tracker->nameAndLocation().location == m_nameAndLocation.location; - } - - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), - m_ctx( ctx ), - m_parent( parent ) - {} - - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } - bool TrackerBase::isComplete() const { - return m_runState == CompletedSuccessfully || m_runState == Failed; - } - bool TrackerBase::isSuccessfullyCompleted() const { - return m_runState == CompletedSuccessfully; - } - bool TrackerBase::isOpen() const { - return m_runState != NotStarted && !isComplete(); - } - bool TrackerBase::hasChildren() const { - return !m_children.empty(); - } - - void TrackerBase::addChild( ITrackerPtr const& child ) { - m_children.push_back( child ); - } - - ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { - auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); - return( it != m_children.end() ) - ? *it - : nullptr; - } - ITracker& TrackerBase::parent() { - assert( m_parent ); // Should always be non-null except for root - return *m_parent; - } - - void TrackerBase::openChild() { - if( m_runState != ExecutingChildren ) { - m_runState = ExecutingChildren; - if( m_parent ) - m_parent->openChild(); - } - } - - bool TrackerBase::isSectionTracker() const { return false; } - bool TrackerBase::isIndexTracker() const { return false; } - - void TrackerBase::open() { - m_runState = Executing; - moveToThis(); - if( m_parent ) - m_parent->openChild(); - } - - void TrackerBase::close() { - - // Close any still open children (e.g. generators) - while( &m_ctx.currentTracker() != this ) - m_ctx.currentTracker().close(); - - switch( m_runState ) { - case NeedsAnotherRun: - break; - - case Executing: - m_runState = CompletedSuccessfully; - break; - case ExecutingChildren: - if( m_children.empty() || m_children.back()->isComplete() ) - m_runState = CompletedSuccessfully; - break; - - case NotStarted: - case CompletedSuccessfully: - case Failed: - CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); - - default: - CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); - } - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::fail() { - m_runState = Failed; - if( m_parent ) - m_parent->markAsNeedingAnotherRun(); - moveToParent(); - m_ctx.completeCycle(); - } - void TrackerBase::markAsNeedingAnotherRun() { - m_runState = NeedsAnotherRun; - } - - void TrackerBase::moveToParent() { - assert( m_parent ); - m_ctx.setCurrentTracker( m_parent ); - } - void TrackerBase::moveToThis() { - m_ctx.setCurrentTracker( this ); - } - - SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : TrackerBase( nameAndLocation, ctx, parent ) - { - if( parent ) { - while( !parent->isSectionTracker() ) - parent = &parent->parent(); - - SectionTracker& parentSection = static_cast( *parent ); - addNextFilters( parentSection.m_filters ); - } - } - - bool SectionTracker::isSectionTracker() const { return true; } - - SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { - std::shared_ptr section; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isSectionTracker() ); - section = std::static_pointer_cast( childTracker ); - } - else { - section = std::make_shared( nameAndLocation, ctx, ¤tTracker ); - currentTracker.addChild( section ); - } - if( !ctx.completedCycle() ) - section->tryOpen(); - return *section; - } - - void SectionTracker::tryOpen() { - if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) - open(); - } - - void SectionTracker::addInitialFilters( std::vector const& filters ) { - if( !filters.empty() ) { - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter - m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); - } - } - void SectionTracker::addNextFilters( std::vector const& filters ) { - if( filters.size() > 1 ) - m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); - } - - IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) - : TrackerBase( nameAndLocation, ctx, parent ), - m_size( size ) - {} - - bool IndexTracker::isIndexTracker() const { return true; } - - IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { - std::shared_ptr tracker; - - ITracker& currentTracker = ctx.currentTracker(); - if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { - assert( childTracker ); - assert( childTracker->isIndexTracker() ); - tracker = std::static_pointer_cast( childTracker ); - } - else { - tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker, size ); - currentTracker.addChild( tracker ); - } - - if( !ctx.completedCycle() && !tracker->isComplete() ) { - if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) - tracker->moveNext(); - tracker->open(); - } - - return *tracker; - } - - int IndexTracker::index() const { return m_index; } - - void IndexTracker::moveNext() { - m_index++; - m_children.clear(); - } - - void IndexTracker::close() { - TrackerBase::close(); - if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) - m_runState = Executing; - } - -} // namespace TestCaseTracking - -using TestCaseTracking::ITracker; -using TestCaseTracking::TrackerContext; -using TestCaseTracking::SectionTracker; -using TestCaseTracking::IndexTracker; - -} // namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif -// end catch_test_case_tracker.cpp -// start catch_test_registry.cpp - -namespace Catch { - - auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { - return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); - } - - NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} - - AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { - try { - getMutableRegistryHub() - .registerTest( - makeTestCase( - invoker, - extractClassName( classOrMethod ), - nameAndTags, - lineInfo)); - } catch (...) { - // Do not throw when constructing global objects, instead register the exception to be processed later - getMutableRegistryHub().registerStartupException(); - } - } - - AutoReg::~AutoReg() = default; -} -// end catch_test_registry.cpp -// start catch_test_spec.cpp - -#include -#include -#include -#include - -namespace Catch { - - TestSpec::Pattern::~Pattern() = default; - TestSpec::NamePattern::~NamePattern() = default; - TestSpec::TagPattern::~TagPattern() = default; - TestSpec::ExcludedPattern::~ExcludedPattern() = default; - - TestSpec::NamePattern::NamePattern( std::string const& name ) - : m_wildcardPattern( toLower( name ), CaseSensitive::No ) - {} - bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { - return m_wildcardPattern.matches( toLower( testCase.name ) ); - } - - TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} - bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { - return std::find(begin(testCase.lcaseTags), - end(testCase.lcaseTags), - m_tag) != end(testCase.lcaseTags); - } - - TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} - bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } - - bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { - // All patterns in a filter must match for the filter to be a match - for( auto const& pattern : m_patterns ) { - if( !pattern->matches( testCase ) ) - return false; - } - return true; - } - - bool TestSpec::hasFilters() const { - return !m_filters.empty(); - } - bool TestSpec::matches( TestCaseInfo const& testCase ) const { - // A TestSpec matches if any filter matches - for( auto const& filter : m_filters ) - if( filter.matches( testCase ) ) - return true; - return false; - } -} -// end catch_test_spec.cpp -// start catch_test_spec_parser.cpp - -namespace Catch { - - TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} - - TestSpecParser& TestSpecParser::parse( std::string const& arg ) { - m_mode = None; - m_exclusion = false; - m_start = std::string::npos; - m_arg = m_tagAliases->expandAliases( arg ); - m_escapeChars.clear(); - for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) - visitChar( m_arg[m_pos] ); - if( m_mode == Name ) - addPattern(); - return *this; - } - TestSpec TestSpecParser::testSpec() { - addFilter(); - return m_testSpec; - } - - void TestSpecParser::visitChar( char c ) { - if( m_mode == None ) { - switch( c ) { - case ' ': return; - case '~': m_exclusion = true; return; - case '[': return startNewMode( Tag, ++m_pos ); - case '"': return startNewMode( QuotedName, ++m_pos ); - case '\\': return escape(); - default: startNewMode( Name, m_pos ); break; - } - } - if( m_mode == Name ) { - if( c == ',' ) { - addPattern(); - addFilter(); - } - else if( c == '[' ) { - if( subString() == "exclude:" ) - m_exclusion = true; - else - addPattern(); - startNewMode( Tag, ++m_pos ); - } - else if( c == '\\' ) - escape(); - } - else if( m_mode == EscapedName ) - m_mode = Name; - else if( m_mode == QuotedName && c == '"' ) - addPattern(); - else if( m_mode == Tag && c == ']' ) - addPattern(); - } - void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { - m_mode = mode; - m_start = start; - } - void TestSpecParser::escape() { - if( m_mode == None ) - m_start = m_pos; - m_mode = EscapedName; - m_escapeChars.push_back( m_pos ); - } - std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } - - void TestSpecParser::addFilter() { - if( !m_currentFilter.m_patterns.empty() ) { - m_testSpec.m_filters.push_back( m_currentFilter ); - m_currentFilter = TestSpec::Filter(); - } - } - - TestSpec parseTestSpec( std::string const& arg ) { - return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); - } - -} // namespace Catch -// end catch_test_spec_parser.cpp -// start catch_timer.cpp - -#include - -static const uint64_t nanosecondsInSecond = 1000000000; - -namespace Catch { - - auto getCurrentNanosecondsSinceEpoch() -> uint64_t { - return std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); - } - - auto estimateClockResolution() -> uint64_t { - uint64_t sum = 0; - static const uint64_t iterations = 1000000; - - auto startTime = getCurrentNanosecondsSinceEpoch(); - - for( std::size_t i = 0; i < iterations; ++i ) { - - uint64_t ticks; - uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); - do { - ticks = getCurrentNanosecondsSinceEpoch(); - } while( ticks == baseTicks ); - - auto delta = ticks - baseTicks; - sum += delta; - - // If we have been calibrating for over 3 seconds -- the clock - // is terrible and we should move on. - // TBD: How to signal that the measured resolution is probably wrong? - if (ticks > startTime + 3 * nanosecondsInSecond) { - return sum / i; - } - } - - // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers - // - and potentially do more iterations if there's a high variance. - return sum/iterations; - } - auto getEstimatedClockResolution() -> uint64_t { - static auto s_resolution = estimateClockResolution(); - return s_resolution; - } - - void Timer::start() { - m_nanoseconds = getCurrentNanosecondsSinceEpoch(); - } - auto Timer::getElapsedNanoseconds() const -> uint64_t { - return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; - } - auto Timer::getElapsedMicroseconds() const -> uint64_t { - return getElapsedNanoseconds()/1000; - } - auto Timer::getElapsedMilliseconds() const -> unsigned int { - return static_cast(getElapsedMicroseconds()/1000); - } - auto Timer::getElapsedSeconds() const -> double { - return getElapsedMicroseconds()/1000000.0; - } - -} // namespace Catch -// end catch_timer.cpp -// start catch_tostring.cpp - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wexit-time-destructors" -# pragma clang diagnostic ignored "-Wglobal-constructors" -#endif - -// Enable specific decls locally -#if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) -#define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER -#endif - -#include -#include - -namespace Catch { - -namespace Detail { - - const std::string unprintableString = "{?}"; - - namespace { - const int hexThreshold = 255; - - struct Endianness { - enum Arch { Big, Little }; - - static Arch which() { - union _{ - int asInt; - char asChar[sizeof (int)]; - } u; - - u.asInt = 1; - return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; - } - }; - } - - std::string rawMemoryToString( const void *object, std::size_t size ) { - // Reverse order for little endian architectures - int i = 0, end = static_cast( size ), inc = 1; - if( Endianness::which() == Endianness::Little ) { - i = end-1; - end = inc = -1; - } - - unsigned char const *bytes = static_cast(object); - ReusableStringStream rss; - rss << "0x" << std::setfill('0') << std::hex; - for( ; i != end; i += inc ) - rss << std::setw(2) << static_cast(bytes[i]); - return rss.str(); - } -} - -template -std::string fpToString( T value, int precision ) { - if (std::isnan(value)) { - return "nan"; - } - - ReusableStringStream rss; - rss << std::setprecision( precision ) - << std::fixed - << value; - std::string d = rss.str(); - std::size_t i = d.find_last_not_of( '0' ); - if( i != std::string::npos && i != d.size()-1 ) { - if( d[i] == '.' ) - i++; - d = d.substr( 0, i+1 ); - } - return d; -} - -//// ======================================================= //// -// -// Out-of-line defs for full specialization of StringMaker -// -//// ======================================================= //// - -std::string StringMaker::convert(const std::string& str) { - if (!getCurrentContext().getConfig()->showInvisibles()) { - return '"' + str + '"'; - } - - std::string s("\""); - for (char c : str) { - switch (c) { - case '\n': - s.append("\\n"); - break; - case '\t': - s.append("\\t"); - break; - default: - s.push_back(c); - break; - } - } - s.append("\""); - return s; -} - -#ifdef CATCH_CONFIG_WCHAR -std::string StringMaker::convert(const std::wstring& wstr) { - std::string s; - s.reserve(wstr.size()); - for (auto c : wstr) { - s += (c <= 0xff) ? static_cast(c) : '?'; - } - return ::Catch::Detail::stringify(s); -} -#endif - -std::string StringMaker::convert(char const* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(char* str) { - if (str) { - return ::Catch::Detail::stringify(std::string{ str }); - } else { - return{ "{null string}" }; - } -} -#ifdef CATCH_CONFIG_WCHAR -std::string StringMaker::convert(wchar_t const * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -std::string StringMaker::convert(wchar_t * str) { - if (str) { - return ::Catch::Detail::stringify(std::wstring{ str }); - } else { - return{ "{null string}" }; - } -} -#endif - -std::string StringMaker::convert(int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(long long value) { - ReusableStringStream rss; - rss << value; - if (value > Detail::hexThreshold) { - rss << " (0x" << std::hex << value << ')'; - } - return rss.str(); -} - -std::string StringMaker::convert(unsigned int value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long value) { - return ::Catch::Detail::stringify(static_cast(value)); -} -std::string StringMaker::convert(unsigned long long value) { - ReusableStringStream rss; - rss << value; - if (value > Detail::hexThreshold) { - rss << " (0x" << std::hex << value << ')'; - } - return rss.str(); -} - -std::string StringMaker::convert(bool b) { - return b ? "true" : "false"; -} - -std::string StringMaker::convert(char value) { - if (value == '\r') { - return "'\\r'"; - } else if (value == '\f') { - return "'\\f'"; - } else if (value == '\n') { - return "'\\n'"; - } else if (value == '\t') { - return "'\\t'"; - } else if ('\0' <= value && value < ' ') { - return ::Catch::Detail::stringify(static_cast(value)); - } else { - char chstr[] = "' '"; - chstr[1] = value; - return chstr; - } -} -std::string StringMaker::convert(signed char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} -std::string StringMaker::convert(unsigned char c) { - return ::Catch::Detail::stringify(static_cast(c)); -} - -std::string StringMaker::convert(std::nullptr_t) { - return "nullptr"; -} - -std::string StringMaker::convert(float value) { - return fpToString(value, 5) + 'f'; -} -std::string StringMaker::convert(double value) { - return fpToString(value, 10); -} - -std::string ratio_string::symbol() { return "a"; } -std::string ratio_string::symbol() { return "f"; } -std::string ratio_string::symbol() { return "p"; } -std::string ratio_string::symbol() { return "n"; } -std::string ratio_string::symbol() { return "u"; } -std::string ratio_string::symbol() { return "m"; } - -} // end namespace Catch - -#if defined(__clang__) -# pragma clang diagnostic pop -#endif - -// end catch_tostring.cpp -// start catch_totals.cpp - -namespace Catch { - - Counts Counts::operator - ( Counts const& other ) const { - Counts diff; - diff.passed = passed - other.passed; - diff.failed = failed - other.failed; - diff.failedButOk = failedButOk - other.failedButOk; - return diff; - } - - Counts& Counts::operator += ( Counts const& other ) { - passed += other.passed; - failed += other.failed; - failedButOk += other.failedButOk; - return *this; - } - - std::size_t Counts::total() const { - return passed + failed + failedButOk; - } - bool Counts::allPassed() const { - return failed == 0 && failedButOk == 0; - } - bool Counts::allOk() const { - return failed == 0; - } - - Totals Totals::operator - ( Totals const& other ) const { - Totals diff; - diff.assertions = assertions - other.assertions; - diff.testCases = testCases - other.testCases; - return diff; - } - - Totals& Totals::operator += ( Totals const& other ) { - assertions += other.assertions; - testCases += other.testCases; - return *this; - } - - Totals Totals::delta( Totals const& prevTotals ) const { - Totals diff = *this - prevTotals; - if( diff.assertions.failed > 0 ) - ++diff.testCases.failed; - else if( diff.assertions.failedButOk > 0 ) - ++diff.testCases.failedButOk; - else - ++diff.testCases.passed; - return diff; - } - -} -// end catch_totals.cpp -// start catch_uncaught_exceptions.cpp - -#include - -namespace Catch { - bool uncaught_exceptions() { -#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) - return std::uncaught_exceptions() > 0; -#else - return std::uncaught_exception(); -#endif - } -} // end namespace Catch -// end catch_uncaught_exceptions.cpp -// start catch_version.cpp - -#include - -namespace Catch { - - Version::Version - ( unsigned int _majorVersion, - unsigned int _minorVersion, - unsigned int _patchNumber, - char const * const _branchName, - unsigned int _buildNumber ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - patchNumber( _patchNumber ), - branchName( _branchName ), - buildNumber( _buildNumber ) - {} - - std::ostream& operator << ( std::ostream& os, Version const& version ) { - os << version.majorVersion << '.' - << version.minorVersion << '.' - << version.patchNumber; - // branchName is never null -> 0th char is \0 if it is empty - if (version.branchName[0]) { - os << '-' << version.branchName - << '.' << version.buildNumber; - } - return os; - } - - Version const& libraryVersion() { - static Version version( 2, 2, 2, "", 0 ); - return version; - } - -} -// end catch_version.cpp -// start catch_wildcard_pattern.cpp - -#include - -namespace Catch { - - WildcardPattern::WildcardPattern( std::string const& pattern, - CaseSensitive::Choice caseSensitivity ) - : m_caseSensitivity( caseSensitivity ), - m_pattern( adjustCase( pattern ) ) - { - if( startsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_pattern, '*' ) ) { - m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } - - bool WildcardPattern::matches( std::string const& str ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_pattern == adjustCase( str ); - case WildcardAtStart: - return endsWith( adjustCase( str ), m_pattern ); - case WildcardAtEnd: - return startsWith( adjustCase( str ), m_pattern ); - case WildcardAtBothEnds: - return contains( adjustCase( str ), m_pattern ); - default: - CATCH_INTERNAL_ERROR( "Unknown enum" ); - } - } - - std::string WildcardPattern::adjustCase( std::string const& str ) const { - return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; - } -} -// end catch_wildcard_pattern.cpp -// start catch_xmlwriter.cpp - -#include - -using uchar = unsigned char; - -namespace Catch { - -namespace { - - size_t trailingBytes(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return 2; - } - if ((c & 0xF0) == 0xE0) { - return 3; - } - if ((c & 0xF8) == 0xF0) { - return 4; - } - CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - uint32_t headerValue(unsigned char c) { - if ((c & 0xE0) == 0xC0) { - return c & 0x1F; - } - if ((c & 0xF0) == 0xE0) { - return c & 0x0F; - } - if ((c & 0xF8) == 0xF0) { - return c & 0x07; - } - CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); - } - - void hexEscapeChar(std::ostream& os, unsigned char c) { - os << "\\x" - << std::uppercase << std::hex << std::setfill('0') << std::setw(2) - << static_cast(c); - } - -} // anonymous namespace - - XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) - : m_str( str ), - m_forWhat( forWhat ) - {} - - void XmlEncode::encodeTo( std::ostream& os ) const { - // Apostrophe escaping not necessary if we always use " to write attributes - // (see: http://www.w3.org/TR/xml/#syntax) - - for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; - switch (c) { - case '<': os << "<"; break; - case '&': os << "&"; break; - - case '>': - // See: http://www.w3.org/TR/xml/#syntax - if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') - os << ">"; - else - os << c; - break; - - case '\"': - if (m_forWhat == ForAttributes) - os << """; - else - os << c; - break; - - default: - // Check for control characters and invalid utf-8 - - // Escape control characters in standard ascii - // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 - if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { - hexEscapeChar(os, c); - break; - } - - // Plain ASCII: Write it to stream - if (c < 0x7F) { - os << c; - break; - } - - // UTF-8 territory - // Check if the encoding is valid and if it is not, hex escape bytes. - // Important: We do not check the exact decoded values for validity, only the encoding format - // First check that this bytes is a valid lead byte: - // This means that it is not encoded as 1111 1XXX - // Or as 10XX XXXX - if (c < 0xC0 || - c >= 0xF8) { - hexEscapeChar(os, c); - break; - } - - auto encBytes = trailingBytes(c); - // Are there enough bytes left to avoid accessing out-of-bounds memory? - if (idx + encBytes - 1 >= m_str.size()) { - hexEscapeChar(os, c); - break; - } - // The header is valid, check data - // The next encBytes bytes must together be a valid utf-8 - // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) - bool valid = true; - uint32_t value = headerValue(c); - for (std::size_t n = 1; n < encBytes; ++n) { - uchar nc = m_str[idx + n]; - valid &= ((nc & 0xC0) == 0x80); - value = (value << 6) | (nc & 0x3F); - } - - if ( - // Wrong bit pattern of following bytes - (!valid) || - // Overlong encodings - (value < 0x80) || - (0x80 <= value && value < 0x800 && encBytes > 2) || - (0x800 < value && value < 0x10000 && encBytes > 3) || - // Encoded value out of range - (value >= 0x110000) - ) { - hexEscapeChar(os, c); - break; - } - - // If we got here, this is in fact a valid(ish) utf-8 sequence - for (std::size_t n = 0; n < encBytes; ++n) { - os << m_str[idx + n]; - } - idx += encBytes - 1; - break; - } - } - } - - std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { - xmlEncode.encodeTo( os ); - return os; - } - - XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) - : m_writer( writer ) - {} - - XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept - : m_writer( other.m_writer ){ - other.m_writer = nullptr; - } - XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { - if ( m_writer ) { - m_writer->endElement(); - } - m_writer = other.m_writer; - other.m_writer = nullptr; - return *this; - } - - XmlWriter::ScopedElement::~ScopedElement() { - if( m_writer ) - m_writer->endElement(); - } - - XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { - m_writer->writeText( text, indent ); - return *this; - } - - XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) - { - writeDeclaration(); - } - - XmlWriter::~XmlWriter() { - while( !m_tags.empty() ) - endElement(); - } - - XmlWriter& XmlWriter::startElement( std::string const& name ) { - ensureTagClosed(); - newlineIfNecessary(); - m_os << m_indent << '<' << name; - m_tags.push_back( name ); - m_indent += " "; - m_tagIsOpen = true; - return *this; - } - - XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { - ScopedElement scoped( this ); - startElement( name ); - return scoped; - } - - XmlWriter& XmlWriter::endElement() { - newlineIfNecessary(); - m_indent = m_indent.substr( 0, m_indent.size()-2 ); - if( m_tagIsOpen ) { - m_os << "/>"; - m_tagIsOpen = false; - } - else { - m_os << m_indent << ""; - } - m_os << std::endl; - m_tags.pop_back(); - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) - m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { - m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; - return *this; - } - - XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { - if( !text.empty() ){ - bool tagWasOpen = m_tagIsOpen; - ensureTagClosed(); - if( tagWasOpen && indent ) - m_os << m_indent; - m_os << XmlEncode( text ); - m_needsNewline = true; - } - return *this; - } - - XmlWriter& XmlWriter::writeComment( std::string const& text ) { - ensureTagClosed(); - m_os << m_indent << ""; - m_needsNewline = true; - return *this; - } - - void XmlWriter::writeStylesheetRef( std::string const& url ) { - m_os << "\n"; - } - - XmlWriter& XmlWriter::writeBlankLine() { - ensureTagClosed(); - m_os << '\n'; - return *this; - } - - void XmlWriter::ensureTagClosed() { - if( m_tagIsOpen ) { - m_os << ">" << std::endl; - m_tagIsOpen = false; - } - } - - void XmlWriter::writeDeclaration() { - m_os << "\n"; - } - - void XmlWriter::newlineIfNecessary() { - if( m_needsNewline ) { - m_os << std::endl; - m_needsNewline = false; - } - } -} -// end catch_xmlwriter.cpp -// start catch_reporter_bases.cpp - -#include -#include -#include -#include -#include - -namespace Catch { - void prepareExpandedExpression(AssertionResult& result) { - result.getExpandedExpression(); - } - - // Because formatting using c++ streams is stateful, drop down to C is required - // Alternatively we could use stringstream, but its performance is... not good. - std::string getFormattedDuration( double duration ) { - // Max exponent + 1 is required to represent the whole part - // + 1 for decimal point - // + 3 for the 3 decimal places - // + 1 for null terminator - const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; - char buffer[maxDoubleSize]; - - // Save previous errno, to prevent sprintf from overwriting it - ErrnoGuard guard; -#ifdef _MSC_VER - sprintf_s(buffer, "%.3f", duration); -#else - sprintf(buffer, "%.3f", duration); -#endif - return std::string(buffer); - } - - TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) - :StreamingReporterBase(_config) {} - - void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} - - bool TestEventListenerBase::assertionEnded(AssertionStats const &) { - return false; - } - -} // end namespace Catch -// end catch_reporter_bases.cpp -// start catch_reporter_compact.cpp - -namespace { - -#ifdef CATCH_PLATFORM_MAC - const char* failedString() { return "FAILED"; } - const char* passedString() { return "PASSED"; } -#else - const char* failedString() { return "failed"; } - const char* passedString() { return "passed"; } -#endif - - // Colour::LightGrey - Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } - - std::string bothOrAll( std::size_t count ) { - return count == 1 ? std::string() : - count == 2 ? "both " : "all " ; - } - -} // anon namespace - -namespace Catch { -namespace { -// Colour, message variants: -// - white: No tests ran. -// - red: Failed [both/all] N test cases, failed [both/all] M assertions. -// - white: Passed [both/all] N test cases (no assertions). -// - red: Failed N tests cases, failed M assertions. -// - green: Passed [both/all] N tests cases with M assertions. -void printTotals(std::ostream& out, const Totals& totals) { - if (totals.testCases.total() == 0) { - out << "No tests ran."; - } else if (totals.testCases.failed == totals.testCases.total()) { - Colour colour(Colour::ResultError); - const std::string qualify_assertions_failed = - totals.assertions.failed == totals.assertions.total() ? - bothOrAll(totals.assertions.failed) : std::string(); - out << - "Failed " << bothOrAll(totals.testCases.failed) - << pluralise(totals.testCases.failed, "test case") << ", " - "failed " << qualify_assertions_failed << - pluralise(totals.assertions.failed, "assertion") << '.'; - } else if (totals.assertions.total() == 0) { - out << - "Passed " << bothOrAll(totals.testCases.total()) - << pluralise(totals.testCases.total(), "test case") - << " (no assertions)."; - } else if (totals.assertions.failed) { - Colour colour(Colour::ResultError); - out << - "Failed " << pluralise(totals.testCases.failed, "test case") << ", " - "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; - } else { - Colour colour(Colour::ResultSuccess); - out << - "Passed " << bothOrAll(totals.testCases.passed) - << pluralise(totals.testCases.passed, "test case") << - " with " << pluralise(totals.assertions.passed, "assertion") << '.'; - } -} - -// Implementation of CompactReporter formatting -class AssertionPrinter { -public: - AssertionPrinter& operator= (AssertionPrinter const&) = delete; - AssertionPrinter(AssertionPrinter const&) = delete; - AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) - : stream(_stream) - , result(_stats.assertionResult) - , messages(_stats.infoMessages) - , itMessage(_stats.infoMessages.begin()) - , printInfoMessages(_printInfoMessages) {} - - void print() { - printSourceInfo(); - - itMessage = messages.begin(); - - switch (result.getResultType()) { - case ResultWas::Ok: - printResultType(Colour::ResultSuccess, passedString()); - printOriginalExpression(); - printReconstructedExpression(); - if (!result.hasExpression()) - printRemainingMessages(Colour::None); - else - printRemainingMessages(); - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) - printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); - else - printResultType(Colour::Error, failedString()); - printOriginalExpression(); - printReconstructedExpression(); - printRemainingMessages(); - break; - case ResultWas::ThrewException: - printResultType(Colour::Error, failedString()); - printIssue("unexpected exception with message:"); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::FatalErrorCondition: - printResultType(Colour::Error, failedString()); - printIssue("fatal error condition with message:"); - printMessage(); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::DidntThrowException: - printResultType(Colour::Error, failedString()); - printIssue("expected exception, got none"); - printExpressionWas(); - printRemainingMessages(); - break; - case ResultWas::Info: - printResultType(Colour::None, "info"); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::Warning: - printResultType(Colour::None, "warning"); - printMessage(); - printRemainingMessages(); - break; - case ResultWas::ExplicitFailure: - printResultType(Colour::Error, failedString()); - printIssue("explicitly"); - printRemainingMessages(Colour::None); - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - printResultType(Colour::Error, "** internal error **"); - break; - } - } - -private: - void printSourceInfo() const { - Colour colourGuard(Colour::FileName); - stream << result.getSourceInfo() << ':'; - } - - void printResultType(Colour::Code colour, std::string const& passOrFail) const { - if (!passOrFail.empty()) { - { - Colour colourGuard(colour); - stream << ' ' << passOrFail; - } - stream << ':'; - } - } - - void printIssue(std::string const& issue) const { - stream << ' ' << issue; - } - - void printExpressionWas() { - if (result.hasExpression()) { - stream << ';'; - { - Colour colour(dimColour()); - stream << " expression was:"; - } - printOriginalExpression(); - } - } - - void printOriginalExpression() const { - if (result.hasExpression()) { - stream << ' ' << result.getExpression(); - } - } - - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - { - Colour colour(dimColour()); - stream << " for: "; - } - stream << result.getExpandedExpression(); - } - } - - void printMessage() { - if (itMessage != messages.end()) { - stream << " '" << itMessage->message << '\''; - ++itMessage; - } - } - - void printRemainingMessages(Colour::Code colour = dimColour()) { - if (itMessage == messages.end()) - return; - - // using messages.end() directly yields (or auto) compilation error: - std::vector::const_iterator itEnd = messages.end(); - const std::size_t N = static_cast(std::distance(itMessage, itEnd)); - - { - Colour colourGuard(colour); - stream << " with " << pluralise(N, "message") << ':'; - } - - for (; itMessage != itEnd; ) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || itMessage->type != ResultWas::Info) { - stream << " '" << itMessage->message << '\''; - if (++itMessage != itEnd) { - Colour colourGuard(dimColour()); - stream << " and"; - } - } - } - } - -private: - std::ostream& stream; - AssertionResult const& result; - std::vector messages; - std::vector::const_iterator itMessage; - bool printInfoMessages; -}; - -} // anon namespace - - std::string CompactReporter::getDescription() { - return "Reports test results on a single line, suitable for IDEs"; - } - - ReporterPreferences CompactReporter::getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - - void CompactReporter::noMatchingTestCases( std::string const& spec ) { - stream << "No test cases matched '" << spec << '\'' << std::endl; - } - - void CompactReporter::assertionStarting( AssertionInfo const& ) {} - - bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool printInfoMessages = true; - - // Drop out if result was successful and we're not printing those - if( !m_config->includeSuccessfulResults() && result.isOk() ) { - if( result.getResultType() != ResultWas::Warning ) - return false; - printInfoMessages = false; - } - - AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); - printer.print(); - - stream << std::endl; - return true; - } - - void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - } - - void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { - printTotals( stream, _testRunStats.totals ); - stream << '\n' << std::endl; - StreamingReporterBase::testRunEnded( _testRunStats ); - } - - CompactReporter::~CompactReporter() {} - - CATCH_REGISTER_REPORTER( "compact", CompactReporter ) - -} // end namespace Catch -// end catch_reporter_compact.cpp -// start catch_reporter_console.cpp - -#include -#include - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - -namespace { - -// Formatter impl for ConsoleReporter -class ConsoleAssertionPrinter { -public: - ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; - ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; - ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) - : stream(_stream), - stats(_stats), - result(_stats.assertionResult), - colour(Colour::None), - message(result.getMessage()), - messages(_stats.infoMessages), - printInfoMessages(_printInfoMessages) { - switch (result.getResultType()) { - case ResultWas::Ok: - colour = Colour::Success; - passOrFail = "PASSED"; - //if( result.hasMessage() ) - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; - break; - case ResultWas::ExpressionFailed: - if (result.isOk()) { - colour = Colour::Success; - passOrFail = "FAILED - but was ok"; - } else { - colour = Colour::Error; - passOrFail = "FAILED"; - } - if (_stats.infoMessages.size() == 1) - messageLabel = "with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "with messages"; - break; - case ResultWas::ThrewException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to unexpected exception with "; - if (_stats.infoMessages.size() == 1) - messageLabel += "message"; - if (_stats.infoMessages.size() > 1) - messageLabel += "messages"; - break; - case ResultWas::FatalErrorCondition: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "due to a fatal error condition"; - break; - case ResultWas::DidntThrowException: - colour = Colour::Error; - passOrFail = "FAILED"; - messageLabel = "because no exception was thrown where one was expected"; - break; - case ResultWas::Info: - messageLabel = "info"; - break; - case ResultWas::Warning: - messageLabel = "warning"; - break; - case ResultWas::ExplicitFailure: - passOrFail = "FAILED"; - colour = Colour::Error; - if (_stats.infoMessages.size() == 1) - messageLabel = "explicitly with message"; - if (_stats.infoMessages.size() > 1) - messageLabel = "explicitly with messages"; - break; - // These cases are here to prevent compiler warnings - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - passOrFail = "** internal error **"; - colour = Colour::Error; - break; - } - } - - void print() const { - printSourceInfo(); - if (stats.totals.assertions.total() > 0) { - if (result.isOk()) - stream << '\n'; - printResultType(); - printOriginalExpression(); - printReconstructedExpression(); - } else { - stream << '\n'; - } - printMessage(); - } - -private: - void printResultType() const { - if (!passOrFail.empty()) { - Colour colourGuard(colour); - stream << passOrFail << ":\n"; - } - } - void printOriginalExpression() const { - if (result.hasExpression()) { - Colour colourGuard(Colour::OriginalExpression); - stream << " "; - stream << result.getExpressionInMacro(); - stream << '\n'; - } - } - void printReconstructedExpression() const { - if (result.hasExpandedExpression()) { - stream << "with expansion:\n"; - Colour colourGuard(Colour::ReconstructedExpression); - stream << Column(result.getExpandedExpression()).indent(2) << '\n'; - } - } - void printMessage() const { - if (!messageLabel.empty()) - stream << messageLabel << ':' << '\n'; - for (auto const& msg : messages) { - // If this assertion is a warning ignore any INFO messages - if (printInfoMessages || msg.type != ResultWas::Info) - stream << Column(msg.message).indent(2) << '\n'; - } - } - void printSourceInfo() const { - Colour colourGuard(Colour::FileName); - stream << result.getSourceInfo() << ": "; - } - - std::ostream& stream; - AssertionStats const& stats; - AssertionResult const& result; - Colour::Code colour; - std::string passOrFail; - std::string messageLabel; - std::string message; - std::vector messages; - bool printInfoMessages; -}; - -std::size_t makeRatio(std::size_t number, std::size_t total) { - std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; - return (ratio == 0 && number > 0) ? 1 : ratio; -} - -std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { - if (i > j && i > k) - return i; - else if (j > k) - return j; - else - return k; -} - -struct ColumnInfo { - enum Justification { Left, Right }; - std::string name; - int width; - Justification justification; -}; -struct ColumnBreak {}; -struct RowBreak {}; - -class Duration { - enum class Unit { - Auto, - Nanoseconds, - Microseconds, - Milliseconds, - Seconds, - Minutes - }; - static const uint64_t s_nanosecondsInAMicrosecond = 1000; - static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; - static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; - static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - - uint64_t m_inNanoseconds; - Unit m_units; - -public: - explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) - : m_inNanoseconds(inNanoseconds), - m_units(units) { - if (m_units == Unit::Auto) { - if (m_inNanoseconds < s_nanosecondsInAMicrosecond) - m_units = Unit::Nanoseconds; - else if (m_inNanoseconds < s_nanosecondsInAMillisecond) - m_units = Unit::Microseconds; - else if (m_inNanoseconds < s_nanosecondsInASecond) - m_units = Unit::Milliseconds; - else if (m_inNanoseconds < s_nanosecondsInAMinute) - m_units = Unit::Seconds; - else - m_units = Unit::Minutes; - } - - } - - auto value() const -> double { - switch (m_units) { - case Unit::Microseconds: - return m_inNanoseconds / static_cast(s_nanosecondsInAMicrosecond); - case Unit::Milliseconds: - return m_inNanoseconds / static_cast(s_nanosecondsInAMillisecond); - case Unit::Seconds: - return m_inNanoseconds / static_cast(s_nanosecondsInASecond); - case Unit::Minutes: - return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); - default: - return static_cast(m_inNanoseconds); - } - } - auto unitsAsString() const -> std::string { - switch (m_units) { - case Unit::Nanoseconds: - return "ns"; - case Unit::Microseconds: - return "µs"; - case Unit::Milliseconds: - return "ms"; - case Unit::Seconds: - return "s"; - case Unit::Minutes: - return "m"; - default: - return "** internal error **"; - } - - } - friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { - return os << duration.value() << " " << duration.unitsAsString(); - } -}; -} // end anon namespace - -class TablePrinter { - std::ostream& m_os; - std::vector m_columnInfos; - std::ostringstream m_oss; - int m_currentColumn = -1; - bool m_isOpen = false; - -public: - TablePrinter( std::ostream& os, std::vector columnInfos ) - : m_os( os ), - m_columnInfos( std::move( columnInfos ) ) {} - - auto columnInfos() const -> std::vector const& { - return m_columnInfos; - } - - void open() { - if (!m_isOpen) { - m_isOpen = true; - *this << RowBreak(); - for (auto const& info : m_columnInfos) - *this << info.name << ColumnBreak(); - *this << RowBreak(); - m_os << Catch::getLineOfChars<'-'>() << "\n"; - } - } - void close() { - if (m_isOpen) { - *this << RowBreak(); - m_os << std::endl; - m_isOpen = false; - } - } - - template - friend TablePrinter& operator << (TablePrinter& tp, T const& value) { - tp.m_oss << value; - return tp; - } - - friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { - auto colStr = tp.m_oss.str(); - // This takes account of utf8 encodings - auto strSize = Catch::StringRef(colStr).numberOfCharacters(); - tp.m_oss.str(""); - tp.open(); - if (tp.m_currentColumn == static_cast(tp.m_columnInfos.size() - 1)) { - tp.m_currentColumn = -1; - tp.m_os << "\n"; - } - tp.m_currentColumn++; - - auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; - auto padding = (strSize + 2 < static_cast(colInfo.width)) - ? std::string(colInfo.width - (strSize + 2), ' ') - : std::string(); - if (colInfo.justification == ColumnInfo::Left) - tp.m_os << colStr << padding << " "; - else - tp.m_os << padding << colStr << " "; - return tp; - } - - friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { - if (tp.m_currentColumn > 0) { - tp.m_os << "\n"; - tp.m_currentColumn = -1; - } - return tp; - } -}; - -ConsoleReporter::ConsoleReporter(ReporterConfig const& config) - : StreamingReporterBase(config), - m_tablePrinter(new TablePrinter(config.stream(), - { - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, - { "iters", 8, ColumnInfo::Right }, - { "elapsed ns", 14, ColumnInfo::Right }, - { "average", 14, ColumnInfo::Right } - })) {} -ConsoleReporter::~ConsoleReporter() = default; - -std::string ConsoleReporter::getDescription() { - return "Reports test results as plain lines of text"; -} - -void ConsoleReporter::noMatchingTestCases(std::string const& spec) { - stream << "No test cases matched '" << spec << '\'' << std::endl; -} - -void ConsoleReporter::assertionStarting(AssertionInfo const&) {} - -bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { - AssertionResult const& result = _assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - // Drop out if result was successful but we're not printing them. - if (!includeResults && result.getResultType() != ResultWas::Warning) - return false; - - lazyPrint(); - - ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); - printer.print(); - stream << std::endl; - return true; -} - -void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { - m_headerPrinted = false; - StreamingReporterBase::sectionStarting(_sectionInfo); -} -void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { - m_tablePrinter->close(); - if (_sectionStats.missingAssertions) { - lazyPrint(); - Colour colour(Colour::ResultError); - if (m_sectionStack.size() > 1) - stream << "\nNo assertions in section"; - else - stream << "\nNo assertions in test case"; - stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; - } - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; - } - if (m_headerPrinted) { - m_headerPrinted = false; - } - StreamingReporterBase::sectionEnded(_sectionStats); -} - -void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { - lazyPrintWithoutClosingBenchmarkTable(); - - auto nameCol = Column( info.name ).width( static_cast( m_tablePrinter->columnInfos()[0].width - 2 ) ); - - bool firstLine = true; - for (auto line : nameCol) { - if (!firstLine) - (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); - else - firstLine = false; - - (*m_tablePrinter) << line << ColumnBreak(); - } -} -void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { - Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); - (*m_tablePrinter) - << stats.iterations << ColumnBreak() - << stats.elapsedTimeInNanoseconds << ColumnBreak() - << average << ColumnBreak(); -} - -void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { - m_tablePrinter->close(); - StreamingReporterBase::testCaseEnded(_testCaseStats); - m_headerPrinted = false; -} -void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { - if (currentGroupInfo.used) { - printSummaryDivider(); - stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; - printTotals(_testGroupStats.totals); - stream << '\n' << std::endl; - } - StreamingReporterBase::testGroupEnded(_testGroupStats); -} -void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { - printTotalsDivider(_testRunStats.totals); - printTotals(_testRunStats.totals); - stream << std::endl; - StreamingReporterBase::testRunEnded(_testRunStats); -} - -void ConsoleReporter::lazyPrint() { - - m_tablePrinter->close(); - lazyPrintWithoutClosingBenchmarkTable(); -} - -void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { - - if (!currentTestRunInfo.used) - lazyPrintRunInfo(); - if (!currentGroupInfo.used) - lazyPrintGroupInfo(); - - if (!m_headerPrinted) { - printTestCaseAndSectionHeader(); - m_headerPrinted = true; - } -} -void ConsoleReporter::lazyPrintRunInfo() { - stream << '\n' << getLineOfChars<'~'>() << '\n'; - Colour colour(Colour::SecondaryText); - stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion() << " host application.\n" - << "Run with -? for options\n\n"; - - if (m_config->rngSeed() != 0) - stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; - - currentTestRunInfo.used = true; -} -void ConsoleReporter::lazyPrintGroupInfo() { - if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { - printClosedHeader("Group: " + currentGroupInfo->name); - currentGroupInfo.used = true; - } -} -void ConsoleReporter::printTestCaseAndSectionHeader() { - assert(!m_sectionStack.empty()); - printOpenHeader(currentTestCaseInfo->name); - - if (m_sectionStack.size() > 1) { - Colour colourGuard(Colour::Headers); - - auto - it = m_sectionStack.begin() + 1, // Skip first section (test case) - itEnd = m_sectionStack.end(); - for (; it != itEnd; ++it) - printHeaderString(it->name, 2); - } - - SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; - - if (!lineInfo.empty()) { - stream << getLineOfChars<'-'>() << '\n'; - Colour colourGuard(Colour::FileName); - stream << lineInfo << '\n'; - } - stream << getLineOfChars<'.'>() << '\n' << std::endl; -} - -void ConsoleReporter::printClosedHeader(std::string const& _name) { - printOpenHeader(_name); - stream << getLineOfChars<'.'>() << '\n'; -} -void ConsoleReporter::printOpenHeader(std::string const& _name) { - stream << getLineOfChars<'-'>() << '\n'; - { - Colour colourGuard(Colour::Headers); - printHeaderString(_name); - } -} - -// if string has a : in first line will set indent to follow it on -// subsequent lines -void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { - std::size_t i = _string.find(": "); - if (i != std::string::npos) - i += 2; - else - i = 0; - stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; -} - -struct SummaryColumn { - - SummaryColumn( std::string _label, Colour::Code _colour ) - : label( std::move( _label ) ), - colour( _colour ) {} - SummaryColumn addRow( std::size_t count ) { - ReusableStringStream rss; - rss << count; - std::string row = rss.str(); - for (auto& oldRow : rows) { - while (oldRow.size() < row.size()) - oldRow = ' ' + oldRow; - while (oldRow.size() > row.size()) - row = ' ' + row; - } - rows.push_back(row); - return *this; - } - - std::string label; - Colour::Code colour; - std::vector rows; - -}; - -void ConsoleReporter::printTotals( Totals const& totals ) { - if (totals.testCases.total() == 0) { - stream << Colour(Colour::Warning) << "No tests ran\n"; - } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { - stream << Colour(Colour::ResultSuccess) << "All tests passed"; - stream << " (" - << pluralise(totals.assertions.passed, "assertion") << " in " - << pluralise(totals.testCases.passed, "test case") << ')' - << '\n'; - } else { - - std::vector columns; - columns.push_back(SummaryColumn("", Colour::None) - .addRow(totals.testCases.total()) - .addRow(totals.assertions.total())); - columns.push_back(SummaryColumn("passed", Colour::Success) - .addRow(totals.testCases.passed) - .addRow(totals.assertions.passed)); - columns.push_back(SummaryColumn("failed", Colour::ResultError) - .addRow(totals.testCases.failed) - .addRow(totals.assertions.failed)); - columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) - .addRow(totals.testCases.failedButOk) - .addRow(totals.assertions.failedButOk)); - - printSummaryRow("test cases", columns, 0); - printSummaryRow("assertions", columns, 1); - } -} -void ConsoleReporter::printSummaryRow(std::string const& label, std::vector const& cols, std::size_t row) { - for (auto col : cols) { - std::string value = col.rows[row]; - if (col.label.empty()) { - stream << label << ": "; - if (value != "0") - stream << value; - else - stream << Colour(Colour::Warning) << "- none -"; - } else if (value != "0") { - stream << Colour(Colour::LightGrey) << " | "; - stream << Colour(col.colour) - << value << ' ' << col.label; - } - } - stream << '\n'; -} - -void ConsoleReporter::printTotalsDivider(Totals const& totals) { - if (totals.testCases.total() > 0) { - std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); - std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); - std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); - while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)++; - while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) - findMax(failedRatio, failedButOkRatio, passedRatio)--; - - stream << Colour(Colour::Error) << std::string(failedRatio, '='); - stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); - if (totals.testCases.allPassed()) - stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); - else - stream << Colour(Colour::Success) << std::string(passedRatio, '='); - } else { - stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); - } - stream << '\n'; -} -void ConsoleReporter::printSummaryDivider() { - stream << getLineOfChars<'-'>() << '\n'; -} - -CATCH_REGISTER_REPORTER("console", ConsoleReporter) - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -// end catch_reporter_console.cpp -// start catch_reporter_junit.cpp - -#include -#include -#include -#include - -namespace Catch { - - namespace { - std::string getCurrentTimestamp() { - // Beware, this is not reentrant because of backward compatibility issues - // Also, UTC only, again because of backward compatibility (%z is C++11) - time_t rawtime; - std::time(&rawtime); - auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); - -#ifdef _MSC_VER - std::tm timeInfo = {}; - gmtime_s(&timeInfo, &rawtime); -#else - std::tm* timeInfo; - timeInfo = std::gmtime(&rawtime); -#endif - - char timeStamp[timeStampSize]; - const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; - -#ifdef _MSC_VER - std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); -#else - std::strftime(timeStamp, timeStampSize, fmt, timeInfo); -#endif - return std::string(timeStamp); - } - - std::string fileNameTag(const std::vector &tags) { - auto it = std::find_if(begin(tags), - end(tags), - [] (std::string const& tag) {return tag.front() == '#'; }); - if (it != tags.end()) - return it->substr(1); - return std::string(); - } - } // anonymous namespace - - JunitReporter::JunitReporter( ReporterConfig const& _config ) - : CumulativeReporterBase( _config ), - xml( _config.stream() ) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } - - JunitReporter::~JunitReporter() {} - - std::string JunitReporter::getDescription() { - return "Reports test results in an XML format that looks like Ant's junitreport target"; - } - - void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} - - void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { - CumulativeReporterBase::testRunStarting( runInfo ); - xml.startElement( "testsuites" ); - } - - void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { - suiteTimer.start(); - stdOutForSuite.clear(); - stdErrForSuite.clear(); - unexpectedExceptions = 0; - CumulativeReporterBase::testGroupStarting( groupInfo ); - } - - void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { - m_okToFail = testCaseInfo.okToFail(); - } - - bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { - if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) - unexpectedExceptions++; - return CumulativeReporterBase::assertionEnded( assertionStats ); - } - - void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - stdOutForSuite += testCaseStats.stdOut; - stdErrForSuite += testCaseStats.stdErr; - CumulativeReporterBase::testCaseEnded( testCaseStats ); - } - - void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { - double suiteTime = suiteTimer.getElapsedSeconds(); - CumulativeReporterBase::testGroupEnded( testGroupStats ); - writeGroup( *m_testGroups.back(), suiteTime ); - } - - void JunitReporter::testRunEndedCumulative() { - xml.endElement(); - } - - void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); - TestGroupStats const& stats = groupNode.value; - xml.writeAttribute( "name", stats.groupInfo.name ); - xml.writeAttribute( "errors", unexpectedExceptions ); - xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); - xml.writeAttribute( "tests", stats.totals.assertions.total() ); - xml.writeAttribute( "hostname", "tbd" ); // !TBD - if( m_config->showDurations() == ShowDurations::Never ) - xml.writeAttribute( "time", "" ); - else - xml.writeAttribute( "time", suiteTime ); - xml.writeAttribute( "timestamp", getCurrentTimestamp() ); - - // Write test cases - for( auto const& child : groupNode.children ) - writeTestCase( *child ); - - xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); - xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); - } - - void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { - TestCaseStats const& stats = testCaseNode.value; - - // All test cases have exactly one section - which represents the - // test case itself. That section may have 0-n nested sections - assert( testCaseNode.children.size() == 1 ); - SectionNode const& rootSection = *testCaseNode.children.front(); - - std::string className = stats.testInfo.className; - - if( className.empty() ) { - className = fileNameTag(stats.testInfo.tags); - if ( className.empty() ) - className = "global"; - } - - if ( !m_config->name().empty() ) - className = m_config->name() + "." + className; - - writeSection( className, "", rootSection ); - } - - void JunitReporter::writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { - std::string name = trim( sectionNode.stats.sectionInfo.name ); - if( !rootName.empty() ) - name = rootName + '/' + name; - - if( !sectionNode.assertions.empty() || - !sectionNode.stdOut.empty() || - !sectionNode.stdErr.empty() ) { - XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); - if( className.empty() ) { - xml.writeAttribute( "classname", name ); - xml.writeAttribute( "name", "root" ); - } - else { - xml.writeAttribute( "classname", className ); - xml.writeAttribute( "name", name ); - } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); - - writeAssertions( sectionNode ); - - if( !sectionNode.stdOut.empty() ) - xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); - if( !sectionNode.stdErr.empty() ) - xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); - } - for( auto const& childNode : sectionNode.childSections ) - if( className.empty() ) - writeSection( name, "", *childNode ); - else - writeSection( className, name, *childNode ); - } - - void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { - for( auto const& assertion : sectionNode.assertions ) - writeAssertion( assertion ); - } - - void JunitReporter::writeAssertion( AssertionStats const& stats ) { - AssertionResult const& result = stats.assertionResult; - if( !result.isOk() ) { - std::string elementName; - switch( result.getResultType() ) { - case ResultWas::ThrewException: - case ResultWas::FatalErrorCondition: - elementName = "error"; - break; - case ResultWas::ExplicitFailure: - elementName = "failure"; - break; - case ResultWas::ExpressionFailed: - elementName = "failure"; - break; - case ResultWas::DidntThrowException: - elementName = "failure"; - break; - - // We should never see these here: - case ResultWas::Info: - case ResultWas::Warning: - case ResultWas::Ok: - case ResultWas::Unknown: - case ResultWas::FailureBit: - case ResultWas::Exception: - elementName = "internalError"; - break; - } - - XmlWriter::ScopedElement e = xml.scopedElement( elementName ); - - xml.writeAttribute( "message", result.getExpandedExpression() ); - xml.writeAttribute( "type", result.getTestMacroName() ); - - ReusableStringStream rss; - if( !result.getMessage().empty() ) - rss << result.getMessage() << '\n'; - for( auto const& msg : stats.infoMessages ) - if( msg.type == ResultWas::Info ) - rss << msg.message << '\n'; - - rss << "at " << result.getSourceInfo(); - xml.writeText( rss.str(), false ); - } - } - - CATCH_REGISTER_REPORTER( "junit", JunitReporter ) - -} // end namespace Catch -// end catch_reporter_junit.cpp -// start catch_reporter_multi.cpp - -namespace Catch { - - void MultipleReporters::add( IStreamingReporterPtr&& reporter ) { - m_reporters.push_back( std::move( reporter ) ); - } - - ReporterPreferences MultipleReporters::getPreferences() const { - return m_reporters[0]->getPreferences(); - } - - std::set MultipleReporters::getSupportedVerbosities() { - return std::set{ }; - } - - void MultipleReporters::noMatchingTestCases( std::string const& spec ) { - for( auto const& reporter : m_reporters ) - reporter->noMatchingTestCases( spec ); - } - - void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkStarting( benchmarkInfo ); - } - void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { - for( auto const& reporter : m_reporters ) - reporter->benchmarkEnded( benchmarkStats ); - } - - void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testRunStarting( testRunInfo ); - } - - void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupStarting( groupInfo ); - } - - void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseStarting( testInfo ); - } - - void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->sectionStarting( sectionInfo ); - } - - void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) { - for( auto const& reporter : m_reporters ) - reporter->assertionStarting( assertionInfo ); - } - - // The return value indicates if the messages buffer should be cleared: - bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) { - bool clearBuffer = false; - for( auto const& reporter : m_reporters ) - clearBuffer |= reporter->assertionEnded( assertionStats ); - return clearBuffer; - } - - void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) { - for( auto const& reporter : m_reporters ) - reporter->sectionEnded( sectionStats ); - } - - void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) { - for( auto const& reporter : m_reporters ) - reporter->testCaseEnded( testCaseStats ); - } - - void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) { - for( auto const& reporter : m_reporters ) - reporter->testGroupEnded( testGroupStats ); - } - - void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) { - for( auto const& reporter : m_reporters ) - reporter->testRunEnded( testRunStats ); - } - - void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) { - for( auto const& reporter : m_reporters ) - reporter->skipTest( testInfo ); - } - - bool MultipleReporters::isMulti() const { - return true; - } - -} // end namespace Catch -// end catch_reporter_multi.cpp -// start catch_reporter_xml.cpp - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch - // Note that 4062 (not all labels are handled - // and default is missing) is enabled -#endif - -namespace Catch { - XmlReporter::XmlReporter( ReporterConfig const& _config ) - : StreamingReporterBase( _config ), - m_xml(_config.stream()) - { - m_reporterPrefs.shouldRedirectStdOut = true; - } - - XmlReporter::~XmlReporter() = default; - - std::string XmlReporter::getDescription() { - return "Reports test results as an XML document"; - } - - std::string XmlReporter::getStylesheetRef() const { - return std::string(); - } - - void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { - m_xml - .writeAttribute( "filename", sourceInfo.file ) - .writeAttribute( "line", sourceInfo.line ); - } - - void XmlReporter::noMatchingTestCases( std::string const& s ) { - StreamingReporterBase::noMatchingTestCases( s ); - } - - void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { - StreamingReporterBase::testRunStarting( testInfo ); - std::string stylesheetRef = getStylesheetRef(); - if( !stylesheetRef.empty() ) - m_xml.writeStylesheetRef( stylesheetRef ); - m_xml.startElement( "Catch" ); - if( !m_config->name().empty() ) - m_xml.writeAttribute( "name", m_config->name() ); - } - - void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { - StreamingReporterBase::testGroupStarting( groupInfo ); - m_xml.startElement( "Group" ) - .writeAttribute( "name", groupInfo.name ); - } - - void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { - StreamingReporterBase::testCaseStarting(testInfo); - m_xml.startElement( "TestCase" ) - .writeAttribute( "name", trim( testInfo.name ) ) - .writeAttribute( "description", testInfo.description ) - .writeAttribute( "tags", testInfo.tagsAsString() ); - - writeSourceInfo( testInfo.lineInfo ); - - if ( m_config->showDurations() == ShowDurations::Always ) - m_testCaseTimer.start(); - m_xml.ensureTagClosed(); - } - - void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { - StreamingReporterBase::sectionStarting( sectionInfo ); - if( m_sectionDepth++ > 0 ) { - m_xml.startElement( "Section" ) - .writeAttribute( "name", trim( sectionInfo.name ) ) - .writeAttribute( "description", sectionInfo.description ); - writeSourceInfo( sectionInfo.lineInfo ); - m_xml.ensureTagClosed(); - } - } - - void XmlReporter::assertionStarting( AssertionInfo const& ) { } - - bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { - - AssertionResult const& result = assertionStats.assertionResult; - - bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); - - if( includeResults || result.getResultType() == ResultWas::Warning ) { - // Print any info messages in tags. - for( auto const& msg : assertionStats.infoMessages ) { - if( msg.type == ResultWas::Info && includeResults ) { - m_xml.scopedElement( "Info" ) - .writeText( msg.message ); - } else if ( msg.type == ResultWas::Warning ) { - m_xml.scopedElement( "Warning" ) - .writeText( msg.message ); - } - } - } - - // Drop out if result was successful but we're not printing them. - if( !includeResults && result.getResultType() != ResultWas::Warning ) - return true; - - // Print the expression if there is one. - if( result.hasExpression() ) { - m_xml.startElement( "Expression" ) - .writeAttribute( "success", result.succeeded() ) - .writeAttribute( "type", result.getTestMacroName() ); - - writeSourceInfo( result.getSourceInfo() ); - - m_xml.scopedElement( "Original" ) - .writeText( result.getExpression() ); - m_xml.scopedElement( "Expanded" ) - .writeText( result.getExpandedExpression() ); - } - - // And... Print a result applicable to each result type. - switch( result.getResultType() ) { - case ResultWas::ThrewException: - m_xml.startElement( "Exception" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::FatalErrorCondition: - m_xml.startElement( "FatalErrorCondition" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - case ResultWas::Info: - m_xml.scopedElement( "Info" ) - .writeText( result.getMessage() ); - break; - case ResultWas::Warning: - // Warning will already have been written - break; - case ResultWas::ExplicitFailure: - m_xml.startElement( "Failure" ); - writeSourceInfo( result.getSourceInfo() ); - m_xml.writeText( result.getMessage() ); - m_xml.endElement(); - break; - default: - break; - } - - if( result.hasExpression() ) - m_xml.endElement(); - - return true; - } - - void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { - StreamingReporterBase::sectionEnded( sectionStats ); - if( --m_sectionDepth > 0 ) { - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); - e.writeAttribute( "successes", sectionStats.assertions.passed ); - e.writeAttribute( "failures", sectionStats.assertions.failed ); - e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); - - m_xml.endElement(); - } - } - - void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { - StreamingReporterBase::testCaseEnded( testCaseStats ); - XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); - e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); - - if ( m_config->showDurations() == ShowDurations::Always ) - e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); - - if( !testCaseStats.stdOut.empty() ) - m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); - if( !testCaseStats.stdErr.empty() ) - m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); - - m_xml.endElement(); - } - - void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { - StreamingReporterBase::testGroupEnded( testGroupStats ); - // TODO: Check testGroupStats.aborting and act accordingly. - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) - .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { - StreamingReporterBase::testRunEnded( testRunStats ); - m_xml.scopedElement( "OverallResults" ) - .writeAttribute( "successes", testRunStats.totals.assertions.passed ) - .writeAttribute( "failures", testRunStats.totals.assertions.failed ) - .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); - m_xml.endElement(); - } - - CATCH_REGISTER_REPORTER( "xml", XmlReporter ) - -} // end namespace Catch - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif -// end catch_reporter_xml.cpp - -namespace Catch { - LeakDetector leakDetector; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -// end catch_impl.hpp -#endif - -#ifdef CATCH_CONFIG_MAIN -// start catch_default_main.hpp - -#ifndef __OBJC__ - -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) -// Standard C/C++ Win32 Unicode wmain entry point -extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { -#else -// Standard C/C++ main entry point -int main (int argc, char * argv[]) { -#endif - - return Catch::Session().run( argc, argv ); -} - -#else // __OBJC__ - -// Objective-C entry point -int main (int argc, char * const argv[]) { -#if !CATCH_ARC_ENABLED - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; -#endif - - Catch::registerTestMethods(); - int result = Catch::Session().run( argc, (char**)argv ); - -#if !CATCH_ARC_ENABLED - [pool drain]; -#endif - - return result; -} - -#endif // __OBJC__ - -// end catch_default_main.hpp -#endif - -#if !defined(CATCH_CONFIG_IMPL_ONLY) - -#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED -# undef CLARA_CONFIG_MAIN -#endif - -#if !defined(CATCH_CONFIG_DISABLE) -////// -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - -#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) -#endif// CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - -#define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - -#define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) - -#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) -#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) - -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) -#define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) -#define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) -#define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) -#define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() - -// "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) -#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc ) -#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) -#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) - -#define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) -#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) - -#define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) -#define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) - -#define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) -#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) - -#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) -#define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) -#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) ) - -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) -#define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) -#define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) -#define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) -#define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) -#define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) - -// "BDD-style" convenience wrappers -#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) - -#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc ) -#define WHEN( desc ) SECTION( std::string(" When: ") + desc ) -#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc ) -#define THEN( desc ) SECTION( std::string(" Then: ") + desc ) -#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc ) - -using Catch::Detail::Approx; - -#else -////// -// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ -#ifdef CATCH_CONFIG_PREFIX_ALL - -#define CATCH_REQUIRE( ... ) (void)(0) -#define CATCH_REQUIRE_FALSE( ... ) (void)(0) - -#define CATCH_REQUIRE_THROWS( ... ) (void)(0) -#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) -#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif// CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) - -#define CATCH_CHECK( ... ) (void)(0) -#define CATCH_CHECK_FALSE( ... ) (void)(0) -#define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) -#define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) -#define CATCH_CHECK_NOFAIL( ... ) (void)(0) - -#define CATCH_CHECK_THROWS( ... ) (void)(0) -#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) -#define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CATCH_CHECK_NOTHROW( ... ) (void)(0) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CATCH_CHECK_THAT( arg, matcher ) (void)(0) - -#define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define CATCH_INFO( msg ) (void)(0) -#define CATCH_WARN( msg ) (void)(0) -#define CATCH_CAPTURE( msg ) (void)(0) - -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_METHOD_AS_TEST_CASE( method, ... ) -#define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) -#define CATCH_SECTION( ... ) -#define CATCH_FAIL( ... ) (void)(0) -#define CATCH_FAIL_CHECK( ... ) (void)(0) -#define CATCH_SUCCEED( ... ) (void)(0) - -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) - -// "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) -#define CATCH_GIVEN( desc ) -#define CATCH_WHEN( desc ) -#define CATCH_AND_WHEN( desc ) -#define CATCH_THEN( desc ) -#define CATCH_AND_THEN( desc ) - -// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required -#else - -#define REQUIRE( ... ) (void)(0) -#define REQUIRE_FALSE( ... ) (void)(0) - -#define REQUIRE_THROWS( ... ) (void)(0) -#define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) -#define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define REQUIRE_NOTHROW( ... ) (void)(0) - -#define CHECK( ... ) (void)(0) -#define CHECK_FALSE( ... ) (void)(0) -#define CHECKED_IF( ... ) if (__VA_ARGS__) -#define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) -#define CHECK_NOFAIL( ... ) (void)(0) - -#define CHECK_THROWS( ... ) (void)(0) -#define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) -#define CHECK_THROWS_WITH( expr, matcher ) (void)(0) -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS -#define CHECK_NOTHROW( ... ) (void)(0) - -#if !defined(CATCH_CONFIG_DISABLE_MATCHERS) -#define CHECK_THAT( arg, matcher ) (void)(0) - -#define REQUIRE_THAT( arg, matcher ) (void)(0) -#endif // CATCH_CONFIG_DISABLE_MATCHERS - -#define INFO( msg ) (void)(0) -#define WARN( msg ) (void)(0) -#define CAPTURE( msg ) (void)(0) - -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define METHOD_AS_TEST_CASE( method, ... ) -#define REGISTER_TEST_CASE( Function, ... ) (void)(0) -#define SECTION( ... ) -#define FAIL( ... ) (void)(0) -#define FAIL_CHECK( ... ) (void)(0) -#define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) - -#endif - -#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) - -// "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) - -#define GIVEN( desc ) -#define WHEN( desc ) -#define AND_WHEN( desc ) -#define THEN( desc ) -#define AND_THEN( desc ) - -using Catch::Detail::Approx; - -#endif - -#endif // ! CATCH_CONFIG_IMPL_ONLY - -// start catch_reenable_warnings.h - - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - -// end catch_reenable_warnings.h -// end catch.hpp -#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - diff --git a/FlippR-Driver/tests/fakeit.hpp b/FlippR-Driver/tests/fakeit.hpp index 2a9e07b..2d30552 100644 --- a/FlippR-Driver/tests/fakeit.hpp +++ b/FlippR-Driver/tests/fakeit.hpp @@ -2,7 +2,7 @@ /* * FakeIt - A Simplified C++ Mocking Framework * Copyright (c) Eran Pe'er 2013 - * Generated: 2017-11-05 20:30:40.182814 + * Generated: 2018-08-17 00:22:40.428924 * Distributed under the MIT License. Please refer to the LICENSE file at: * https://github.com/eranpeer/FakeIt */ @@ -253,6 +253,35 @@ namespace fakeit { } }; + template <> + struct Formatter + { + static std::string format(char const* const &val) + { + std::string s; + if(val != nullptr) + { + s += '"'; + s += val; + s += '"'; + } + else + { + s = "[nullptr]"; + } + return s; + } + }; + + template <> + struct Formatter + { + static std::string format(char* const &val) + { + return Formatter::format( val ); + } + }; + template struct Formatter::value>::type> { static std::string format(C const &) @@ -742,6 +771,9 @@ namespace fakeit { }; } +#ifdef FAKEIT_ASSERT_ON_UNEXPECTED_METHOD_INVOCATION +#include +#endif namespace fakeit { @@ -831,7 +863,7 @@ namespace fakeit { out << "Unexpected method invocation: "; out << e.getInvocation().format() << std::endl; if (UnexpectedType::Unmatched == e.getUnexpectedType()) { - out << " Could not find Any recorded behavior to support this method call."; + out << " Could not find any recorded behavior to support this method call."; } else { out << " An unmocked method was invoked. All used virtual methods must be stubbed!"; } @@ -868,7 +900,7 @@ namespace fakeit { virtual std::string format(const NoMoreInvocationsVerificationEvent &e) override { std::ostringstream out; out << "Verification error" << std::endl; - out << "Expected no more invocations!! But the following unverified invocations were found:" << std::endl; + out << "Expected no more invocations!! but the following unverified invocations were found:" << std::endl; formatInvocationList(out, e.unverifedIvocations()); return out.str(); } @@ -915,8 +947,8 @@ namespace fakeit { static void formatInvocationList(std::ostream &out, const std::vector &actualSequence) { size_t max_size = actualSequence.size(); - if (max_size > 5) - max_size = 5; + if (max_size > 50) + max_size = 50; for (unsigned int i = 0; i < max_size; i++) { out << " "; @@ -1170,12 +1202,13 @@ namespace fakeit { std::string fomattedMessage, Catch::ResultWas::OfType resultWas = Catch::ResultWas::OfType::ExpressionFailed ){ Catch::AssertionHandler catchAssertionHandler( vetificationType, sourceLineInfo, failingExpression, Catch::ResultDisposition::Normal ); - INTERNAL_CATCH_TRY( catchAssertionHandler ) { \ + INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ - catchAssertionHandler.handle( resultWas , fomattedMessage); \ + catchAssertionHandler.handleMessage(resultWas, fomattedMessage); \ CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ - } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ - INTERNAL_CATCH_REACT( catchAssertionHandler ) + } INTERNAL_CATCH_CATCH(catchAssertionHandler) { \ + INTERNAL_CATCH_REACT(catchAssertionHandler) \ + } } virtual void handle(const UnexpectedMethodCallEvent &evt) override { @@ -1237,11 +1270,13 @@ static fakeit::DefaultFakeit& Fakeit = fakeit::CatchFakeit::getInstance(); #include #include +#undef max #include #include #include #include #include +#include #include #include @@ -5281,7 +5316,9 @@ namespace fakeit { } namespace fakeit { - class NoVirtualDtor { + class NoVirtualDtor : public std::runtime_error { + public: + NoVirtualDtor() :std::runtime_error("Can't mock the destructor. No virtual destructor was found") {} }; class VTUtils { @@ -5308,6 +5345,18 @@ namespace fakeit { throw NoVirtualDtor(); } + template + static typename std::enable_if::value, bool>::type + hasVirtualDestructor() { + return true; + } + + template + static typename std::enable_if::value, bool>::type + hasVirtualDestructor() { + return false; + } + template static unsigned int getVTSize() { struct Derrived : public C { @@ -5935,6 +5984,10 @@ namespace fakeit { std::vector> &methodMocks, std::vector &offsets) : _methodMocks(methodMocks), _offsets(offsets) { + for (std::vector::iterator it = _offsets.begin(); it != _offsets.end(); ++it) + { + *it = std::numeric_limits::max(); + } } Destructible *getInvocatoinHandlerPtrById(unsigned int id) override { @@ -7900,22 +7953,13 @@ namespace fakeit { } MockImpl(FakeitContext &fakeit) - : MockImpl(fakeit, *(createFakeInstance()), false) { - FakeObject *fake = reinterpret_cast *>(_instance); + : MockImpl(fakeit, *(createFakeInstance()), false){ + FakeObject *fake = asFakeObject(_instanceOwner.get()); fake->getVirtualTable().setCookie(1, this); } virtual ~MockImpl() NO_THROWS { _proxy.detach(); - if (_isOwner) { - FakeObject *fake = reinterpret_cast *>(_instance); - delete fake; - } - } - - void detach() { - _isOwner = false; - _proxy.detach(); } @@ -7929,8 +7973,8 @@ namespace fakeit { void initDataMembersIfOwner() { - if (_isOwner) { - FakeObject *fake = reinterpret_cast *>(_instance); + if (isOwner()) { + FakeObject *fake = asFakeObject(_instanceOwner.get()); fake->initializeDataMembersArea(); } } @@ -7974,12 +8018,35 @@ namespace fakeit { return DtorMockingContext(new DtorMockingContextImpl(*this)); } + + + + + + private: - DynamicProxy _proxy; - C *_instance; - bool _isOwner; + + + + + + + + + + std::shared_ptr> _instanceOwner; + DynamicProxy _proxy; FakeitContext &_fakeit; + MockImpl(FakeitContext &fakeit, C &obj, bool isSpy) + : _instanceOwner(isSpy ? nullptr : asFakeObject(&obj)) + , _proxy{obj} + , _fakeit(fakeit) {} + + static FakeObject* asFakeObject(void* instance){ + return reinterpret_cast *>(instance); + } + template class MethodMockingContextBase : public MethodMockingContext::Context { protected: @@ -8086,12 +8153,16 @@ namespace fakeit { }; static MockImpl *getMockImpl(void *instance) { - FakeObject *fake = reinterpret_cast *>(instance); + FakeObject *fake = asFakeObject(instance); MockImpl *mock = reinterpret_cast *>(fake->getVirtualTable().getCookie( 1)); return mock; } + bool isOwner(){ return _instanceOwner != nullptr;} + + void unmockedDtor() {} + void unmocked() { ActualInvocation<> invocation(Invocation::nextInvocationOrdinal(), UnknownMethod::instance()); UnexpectedMethodCallEvent event(UnexpectedType::Unmocked, invocation); @@ -8106,8 +8177,11 @@ namespace fakeit { static C *createFakeInstance() { FakeObject *fake = new FakeObject(); void *unmockedMethodStubPtr = union_cast(&MockImpl::unmocked); - fake->getVirtualTable().initAll(unmockedMethodStubPtr); - return reinterpret_cast(fake); + void *unmockedDtorStubPtr = union_cast(&MockImpl::unmockedDtor); + fake->getVirtualTable().initAll(unmockedMethodStubPtr); + if (VTUtils::hasVirtualDestructor()) + fake->setDtor(unmockedDtorStubPtr); + return reinterpret_cast(fake); } template @@ -8145,10 +8219,6 @@ namespace fakeit { return *dtorMock; } - MockImpl(FakeitContext &fakeit, C &obj, bool isSpy) - : _proxy{obj}, _instance(&obj), _isOwner(!isSpy), _fakeit(fakeit) { - } - template static RecordedMethodBody *createRecordedMethodBody(MockObject &mock, R(C::*vMethod)(arglist...)) { @@ -8158,7 +8228,6 @@ namespace fakeit { static RecordedMethodBody *createRecordedDtorBody(MockObject &mock) { return new RecordedMethodBody(mock.getFakeIt(), "dtor"); } - }; } namespace fakeit { @@ -8232,7 +8301,11 @@ namespace fakeit { return impl.get(); } - C &operator()() { + + + + + C &operator()() { return get(); } @@ -8753,12 +8826,12 @@ namespace fakeit { return !isAtLeastVerification(); } - bool atLeastLimitNotReached(int count) { - return count < -_expectedCount; + bool atLeastLimitNotReached(int actualCount) { + return actualCount < -_expectedCount; } - bool exactLimitNotMatched(int count) { - return count != _expectedCount; + bool exactLimitNotMatched(int actualCount) { + return actualCount != _expectedCount; } void handleExactVerificationEvent(VerificationEventHandler &verificationErrorHandler, @@ -8850,7 +8923,7 @@ namespace fakeit { ~SequenceVerificationProgress() THROWS { }; - operator bool() { + operator bool() const { return Terminator(_expectationPtr); } @@ -9105,8 +9178,8 @@ namespace fakeit { return *this; } - operator bool() { - return toBool(); + operator bool() const { + return const_cast(this)->toBool(); } bool operator!() const { return !const_cast(this)->toBool(); } @@ -9300,4 +9373,3 @@ namespace fakeit { #endif - diff --git a/FlippR-Driver/tests/input/TestDetector.cpp b/FlippR-Driver/tests/input/TestDetector.cpp new file mode 100644 index 0000000..40cce88 --- /dev/null +++ b/FlippR-Driver/tests/input/TestDetector.cpp @@ -0,0 +1,139 @@ +/* + * TestDetector.cpp + * + * Created on: Jun 27, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + + +#include "catch.hpp" +#include "fakeit.hpp" + +#include +#include +#include + + +#define private public + +#include "input/EventNotifier.h" +#include "input/DistributingEvent.h" +#include "input/detail/Detector.h" +#include "input/detail/InputPinController.h" +#include "utility/LoggerFactory.h" + + +using namespace fakeit; +using namespace flippR_driver; +using namespace input; +using namespace utility; + + +SCENARIO("Creating a Detector object", "") +{ + GIVEN("An IEventNofifier, IInputGPIOInterface") + { + LoggerFactory::CreateInputTestLogger(); + + Mock event_notifier_mock; + Mock gpio_interface_mock; + + Fake(Dtor(gpio_interface_mock)); + When(Method(gpio_interface_mock, read_data)).AlwaysReturn(false); + + Fake(Dtor(event_notifier_mock)); + When(Method(event_notifier_mock, distribute_event)).AlwaysReturn(); + + std::vector> events; + + WHEN("Detector is created") + { + detail::Detector detector(std::unique_ptr(&gpio_interface_mock.get()), events); + THEN("a thread should be created") + { + REQUIRE(typeid(detector.detect_thread).hash_code() == typeid(std::thread).hash_code()); + } + } + } +} + +SCENARIO("There are events at the input", "") +{ + GIVEN("An IEventNofifier, three Events and an InputPinController") + { + LoggerFactory::CreateInputTestLogger(); + + Mock event_notifier_mock; + Mock gpio_interface_mock; + + Fake(Dtor(gpio_interface_mock)); + When(Method(gpio_interface_mock, read_data)).AlwaysDo([](char c){return c==2;}); + + Fake(Dtor(event_notifier_mock)); + When(Method(event_notifier_mock, distribute_event)).AlwaysReturn(); + + std::shared_ptr event_notifier; + DistributingEvent event1(1, '1', "event 1", std::chrono::milliseconds(0), event_notifier); + DistributingEvent event2(2, '2', "event 2", std::chrono::milliseconds(0), event_notifier); + DistributingEvent event3(3, '3', "event 3", std::chrono::milliseconds(0), event_notifier); + + std::vector> events; + + auto event2ptr = std::make_shared(event2); + events.push_back(std::make_shared(event1)); + events.push_back(event2ptr); + events.push_back(std::make_shared(event3)); + + WHEN("an event can be found at gpio interface") + { + detail::Detector detector(std::unique_ptr(&gpio_interface_mock.get()), events); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + THEN("the event should be distributed") + { + detector.is_running = false; + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + REQUIRE((bool)Verify(Method(event_notifier_mock, distribute_event).Using(*event2ptr))); + } + } + } +} + +SCENARIO("There are events at the input but no suitable event in map", "") +{ + GIVEN("An IEventNofifier, three Events and an InputPinController") + { + LoggerFactory::CreateInputTestLogger(); + + Mock event_notifier_mock; + Mock gpio_interface_mock; + + Fake(Dtor(gpio_interface_mock)); + When(Method(gpio_interface_mock, read_data)).AlwaysDo([](char c){return c==4;}); + + Fake(Dtor(event_notifier_mock)); + When(Method(event_notifier_mock, distribute_event)).AlwaysReturn(); + + std::shared_ptr event_notifier; + DistributingEvent event1(1, '1', "event 1", std::chrono::milliseconds(0), event_notifier); + DistributingEvent event2(2, '2', "event 2", std::chrono::milliseconds(0), event_notifier); + DistributingEvent event3(3, '3', "event 3", std::chrono::milliseconds(0), event_notifier); + + std::vector> events; + + events.push_back(std::make_shared(event1)); + events.push_back(std::make_shared(event2)); + events.push_back(std::make_shared(event3)); + + WHEN("an event can be found at gpio interface") + { + detail::Detector detector(std::unique_ptr(&gpio_interface_mock.get()), events); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + THEN("the event should be distributed") + { + detector.is_running = false; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + REQUIRE_FALSE((bool)Verify(Method(event_notifier_mock, distribute_event))); + } + } + } +} diff --git a/FlippR-Driver/tests/input/TestEventHandler.cpp b/FlippR-Driver/tests/input/TestEventHandler.cpp new file mode 100644 index 0000000..2231c21 --- /dev/null +++ b/FlippR-Driver/tests/input/TestEventHandler.cpp @@ -0,0 +1,44 @@ +/* + * TestEventHandler.cpp + * + * Created on: Jun 28, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "catch.hpp" +#include "fakeit.hpp" + +// testing purposes +#define private public + +#include "utility/LoggerFactory.h" +#include "input/InputDriver.h" + + +using namespace fakeit; +using namespace flippR_driver::utility; +/* todo ? +SCENARIO("An EventHandler gets created", "[construction}") +{ + GIVEN("An IInputDriver") + { + LoggerFactory::CreateInputTestLogger(); + + Mock input_driver_mock; + Fake(Dtor(input_driver_mock)); + When(Method(input_driver_mock, register_event_handler)).AlwaysReturn(); + When(Method(input_driver_mock, unregister_event_handler)).AlwaysReturn(); + + WHEN("the event handler gets created") + { + std::shared_ptr driver_ptr(&input_driver_mock.get()); + flippR_driver::input::detail::EventHandler handler(driver_ptr); + + THEN("It should register itself at the input_driver") + { + REQUIRE((bool)Verify(Method(input_driver_mock, register_event_handler).Using(&handler))); + } + } + } +} +*/ \ No newline at end of file diff --git a/FlippR-Driver/tests/input/TestEventNotifier.cpp b/FlippR-Driver/tests/input/TestEventNotifier.cpp new file mode 100644 index 0000000..fb8681f --- /dev/null +++ b/FlippR-Driver/tests/input/TestEventNotifier.cpp @@ -0,0 +1,153 @@ +/* + * TestEventNotifier.cpp + * + * Created on: Jun 19, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + + +#include "catch.hpp" +#include "fakeit.hpp" + +// testing purposes +#define private public + +#include "utility/LoggerFactory.h" +#include "input/EventHandler.h" +#include "utility/IBlockingQueue.h" +#include "input/detail/EventNotifier.h" + +#include "input/EventNotifier.h" + + +using namespace flippR_driver; +using namespace input; +using namespace fakeit; +using namespace utility; + +SCENARIO("An EventNotifier gets created", "[construction]") +{ + LoggerFactory::CreateInputTestLogger(); + + WHEN("The EventNotifier gets created") + { + Event event(0, 0, "test"); + + Mock> queue_mock; + Fake(Method(queue_mock, push)); + When(Method(queue_mock, pop)).AlwaysDo([event](){return event;}); + Fake(Dtor(queue_mock)); + + input::detail::EventNotifier notifier(&(queue_mock.get())); + THEN("It sets the running variable to true") + { + REQUIRE(notifier.is_running); + } + THEN("It creates a notify thread") + { + REQUIRE(typeid(notifier.notify_thread).hash_code() == typeid(std::thread).hash_code()); + } + } +} + +SCENARIO("An EventHandler gets [un]registered at the notifier", "[un-register notifier]") +{ + GIVEN("An EventHandler") + { + LoggerFactory::CreateInputTestLogger(); + + Event event(0, 0, "test"); + + Mock> queue_mock; + Fake(Method(queue_mock, push)); + When(Method(queue_mock, pop)).AlwaysDo([event](){return event;}); + Fake(Dtor(queue_mock)); + + Mock event_handler_mock; + Fake(Method(event_handler_mock, handle)); + Fake(Dtor(event_handler_mock)); + + input::detail::EventNotifier notifier(&(queue_mock.get())); + + WHEN("The EventHandler gets registered at the eventNotifier") + { + notifier.register_event_handler(&event_handler_mock.get()); + + THEN("The EventHandler gets saved") + { + } + + AND_WHEN("The EventHandler gets unregistered at the driver") + { + REQUIRE(!notifier.event_handlers.empty()); + + notifier.unregister_event_handler(&event_handler_mock.get()); + + THEN("The list of event_handlers is empty") + { + REQUIRE(notifier.event_handlers.empty()); + } + } + } + + + } +} + +SCENARIO("An event should be distributed", "[distribute]") +{ + GIVEN("An event") + { + Event event(0, 0, "test"); + + Mock> queue_mock; + Fake(Method(queue_mock, push)); + When(Method(queue_mock, pop)).AlwaysDo([event](){return event;}); + Fake(Dtor(queue_mock)); + + input::detail::EventNotifier notifier(&(queue_mock.get())); + + WHEN("The event comes in") + { + notifier.distribute_event(event); + THEN("The event gets queued") + { + notifier.is_running = false; +// REQUIRE((bool)Verify(Method(queue_mock, push))); + REQUIRE((bool)Verify(Method(queue_mock, push).Using(event))); + } + } + } +} + +SCENARIO("The EventHandler gets notified") +{ + GIVEN("An Event and an EventHandler") + { + Event event(0, 0, "test"); + + Mock event_handler_mock; + When(Method(event_handler_mock, handle)).AlwaysReturn(); + Fake(Dtor(event_handler_mock)); + + Event test_event(0, 0, "test"); + + Mock> queue_mock; + Fake(Method(queue_mock, push)); + When(Method(queue_mock, pop)).AlwaysDo([test_event](void){return test_event;}); + Fake(Dtor(queue_mock)); + + input::detail::EventNotifier notifier(&(queue_mock.get())); + + notifier.event_handlers.insert(&(event_handler_mock.get())); + + WHEN("The event gets queued") + { + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + THEN("The EventHandler gets called") + { + REQUIRE((bool) Verify(Method(event_handler_mock, handle).Using(test_event))); + } + } + } +} diff --git a/FlippR-Driver/tests/input/TestInputDriver.cpp b/FlippR-Driver/tests/input/TestInputDriver.cpp index 9b54ecb..7b4700e 100644 --- a/FlippR-Driver/tests/input/TestInputDriver.cpp +++ b/FlippR-Driver/tests/input/TestInputDriver.cpp @@ -2,56 +2,77 @@ * TestInputDriver.cpp * * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert */ -#include "../catch.hpp" -#include "../fakeit.hpp" +#include "catch.hpp" +#include "fakeit.hpp" +#include "utility/LoggerFactory.h" +// testing purposes #define private public -#include "../../src/input/InputDriver.hpp" +#include "input/detail/InputDriver.h" -#include "../../src/input/Event.hpp" -#include "../../src/input/IEventNotifier.h" -#include "../../src/input/IDetector.h" +#include "input/EventNotifier.h" +#include "input/Detector.h" using namespace fakeit; +using namespace flippR_driver; +using namespace input; +using namespace utility; SCENARIO("An InputDriver gets created", "[construction}") { - GIVEN("An EventNotifier") + GIVEN("An EventNotifier and a Detector") { - Mock detector_mock; + LoggerFactory::CreateInputTestLogger(); - Mock event_notifier_mock; - Mock event_handler_mock; + Mock detector_mock; + Fake(Dtor(detector_mock)); + Mock event_notifier_mock; + Fake(Dtor(event_notifier_mock)); WHEN("The InputDriver gets created") { - Input::InputDriver input_driver(&event_notifier_mock.get(), &detector_mock.get()); + std::shared_ptr event_notifier_ptr(&event_notifier_mock.get()); + std::map> events; - THEN("It saved the EventNotifier") + input::detail::InputDriver input_driver(event_notifier_ptr, std::unique_ptr(&detector_mock.get()), events); + + THEN("It saves the EventNotifier and the Detector") { - REQUIRE(input_driver.event_notifier == &event_notifier_mock.get()); + REQUIRE(input_driver.event_notifier == event_notifier_ptr); + REQUIRE(&(*input_driver.detector) == &detector_mock.get()); } } } } -SCENARIO("An EventHandler [un]registers at the driver", "[[un]register]") +SCENARIO("An EventHandler [un]registers at the driver", "[un-register]") { GIVEN("An InputDriver, EventHandler and an EventNotifier") { - Mock detector_mock; + LoggerFactory::CreateInputTestLogger(); - Mock event_handler_mock; - Mock event_notifier_mock; - When(Method(event_notifier_mock, register_event_handler)); - When(Method(event_notifier_mock, unregister_event_handler)); + Mock detector_mock; + Fake(Dtor(detector_mock)); - Input::InputDriver input_driver(&event_notifier_mock.get(), &detector_mock.get()); + Mock event_handler_mock; + Fake(Method(event_handler_mock, handle)); + Fake(Dtor(event_handler_mock)); + + Mock event_notifier_mock; + Fake(Method(event_notifier_mock, register_event_handler)); + Fake(Method(event_notifier_mock, unregister_event_handler)); + Fake(Dtor(event_notifier_mock)); + + std::shared_ptr event_notifier_ptr(&event_notifier_mock.get()); + + std::map> events; + + input::detail::InputDriver input_driver(event_notifier_ptr, std::unique_ptr(&detector_mock.get()), events); WHEN("The EventHandler registers at the driver") { @@ -59,21 +80,73 @@ SCENARIO("An EventHandler [un]registers at the driver", "[[un]register]") THEN("The register_event_handler at the event_notifier gets called") { - REQUIRE(Verify(Method(event_notifier_mock, register_event_handler).Using(&event_handler_mock.get()))); + REQUIRE((bool)Verify(Method(event_notifier_mock, register_event_handler).Using(&event_handler_mock.get()))); } } - WHEN("The EventHandler unregisters at the driver") + WHEN("The EventHandler then unregisters at the driver") { - REQUIRE(Verify(Method(event_notifier_mock, register_event_handler).Using(&event_handler_mock.get()))); input_driver.unregister_event_handler(&event_handler_mock.get()); THEN("The unregister_event_handler at the event_notifier gets called") { - REQUIRE(Verify(Method(event_notifier_mock, unregister_event_handler).Using(&event_handler_mock.get()))); + REQUIRE((bool)Verify(Method(event_notifier_mock, unregister_event_handler).Using(&event_handler_mock.get()))); } } } } +SCENARIO("An Input Driver is created normally", "") +{ + GIVEN("An InputDriver, EventHandler and an EventNotifier and some events") + { + LoggerFactory::CreateInputTestLogger(); + + Mock detector_mock; + Fake(Dtor(detector_mock)); + + Mock event_handler_mock; + Fake(Dtor(event_handler_mock)); + + Mock event_notifier_mock; + Fake(Dtor(event_notifier_mock)); + + std::shared_ptr event_notifier_ptr(&event_notifier_mock.get()); + + Event event1('a', 2, "e1"); + auto event1_ptr = std::make_shared(event1 ); + Event event2('b', 1, "e2"); + Event event3('c', 2, "e3"); + Event event4('d', 1, "e4"); + + std::map> events; + events.emplace("e1", event1_ptr); + events.emplace("e2", std::make_shared(event2)); + events.emplace("e3", std::make_shared(event3)); + events.emplace("e4", std::make_shared(event4)); + + + input::detail::InputDriver input_driver(event_notifier_ptr, std::unique_ptr(&detector_mock.get()), events); + + WHEN("Someone asks for an event that is registered") + { + auto event = input_driver.get_event("e1"); + + THEN("The obtained event should be the same as emplaced before") + { + REQUIRE(event==event1_ptr); + } + } + + WHEN("someone asks for an event that is not registered") + { + auto event = input_driver.get_event("no event"); + + THEN("the obtained event should be null") + { + REQUIRE(event->get()->name == "ERROR"); + } + } + } +} \ No newline at end of file diff --git a/FlippR-Driver/tests/input/mocks/EventHandlerMock.hpp b/FlippR-Driver/tests/input/mocks/EventHandlerMock.hpp deleted file mode 100644 index d9d1684..0000000 --- a/FlippR-Driver/tests/input/mocks/EventHandlerMock.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * EventHandlerMock.hpp - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_TESTS_INPUT_MOCKS_EVENTHANDLERMOCK_HPP_ -#define SRC_TESTS_INPUT_MOCKS_EVENTHANDLERMOCK_HPP_ - -namespace Input -{ -class EventHandler; -class Event; - -class EventHandlerMock : EventHandler -{ -public: - void handle(Event& event) override - { - - } -}; - -} - -#endif /* SRC_TESTS_INPUT_MOCKS_EVENTHANDLERMOCK_HPP_ */ diff --git a/FlippR-Driver/tests/input/mocks/EventNotifierMock.hpp b/FlippR-Driver/tests/input/mocks/EventNotifierMock.hpp deleted file mode 100644 index b00af63..0000000 --- a/FlippR-Driver/tests/input/mocks/EventNotifierMock.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * EventNotfierMock.hpp - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_TESTS_INPUT_MOCKS_EVENTNOTIFIERMOCK_HPP_ -#define SRC_TESTS_INPUT_MOCKS_EVENTNOTIFIERMOCK_HPP_ - -namespace Input -{ -class EventNotifier; -class EventHandler; - -class EventNotifierMock : EventNotifier -{ -public: - EventNotifierMock() : - registered(false) - {} - - void register_event_handler(EventHandler* handler) override - { - registered = true; - } - - void unregister_event_handler(EventHandler* handler) override - { - registered = false; - } - -public: - bool registered; -}; - -} - -#endif /* SRC_TESTS_INPUT_MOCKS_EVENTNOTIFIERMOCK_HPP_ */ diff --git a/FlippR-Driver/tests/input/mocks/InputDriverMock.hpp b/FlippR-Driver/tests/input/mocks/InputDriverMock.hpp deleted file mode 100644 index 6e63a91..0000000 --- a/FlippR-Driver/tests/input/mocks/InputDriverMock.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/* - * InputDriverMock.hpp - * - * Created on: May 31, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht - */ - -#ifndef SRC_TESTS_INPUT_MOCKS_INPUTDRIVERMOCK_HPP_ -#define SRC_TESTS_INPUT_MOCKS_INPUTDRIVERMOCK_HPP_ - -namespace Input -{ -class InputDriver; -class EventHandler; - -class InputDriverMock : InputDriver -{ -public: - InputDriverMock() : - registered(false) - {} - - void register_event_handler(EventHandler* handler) - { - registered = true; - } - -public: - bool registered; -}; - -} - -#endif /* SRC_TESTS_INPUT_MOCKS_INPUTDRIVERMOCK_HPP_ */ diff --git a/FlippR-Driver/tests/input/main.cpp b/FlippR-Driver/tests/main.cpp similarity index 70% rename from FlippR-Driver/tests/input/main.cpp rename to FlippR-Driver/tests/main.cpp index f0e73c1..519b7db 100644 --- a/FlippR-Driver/tests/input/main.cpp +++ b/FlippR-Driver/tests/main.cpp @@ -2,8 +2,8 @@ * tests-main.cpp * * Created on: May 6, 2018 - * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert, Rafael Vinci, Dr. Franca Rupprecht + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert */ #define CATCH_CONFIG_MAIN -#include "../catch.hpp" +#include "catch.hpp" diff --git a/FlippR-Driver/tests/output/TestDisplay.cpp b/FlippR-Driver/tests/output/TestDisplay.cpp new file mode 100644 index 0000000..4df2f4b --- /dev/null +++ b/FlippR-Driver/tests/output/TestDisplay.cpp @@ -0,0 +1,68 @@ +/* + * TestDisplay.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + + + + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + + +// testing purposes +#define private public + +#include "output/items/detail/Display.h" + +using namespace flippR_driver::output; +using namespace fakeit; + +//todo fix the tests +//SCENARIO("Creating a Display object", "") +//{ +// GIVEN("Just a Display with 7 digits") +// { +// SevenDigitDisplay display(5,5); +// WHEN("A content is set for the display") +// { +// std::string content_string = "1234567"; +// std::array content; +// std::copy(content_string.begin(), content_string.end(), content.data()); +// display.write_content(content); +// THEN("This content should be set for the display") +// { +// REQUIRE(content == display.content); +// } +// } +// WHEN("A score (12345) within the size of the display is written") +// { +// display.write_score(12345); +// THEN("The content should look like: \" 12345\" ") +// { +// std::string content_string = "\0\012345"; +// std::array content; +// std::copy(content_string.begin(), content_string.end(), content.data()); +// +// REQUIRE(display.content == content); +// } +// } +// WHEN("A score (12345678), which is longer than the digit is written") +// { +// display.write_score(12345678); +// THEN("The content should look like: \"9999999\"-> highest number ") +// { +// std::string content_string = "9999999"; +// std::array content; +// std::copy(content_string.begin(), content_string.end(), content.data()); +// +// REQUIRE(display.content == content); +// } +// } +// } +//} + diff --git a/FlippR-Driver/tests/output/TestDisplayController.cpp b/FlippR-Driver/tests/output/TestDisplayController.cpp new file mode 100644 index 0000000..8d190db --- /dev/null +++ b/FlippR-Driver/tests/output/TestDisplayController.cpp @@ -0,0 +1,61 @@ +/* + * TestDisplayController.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include +#include + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + +#include "output/DisplayController.h" +#include "output/items/OutputDisplay.h" +#include "output/DisplayBoardPinController.h" +#include "output/DisplayController.h" + + +// testing purposes +#define private public + +using namespace flippR_driver::output; +using namespace fakeit; +using namespace flippR_driver::utility; + +SCENARIO("A display controller gets created", "") +{ + GIVEN("A set of displays and a pin controller") + { +// LoggerFactory::CreateInputTestLogger(); +// +// std::vector> output_diplays; +// for(int i = 0; i < 3; i++) +// { +// Mock display_mock; +// Fake(Dtor(display_mock)); +// output_diplays.push_back(std::make_shared(display_mock)); +// } +// +// Mock display_board_pin_controller_mock; +// Fake(Dtor(display_board_pin_controller_mock)); +// +// When(Method(display_board_pin_controller_mock, write_display)).AlwaysReturn(); +// When(Method(display_board_pin_controller_mock, activate_displays)).AlwaysReturn(); +// When(Method(display_board_pin_controller_mock, deactivate_displays)).AlwaysReturn(); + + WHEN("The DisplayController is created") + { +// detail::DisplayController controller(output_diplays, std::make_unique(display_board_pin_controller_mock)); + + THEN("All Displays should be activated") + { +// REQUIRE(display_board_pin_controller_mock.) +// ToDo: to be continued! + } + } + } +} diff --git a/FlippR-Driver/tests/output/TestLamp.cpp b/FlippR-Driver/tests/output/TestLamp.cpp new file mode 100644 index 0000000..a4dd0ff --- /dev/null +++ b/FlippR-Driver/tests/output/TestLamp.cpp @@ -0,0 +1,72 @@ +/* + * TestLamp.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + +#include "output/items/detail/Lamp.h" + +using namespace flippR_driver::output; +using namespace fakeit; + +SCENARIO("A Lamp gets activated") +{ + GIVEN("A Lamp") + { + Mock pin_controller; + Fake(Dtor(pin_controller)); + Fake(Method(pin_controller, activate)); + + items::detail::Lamp lamp(std::shared_ptr(&pin_controller.get()), 0, 1, "test"); + + WHEN("The lamp gets activated") + { + lamp.activate(); + + THEN("It should call the pin_controller with itself") + { + // todo why doesnt this compile? + //REQUIRE((bool) Verify(Method(pin_controller, activate).Using(&lamp))); + AND_THEN("It should set its status to activated") + { + REQUIRE(lamp.is_activated()); + } + } + } + } +} + +SCENARIO("A Lamp gets deactivated") +{ + GIVEN("A Lamp") + { + Mock pin_controller; + Fake(Dtor(pin_controller)); + Fake(Method(pin_controller, deactivate)); + + items::detail::Lamp lamp(std::shared_ptr(&pin_controller.get()), 0, 1, "test"); + + WHEN("The lamp gets deactivated") + { + lamp.deactivate(); + + THEN("It should call the pin_controller with itself") + { + // todo why doesnt this compile? + //REQUIRE((bool) Verify(Method(pin_controller, deactivate).Using(&lamp))); + + AND_THEN("It should set its status to deactivated") + { + REQUIRE_FALSE(lamp.is_activated()); + } + } + } + } +} + diff --git a/FlippR-Driver/tests/output/TestOutputDriver.cpp b/FlippR-Driver/tests/output/TestOutputDriver.cpp new file mode 100644 index 0000000..7775697 --- /dev/null +++ b/FlippR-Driver/tests/output/TestOutputDriver.cpp @@ -0,0 +1,78 @@ +/* + * TestOutputDriver.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + +#include +#include "output/items/Solenoid.h" +#include "output/items/Lamp.h" +#include "output/items/Sound.h" +#include "output/items/Display.h" + +// testing purposes +#define private public + +#include "output/OutputDriver.h" + +using namespace flippR_driver; +using namespace flippR_driver::output; +using namespace fakeit; + + +SCENARIO("The OutputDriver should (de)activates the displays") +{ + GIVEN("An OutputDriver") + { + Mock display_controller; + Fake(Method(display_controller, activate_displays)); + Fake(Method(display_controller, deactivate_displays)); + + std::map> solenoids; + std::map> lamps; + std::map> sounds; + std::map> flippers; + std::map> displays; + + output::OutputDriver output_driver(std::unique_ptr(&display_controller.get()), solenoids, lamps, sounds, flippers, displays); + + WHEN("The displays get activated") + { + output_driver.activate_displays(); + THEN("The display controller should be called") + { + REQUIRE((bool)Verify(Method(display_controller, activate_displays))); + } + } + + WHEN("The displays get deactivated") + { + output_driver.deactivate_displays(); + THEN("The display controller should be called") + { + REQUIRE((bool)Verify(Method(display_controller, deactivate_displays))); + } + } + } +} + + +SCENARIO("The OutputDriver should return a list of all items") +{ + GIVEN("An OutputDriver with some items") + { + Mock display_controller; + + std::map> solenoids; + std::map> lamps; + std::map> sounds; + std::map> displays; + } + +} \ No newline at end of file diff --git a/FlippR-Driver/tests/output/TestOutputItem.cpp b/FlippR-Driver/tests/output/TestOutputItem.cpp new file mode 100644 index 0000000..2e7f8c8 --- /dev/null +++ b/FlippR-Driver/tests/output/TestOutputItem.cpp @@ -0,0 +1,29 @@ +/* + * TestCabinetItem.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + + + + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + + +// testing purposes +#define private public + +#include "output/items/Item.h" + +using namespace flippR_driver::output; +using namespace fakeit; + +SCENARIO("") +{ + +} + diff --git a/FlippR-Driver/tests/output/TestSolenoid.cpp b/FlippR-Driver/tests/output/TestSolenoid.cpp new file mode 100644 index 0000000..8dc6d12 --- /dev/null +++ b/FlippR-Driver/tests/output/TestSolenoid.cpp @@ -0,0 +1,29 @@ +/* + * TestSolenoid.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + + + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + + +// testing purposes +#define private public + +#include "output/items/detail/Solenoid.h" + +using namespace flippR_driver::output; +using namespace fakeit; + +SCENARIO("") +{ + +} + + diff --git a/FlippR-Driver/tests/output/TestSound.cpp b/FlippR-Driver/tests/output/TestSound.cpp new file mode 100644 index 0000000..2c73163 --- /dev/null +++ b/FlippR-Driver/tests/output/TestSound.cpp @@ -0,0 +1,27 @@ +/* + * TestSound.cpp + * + * Created on: Aug 7, 2018 + * Author: Andreas Schneider, Johannes Wendel, Jonas Zeunert + */ + +#include "catch.hpp" +#include "fakeit.hpp" + +#include "utility/LoggerFactory.h" + + +// testing purposes +#define private public + +#include "output/items/detail/Sound.h" + +using namespace flippR_driver::output; +using namespace fakeit; + +SCENARIO("") +{ + +} + + diff --git a/README b/README deleted file mode 100644 index 9a14950..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -Here you will find code for the Flipper-project diff --git a/README.md b/README.md new file mode 100644 index 0000000..793febd --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +## Build the driver library +To build the flippr-driver library run the following commands: +```sh1 +$ cd flippr-code/FlippR-Driver/build +$ cmake .. +$ make +``` +This will create you the static-library file: _flippr-code/FlippR-Driver/bin/libFlippR-Driver.a_ + +The library uses wiringPi Pin numbering important for the config files + +We added a script /usr/bin/reset_flippr this can be found in the repo and must be chosen in /etc/rc.local. It prevents the solenois from burning! diff --git a/cli/Bank.py b/cli/Bank.py new file mode 100644 index 0000000..9a92428 --- /dev/null +++ b/cli/Bank.py @@ -0,0 +1,21 @@ +class Bank(Target): + def __init__(self, targets): + self.targets = targets + self.__register_targets__() + + def __target_hit__(self, target): + if all(target.is_hit for target in self.targets): + self.__all_targets_hit__() + + def __all_targets_hit__(self): + self.__reset_all_targets__() + super.hit() + pass + + def __reset_all_targets__(self): + for target in self.targets: + target.reset() + + def __register_targets__(self): + for target in self.targets: + target.on(target.hit_key, self.__target_hit__) \ No newline at end of file diff --git a/cli/BankTarget.py b/cli/BankTarget.py new file mode 100644 index 0000000..238b44c --- /dev/null +++ b/cli/BankTarget.py @@ -0,0 +1,15 @@ +from Target import Target + + +class BankTarget(Target): + def __init__(self, points): + super(points) + self.is_hit = False + + def hit(self): + self.is_hit = True + super.hit() + #notify Bank + + def reset(self): + self.is_hit = False \ No newline at end of file diff --git a/cli/FlippR_Networking.py b/cli/FlippR_Networking.py new file mode 100644 index 0000000..e3de1f1 --- /dev/null +++ b/cli/FlippR_Networking.py @@ -0,0 +1,55 @@ +import requests_unixsocket as req +import socket + +class Networking: + def __init__(self, output_server_address, input_socket_address): + self.server_address = "" + self.input_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.output_session = req.Session() + self.server_address = "http+unix://" + output_server_address.replace("/", "%2F") + self.input_socket.connect(input_socket_address) + print("Connected to " + input_socket_address + " and started server " + self.server_address) + + def get(self, path): + response = self.output_session.get(self.server_address + path) + assert response.status_code == 200 + return response + + def getSolenoids(self): + return self.get("/solenoids").json() + + def getSounds(self): + return self.get("/sounds").json() + + def getLamps(self): + return self.get("/lamps").json() + + def getDisplays(self): + return self.get("/displays").json() + + def triggerSolenoid(self, solenoid): + self.get("/solenoids/" + solenoid + "/trigger") + + def playSound(self, sound): + self.get("/sounds/" + sound + "/play") + + def activateLamp(self, lamp): + self.get("/lamps/" + lamp + "/activate") + + def deactivateLamp(self, lamp): + self.get("/lamps/" + lamp + "/deactivate") + + def lampStatus(self, lamp): + return self.get("/lamps/" + lamp + "/status").json() + + def writeDisplayScore(self, display, score): + self.get("/displays/" + display + "/write_score/" + str(score)) + + def getInputEvent(self): + header = list() + while b'\x02' not in header: + byte = self.input_socket.recv(1) + header.append(byte) + header = [x.decode('utf8') for x in header[:-1]] + + return str().join(header) diff --git a/cli/Main.puml b/cli/Main.puml new file mode 100644 index 0000000..62d0bf3 --- /dev/null +++ b/cli/Main.puml @@ -0,0 +1,70 @@ +@startuml +class Observable { + trigger(string event) + on(string event, function fun) +} + +class FlippR + +class Game + +Game --* Cabinet : isAchievementStrategy ? +Game --* State : observes > +Game "1" --* "*" TargetStrategy + +class TargetStrategy +Target "1" o-- "1" TargetStrategy : observe < +State o-- TargetStrategy : changes < + +class State { + int ballsLeft + int currentBall +} + +State --* BallState + +class BallState { + int score + int globalMultiplier + addScore(int points) +} + +class UpperPlayFieldTimer { + int timeLeft = 0 + start() + stop() +} + +BallState --* UpperPlayFieldTimer +class Cabinet { +} + +Observable <|-- Cabinet +Cabinet "1" --* "*" Target + +Observable <|-- Target +abstract class Target { + int points + string name + hit() +} + +class AchievementTarget { +} + +Target "1..*" *-- "1" AchievementTarget : observe < +Target <|-- AchievementTarget + +class BankTarget { + bool isHit + hit() + reset() +} +Target <|-- BankTarget + +class Bank + +Target <|-- Bank +Bank "1" --* "1..*" BankTarget : observe > + +@enduml \ No newline at end of file diff --git a/cli/Target.py b/cli/Target.py new file mode 100644 index 0000000..9ae693d --- /dev/null +++ b/cli/Target.py @@ -0,0 +1,10 @@ +class Target(Observable): + def __init__(self, points, name): + self.points = points + self.name = name + self.hit_key = "hit" + + def hit(self): + #notify Observers + #notify Gamestate + self.trigger(self.hit_key, self) \ No newline at end of file diff --git a/cli/Target_Strategy_Sequence.puml b/cli/Target_Strategy_Sequence.puml new file mode 100644 index 0000000..37ec753 --- /dev/null +++ b/cli/Target_Strategy_Sequence.puml @@ -0,0 +1,7 @@ +@startuml +Cabinet -> TargetStrategy : Event +Game -> TargetStrategy : defines + + + +@enduml \ No newline at end of file diff --git a/cli/game.py b/cli/game.py new file mode 100644 index 0000000..b15ff0b --- /dev/null +++ b/cli/game.py @@ -0,0 +1,46 @@ +output_server_address = '' +input_server_address = '' + +#network = Networking(output_server_address, input_server_address) +network = '' + +class EventHandler(): + def __init__(self, network): + # brace yourselves, python incoming + self.subclasses = {subcls.__name__: subcls for subcls in self.__class__.__subclasses__()} + self.network = network + + def handle(self, name): + self.subclasses[name](network) + +class LeftFlapEventHandler(EventHandler): + def __init__(self, network): + print('Left Flap Event gets handled') + self.handle() + + def handle(self): + # do stuff... + pass + +class GameState: + def __init__(self, targets): + self.score = 0 + self.targets = targets + for target in self.targets: + target.on(target.hit_key, self.__target_hit__) + + def __target_hit__(self, target): + pass + +def snake_to_camel(word): + return ''.join(x.capitalize() or '' for x in word.split('_')) + +handler = EventHandler(network) +handler.handle(snake_to_camel('left_flap') + 'EventHandler') + +# while True: +# event_name = snake_to_camel(network.getInputEvent()) +# handler.handle(event_name + 'EventHandler') + + + diff --git a/cli/main.py b/cli/main.py new file mode 100644 index 0000000..a7bc85b --- /dev/null +++ b/cli/main.py @@ -0,0 +1,112 @@ +#!/usr/bin/python3 +from cursesmenu import * +from cursesmenu.items import * +import curses +import argparse as ap +from FlippR_Networking import Networking +import signal +import os + +networking = "notset" + +def create_menu(): + menu = CursesMenu("FlippR") + + solenoids = networking.getSolenoids()["solenoids"] + sol_menu = create_submenu("Solenoids", solenoids, networking.triggerSolenoid) + sol_menu_item = SubmenuItem("Solenoids", sol_menu, menu) + menu.append_item(sol_menu_item) + + sounds = networking.getSounds()["sounds"] + sound_menu = create_submenu("Sounds", sounds, networking.playSound) + sound_menu_item = SubmenuItem("Sounds", sound_menu, menu) + menu.append_item(sound_menu_item) + + displays = networking.getDisplays()["displays"] + display_menu = create_displays_submenu(displays) + display_menu_item = SubmenuItem("Displays", display_menu, menu) + menu.append_item(display_menu_item) + + lamps = networking.getLamps()["lamps"] + lamp_menu = create_lamps_submenu(lamps) + lamp_menu_item = SubmenuItem("Lamps", lamp_menu, menu) + menu.append_item(lamp_menu_item) + + input_item = FunctionItem("Print Input", print_input) + menu.append_item(input_item) + + #win = curses.newwin(20,20,20,20) + menu.show() + +#quit = False +#def sigint_handler(quit): + # quit = True + +def print_input(): + print("Starting to print incoming events:") + # end_loop_handler = signal.signal(signal.SIGINT, sigint_handler) + while(True): + print(networking.getInputEvent()) + # signal.signal(signal.SIGINT, end_loop_handler) + +def create_lamps_submenu(lamps): + menu = CursesMenu("Output", "Lamps") + for lamp in lamps: + lamp_submenu = create_lamp_submenu(lamp) + sub_item = SubmenuItem(lamp['name'], lamp_submenu, menu) + menu.append_item(sub_item) + return menu + +def create_lamp_submenu(lamp): + args = list() + args.append(lamp['name']) + menu = CursesMenu("Lamps", lamp['name']) + activate_item = FunctionItem("Activate", networking.activateLamp, args) + deactivate_item = FunctionItem("Deactivate", networking.deactivateLamp, args) + status_item = FunctionItem("Status", print_lamp_status, args) + menu.append_item(activate_item) + menu.append_item(deactivate_item) + menu.append_item(status_item) + return menu + +def print_lamp_status(lamp): + status = networking.lampStatus(lamp) + print(status) + +def create_displays_submenu(displays): + menu = CursesMenu("Output", "Displays") + for display in displays: + args = list() + args.append(display['name']) + fun_item = FunctionItem(display['name'], write_display_score, args) + menu.append_item(fun_item) + return menu + +def write_display_score(display): + score = input("Score: ") + networking.writeDisplayScore(display, score) + +def create_submenu(title, items, fun): + menu = CursesMenu("Output", title) + for item in items: + args = list() + args.append(item["name"]) + fun_item = FunctionItem(item["name"], fun, args) + menu.append_item(fun_item) + return menu + +def main(): + argparser = ap.ArgumentParser() + global networking + if os.environ["XDG_RUNTIME_DIR"]: + path = os.environ["XDG_RUNTIME_DIR"] + else: + path = "/tmp" + in_path = path + "/S.flippR_driver.in" + out_path = path + "/S.flippR_driver.out" + print("Input path: " + in_path + " output path " + out_path ) + networking = Networking(out_path, in_path) + print(networking) + create_menu() + +main()