From 1c54371b1c83678f3573565a7ed7ea32e7656bde Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 28 Aug 2015 22:16:48 +0100 Subject: [PATCH] Update tests & add travis --- .gitignore | 1 + .travis.yml | 9 +++ PubSubClient/src/PubSubClient.cpp | 1 + tests/Makefile | 13 +++- tests/src/connect_spec.cpp | 84 ++++++++++++------------ tests/src/keepalive_spec.cpp | 71 ++++++++++---------- tests/src/lib/BDDTest.cpp | 18 ++++-- tests/src/lib/BDDTest.h | 2 + tests/src/lib/IPAddress.cpp | 44 +++++++++++++ tests/src/lib/IPAddress.h | 67 ++++++++++++++++++- tests/src/lib/ShimClient.cpp | 13 ++-- tests/src/publish_spec.cpp | 55 ++++++++-------- tests/src/receive_spec.cpp | 103 +++++++++++++++--------------- tests/src/subscribe_spec.cpp | 37 +++++------ 14 files changed, 327 insertions(+), 191 deletions(-) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 tests/src/lib/IPAddress.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1c3ba189 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tests/bin diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..f660fe6f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: cpp + +compiler: + - g++ + +script: cd tests && make && make test + +os: + - linux diff --git a/PubSubClient/src/PubSubClient.cpp b/PubSubClient/src/PubSubClient.cpp index b3313a07..61d8ef27 100755 --- a/PubSubClient/src/PubSubClient.cpp +++ b/PubSubClient/src/PubSubClient.cpp @@ -202,6 +202,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass } return false; } + return true; } uint8_t PubSubClient::readByte() { diff --git a/tests/Makefile b/tests/Makefile index 931a6ca6..973f2871 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,15 +4,22 @@ TEST_SRC=$(wildcard ${SRC_PATH}/*_spec.cpp) TEST_BIN= $(TEST_SRC:${SRC_PATH}/%.cpp=${OUT_PATH}/%) VPATH=${SRC_PATH} SHIM_FILES=${SRC_PATH}/lib/*.cpp -PSC_FILE=../PubSubClient/PubSubClient.cpp +PSC_FILE=../PubSubClient/src/PubSubClient.cpp CC=g++ -CFLAGS=-I${SRC_PATH}/lib -I../PubSubClient +CFLAGS=-I${SRC_PATH}/lib -I../PubSubClient/src all: $(TEST_BIN) ${OUT_PATH}/%: ${SRC_PATH}/%.cpp ${PSC_FILE} ${SHIM_FILES} mkdir -p ${OUT_PATH} ${CC} ${CFLAGS} $^ -o $@ - + clean: @rm -rf ${OUT_PATH} + +test: + @bin/connect_spec + @bin/keepalive_spec + @bin/publish_spec + @bin/receive_spec + @bin/subscribe_spec diff --git a/tests/src/connect_spec.cpp b/tests/src/connect_spec.cpp index 46bfb9aa..2992e92d 100644 --- a/tests/src/connect_spec.cpp +++ b/tests/src/connect_spec.cpp @@ -35,38 +35,38 @@ int test_connect_fails_on_no_response() { int test_connect_properly_formatted() { IT("sends a properly formatted connect packet and succeeds"); ShimClient shimClient; - + shimClient.setAllowConnect(true); byte expectServer[] = { 172, 16, 0, 2 }; shimClient.expectConnect(expectServer,1883); - byte connect[] = {0x10,0x1a,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; + byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,28); + shimClient.expect(connect,26); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); IS_FALSE(shimClient.error()); - + END_IT } int test_connect_properly_formatted_hostname() { IT("accepts a hostname"); ShimClient shimClient; - + shimClient.setAllowConnect(true); shimClient.expectConnect((char* const)"localhost",1883); byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client((char* const)"localhost", 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); IS_FALSE(shimClient.error()); - + END_IT } @@ -77,7 +77,7 @@ int test_connect_fails_on_bad_rc() { shimClient.setAllowConnect(true); byte connack[] = { 0x20, 0x02, 0x00, 0x01 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_FALSE(rc); @@ -88,12 +88,12 @@ int test_connect_accepts_username_password() { IT("accepts a username and password"); ShimClient shimClient; shimClient.setAllowConnect(true); - - byte connect[] = { 0x10,0x26,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x4,0x70,0x61,0x73,0x73}; + + byte connect[] = { 0x10,0x24,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x4,0x70,0x61,0x73,0x73}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x28); + shimClient.expect(connect,0x26); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass"); IS_TRUE(rc); @@ -106,14 +106,14 @@ int test_connect_accepts_username_no_password() { IT("accepts a username but no password"); ShimClient shimClient; shimClient.setAllowConnect(true); - - byte connect[] = { 0x10,0x20,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x82,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72}; + + byte connect[] = { 0x10,0x1e,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x82,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x22); + shimClient.expect(connect,0x20); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",(char*)"user",'\0'); + int rc = client.connect((char*)"client_test1",(char*)"user",0); IS_TRUE(rc); IS_FALSE(shimClient.error()); @@ -124,14 +124,14 @@ int test_connect_ignores_password_no_username() { IT("ignores a password but no username"); ShimClient shimClient; shimClient.setAllowConnect(true); - - byte connect[] = {0x10,0x1a,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; + + byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,28); + shimClient.expect(connect,26); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); - int rc = client.connect((char*)"client_test1",'\0',(char*)"pass"); + int rc = client.connect((char*)"client_test1",0,(char*)"pass"); IS_TRUE(rc); IS_FALSE(shimClient.error()); @@ -142,12 +142,12 @@ int test_connect_with_will() { IT("accepts a will"); ShimClient shimClient; shimClient.setAllowConnect(true); - - byte connect[] = {0x10,0x32,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0xe,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; + + byte connect[] = {0x10,0x30,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xe,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x34); + shimClient.expect(connect,0x32); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1",(char*)"willTopic",1,0,(char*)"willMessage"); IS_TRUE(rc); @@ -160,12 +160,12 @@ int test_connect_with_will_username_password() { IT("accepts a will, username and password"); ShimClient shimClient; shimClient.setAllowConnect(true); - - byte connect[] = {0x10,0x42,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0xce,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x8,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64}; + + byte connect[] = {0x10,0x40,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xce,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x8,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,0x44); + shimClient.expect(connect,0x42); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"password",(char*)"willTopic",1,0,(char*)"willMessage"); IS_TRUE(rc); @@ -177,52 +177,54 @@ int test_connect_with_will_username_password() { int test_connect_disconnect_connect() { IT("connects, disconnects and connects again"); ShimClient shimClient; - + shimClient.setAllowConnect(true); byte expectServer[] = { 172, 16, 0, 2 }; shimClient.expectConnect(expectServer,1883); - byte connect[] = {0x10,0x1a,0x0,0x6,0x4d,0x51,0x49,0x73,0x64,0x70,0x3,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; + byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; - shimClient.expect(connect,28); + shimClient.expect(connect,26); shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); IS_FALSE(shimClient.error()); - + byte disconnect[] = {0xE0,0x00}; shimClient.expect(disconnect,2); client.disconnect(); - + IS_FALSE(client.connected()); IS_FALSE(shimClient.connected()); IS_FALSE(shimClient.error()); - + shimClient.expect(connect,28); shimClient.respond(connack,4); rc = client.connect((char*)"client_test1"); IS_TRUE(rc); IS_FALSE(shimClient.error()); - + END_IT } int main() { + SUITE("Connect"); test_connect_fails_no_network(); test_connect_fails_on_no_response(); + test_connect_properly_formatted(); + test_connect_accepts_username_password(); test_connect_fails_on_bad_rc(); test_connect_properly_formatted_hostname(); - test_connect_accepts_username_password(); + test_connect_accepts_username_no_password(); test_connect_ignores_password_no_username(); test_connect_with_will(); test_connect_with_will_username_password(); test_connect_disconnect_connect(); - FINISH } diff --git a/tests/src/keepalive_spec.cpp b/tests/src/keepalive_spec.cpp index ec518688..87f03640 100644 --- a/tests/src/keepalive_spec.cpp +++ b/tests/src/keepalive_spec.cpp @@ -3,7 +3,7 @@ #include "Buffer.h" #include "BDDTest.h" #include "trace.h" - +#include byte server[] = { 172, 16, 0, 2 }; @@ -13,49 +13,49 @@ void callback(char* topic, byte* payload, unsigned int length) { int test_keepalive_pings_idle() { - IT("keeps an idle connection alive"); - + IT("keeps an idle connection alive (takes 1 minute)"); + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte pingreq[] = { 0xC0,0x0 }; shimClient.expect(pingreq,2); byte pingresp[] = { 0xD0,0x0 }; shimClient.respond(pingresp,2); - + for (int i = 0; i < 50; i++) { sleep(1); rc = client.loop(); IS_TRUE(rc); } - + IS_FALSE(shimClient.error()); END_IT } int test_keepalive_pings_with_outbound_qos0() { - IT("keeps a connection alive that only sends qos0"); - + IT("keeps a connection alive that only sends qos0 (takes 1 minute)"); + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - + for (int i = 0; i < 50; i++) { TRACE(i<<":"); shimClient.expect(publish,16); @@ -73,25 +73,25 @@ int test_keepalive_pings_with_outbound_qos0() { IS_TRUE(rc); IS_FALSE(shimClient.error()); } - + END_IT } int test_keepalive_pings_with_inbound_qos0() { - IT("keeps a connection alive that only receives qos0"); - + IT("keeps a connection alive that only receives qos0 (takes 1 minute)"); + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - + for (int i = 0; i < 50; i++) { TRACE(i<<":"); sleep(1); @@ -106,23 +106,23 @@ int test_keepalive_pings_with_inbound_qos0() { IS_TRUE(rc); IS_FALSE(shimClient.error()); } - + END_IT } int test_keepalive_no_pings_inbound_qos1() { - IT("does not send pings for connections with inbound qos1"); - + IT("does not send pings for connections with inbound qos1 (takes 1 minute)"); + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; byte puback[] = {0x40,0x2,0x12,0x34}; @@ -139,27 +139,27 @@ int test_keepalive_no_pings_inbound_qos1() { } int test_keepalive_disconnects_hung() { - IT("disconnects a hung connection"); - + IT("disconnects a hung connection (takes 30 seconds)"); + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte pingreq[] = { 0xC0,0x0 }; shimClient.expect(pingreq,2); - + for (int i = 0; i < 32; i++) { sleep(1); rc = client.loop(); } IS_FALSE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -167,11 +167,12 @@ int test_keepalive_disconnects_hung() { int main() { + SUITE("Keep-alive"); test_keepalive_pings_idle(); test_keepalive_pings_with_outbound_qos0(); test_keepalive_pings_with_inbound_qos0(); test_keepalive_no_pings_inbound_qos1(); test_keepalive_disconnects_hung(); - + FINISH } diff --git a/tests/src/lib/BDDTest.cpp b/tests/src/lib/BDDTest.cpp index 1fb8ad9b..a72bf65e 100644 --- a/tests/src/lib/BDDTest.cpp +++ b/tests/src/lib/BDDTest.cpp @@ -9,25 +9,29 @@ int testCount = 0; int testPasses = 0; const char* testDescription; -std::list failureList; +std::list failureList; + +void bddtest_suite(const char* name) { + LOG(name << "\n"); +} int bddtest_test(const char* file, int line, const char* assertion, int result) { if (!result) { - LOG("F"); + LOG("✗\n"); std::ostringstream os; - os << " ! "<::iterator it = failureList.begin(); it != failureList.end(); it++) { LOG("\n"); LOG(*it); + LOG("\n"); } - LOG("\n" << std::dec << testPasses << "/" << testCount << " tests passed\n"); + + LOG(std::dec << testPasses << "/" << testCount << " tests passed\n\n"); if (testPasses == testCount) { return 0; } diff --git a/tests/src/lib/BDDTest.h b/tests/src/lib/BDDTest.h index dc1389b9..1197fdd4 100644 --- a/tests/src/lib/BDDTest.h +++ b/tests/src/lib/BDDTest.h @@ -1,11 +1,13 @@ #ifndef bddtest_h #define bddtest_h +void bddtest_suite(const char* name); int bddtest_test(const char*, int, const char*, int); void bddtest_start(const char*); void bddtest_end(); int bddtest_summary(); +#define SUITE(x) { bddtest_suite(x); } #define TEST(x) { if (!bddtest_test(__FILE__, __LINE__, #x, (x))) return false; } #define IT(x) { bddtest_start(x); } diff --git a/tests/src/lib/IPAddress.cpp b/tests/src/lib/IPAddress.cpp new file mode 100644 index 00000000..610ff4c5 --- /dev/null +++ b/tests/src/lib/IPAddress.cpp @@ -0,0 +1,44 @@ + +#include +#include + +IPAddress::IPAddress() +{ + memset(_address, 0, sizeof(_address)); +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address[0] = first_octet; + _address[1] = second_octet; + _address[2] = third_octet; + _address[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + memcpy(_address, &address, sizeof(_address)); +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address, address, sizeof(_address)); +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address, address, sizeof(_address)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + memcpy(_address, (const uint8_t *)&address, sizeof(_address)); + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) +{ + return memcmp(addr, _address, sizeof(_address)) == 0; +} + diff --git a/tests/src/lib/IPAddress.h b/tests/src/lib/IPAddress.h index dc05be4c..e75a8fe6 100644 --- a/tests/src/lib/IPAddress.h +++ b/tests/src/lib/IPAddress.h @@ -1,11 +1,72 @@ +/* + * + * MIT License: + * Copyright (c) 2011 Adrian McEwen + * 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. + * + * adrianm@mcqn.com 1/1/2011 + */ + #ifndef IPAddress_h #define IPAddress_h -extern "C" { -#define IPAddress uint8_t* +// A class to make it easier to handle and pass around IP addresses + +class IPAddress { +private: + uint8_t _address[4]; // IPv4 address + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address; }; + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() { return *((uint32_t*)_address); }; + bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; + bool operator==(const uint8_t* addr); + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address[index]; }; + uint8_t& operator[](int index) { return _address[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + -} + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; #endif diff --git a/tests/src/lib/ShimClient.cpp b/tests/src/lib/ShimClient.cpp index 280c2c7c..f70115fa 100644 --- a/tests/src/lib/ShimClient.cpp +++ b/tests/src/lib/ShimClient.cpp @@ -26,10 +26,10 @@ int ShimClient::connect(IPAddress ip, uint16_t port) { this->_connected = true; } if (this->_expectedPort !=0) { - if (memcmp(ip,this->_expectedIP,4) != 0) { - TRACE( "ip mismatch\n"); - this->_error = true; - } + // if (memcmp(ip,this->_expectedIP,4) != 0) { + // TRACE( "ip mismatch\n"); + // this->_error = true; + // } if (port != this->_expectedPort) { TRACE( "port mismatch\n"); this->_error = true; @@ -80,7 +80,7 @@ size_t ShimClient::write(const uint8_t *buf, size_t size) { TRACE(":"); } TRACE(std::hex << (unsigned int)(buf[i])); - + if (!this->expectAnything) { if (this->expectBuffer->available()) { uint8_t expected = this->expectBuffer->next(); @@ -100,7 +100,7 @@ int ShimClient::available() { return this->responseBuffer->available(); } int ShimClient::read() { return this->responseBuffer->next(); } -int ShimClient::read(uint8_t *buf, size_t size) { +int ShimClient::read(uint8_t *buf, size_t size) { uint16_t i = 0; for (;iread(); @@ -151,4 +151,3 @@ void ShimClient::expectConnect(const char *host, uint16_t port) { this->_expectedHost = host; this->_expectedPort = port; } - diff --git a/tests/src/publish_spec.cpp b/tests/src/publish_spec.cpp index 7689f772..c52c85cf 100644 --- a/tests/src/publish_spec.cpp +++ b/tests/src/publish_spec.cpp @@ -15,20 +15,20 @@ int test_publish() { IT("publishes a null-terminated string"); ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; shimClient.expect(publish,16); - + rc = client.publish((char*)"topic",(char*)"payload"); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -39,23 +39,23 @@ int test_publish_bytes() { IT("publishes a byte array"); ShimClient shimClient; shimClient.setAllowConnect(true); - + byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; int length = 5; - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x30,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; shimClient.expect(publish,14); - + rc = client.publish((char*)"topic",payload,length); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -66,23 +66,23 @@ int test_publish_retained() { IT("publishes retained"); ShimClient shimClient; shimClient.setAllowConnect(true); - + byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; int length = 5; - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; shimClient.expect(publish,14); - + rc = client.publish((char*)"topic",payload,length,true); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -91,12 +91,12 @@ int test_publish_retained() { int test_publish_not_connected() { IT("publish fails when not connected"); ShimClient shimClient; - + PubSubClient client(server, 1883, callback, shimClient); - + int rc = client.publish((char*)"topic",(char*)"payload"); IS_FALSE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -107,23 +107,23 @@ int test_publish_P() { IT("publishes using PROGMEM"); ShimClient shimClient; shimClient.setAllowConnect(true); - + byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; int length = 5; - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; shimClient.expect(publish,14); - + rc = client.publish_P((char*)"topic",payload,length,true); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -132,11 +132,12 @@ int test_publish_P() { int main() { + SUITE("Publish"); test_publish(); test_publish_bytes(); test_publish_retained(); test_publish_not_connected(); test_publish_P(); - + FINISH } diff --git a/tests/src/receive_spec.cpp b/tests/src/receive_spec.cpp index 42ace540..8ec45a8c 100644 --- a/tests/src/receive_spec.cpp +++ b/tests/src/receive_spec.cpp @@ -29,29 +29,29 @@ void callback(char* topic, byte* payload, unsigned int length) { int test_receive_callback() { IT("receives a callback message"); reset_callback(); - + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; shimClient.respond(publish,16); - + rc = client.loop(); IS_TRUE(rc); - + IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); IS_TRUE(memcmp(lastPayload,"payload",7)==0); IS_TRUE(lastLength == 7); - + IS_FALSE(shimClient.error()); END_IT @@ -60,31 +60,31 @@ int test_receive_callback() { int test_receive_stream() { IT("receives a streamed callback message"); reset_callback(); - + Stream stream; stream.expect((uint8_t*)"payload",7); - + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient, stream); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; shimClient.respond(publish,16); - + rc = client.loop(); IS_TRUE(rc); - + IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); IS_TRUE(lastLength == 7); - + IS_FALSE(stream.error()); IS_FALSE(shimClient.error()); @@ -94,17 +94,17 @@ int test_receive_stream() { int test_receive_max_sized_message() { IT("receives an max-sized message"); reset_callback(); - + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte length = MQTT_MAX_PACKET_SIZE; byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; byte bigPublish[length]; @@ -112,16 +112,16 @@ int test_receive_max_sized_message() { bigPublish[length] = 'B'; memcpy(bigPublish,publish,16); shimClient.respond(bigPublish,length); - + rc = client.loop(); - + IS_TRUE(rc); - + IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); IS_TRUE(lastLength == length-9); IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0); - + IS_FALSE(shimClient.error()); END_IT @@ -130,17 +130,17 @@ int test_receive_max_sized_message() { int test_receive_oversized_message() { IT("drops an oversized message"); reset_callback(); - + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte length = MQTT_MAX_PACKET_SIZE+1; byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; byte bigPublish[length]; @@ -148,13 +148,13 @@ int test_receive_oversized_message() { bigPublish[length] = 'B'; memcpy(bigPublish,publish,16); shimClient.respond(bigPublish,length); - + rc = client.loop(); - + IS_TRUE(rc); - + IS_FALSE(callback_called); - + IS_FALSE(shimClient.error()); END_IT @@ -163,38 +163,38 @@ int test_receive_oversized_message() { int test_receive_oversized_stream_message() { IT("drops an oversized message"); reset_callback(); - + Stream stream; ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient, stream); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte length = MQTT_MAX_PACKET_SIZE+1; byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; - + byte bigPublish[length]; memset(bigPublish,'A',length); bigPublish[length] = 'B'; memcpy(bigPublish,publish,16); - + shimClient.respond(bigPublish,length); stream.expect(bigPublish+9,length-9); - + rc = client.loop(); - + IS_TRUE(rc); - + IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); IS_TRUE(lastLength == length-9); - + IS_FALSE(stream.error()); IS_FALSE(shimClient.error()); @@ -204,32 +204,32 @@ int test_receive_oversized_stream_message() { int test_receive_qos1() { IT("receives a qos1 message"); reset_callback(); - + ShimClient shimClient; shimClient.setAllowConnect(true); - + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; shimClient.respond(publish,18); - + byte puback[] = {0x40,0x2,0x12,0x34}; shimClient.expect(puback,4); - + rc = client.loop(); - + IS_TRUE(rc); - + IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); IS_TRUE(memcmp(lastPayload,"payload",7)==0); IS_TRUE(lastLength == 7); - + IS_FALSE(shimClient.error()); END_IT @@ -237,12 +237,13 @@ int test_receive_qos1() { int main() { + SUITE("Receive"); test_receive_callback(); test_receive_stream(); test_receive_max_sized_message(); test_receive_oversized_message(); test_receive_oversized_stream_message(); test_receive_qos1(); - + FINISH } diff --git a/tests/src/subscribe_spec.cpp b/tests/src/subscribe_spec.cpp index b682f48f..20df53cd 100644 --- a/tests/src/subscribe_spec.cpp +++ b/tests/src/subscribe_spec.cpp @@ -20,7 +20,7 @@ int test_subscribe_no_qos() { byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); @@ -29,10 +29,10 @@ int test_subscribe_no_qos() { shimClient.expect(subscribe,12); byte suback[] = { 0x90,0x3,0x0,0x2,0x0 }; shimClient.respond(suback,5); - + rc = client.subscribe((char*)"topic"); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -45,7 +45,7 @@ int test_subscribe_qos_1() { byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); @@ -54,10 +54,10 @@ int test_subscribe_qos_1() { shimClient.expect(subscribe,12); byte suback[] = { 0x90,0x3,0x0,0x2,0x1 }; shimClient.respond(suback,5); - + rc = client.subscribe((char*)"topic",1); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -66,12 +66,12 @@ int test_subscribe_qos_1() { int test_subscribe_not_connected() { IT("subscribe fails when not connected"); ShimClient shimClient; - + PubSubClient client(server, 1883, callback, shimClient); - + int rc = client.subscribe((char*)"topic"); IS_FALSE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -84,16 +84,16 @@ int test_subscribe_invalid_qos() { byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - + rc = client.subscribe((char*)"topic",2); IS_FALSE(rc); rc = client.subscribe((char*)"topic",254); IS_FALSE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -106,7 +106,7 @@ int test_unsubscribe() { byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); - + PubSubClient client(server, 1883, callback, shimClient); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); @@ -115,10 +115,10 @@ int test_unsubscribe() { shimClient.expect(unsubscribe,12); byte unsuback[] = { 0xB0,0x2,0x0,0x2 }; shimClient.respond(unsuback,4); - + rc = client.unsubscribe((char*)"topic"); IS_TRUE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -127,12 +127,12 @@ int test_unsubscribe() { int test_unsubscribe_not_connected() { IT("unsubscribe fails when not connected"); ShimClient shimClient; - + PubSubClient client(server, 1883, callback, shimClient); - + int rc = client.unsubscribe((char*)"topic"); IS_FALSE(rc); - + IS_FALSE(shimClient.error()); END_IT @@ -140,6 +140,7 @@ int test_unsubscribe_not_connected() { int main() { + SUITE("Subscribe"); test_subscribe_no_qos(); test_subscribe_qos_1(); test_subscribe_not_connected();