diff --git a/examples/basic_verbose/basic_verbose.ino b/examples/basic_verbose/basic_verbose.ino new file mode 100644 index 0000000..63b83d3 --- /dev/null +++ b/examples/basic_verbose/basic_verbose.ino @@ -0,0 +1,32 @@ +#line 2 "basic_verbose.ino" + +// Same as ../basic/basic.ino except this uses instead of +// to get the more verbose assertion messages containing the string +// fragment of the actual arguments in the assertXxx() macros. The cost is +// ~20-25% increase in flash memory to store those strings for moderate to +// large unit tests. But the verbose version may be helpful for debugging. + +#include + +test(correct) { + int x = 1; + assertEqual(x, 1); +} + +test(incorrect) { + int x = 1; + assertNotEqual(x, 1); +} + +void setup() { + delay(1000); // wait for stability on some boards to prevent garbage Serial + Serial.begin(115200); // ESP8266 default of 74880 not supported on Linux + while(!Serial); // for the Arduino Leonardo/Micro only +} + +void loop() { + // Should get: + // TestRunner summary: + // 1 passed, 1 failed, 0 skipped, 0 timed out, out of 2 test(s). + aunit::TestRunner::run(); +} diff --git a/src/AUnit.h b/src/AUnit.h index 6ff8cd4..58a685a 100644 --- a/src/AUnit.h +++ b/src/AUnit.h @@ -41,7 +41,7 @@ SOFTWARE. #include "aunit/TestOnce.h" #include "aunit/TestAgain.h" #include "aunit/TestRunner.h" -#include "aunit/AssertMacros.h" +#include "aunit/AssertMacros.h" // terse assertXxx() macros #include "aunit/MetaAssertMacros.h" #include "aunit/TestMacros.h" diff --git a/src/AUnitVerbose.h b/src/AUnitVerbose.h new file mode 100644 index 0000000..cc79010 --- /dev/null +++ b/src/AUnitVerbose.h @@ -0,0 +1,54 @@ +/* +MIT License + +Copyright (c) 2018 Brian T. Park + +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. +*/ + +/** + * @file AUnitVerbose.h + * + * Same as AUnit.h except that the verbose versions of teh various assertXxx() + * macros are provided. These capture the strings of the actual arguments in + * the assert macros and print more verbose and helpful messages in the same + * format used by ArduinoUnit. The cost is 20-25% increase in flash memory to + * hold those strings for medium to large unit tests. + */ + +#ifndef AUNIT_AUNIT_VERBOSE_H +#define AUNIT_AUNIT_VERBOSE_H + +#include "aunit/Verbosity.h" +#include "aunit/Compare.h" +#include "aunit/Printer.h" +#include "aunit/Test.h" +#include "aunit/Assertion.h" +#include "aunit/MetaAssertion.h" +#include "aunit/TestOnce.h" +#include "aunit/TestAgain.h" +#include "aunit/TestRunner.h" +#include "aunit/AssertVerboseMacros.h" // verbose assertXxx() macros +#include "aunit/MetaAssertMacros.h" +#include "aunit/TestMacros.h" + +// Version format: xxyyzz == "xx.yy.zz" +#define AUNIT_VERSION 000402 + +#endif diff --git a/src/aunit/AssertVerboseMacros.h b/src/aunit/AssertVerboseMacros.h new file mode 100644 index 0000000..c36cf33 --- /dev/null +++ b/src/aunit/AssertVerboseMacros.h @@ -0,0 +1,82 @@ +/* +MIT License + +Copyright (c) 2018 Brian T. Park + +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. +*/ + +// Significant portions of the design and implementation of this file came from +// https://github.com/mmurdoch/arduinounit/blob/master/src/ArduinoUnit.h + +/** + * @file AssertVerboseMacros.h + * + * Verbose versions of the macros in AssertMacros.h. These capture the string + * of the actual arguments and pass them to the respective assertionVerbose() + * methods so that verbose messages can be printed. + */ + +#ifndef AUNIT_ASSERT_VERBOSE_MACROS_H +#define AUNIT_ASSERT_VERBOSE_MACROS_H + +/** Assert that arg1 is equal to arg2. */ +#define assertEqual(arg1,arg2) \ + assertOpVerboseInternal(arg1,aunit::compareEqual,"==",arg2) + +/** Assert that arg1 is not equal to arg2. */ +#define assertNotEqual(arg1,arg2) \ + assertOpVerboseInternal(arg1,aunit::compareNotEqual,"!=",arg2) + +/** Assert that arg1 is less than arg2. */ +#define assertLess(arg1,arg2) \ + assertOpVerboseInternal(arg1,aunit::compareLess,"<",arg2) + +/** Assert that arg1 is more than arg2. */ +#define assertMore(arg1,arg2) \ + assertOpVerboseInternal(arg1,aunit::compareMore,">",arg2) + +/** Assert that arg1 is less than or equal to arg2. */ +#define assertLessOrEqual(arg1,arg2) \ + assertOpVerboseInternal(arg1,aunit::compareLessOrEqual,"<=",arg2) + +/** Assert that arg1 is more than or equal to arg2. */ +#define assertMoreOrEqual(arg1,arg2) \ + assertOpVerboseInternal(arg1,aunit::compareMoreOrEqual,">=",arg2) + +/** Assert that arg is true. */ +#define assertTrue(arg) assertBoolVerboseInternal(arg,true) + +/** Assert that arg is false. */ +#define assertFalse(arg) assertBoolVerboseInternal(arg,false) + +/** Internal helper macro, shouldn't be called directly by users. */ +#define assertOpVerboseInternal(arg1,op,opName,arg2) do {\ + if (!assertionVerbose(__FILE__,__LINE__,\ + (arg1),AUNIT_F(#arg1),opName,op,(arg2),AUNIT_F(#arg2)))\ + return;\ +} while (false) + +/** Internal helper macro, shouldn't be called directly by users. */ +#define assertBoolVerboseInternal(arg,value) do {\ + if (!assertionBoolVerbose(__FILE__,__LINE__,(arg),AUNIT_F(#arg),(value)))\ + return;\ +} while (false) + +#endif diff --git a/src/aunit/Assertion.cpp b/src/aunit/Assertion.cpp index 4123ae8..acb7a80 100644 --- a/src/aunit/Assertion.cpp +++ b/src/aunit/Assertion.cpp @@ -23,7 +23,7 @@ SOFTWARE. */ #include // definition of Print -#include "TestRunner.h" // seems like a circular reference but ok from cpp file +#include "Flash.h" #include "Printer.h" #include "Assertion.h" @@ -323,4 +323,330 @@ bool Assertion::assertion(const char* file, uint16_t line, return ok; } +// Verbose versions of above which accept the string arguments of the +// assertXxx() macros, so that the error messages are more verbose. + +template +static void printAssertionMessageVerbose(bool ok, const char* file, + uint16_t line, const A& lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, const B& rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + + // Don't use F() strings here because flash memory strings are not deduped by + // the compiler, so each template instantiation of this method causes a + // duplication of all the strings below. See + // https://github.com/mmurdoch/arduinounit/issues/70 + // for more info. + Print* printer = Printer::getPrinter(); + printer->print("Assertion "); + printer->print(ok ? "passed" : "failed"); + printer->print(": ("); + printer->print(lhsString); + printer->print('='); + printer->print(lhs); + printer->print(") "); + printer->print(opName); + printer->print(" ("); + printer->print(rhsString); + printer->print('='); + printer->print(rhs); + printer->print(')'); + // reuse string in MataAssertion::printAssertionTestStatusMessage() + printer->print(", file "); + printer->print(file); + printer->print(", line "); + printer->print(line); + printer->println('.'); +} + +// Special version of (bool, bool) because Arduino Print.h converts +// bool into int, which prints out "(1) == (0)", which isn't as useful. +// This prints "(true) == (false)". +static void printAssertionMessageVerbose(bool ok, const char* file, + uint16_t line, bool lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, bool rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + + // Don't use F() strings here. Same reason as above. + Print* printer = Printer::getPrinter(); + printer->print("Assertion "); + printer->print(ok ? "passed" : "failed"); + printer->print(": ("); + printer->print(lhsString); + printer->print('='); + printer->print(lhs ? "true" : "false"); + printer->print(") "); + printer->print(opName); + printer->print(" ("); + printer->print(rhsString); + printer->print('='); + printer->print(rhs ? "true" : "false"); + printer->print(')'); + printer->print(", file "); + printer->print(file); + printer->print(", line "); + printer->print(line); + printer->println('.'); +} + +// Special version for assertTrue(arg) and assertFalse(arg). +// Prints: +// "Assertion passed/failed: (arg) is true" +// "Assertion passed/failed: (arg) is false" +static void printAssertionBoolMessageVerbose(bool ok, const char* file, + uint16_t line, bool arg, AUNIT_FLASH_STRING_HELPER argString, bool value) { + + // Don't use F() strings here. Same reason as above. + Print* printer = Printer::getPrinter(); + printer->print("Assertion "); + printer->print(ok ? "passed" : "failed"); + printer->print(": ("); + printer->print(argString); + printer->print('='); + printer->print(arg ? "true" : "false"); + printer->print(") is "); + printer->print(value ? "true" : "false"); + printer->print(", file "); + printer->print(file); + printer->print(", line "); + printer->print(line); + printer->println('.'); +} + +bool Assertion::assertionBoolVerbose(const char* file, uint16_t line, bool arg, + AUNIT_FLASH_STRING_HELPER argString, bool value) { + if (isDone()) return false; + bool ok = (arg == value); + if (isOutputEnabled(ok)) { + printAssertionBoolMessageVerbose(ok, file, line, arg, argString, value); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, bool lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(bool lhs, bool rhs), bool rhs, + AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, char lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(char lhs, char rhs), char rhs, + AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, int lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(int lhs, int rhs), int rhs, + AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + unsigned int lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(unsigned int lhs, unsigned int rhs), + unsigned int rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, long lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(long lhs, long rhs), long rhs, + AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + unsigned long lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(unsigned long lhs, unsigned long rhs), + unsigned long rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, double lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(double lhs, double rhs), double rhs, + AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const char* lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(const char* lhs, const char* rhs), + const char* rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const char* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, bool (*op)(const char* lhs, const String& rhs), + const String& rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const char* lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const char* lhs, const __FlashStringHelper* rhs), + const __FlashStringHelper* rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const String& lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const String& lhs, const char* rhs), + const char* rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const String& lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const String& lhs, const String& rhs), + const String& rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const String& lhs, AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const String& lhs, const __FlashStringHelper* rhs), + const __FlashStringHelper* rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const __FlashStringHelper* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, + bool (*op)(const __FlashStringHelper* lhs, const char* rhs), + const char* rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const __FlashStringHelper* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, + bool (*op)(const __FlashStringHelper* lhs, const String& rhs), + const String& rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + +bool Assertion::assertionVerbose(const char* file, uint16_t line, + const __FlashStringHelper* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, + bool (*op)(const __FlashStringHelper* lhs, const __FlashStringHelper* rhs), + const __FlashStringHelper* rhs, AUNIT_FLASH_STRING_HELPER rhsString) { + if (isDone()) return false; + bool ok = op(lhs, rhs); + if (isOutputEnabled(ok)) { + printAssertionMessageVerbose(ok, file, line, lhs, lhsString, opName, rhs, + rhsString); + } + setPassOrFail(ok); + return ok; +} + } diff --git a/src/aunit/Assertion.h b/src/aunit/Assertion.h index 7f6b500..74c7f3c 100644 --- a/src/aunit/Assertion.h +++ b/src/aunit/Assertion.h @@ -25,6 +25,7 @@ SOFTWARE. #ifndef AUNIT_ASSERTION_H #define AUNIT_ASSERTION_H +#include "Flash.h" #include "Test.h" class __FlashStringHelper; @@ -132,6 +133,95 @@ class Assertion: public Test { const __FlashStringHelper* rhs), const __FlashStringHelper* rhs); + // Verbose versions of above. + + bool assertionBoolVerbose(const char* file, uint16_t line, bool arg, + AUNIT_FLASH_STRING_HELPER argString, bool value); + + bool assertionVerbose(const char* file, uint16_t line, bool lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(bool lhs, bool rhs), + bool rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, char lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(char lhs, char rhs), + char rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, int lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(int lhs, int rhs), + int rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, unsigned int lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(unsigned int lhs, unsigned int rhs), + unsigned int rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, long lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(long lhs, long rhs), + long rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, unsigned long lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(unsigned long lhs, unsigned long rhs), + unsigned long rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, double lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(double lhs, double rhs), + double rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, const char* lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char* opName, + bool (*op)(const char* lhs, const char* rhs), + const char* rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, const char* lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const char* lhs, const String& rhs), + const String& rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, const char* lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const char* lhs, const __FlashStringHelper* rhs), + const __FlashStringHelper* rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, const String& lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const String& lhs, const char* rhs), + const char* rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, const String& lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const String& lhs, const String& rhs), + const String& rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, const String& lhs, + AUNIT_FLASH_STRING_HELPER lhsString, const char *opName, + bool (*op)(const String& lhs, const __FlashStringHelper* rhs), + const __FlashStringHelper* rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, + const __FlashStringHelper* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, + bool (*op)(const __FlashStringHelper* lhs, const char* rhs), + const char* rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, + const __FlashStringHelper* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, + bool (*op)(const __FlashStringHelper* lhs, const String& rhs), + const String& rhs, AUNIT_FLASH_STRING_HELPER rhsString); + + bool assertionVerbose(const char* file, uint16_t line, + const __FlashStringHelper* lhs, AUNIT_FLASH_STRING_HELPER lhsString, + const char *opName, + bool (*op)(const __FlashStringHelper* lhs, + const __FlashStringHelper* rhs), + const __FlashStringHelper* rhs, AUNIT_FLASH_STRING_HELPER rhsString); + private: // Disable copy-constructor and assignment operator Assertion(const Assertion&) = delete; diff --git a/src/aunit/Compare.cpp b/src/aunit/Compare.cpp index ad7874b..397926d 100644 --- a/src/aunit/Compare.cpp +++ b/src/aunit/Compare.cpp @@ -129,13 +129,7 @@ inlining them because they are almost always used through a function pointer. #include #include - -#ifdef ESP8266 -#include -#else -#include -#endif - +#include "Flash.h" #include "Compare.h" #include "FCString.h" diff --git a/src/aunit/Flash.h b/src/aunit/Flash.h new file mode 100644 index 0000000..f6fec98 --- /dev/null +++ b/src/aunit/Flash.h @@ -0,0 +1,65 @@ +/* +MIT License + +Copyright (c) 2018 Brian T. Park + +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. +*/ + +/** + * @file Flash.h + * + * Flash strings (using F() macro) on the ESP8266 platform cannot be placed in + * an inline context, because it interferes with other PROGMEM strings in + * non-inline contexts. See https://github.com/esp8266/Arduino/issues/3369. In + * some cases (e.g. TestMacros.h), we were able to move the F() macro into a + * non-inline context. But in other cases (e.g. AssertVerboseMacros.h) it is + * impossible to move these out of inline contexts because we want to support + * assertXxx() statements inside inlined methods. + */ + +#ifndef AUNIT_FLASH_H +#define AUNIT_FLASH_H + +class __FlashStringHelper; + +#ifdef ESP8266 + #include +#else + #include +#endif + +// Defined in ESP8266, not defined in AVR or Teensy +#ifndef FPSTR + #define FPSTR(pstr_pointer) \ + (reinterpret_cast(pstr_pointer)) +#endif + +// These are used only in AssertionVerboseMacros.h and the "Verbose" methods of +// Assertion.h because ESP8266 cannot handle F() strings in both inline and +// non-inlnie contexts. So don't use F() strings on ESP8266. +#ifdef ESP8266 + #define AUNIT_F(x) (x) + #define AUNIT_FLASH_STRING_HELPER const char* +#else + #define AUNIT_F(x) F(x) + #define AUNIT_FLASH_STRING_HELPER const __FlashStringHelper* +#endif + +#endif diff --git a/src/aunit/MetaAssertion.cpp b/src/aunit/MetaAssertion.cpp index e85135b..1ae3aab 100644 --- a/src/aunit/MetaAssertion.cpp +++ b/src/aunit/MetaAssertion.cpp @@ -22,13 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifdef ESP8266 -#include -#else -#include -#endif #include // definition of Print +#include "Flash.h" #include "Printer.h" #include "Verbosity.h" #include "Compare.h" diff --git a/src/aunit/Test.cpp b/src/aunit/Test.cpp index dd2e835..406ff74 100644 --- a/src/aunit/Test.cpp +++ b/src/aunit/Test.cpp @@ -22,13 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifdef ESP8266 -#include -#else -#include -#endif - #include // for declaration of 'Serial' on Teensy and others +#include "Flash.h" #include "Verbosity.h" #include "Printer.h" #include "Compare.h" diff --git a/src/aunit/Test.h b/src/aunit/Test.h index 45cd527..71f1c82 100644 --- a/src/aunit/Test.h +++ b/src/aunit/Test.h @@ -32,12 +32,6 @@ SOFTWARE. #include "FCString.h" #include "Verbosity.h" -// Defined in ESP8266, not defined in AVR or Teensy -#ifndef FPSTR -#define FPSTR(pstr_pointer) \ - (reinterpret_cast(pstr_pointer)) -#endif - namespace aunit { /** diff --git a/src/aunit/TestMacros.h b/src/aunit/TestMacros.h index 51d0409..ff364c2 100644 --- a/src/aunit/TestMacros.h +++ b/src/aunit/TestMacros.h @@ -37,6 +37,7 @@ SOFTWARE. #include #include // F() macro +#include "Flash.h" #include "FCString.h" #include "TestOnce.h" #include "TestAgain.h" diff --git a/tests/AUnitTest/AUnitTest.h b/tests/AUnitTest/AUnitTest.h index 799b63a..c6d8ab5 100644 --- a/tests/AUnitTest/AUnitTest.h +++ b/tests/AUnitTest/AUnitTest.h @@ -10,7 +10,19 @@ #if USE_AUNIT == 1 #include // random() -#include + +// AVR: +// AUnit.h: flash/static: 29186/1369 +// AUnitVerbose.h: flash/static: 37352/1373 (too big for ATmega328P) +// ESP8266: +// AUnit.h: flash/static: 276112/33476 +// AUnitVerbose.h: flash/static: 281464/36100 +// Teensy 3.2: +// AUnit.h: flash/static: 43328/5440 +// AUnitVerbose.h: flash/static: 49820/5440 +//#include +#include + using namespace aunit; class CustomOnceFixture: public TestOnce { diff --git a/tests/AUnitTest/AUnitTest.ino b/tests/AUnitTest/AUnitTest.ino index aab930d..1f9ed1a 100644 --- a/tests/AUnitTest/AUnitTest.ino +++ b/tests/AUnitTest/AUnitTest.ino @@ -577,7 +577,9 @@ testF(CustomAgainFixture, crossedAgain) { externTestF(CustomOnceFixture, fixture_external); testing(fixture_external_monitor) { + // this will loop forever unless explicitly passed assertTestDoneF(CustomOnceFixture, fixture_external); + pass(); } externTestingF(CustomAgainFixture, fixture_slow_pass); @@ -742,7 +744,7 @@ void setup() { #if USE_AUNIT == 1 // These are useful for debugging. - //TestRunner::setVerbosity(Verbosity::kAll); + TestRunner::setVerbosity(Verbosity::kAll); //TestRunner::setVerbosity(Verbosity::kTestRunSummary); //TestRunner::list(); @@ -762,7 +764,7 @@ void loop() { #if USE_AUNIT == 1 // Should get something like: // TestRunner summary: - // 26 passed, 4 failed, 2 skipped, 4 timed out, out of 36 test(s). + // 27 passed, 4 failed, 2 skipped, 3 timed out, out of 36 test(s). TestRunner::run(); #else Test::run();