#!/bin/bash # Test cppp compliance. set -euo pipefail CPPP=./cppp #CPPP="perl $(dirname "$0")/cppp.pl" function die() { echo "$CPPP: Failed at line $1" exit 1 } function verify() { if [ $# -gt 2 ]; then ( echo "$2" | $CPPP "$3" | grep -qF "OK" ) || die "$1" ( echo "$2" | $CPPP "$3" | grep -qF "UNREACHABLE" ) && die "$1" else ( echo "$2" | $CPPP | grep -qF "OK" ) || die "$1" ( echo "$2" | $CPPP | grep -qF "UNREACHABLE" ) && die "$1" fi return 0 } function expect_unmatched_error() { ( echo "$2" | $CPPP 2>&1 | grep -qF "Unmatched" ) && die "$1" return 0 } # Trivial inputs. $CPPP /dev/null > /dev/null 2>&1 || die "$LINENO" verify "$LINENO" "OK" # Simple conditional tests. verify "$LINENO" " #if 1 OK #else UNREACHABLE #endif " verify "$LINENO" " #if 0 UNREACHABLE #else OK #endif " # Define tests. verify "$LINENO" " #ifdef UNDEFINED UNREACHABLE #else OK #endif " verify "$LINENO" " #define DEFINED #ifndef DEFINED UNREACHABLE #else OK #endif " verify "$LINENO" " #ifndef UNDEFINED OK #else UNREACHABLE #endif " verify "$LINENO" " #define DEFINED #ifdef DEFINED OK #else UNREACHABLE #endif " verify "$LINENO" " #define X #ifdef X OK #endif #undef X #ifdef X UNREACHABLE #endif " verify "$LINENO" " #undef X #ifndef X OK #endif #undef X #ifdef X UNREACHABLE #endif " # Evaluate constant expressions. verify "$LINENO" " #define X 3 #if X % 2 == 1 OK #else UNREACHABLE #endif " verify "$LINENO" " #define X 3 #if X > 2 OK #else UNREACHABLE #endif " verify "$LINENO" " #define X 3 #if X < 2 UNREACHABLE #else OK #endif " verify "$LINENO" " #define X 1 #if X == 1 OK #elif X == 2 UNREACHABLE #elif X == 3 UNREACHABLE #else UNREACHABLE #endif " verify "$LINENO" " #define X 2 #if X == 1 UNREACHABLE #elif X == 2 OK #elif X == 3 UNREACHABLE #else UNREACHABLE #endif " verify "$LINENO" " #define X 3 #if X == 1 UNREACHABLE #elif X == 2 UNREACHABLE #elif X == 3 OK #else UNREACHABLE #endif " verify "$LINENO" " #define X 4 #if X == 1 UNREACHABLE #elif X == 2 UNREACHABLE #elif X == 3 UNREACHABLE #else OK #endif " # Conditional definitions. verify "$LINENO" " #ifndef X #define X #endif #ifdef X OK #else UNREACHABLE #endif " verify "$LINENO" " #define X #define Y #ifdef X #undef Y #endif #ifndef Y OK #else UNREACHABLE #endif " verify "$LINENO" " #define A #define B #ifdef A #ifdef B OK #else UNREACHABLE #endif #else #ifdef B UNREACHABLE #else UNREACHABLE #endif #endif " verify "$LINENO" " #undef A #define B #ifdef A #ifdef B UNREACHABLE #else UNREACHABLE #endif #else #ifdef B OK #else UNREACHABLE #endif #endif " verify "$LINENO" " #define A #undef B #ifdef A #ifdef B UNREACHABLE #else OK #endif #else #ifdef B UNREACHABLE #else UNREACHABLE #endif #endif " verify "$LINENO" " #undef A #undef B #ifdef A #ifdef B UNREACHABLE #else UNREACHABLE #endif #else #ifdef B UNREACHABLE #else OK #endif #endif " # Definitions via command line flags. verify "$LINENO" " #ifdef X OK #else UNREACHABLE #endif " -DX verify "$LINENO" " #if X > 1 OK #elif X == 1 UNREACHABLE #else UNREACHABLE #endif " -DX=2 verify "$LINENO" " #if X > 1 UNREACHABLE #elif X == 1 OK #else UNREACHABLE #endif " -DX=1 verify "$LINENO" " #if X > 1 UNREACHABLE #elif X == 1 UNREACHABLE #else OK #endif " -DX=0 # Include tests. verify "$LINENO" " #ifdef I OK #else #define I #include __FILE__ #endif " verify "$LINENO" " #ifdef I OK #else #define I #define F __FILE__ #include F #endif " verify "$LINENO" " #ifdef A #define B #undef A #include __FILE__ #else #ifndef B #define A #include __FILE__ #else OK #endif #endif " verify "$LINENO" " #ifdef A #define B #undef A #include __FILE__ #else #ifndef B #define A #include __FILE__ #else #define C #endif #endif #ifdef C OK #else UNREACHABLE #endif " # Multi-step substitutions. verify "$LINENO" " #define A 2 #define B A #if B > 0 OK #else UNREACHABLE #endif " verify "$LINENO" " #define A 2 #define B A #define C B #if C > 0 OK #else UNREACHABLE #endif " verify "$LINENO" " #ifndef GUARD #define GUARD #define A __FILE__ #define B A #include B #else OK #endif " verify "$LINENO" " #ifndef GUARD #define GUARD #define A __FILE__ #define B A #define C B #include C #else OK #endif " # Test various malformed input. expect_unmatched_error "$LINENO" " #if X " expect_unmatched_error "$LINENO" " #ifdef X " expect_unmatched_error "$LINENO" " #ifndef X " expect_unmatched_error "$LINENO" " #endif " expect_unmatched_error "$LINENO" " #else #endif " expect_unmatched_error "$LINENO" " #elif X #endif " # Test #warning and #error ( echo "#warning OK" | $CPPP 2>&1 | grep -qF "OK" ) || die "$LINENO" ( echo "#error" | $CPPP > /dev/null 2>&1 ) && die "$LINENO" ( echo " #error OK UNREACHABLE " | $CPPP 2>&1 | grep -qF "UNREACHABLE" ) && die "$LINENO" # Output a message at the end to confirm that we didn't exit early due to # "set -e" echo "$CPPP: OK"