firmware-base/lib/Streaming/examples/StreamingTests/StreamingTests.ino

277 lines
8.5 KiB
C++

#include <Streaming.h>
// Unit test helper class
class _Assert : public Print
{
public:
_Assert() : m_idx(0) {}
size_t write(uint8_t b) { m_buf[m_idx++] = b; return 1; }
int8_t compare(const char * expected) const
{
int8_t len_comparison = strlen(expected) - m_idx;
if ( len_comparison != 0 ) return len_comparison;
return memcmp(m_buf, expected, m_idx );
}
int8_t compare(const __FlashStringHelper* expected) const
{
int8_t len_comparison = strlen_P(reinterpret_cast<const char *>(expected)) - m_idx;
if ( len_comparison != 0) return len_comparison;
return memcmp_P(m_buf, expected, m_idx);
}
void reset(void) { m_idx = 0; }
const char *buffer(void) { m_buf[m_idx] = 0; return m_buf; }
private:
char m_buf[40];
uint8_t m_idx;
};
_Assert Assert;
uint16_t ran=0;
uint16_t passed=0;
template<typename T>
inline Print& operator==(Print& stm, T expected)
{
// Hackery since we know stm is of type _Assert
_Assert* assert = reinterpret_cast<_Assert*>(&stm);
int8_t cmp = assert->compare(expected);
// Would love to use the streaming functions here, but as we're testing them we can't
Serial.print("Test ");
Serial.print(++ran);
if ( cmp == 0 )
{
Serial.println(" passed.");
passed++;
}
else
{
Serial.print(" failed. Expected [");
Serial.print(expected);
Serial.print("] but was [");
Serial.print(assert->buffer());
Serial.println("].");
}
assert->reset();
return stm;
}
class PrintableTest : public Printable
{
size_t printTo(Print& p) const { return p.print("printed"); }
};
class NoCopyConstructorType : public Printable
{
public:
NoCopyConstructorType() {}
size_t printTo(Print& p) const { return p.print("NoCopyCtr"); }
private:
// Remove the copy constructor which will ensure that it can't be passed to the streaming template by value
NoCopyConstructorType(NoCopyConstructorType&) {}
};
void setup()
{
Serial.begin(115200);
}
void loop()
{
ran = passed = 0;
//
// Check the assertion comparators
//
Assert.print("one");
if ( Assert.compare("one") != 0 )
{
Serial.println(F("const char* comparator failed"));
while(true);
}
if ( Assert.compare(F("one")) != 0)
{
Serial.println(F("const __FlashStringHelper* comparator failed"));
while(true);
}
Assert.reset();
const char abc[] = "abc";
//
// Start by testing that simple types all function correctly
// using the generic template
//
Assert << 1 == F("1");
Assert << 10 == F("10");
Assert << -5 == F("-5");
Assert << 'a' == F("a");
Assert << B1000 == F("8");
Assert << 1.0 == F("1.00");
Assert << 1.005 == F("1.00");
Assert << -10.23 == F("-10.23");
Assert << "abc" == F("abc");
Assert << abc == F("abc");
Assert << abc == abc;
Assert << F("abc") == F("abc");
Assert << String("string") == F("string");
Assert << PrintableTest() == F("printed");
//
// Check that chaining works
//
Assert << 1 << '2' << 0x3 << "4" << F("5") == F("12345");
//
// Now check that the _BASED ones work too
//
Assert << _DEC(1) == F("1");
Assert << _DEC(-1) == F("-1");
Assert << _DEC((int8_t)1) == F("1");
Assert << _DEC((int8_t)-1) == F("-1");
Assert << _DEC((uint8_t)1) == F("1");
Assert << _DEC((uint8_t)-1) == F("255");
Assert << _DEC((int16_t)1) == F("1");
Assert << _DEC((int16_t)-1) == F("-1");
Assert << _DEC((uint16_t)1) == F("1");
Assert << _DEC((uint16_t)-1) == F("65535");
Assert << _DEC((int32_t)1) == F("1");
Assert << _DEC((int32_t)-1) == F("-1");
Assert << _DEC((uint32_t)1) == F("1");
Assert << _DEC((uint32_t)-1) == F("4294967295");
Assert << (uint32_t)4294967295 == F("4294967295");
Assert << _HEX(15) == F("F");
Assert << _OCT(15) == F("17");
Assert << _BIN(15) == F("1111");
Assert << _BYTE(64) == F("@");
//
// _FLOAT
//
double v = 1.23456789012345;
Assert << _FLOAT(v, 1) == F("1.2");
Assert << _FLOAT(v, 2) == F("1.23");
Assert << _FLOAT(v, 3) == F("1.235");
Assert << _FLOAT(v, 4) == F("1.2346");
Assert << _FLOAT(v, 5) == F("1.23457");
Assert << _FLOAT(v, 6) == F("1.234568");
Assert << _FLOAT(1.7649E22, 5) == F("ovf"); // This really needs work!
//
// endl
//
Assert << 1 << endl == F("1\r\n");
//
// Padding helper
//
Assert << _PAD(10,' ') == F(" ");
Assert << _PAD(4, '0') == F("0000");
Assert << _PAD(20, '=') == F("====================");
//
// Width streaming
//
Assert << _WIDTH(1, 5) == F(" 1");
Assert << _WIDTH(-1, 5) == F(" -1");
Assert << _WIDTHZ(1, 5) == F("00001");
Assert << _WIDTHZ(128,5) == F("00128");
Assert << _WIDTHZ(_HEX(128), 5) == F("00080");
Assert << _WIDTH(abc, 5) == F(" abc");
Assert << _WIDTH("one", 5) == F(" one");
Assert << _WIDTH(F("one"), 5) == F(" one");
// Check lightweight std::is_signed on AVR platforms
Assert << _WIDTH((int8_t)-1, 11) == F(" -1");
Assert << _WIDTH((uint8_t)-1, 11) == F(" 255");
Assert << _WIDTH((int16_t)-1, 11) == F(" -1");
Assert << _WIDTH((uint16_t)-1, 11) == F(" 65535");
Assert << _WIDTH((int32_t)-1, 11) == F(" -1");
Assert << _WIDTH((uint32_t)-1, 11) == F(" 4294967295");
Assert << _WIDTH((int8_t)-20, 11) == F(" -20");
Assert << _WIDTH((int16_t)-32767, 11) ==F(" -32767");
Assert << _WIDTH((int32_t)-65536, 11) ==F(" -65536");
//
// Width streaming for floats
//
Assert << _WIDTH(_FLOAT(-9.99, 1), 11)==F(" -10.0");
Assert << _WIDTH(-3.14159, 11) == F(" -3.14"); // default nb of digits after decimal point is 2 for print(double)
Assert << _WIDTH((float)12.566, 11) == F(" 12.57");
Assert << _FLOATW(-1, 2, 11) == F(" -1.00");
Assert << _FLOATW(1.23456e4, 1, 11) == F(" 12345.6");
#ifdef ARDUINO_ARCH_AVR
Assert << _FLOATW(-3.1415926, 6, 11) == F(" -3.141592");
#else
Assert << _FLOATW(-3.1415926, 6, 11) == F(" -3.141593");
#endif
Assert << _FLOATW(-9.999999, 4, 11) == F(" -10.0000");
Assert << _FLOATW(-0.0, 1, 11) == F(" 0.0");
Assert << _FLOATW(-0.01, 1, 11) == F(" -0.0");
Assert << _FLOATW(-0.01, 0, 11) == F(" -0");
Assert << _FLOATW(1.4, 0, 11) == F(" 1");
Assert << _FLOATW(0. / 0., 2, 11) == F(" nan");
Assert << _FLOATW(-1. / 0., 2, 11) == F(" inf");
#ifndef ESP8266 // no ovf on esp8266
Assert << _FLOATW(1.e10, 2, 11) == F(" ovf");
#endif
//
// Stream formatter
//
Assert << _FMT("Hello % the time is %:%:%", "gazoodle", _WIDTHZ(1,2), _WIDTHZ(4,2), _WIDTHZ(8,2)) == F("Hello gazoodle the time is 01:04:08");
Assert << _FMT("Too many % % % for the parms", 1) == F("Too many 1 % % for the parms");
Assert << _FMT("Too few % for the parms", 1, 2) == F("Too few 1 for the parms");
Assert << _FMT("Output a \\% sign") == F("Output a % sign");
Assert << _FMT("Handle trailing \\") == F("Handle trailing ");
Assert << _FMT(F("Replace % with %"), 1, 2 ) == F("Replace 1 with 2");
Assert << _FMT("Your score is %\\%", 65.3) == F("Your score is 65.30%");
Assert << _FMT("Once % a %%%", F("upon"), 't', 1, "me" ) == F("Once upon a t1me");
Assert << _FMT("This [%][%][%] grid", _WIDTH(10, 4), _WIDTH(_HEX(619),4), _WIDTH(3,4)) == F("This [ 10][ 26B][ 3] grid");
//
// Make sure that all the stream operators return the stream
// by chaining them together.
//
Assert
<< (int8_t)1 // Generic template
<< _BYTE(50) // _BYTE_CODE
<< _HEX(3) // _BASED
<< _FLOAT(4,0) // _FLOAT
<< _PAD(1,'5') // Padding
<< _WIDTH(6,1) // Width
<< _FMT("%",7) // Formatter
<< endl
== F("1234567\r\n");
//
// Ensure streaming template overide doesn't pass by value
//
Assert
<< NoCopyConstructorType()
== F("NoCopyCtr");
//
// Final report
//
Serial.println();
Serial.print(F("Tests complete. "));
Serial.print(ran);
Serial.print(F(" tests ran. "));
Serial.print(passed);
Serial.print(" passed, ");
Serial.print(ran-passed);
Serial.println(" failed.");
delay(1000);
}