summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2020-04-09 01:02:40 +0200
committerSven Gothel <[email protected]>2020-04-09 01:02:40 +0200
commit8891be2fd6ecb4386ee7bdbb61ccc209b54f5bcf (patch)
tree0d54edb80e50c8389ce340e3e66dd35d0f5fa4b3 /test
parentdb63cc6278beed8a7fe2899af9f31995796a9651 (diff)
Implement direct_bt: Direct Bluetooth access via Linux's Kernel BlueZ protocol stack w/o D-Bus bluetoothd.
By dropping BlueZ userspace D-Bus bluetoothd, we target high-performance reliable bluetooth support with least dependencies for embedded device configurations. See COPYING, describing which Linux Kernel BlueZ IOCTL information has been included in the source tree. We claim Linus Torvalds's Linux Kernel license exception regarding kernel syscalls (ioctl): <https://github.com/torvalds/linux/blob/master/LICENSES/exceptions/Linux-syscall-note> and hence maintain this project's license. The new direct_bt feature set is organized as follows - include/cppunit - api/direct_bt - api/ieee11073 - src/direct_bt - examples/direct_bt Note that the C++ direct_bt layer is not backward compatible to tinyb. Since the Java layer still needs to be completed, it has to be seen whether we will achieve compatibility or drop the original D-Bus tinyb module altogether in favor of a more streamlined API and implementation. Current state allows scanning for LE devices, connecting and parsing GATT plus receiving notifications and indications. See examples/direct_bt_scanner/dbt_scanner.cpp. The Linux Kernel BlueZ is configured via module MgmtComm.[hpp/cpp]
Diffstat (limited to 'test')
-rw-r--r--test/direct_bt/CMakeLists.txt27
-rw-r--r--test/direct_bt/README.txt11
-rw-r--r--test/direct_bt/test_attpdu01.cpp38
-rw-r--r--test/direct_bt/test_basictypes01.cpp68
-rw-r--r--test/direct_bt/test_lfringbuffer01.cpp331
-rw-r--r--test/direct_bt/test_lfringbuffer11.cpp178
-rw-r--r--test/direct_bt/test_uuid.cpp70
-rw-r--r--test/ieee11073/CMakeLists.txt15
-rw-r--r--test/ieee11073/test_datatypes01.cpp63
9 files changed, 801 insertions, 0 deletions
diff --git a/test/direct_bt/CMakeLists.txt b/test/direct_bt/CMakeLists.txt
new file mode 100644
index 00000000..0aad6245
--- /dev/null
+++ b/test/direct_bt/CMakeLists.txt
@@ -0,0 +1,27 @@
+include_directories(
+ ${PROJECT_SOURCE_DIR}/include/cppunit
+ ${PROJECT_SOURCE_DIR}/api
+)
+
+add_executable (test_uuid test_uuid.cpp)
+add_executable (test_basictypes01 test_basictypes01.cpp)
+add_executable (test_attpdu01 test_attpdu01.cpp)
+add_executable (test_lfringbuffer01 test_lfringbuffer01.cpp)
+add_executable (test_lfringbuffer11 test_lfringbuffer11.cpp)
+
+set_target_properties(list_mfg
+ PROPERTIES
+ CXX_STANDARD 11)
+
+target_link_libraries (test_basictypes01 direct_bt)
+target_link_libraries (test_uuid direct_bt)
+target_link_libraries (test_attpdu01 direct_bt)
+target_link_libraries (test_lfringbuffer01 direct_bt)
+target_link_libraries (test_lfringbuffer11 direct_bt)
+
+add_test (NAME basictypes01 COMMAND test_basictypes01)
+add_test (NAME uuid COMMAND test_uuid)
+add_test (NAME attpdu01 COMMAND test_attpdu01)
+add_test (NAME lfringbuffer01 COMMAND test_lfringbuffer01)
+add_test (NAME lfringbuffer11 COMMAND test_lfringbuffer11)
+
diff --git a/test/direct_bt/README.txt b/test/direct_bt/README.txt
new file mode 100644
index 00000000..d49b9045
--- /dev/null
+++ b/test/direct_bt/README.txt
@@ -0,0 +1,11 @@
+Rudimentary unit testing for our direct_bt
+using the very flat cppunit <https://github.com/cppunit/cppunit.git>.
+
+The 'cppunit.h' file has been dropped to: ${PROJECT_SOURCE_DIR}/include/cppunit/cppunit.h
+
+After a normal build, you may invoke testing via 'ctest'
+
+To see the normal test stdout/stderr, invoke 'ctest -V'.
+Sadly I haven't seen a way to inject this into the CMakeLists.txt file.
+
+
diff --git a/test/direct_bt/test_attpdu01.cpp b/test/direct_bt/test_attpdu01.cpp
new file mode 100644
index 00000000..1e6c30ce
--- /dev/null
+++ b/test/direct_bt/test_attpdu01.cpp
@@ -0,0 +1,38 @@
+#include <iostream>
+#include <cassert>
+#include <cinttypes>
+#include <cstring>
+
+#include <cppunit.h>
+
+#include <direct_bt/UUID.hpp>
+// #include <direct_bt/BTAddress.hpp>
+// #include <direct_bt/HCITypes.hpp>
+#include <direct_bt/ATTPDUTypes.hpp>
+// #include <direct_bt/GATTHandler.hpp>
+// #include <direct_bt/GATTIoctl.hpp>
+
+using namespace direct_bt;
+
+// Test examples.
+class Cppunit_tests: public Cppunit {
+ void single_test() override {
+ const uuid16_t uuid16 = uuid16_t(uuid16_t(0x1234));
+ const AttReadByNTypeReq req(true /* group */, 1, 0xffff, uuid16);
+
+ std::shared_ptr<const uuid_t> uuid16_2 = req.getNType();
+ CHECK(uuid16.getTypeSize(), 2);
+ CHECK(uuid16_2->getTypeSize(), 2);
+ CHECKT( 0 == memcmp(uuid16.data(), uuid16_2->data(), 2) )
+ CHECKT( uuid16.toString() == uuid16_2->toString() );
+
+ CHECK(req.getStartHandle(), 1);
+ CHECK(req.getEndHandle(), 0xffff);
+ }
+};
+
+int main(int argc, char *argv[]) {
+ Cppunit_tests test1;
+ return test1.run();
+}
+
diff --git a/test/direct_bt/test_basictypes01.cpp b/test/direct_bt/test_basictypes01.cpp
new file mode 100644
index 00000000..e541c4ac
--- /dev/null
+++ b/test/direct_bt/test_basictypes01.cpp
@@ -0,0 +1,68 @@
+#include <iostream>
+#include <cassert>
+#include <cinttypes>
+#include <cstring>
+
+#include <cppunit.h>
+
+#include <direct_bt/BasicTypes.hpp>
+
+using namespace direct_bt;
+
+// Test examples.
+class Cppunit_tests : public Cppunit {
+ private:
+
+ void test_int32_t(const std::string msg, const int32_t v, const int expStrLen, const std::string expStr) {
+ const std::string str = int32SeparatedString(v);
+ PRINTM(msg+": has '"+str+"', len "+std::to_string(str.length()));
+ PRINTM(msg+": exp '"+expStr+"', len "+std::to_string(expStr.length())+", equal: "+std::to_string(str==expStr));
+ CHECKM(msg, str.length(), expStrLen);
+ CHECKTM(msg, str == expStr);
+ }
+
+ void test_uint32_t(const std::string msg, const uint32_t v, const int expStrLen, const std::string expStr) {
+ const std::string str = uint32SeparatedString(v);
+ PRINTM(msg+": has '"+str+"', len "+std::to_string(str.length()));
+ PRINTM(msg+": exp '"+expStr+"', len "+std::to_string(expStr.length())+", equal: "+std::to_string(str==expStr));
+ CHECKM(msg, str.length(), expStrLen);
+ CHECKTM(msg, str == expStr);
+ }
+
+ void test_uint64_t(const std::string msg, const uint64_t v, const int expStrLen, const std::string expStr) {
+ const std::string str = uint64SeparatedString(v);
+ PRINTM(msg+": has '"+str+"', len "+std::to_string(str.length()));
+ PRINTM(msg+": exp '"+expStr+"', len "+std::to_string(expStr.length())+", equal: "+std::to_string(str==expStr));
+ CHECKM(msg, str.length(), expStrLen);
+ CHECKTM(msg, str == expStr);
+ }
+
+ public:
+ void single_test() override {
+
+ {
+ test_int32_t("INT32_MIN", INT32_MIN, 14, "-2,147,483,648");
+ test_int32_t("int32_t -thousand", -1000, 6, "-1,000");
+ test_int32_t("int32_t one", 1, 1, "1");
+ test_int32_t("int32_t thousand", 1000, 5, "1,000");
+ test_int32_t("INT32_MAX", INT32_MAX, 13, "2,147,483,647");
+
+ test_uint32_t("UINT32_MIN", 0, 1, "0");
+ test_uint32_t("uint32_t one", 1, 1, "1");
+ test_uint32_t("uint32_t thousand", 1000, 5, "1,000");
+ test_uint32_t("UINT32_MAX", UINT32_MAX, 13, "4,294,967,295");
+
+ test_uint64_t("UINT64_MIN", 0, 1, "0");
+ test_uint64_t("uint64_t one", 1, 1, "1");
+ test_uint64_t("uint64_t thousand", 1000, 5, "1,000");
+ test_uint64_t("UINT64_MAX", UINT64_MAX, 26, "18,446,744,073,709,551,615");
+ }
+
+ }
+};
+
+int main(int argc, char *argv[]) {
+ Cppunit_tests test1;
+ return test1.run();
+}
+
diff --git a/test/direct_bt/test_lfringbuffer01.cpp b/test/direct_bt/test_lfringbuffer01.cpp
new file mode 100644
index 00000000..97297513
--- /dev/null
+++ b/test/direct_bt/test_lfringbuffer01.cpp
@@ -0,0 +1,331 @@
+#include <iostream>
+#include <cassert>
+#include <cinttypes>
+#include <cstring>
+#include <memory>
+
+#include <cppunit.h>
+
+#include <direct_bt/UUID.hpp>
+#include <direct_bt/Ringbuffer.hpp>
+#include <direct_bt/LFRingbuffer.hpp>
+
+using namespace direct_bt;
+
+class Integer {
+ public:
+ int value;
+
+ Integer(int v) : value(v) {}
+
+ Integer(const Integer &o) noexcept = default;
+ Integer(Integer &&o) noexcept = default;
+ Integer& operator=(const Integer &o) noexcept = default;
+ Integer& operator=(Integer &&o) noexcept = default;
+
+ operator int() const {
+ return value;
+ }
+ int intValue() const { return value; }
+ static Integer valueOf(const int i) { return Integer(i); }
+};
+
+std::shared_ptr<Integer> NullInteger = nullptr;
+
+typedef std::shared_ptr<Integer> SharedType;
+typedef Ringbuffer<SharedType> SharedTypeRingbuffer;
+typedef LFRingbuffer<SharedType, nullptr> SharedTypeLFRingbuffer;
+
+// Test examples.
+class Cppunit_tests : public Cppunit {
+ private:
+
+ std::shared_ptr<SharedTypeRingbuffer> createEmpty(int initialCapacity) {
+ return std::shared_ptr<SharedTypeRingbuffer>(new SharedTypeLFRingbuffer(initialCapacity));
+ }
+ std::shared_ptr<SharedTypeRingbuffer> createFull(const std::vector<std::shared_ptr<Integer>> & source) {
+ return std::shared_ptr<SharedTypeRingbuffer>(new SharedTypeLFRingbuffer(source));
+ }
+
+ std::vector<SharedType> createIntArray(const int capacity, const int startValue) {
+ std::vector<SharedType> array(capacity);
+ for(int i=0; i<capacity; i++) {
+ array[i] = SharedType(new Integer(startValue+i));
+ }
+ return array;
+ }
+
+ void readTestImpl(Ringbuffer<SharedType> &rb, bool clearRef, int capacity, int len, int startValue) {
+ int preSize = rb.getSize();
+ CHECKM("Wrong capacity "+rb.toString(), capacity, rb.capacity());
+ CHECKTM("Too low capacity to read "+std::to_string(len)+" elems: "+rb.toString(), capacity-len >= 0);
+ CHECKTM("Too low size to read "+std::to_string(len)+" elems: "+rb.toString(), preSize >= len);
+ CHECKTM("Is empty "+rb.toString(), !rb.isEmpty());
+
+ for(int i=0; i<len; i++) {
+ SharedType svI = rb.get();
+ CHECKTM("Empty at read #"+std::to_string(i+1)+": "+rb.toString(), svI!=nullptr);
+ CHECKM("Wrong value at read #"+std::to_string(i+1)+": "+rb.toString(), startValue+i, svI->intValue());
+ }
+
+ CHECKM("Invalid size "+rb.toString(), preSize-len, rb.getSize());
+ CHECKTM("Invalid free slots after reading "+std::to_string(len)+": "+rb.toString(), rb.getFreeSlots()>= len);
+ CHECKTM("Is full "+rb.toString(), !rb.isFull());
+ }
+
+ void writeTestImpl(Ringbuffer<SharedType> &rb, int capacity, int len, int startValue) {
+ int preSize = rb.getSize();
+
+ CHECKM("Wrong capacity "+rb.toString(), capacity, rb.capacity());
+ CHECKTM("Too low capacity to write "+std::to_string(len)+" elems: "+rb.toString(), capacity-len >= 0);
+ CHECKTM("Too low size to write "+std::to_string(len)+" elems: "+rb.toString(), preSize+len <= capacity);
+ CHECKTM("Is full "+rb.toString(), !rb.isFull());
+
+ for(int i=0; i<len; i++) {
+ std::string m = "Buffer is full at put #"+std::to_string(i)+": "+rb.toString();
+ CHECKTM(m, rb.put( SharedType( new Integer(startValue+i) ) ) );
+ }
+
+ CHECKM("Invalid size "+rb.toString(), preSize+len, rb.getSize());
+ CHECKTM("Is empty "+rb.toString(), !rb.isEmpty());
+ }
+
+ void moveGetPutImpl(Ringbuffer<SharedType> &rb, int pos) {
+ CHECKTM("RB is empty "+rb.toString(), !rb.isEmpty());
+ for(int i=0; i<pos; i++) {
+ CHECKM("MoveFull.get failed "+rb.toString(), i, rb.get()->intValue());
+ CHECKTM("MoveFull.put failed "+rb.toString(), rb.put( SharedType( new Integer(i) ) ) );
+ }
+ }
+
+ void movePutGetImpl(Ringbuffer<SharedType> &rb, int pos) {
+ CHECKTM("RB is full "+rb.toString(), !rb.isFull());
+ for(int i=0; i<pos; i++) {
+ CHECKTM("MoveEmpty.put failed "+rb.toString(), rb.put( SharedType( new Integer(600+i) ) ) );
+ CHECKM("MoveEmpty.get failed "+rb.toString(), 600+i, rb.get()->intValue());
+ }
+ }
+
+ void test01_FullRead() {
+ int capacity = 11;
+ std::vector<SharedType> source = createIntArray(capacity, 0);
+ std::shared_ptr<SharedTypeRingbuffer> rb = createFull(source);
+ fprintf(stderr, "test01_FullRead: Created / %s\n", rb->toString().c_str());
+ CHECKM("Not full size "+rb->toString(), capacity, rb->getSize());
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, true, capacity, capacity, 0);
+ fprintf(stderr, "test01_FullRead: PostRead / %s\n", rb->toString().c_str());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ }
+
+ void test02_EmptyWrite() {
+ int capacity = 11;
+ std::shared_ptr<Ringbuffer<SharedType>> rb = createEmpty(capacity);
+ fprintf(stderr, "test01_EmptyWrite: Created / %s\n", rb->toString().c_str());
+ CHECKM("Not zero size "+rb->toString(), 0, rb->getSize());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ writeTestImpl(*rb, capacity, capacity, 0);
+ fprintf(stderr, "test01_EmptyWrite: PostWrite / %s\n", rb->toString().c_str());
+ CHECKM("Not full size "+rb->toString(), capacity, rb->getSize());
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, true, capacity, capacity, 0);
+ fprintf(stderr, "test01_EmptyWrite: PostRead / %s\n", rb->toString().c_str());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ }
+
+ void test03_FullReadReset() {
+ int capacity = 11;
+ std::vector<SharedType> source = createIntArray(capacity, 0);
+ std::shared_ptr<Ringbuffer<SharedType>> rb = createFull(source);
+ fprintf(stderr, "test01_FullReadReset: Created / %s\n", rb->toString().c_str());
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ rb->reset(source);
+ fprintf(stderr, "test01_FullReadReset: Post Reset w/ source / %s\n", rb->toString().c_str());
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, capacity, 0);
+ fprintf(stderr, "test01_FullReadReset: Post Read / %s\n", rb->toString().c_str());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ rb->reset(source);
+ fprintf(stderr, "test01_FullReadReset: Post Reset w/ source / %s\n", rb->toString().c_str());
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, capacity, 0);
+ fprintf(stderr, "test01_FullReadReset: Post Read / %s\n", rb->toString().c_str());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ }
+
+ void test04_EmptyWriteClear() {
+ int capacity = 11;
+ std::shared_ptr<Ringbuffer<SharedType>> rb = createEmpty(capacity);
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ rb->clear();
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ writeTestImpl(*rb, capacity, capacity, 0);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, capacity, 0);
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ rb->clear();
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ writeTestImpl(*rb, capacity, capacity, 0);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, capacity, 0);
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ }
+
+ void test05_ReadResetMid01() {
+ int capacity = 11;
+ std::vector<SharedType> source = createIntArray(capacity, 0);
+ std::shared_ptr<Ringbuffer<SharedType>> rb = createFull(source);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ rb->reset(source);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, 5, 0);
+ CHECKTM("Is empty "+rb->toString(), !rb->isEmpty());
+ CHECKTM("Is Full "+rb->toString(), !rb->isFull());
+
+ rb->reset(source);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, capacity, 0);
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ }
+
+ void test06_ReadResetMid02() {
+ int capacity = 11;
+ std::vector<SharedType> source = createIntArray(capacity, 0);
+ std::shared_ptr<Ringbuffer<SharedType>> rb = createFull(source);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ rb->reset(source);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ moveGetPutImpl(*rb, 5);
+ readTestImpl(*rb, false, capacity, 5, 5);
+ CHECKTM("Is empty "+rb->toString(), !rb->isEmpty());
+ CHECKTM("Is Full "+rb->toString(), !rb->isFull());
+
+ rb->reset(source);
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ readTestImpl(*rb, false, capacity, capacity, 0);
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ }
+
+ void test_GrowFullImpl(int initialCapacity, int pos) {
+ int growAmount = 5;
+ int grownCapacity = initialCapacity+growAmount;
+ std::vector<SharedType> source = createIntArray(initialCapacity, 0);
+ std::shared_ptr<Ringbuffer<SharedType>> rb = createFull(source);
+
+ for(int i=0; i<initialCapacity; i++) {
+ SharedType svI = rb->get();
+ CHECKTM("Empty at read #"+std::to_string(i+1)+": "+rb->toString(), svI!=nullptr);
+ CHECKM("Wrong value at read #"+std::to_string(i+1)+": "+rb->toString(), (0+i)%initialCapacity, svI->intValue());
+ }
+ CHECKM("Not zero size "+rb->toString(), 0, rb->getSize());
+
+ rb->reset(source);
+ CHECKM("Not orig size "+rb->toString(), initialCapacity, rb->getSize());
+
+ moveGetPutImpl(*rb, pos);
+ // PRINTM("X02 "+rb->toString());
+ // rb->dump(stderr, "X02");
+
+ rb->recapacity(grownCapacity);
+ CHECKM("Wrong capacity "+rb->toString(), grownCapacity, rb->capacity());
+ CHECKM("Not orig size "+rb->toString(), initialCapacity, rb->getSize());
+ CHECKTM("Is full "+rb->toString(), !rb->isFull());
+ CHECKTM("Is empty "+rb->toString(), !rb->isEmpty());
+ // PRINTM("X03 "+rb->toString());
+ // rb->dump(stderr, "X03");
+
+ for(int i=0; i<growAmount; i++) {
+ CHECKTM("Buffer is full at put #"+std::to_string(i)+": "+rb->toString(), rb->put( SharedType( new Integer(100+i) ) ) );
+ }
+ CHECKM("Not new size "+rb->toString(), grownCapacity, rb->getSize());
+ CHECKTM("Not full "+rb->toString(), rb->isFull());
+
+ for(int i=0; i<initialCapacity; i++) {
+ SharedType svI = rb->get();
+ // PRINTM("X05["+std::to_string(i)+"]: "+rb->toString()+", svI-null: "+std::to_string(svI==nullptr));
+ CHECKTM("Empty at read #"+std::to_string(i+1)+": "+rb->toString(), svI!=nullptr);
+ CHECKM("Wrong value at read #"+std::to_string(i+1)+": "+rb->toString(), (pos+i)%initialCapacity, svI->intValue());
+ }
+
+ for(int i=0; i<growAmount; i++) {
+ SharedType svI = rb->get();
+ // PRINTM("X07["+std::to_string(i)+"]: "+rb->toString()+", svI-null: "+std::to_string(svI==nullptr));
+ CHECKTM("Empty at read #"+std::to_string(i+1)+": "+rb->toString(), svI!=nullptr);
+ CHECKM("Wrong value at read #"+std::to_string(i+1)+": "+rb->toString(), 100+i, svI->intValue());
+ }
+
+ CHECKM("Not zero size "+rb->toString(), 0, rb->getSize());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ CHECKTM("Is full "+rb->toString(), !rb->isFull());
+ }
+
+ public:
+
+ void test20_GrowFull01_Begin() {
+ test_GrowFullImpl(11, 0);
+ }
+ void test21_GrowFull02_Begin1() {
+ test_GrowFullImpl(11, 0+1);
+ }
+ void test22_GrowFull03_Begin2() {
+ test_GrowFullImpl(11, 0+2);
+ }
+ void test23_GrowFull04_Begin3() {
+ test_GrowFullImpl(11, 0+3);
+ }
+ void test24_GrowFull05_End() {
+ test_GrowFullImpl(11, 11-1);
+ }
+ void test25_GrowFull11_End1() {
+ test_GrowFullImpl(11, 11-1-1);
+ }
+ void test26_GrowFull12_End2() {
+ test_GrowFullImpl(11, 11-1-2);
+ }
+ void test27_GrowFull13_End3() {
+ test_GrowFullImpl(11, 11-1-3);
+ }
+
+ void test_list() override {
+ test01_FullRead();
+ test02_EmptyWrite();
+ test03_FullReadReset();
+ test04_EmptyWriteClear();
+ test05_ReadResetMid01();
+ test06_ReadResetMid02();
+
+ test20_GrowFull01_Begin();
+ test21_GrowFull02_Begin1();
+ test22_GrowFull03_Begin2();
+ test23_GrowFull04_Begin3();
+ test24_GrowFull05_End();
+ test25_GrowFull11_End1();
+ test26_GrowFull12_End2();
+ test27_GrowFull13_End3();
+ }
+};
+
+int main(int argc, char *argv[]) {
+ Cppunit_tests test1;
+ return test1.run();
+}
+
diff --git a/test/direct_bt/test_lfringbuffer11.cpp b/test/direct_bt/test_lfringbuffer11.cpp
new file mode 100644
index 00000000..43350395
--- /dev/null
+++ b/test/direct_bt/test_lfringbuffer11.cpp
@@ -0,0 +1,178 @@
+#include <iostream>
+#include <cassert>
+#include <cinttypes>
+#include <cstring>
+#include <memory>
+#include <thread>
+#include <pthread.h>
+
+#include <cppunit.h>
+
+#include <direct_bt/UUID.hpp>
+#include <direct_bt/Ringbuffer.hpp>
+#include <direct_bt/LFRingbuffer.hpp>
+
+using namespace direct_bt;
+
+class Integer {
+ public:
+ int value;
+
+ Integer(int v) : value(v) {}
+
+ Integer(const Integer &o) noexcept = default;
+ Integer(Integer &&o) noexcept = default;
+ Integer& operator=(const Integer &o) noexcept = default;
+ Integer& operator=(Integer &&o) noexcept = default;
+
+ operator int() const {
+ return value;
+ }
+ int intValue() const { return value; }
+ static Integer valueOf(const int i) { return Integer(i); }
+};
+
+std::shared_ptr<Integer> NullInteger = nullptr;
+
+typedef std::shared_ptr<Integer> SharedType;
+typedef Ringbuffer<SharedType> SharedTypeRingbuffer;
+typedef LFRingbuffer<SharedType, nullptr> SharedTypeLFRingbuffer;
+
+// Test examples.
+class Cppunit_tests : public Cppunit {
+ private:
+
+ std::shared_ptr<SharedTypeRingbuffer> createEmpty(int initialCapacity) {
+ return std::shared_ptr<SharedTypeRingbuffer>(new SharedTypeLFRingbuffer(initialCapacity));
+ }
+ std::shared_ptr<SharedTypeRingbuffer> createFull(const std::vector<std::shared_ptr<Integer>> & source) {
+ return std::shared_ptr<SharedTypeRingbuffer>(new SharedTypeLFRingbuffer(source));
+ }
+
+ std::vector<SharedType> createIntArray(const int capacity, const int startValue) {
+ std::vector<SharedType> array(capacity);
+ for(int i=0; i<capacity; i++) {
+ array[i] = SharedType(new Integer(startValue+i));
+ }
+ return array;
+ }
+
+ void getThreadType01(const std::string msg, std::shared_ptr<Ringbuffer<SharedType>> rb, int len, int startValue) {
+ // std::thread::id this_id = std::this_thread::get_id();
+ // pthread_t this_id = pthread_self();
+
+ fprintf(stderr, "%s: Created / %s\n", msg.c_str(), rb->toString().c_str());
+ for(int i=0; i<len; i++) {
+ SharedType svI = rb->getBlocking();
+ CHECKTM(msg+": Empty at read #"+std::to_string(i+1)+": "+rb->toString(), svI!=nullptr);
+ fprintf(stderr, "%s: Got %d / %s\n",
+ msg.c_str(), svI->intValue(), rb->toString().c_str());
+ if( 0 <= startValue ) {
+ CHECKM(msg+": %s: Wrong value at read #"+std::to_string(i+1)+": "+rb->toString(), startValue+i, svI->intValue());
+ }
+ }
+ fprintf(stderr, "%s: Dies / %s\n", msg.c_str(), rb->toString().c_str());
+ }
+
+ void putThreadType01(const std::string msg, std::shared_ptr<Ringbuffer<SharedType>> rb, int len, int startValue) {
+ // std::thread::id this_id = std::this_thread::get_id();
+ // pthread_t this_id = pthread_self();
+
+ fprintf(stderr, "%s: Created / %s\n", msg.c_str(), rb->toString().c_str());
+ int preSize = rb->getSize();
+
+ for(int i=0; i<len; i++) {
+ Integer * vI = new Integer(startValue+i);
+ fprintf(stderr, "%s: Putting %d ... / %s\n",
+ msg.c_str(), vI->intValue(), rb->toString().c_str());
+ rb->putBlocking( SharedType( vI ) );
+ }
+ fprintf(stderr, "%s: Dies / %s\n", msg.c_str(), rb->toString().c_str());
+ }
+
+ public:
+
+ void test01_Read1Write1() {
+ fprintf(stderr, "\n\ntest01_Read1Write1\n");
+ int capacity = 100;
+ std::shared_ptr<SharedTypeRingbuffer> rb = createEmpty(capacity);
+ CHECKM("Not empty size "+rb->toString(), 0, rb->getSize());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test01.get01", rb, capacity, 0);
+ std::thread putThread01(&Cppunit_tests::putThreadType01, this, "test01.put01", rb, capacity, 0);
+ putThread01.join();
+ getThread01.join();
+
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ CHECKM("Not empty size "+rb->toString(), 0, rb->getSize());
+ }
+
+ void test02_Read4Write1() {
+ fprintf(stderr, "\n\ntest02_Read4Write1\n");
+ int capacity = 400;
+ std::shared_ptr<SharedTypeRingbuffer> rb = createEmpty(capacity);
+ CHECKM("Not empty size "+rb->toString(), 0, rb->getSize());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test02.get01", rb, capacity/4, -1);
+ std::thread getThread02(&Cppunit_tests::getThreadType01, this, "test02.get02", rb, capacity/4, -1);
+ std::thread putThread01(&Cppunit_tests::putThreadType01, this, "test02.put01", rb, capacity, 0);
+ std::thread getThread03(&Cppunit_tests::getThreadType01, this, "test02.get03", rb, capacity/4, -1);
+ std::thread getThread04(&Cppunit_tests::getThreadType01, this, "test02.get04", rb, capacity/4, -1);
+ putThread01.join();
+ getThread01.join();
+ getThread02.join();
+ getThread03.join();
+ getThread04.join();
+
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ CHECKM("Not empty size "+rb->toString(), 0, rb->getSize());
+ }
+
+ void test03_Read8Write2() {
+ fprintf(stderr, "\n\ntest03_Read8Write2\n");
+ int capacity = 800;
+ std::shared_ptr<SharedTypeRingbuffer> rb = createEmpty(capacity);
+ CHECKM("Not empty size "+rb->toString(), 0, rb->getSize());
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+
+ std::thread getThread01(&Cppunit_tests::getThreadType01, this, "test03.get01", rb, capacity/8, -1);
+ std::thread getThread02(&Cppunit_tests::getThreadType01, this, "test03.get02", rb, capacity/8, -1);
+ std::thread putThread01(&Cppunit_tests::putThreadType01, this, "test03.put01", rb, capacity/2, 0);
+ std::thread getThread03(&Cppunit_tests::getThreadType01, this, "test03.get03", rb, capacity/8, -1);
+ std::thread getThread04(&Cppunit_tests::getThreadType01, this, "test03.get04", rb, capacity/8, -1);
+
+ std::thread getThread05(&Cppunit_tests::getThreadType01, this, "test03.get05", rb, capacity/8, -1);
+ std::thread getThread06(&Cppunit_tests::getThreadType01, this, "test03.get06", rb, capacity/8, -1);
+ std::thread putThread02(&Cppunit_tests::putThreadType01, this, "test03.put02", rb, capacity/2, 400);
+ std::thread getThread07(&Cppunit_tests::getThreadType01, this, "test03.get07", rb, capacity/8, -1);
+ std::thread getThread08(&Cppunit_tests::getThreadType01, this, "test03.get08", rb, capacity/8, -1);
+
+ putThread01.join();
+ putThread02.join();
+ getThread01.join();
+ getThread02.join();
+ getThread03.join();
+ getThread04.join();
+ getThread05.join();
+ getThread06.join();
+ getThread07.join();
+ getThread08.join();
+
+ CHECKTM("Not empty "+rb->toString(), rb->isEmpty());
+ CHECKM("Not empty size "+rb->toString(), 0, rb->getSize());
+ }
+
+ void test_list() override {
+ test01_Read1Write1();
+ test02_Read4Write1();
+ test03_Read8Write2();
+ }
+};
+
+int main(int argc, char *argv[]) {
+ Cppunit_tests test1;
+ return test1.run();
+}
+
diff --git a/test/direct_bt/test_uuid.cpp b/test/direct_bt/test_uuid.cpp
new file mode 100644
index 00000000..44638373
--- /dev/null
+++ b/test/direct_bt/test_uuid.cpp
@@ -0,0 +1,70 @@
+#include <iostream>
+#include <cassert>
+#include <cinttypes>
+#include <cstring>
+
+#include <cppunit.h>
+
+#include <direct_bt/UUID.hpp>
+
+using namespace direct_bt;
+
+// Test examples.
+class Cppunit_tests : public Cppunit {
+ public:
+ void single_test() override {
+
+ std::cout << "Hello COUT" << std::endl;
+ std::cerr << "Hello CERR" << std::endl;
+
+ uint8_t buffer[100];
+ static uint8_t uuid128_bytes[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
+
+ {
+ const uuid128_t v01 = uuid128_t(uuid128_bytes, 0, true);
+ CHECK(v01.getTypeSize(), 16);
+ CHECK(v01.getTypeSize(), sizeof(v01.value));
+ CHECK(v01.getTypeSize(), sizeof(v01.value.data));
+ CHECKT( 0 == memcmp(uuid128_bytes, v01.data(), 16) )
+
+ put_uuid(buffer, 0, v01, true);
+ std::shared_ptr<const uuid_t> v02 = uuid_t::create(uuid_t::TypeSize::UUID128_SZ, buffer, 0, true);
+ CHECK(v02->getTypeSize(), 16);
+ CHECKT( 0 == memcmp(v01.data(), v02->data(), 16) )
+ CHECKT( v01.toString() == v02->toString() );
+ }
+
+ {
+ const uuid32_t v01 = uuid32_t(uuid32_t(0x12345678));
+ CHECK(v01.getTypeSize(), 4);
+ CHECK(v01.getTypeSize(), sizeof(v01.value));
+ CHECK(0x12345678, v01.value);
+
+ put_uuid(buffer, 0, v01, true);
+ std::shared_ptr<const uuid_t> v02 = uuid_t::create(uuid_t::TypeSize::UUID32_SZ, buffer, 0, true);
+ CHECK(v02->getTypeSize(), 4);
+ CHECKT( 0 == memcmp(v01.data(), v02->data(), 4) )
+ CHECKT( v01.toString() == v02->toString() );
+ }
+
+ {
+ const uuid16_t v01 = uuid16_t(uuid16_t(0x1234));
+ CHECK(v01.getTypeSize(), 2);
+ CHECK(v01.getTypeSize(), sizeof(v01.value));
+ CHECK(0x1234, v01.value);
+
+ put_uuid(buffer, 0, v01, true);
+ std::shared_ptr<const uuid_t> v02 = uuid_t::create(uuid_t::TypeSize::UUID16_SZ, buffer, 0, true);
+ CHECK(v02->getTypeSize(), 2);
+ CHECKT( 0 == memcmp(v01.data(), v02->data(), 2) )
+ CHECKT( v01.toString() == v02->toString() );
+ }
+ }
+};
+
+int main(int argc, char *argv[]) {
+ Cppunit_tests test1;
+ return test1.run();
+}
+
diff --git a/test/ieee11073/CMakeLists.txt b/test/ieee11073/CMakeLists.txt
new file mode 100644
index 00000000..34cdbc41
--- /dev/null
+++ b/test/ieee11073/CMakeLists.txt
@@ -0,0 +1,15 @@
+include_directories(
+ ${PROJECT_SOURCE_DIR}/include/cppunit
+ ${PROJECT_SOURCE_DIR}/api
+)
+
+add_executable (test_datatypes01 test_datatypes01.cpp)
+
+set_target_properties(list_mfg
+ PROPERTIES
+ CXX_STANDARD 11)
+
+target_link_libraries (test_datatypes01 direct_bt)
+
+add_test (NAME datatypes01 COMMAND test_datatypes01)
+
diff --git a/test/ieee11073/test_datatypes01.cpp b/test/ieee11073/test_datatypes01.cpp
new file mode 100644
index 00000000..12e0bd3d
--- /dev/null
+++ b/test/ieee11073/test_datatypes01.cpp
@@ -0,0 +1,63 @@
+#include <iostream>
+#include <cassert>
+#include <cinttypes>
+#include <cstring>
+
+#include <cppunit.h>
+
+#include "ieee11073/DataTypes.hpp"
+
+using namespace ieee11073;
+
+// Test examples.
+class Cppunit_tests : public Cppunit {
+ private:
+ void test_float32_IEEE11073_to_IEEE754(const std::string msg, const uint32_t raw, const float expFloat) {
+ const float has = FloatTypes::float32_IEEE11073_to_IEEE754(raw);
+ PRINTM(msg+": has '"+std::to_string(has));
+ PRINTM(msg+": exp '"+std::to_string(expFloat)+"', diff "+std::to_string(fabsf(has-expFloat)));
+ CHECKD(msg, has, expFloat);
+ }
+
+ void test_AbsoluteTime_IEEE11073(const std::string msg, const uint8_t * data_le, const int size, const std::string expStr) {
+ ieee11073::AbsoluteTime has(data_le, size);
+ const std::string has_str = has.toString();
+ PRINTM(msg+": has '"+has_str+"', len "+std::to_string(has_str.length()));
+ PRINTM(msg+": exp '"+expStr+"', len "+std::to_string(expStr.length())+", equal: "+std::to_string(has_str==expStr));
+ CHECKM(msg, has_str.length(), expStr.length());
+ CHECKTM(msg, has_str == expStr);
+ }
+
+ public:
+ void single_test() override {
+
+ {
+ // 0x06 670100FF E40704040B1A00 00
+ // 0x06 640100FF E40704040B2C00 00
+
+ // 79 09 00 FE -> 24.25f
+ test_float32_IEEE11073_to_IEEE754("IEEE11073-float01", 0xFE000979, 24.25f);
+ // 670100FF -> 35.900002
+ test_float32_IEEE11073_to_IEEE754("IEEE11073-float01", 0xFF000167, 35.900002f);
+ // 640100FF -> 35.600002
+ test_float32_IEEE11073_to_IEEE754("IEEE11073-float02", 0xFF000164, 35.600002f);
+
+ {
+ // E40704040B1A00 -> 2020-04-04 11:26:00
+ const uint8_t input[] = { 0xE4, 0x07, 0x04, 0x04, 0x0B, 0x1A, 0x00 };
+ test_AbsoluteTime_IEEE11073("IEEE11073 time01", input, 7, "2020-04-04 11:26:00");
+ }
+ {
+ // E40704040B2C00 -> 2020-04-04 11:44:00
+ const uint8_t input[] = { 0xE4, 0x07, 0x04, 0x04, 0x0B, 0x2C, 0x00 };
+ test_AbsoluteTime_IEEE11073("IEEE11073 time02", input, 7, "2020-04-04 11:44:00");
+ }
+ }
+ }
+};
+
+int main(int argc, char *argv[]) {
+ Cppunit_tests test1;
+ return test1.run();
+}
+