Skip to content

Commit

Permalink
Fixed broken examples, added unit tests. (#123)
Browse files Browse the repository at this point in the history
* Fixed broken examples, added unit tests.

* Linting

* More fixes

* Fixed PyTest execution

* Fixed PyTest execution

* Fixed PyTest execution

* Fixed uninitialized memory
  • Loading branch information
kdewald authored Oct 16, 2022
1 parent 4a0e9f2 commit 86642a3
Show file tree
Hide file tree
Showing 17 changed files with 161 additions and 29 deletions.
28 changes: 27 additions & 1 deletion .github/workflows/ci_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,30 @@ jobs:
cmake --build $GITHUB_WORKSPACE/build_tsan_simpledbus --config Release --parallel 4
$GITHUB_WORKSPACE/build_tsan_simpledbus/bin/simpledbus_test
cp "$(ls tsan_log.txt.* | head -1)" tsan_log.txt || true
(test ! -f tsan_log.txt && echo "No TSAN log found") || (cat tsan_log.txt && exit 1)
(test ! -f tsan_log.txt && echo "No TSAN log found") || (cat tsan_log.txt && exit 1)
# ------------------------------------------------------------

test-python:
runs-on: "ubuntu-20.04"

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Python 3.9
uses: actions/setup-python@v2
with:
python-version: 3.9
cache: "pip"

- name: Install dependencies
run: pip install -r simplepyble/requirements.txt

- name: Install SimplePyBLE with Plain flavor
run: python setup.py install --plain
working-directory: ./simplepyble

- name: Run PyTest
run: pytest
working-directory: ./simplepyble/test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ _doxygen

/build_*
simplepyble/build
simplepyble/dist

__pycache__
*.egg-info
Expand Down
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The format is based on `Keep a Changelog`_, and this project adheres to

- Option to build SimpleBLE plain-flavored (without any BLE code) for testing and debugging purposes.

**Fixed**

- Fixed incorrect handling of services and characteristics in the Python examples. *(Thanks Carl-CWX!)*


[0.5.0] - 2022-09-25
--------------------
Expand Down
6 changes: 3 additions & 3 deletions examples/simplepyble/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
print("Successfully connected, listing services...")
services = peripheral.services()
for service in services:
print(f"Service: {service.uuid}")
for characteristic in service.characteristics:
print(f" Characteristic: {characteristic}")
print(f"Service: {service.uuid()}")
for characteristic in service.characteristics():
print(f" Characteristic: {characteristic.uuid()}")

peripheral.disconnect()
4 changes: 2 additions & 2 deletions examples/simplepyble/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@
services = peripheral.services()
service_characteristic_pair = []
for service in services:
for characteristic in service.characteristics:
service_characteristic_pair.append((service.uuid, characteristic))
for characteristic in service.characteristics():
service_characteristic_pair.append((service.uuid(), characteristic.uuid()))

# Query the user to pick a service/characteristic pair
print("Please select a service/characteristic pair:")
Expand Down
4 changes: 2 additions & 2 deletions examples/simplepyble/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
services = peripheral.services()
service_characteristic_pair = []
for service in services:
for characteristic in service.characteristics:
service_characteristic_pair.append((service.uuid, characteristic))
for characteristic in service.characteristics():
service_characteristic_pair.append((service.uuid(), characteristic.uuid()))

# Query the user to pick a service/characteristic pair
print("Please select a service/characteristic pair:")
Expand Down
4 changes: 2 additions & 2 deletions examples/simplepyble/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
services = peripheral.services()
service_characteristic_pair = []
for service in services:
for characteristic in service.characteristics:
service_characteristic_pair.append((service.uuid, characteristic))
for characteristic in service.characteristics():
service_characteristic_pair.append((service.uuid(), characteristic.uuid()))

# Query the user to pick a service/characteristic pair
print("Please select a service/characteristic pair:")
Expand Down
3 changes: 1 addition & 2 deletions simpleble/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,5 @@ if(SIMPLEBLE_TEST)
POSITION_INDEPENDENT_CODE ON
WINDOWS_EXPORT_ALL_SYMBOLS ON)

target_link_libraries(simpleble_test PRIVATE simpleble::simpleble ${GTEST_LIBRARIES})
target_include_directories(simpleble_test PRIVATE ${GTEST_INCLUDE_DIRS})
target_link_libraries(simpleble_test PRIVATE simpleble::simpleble GTest::gtest)
endif()
9 changes: 3 additions & 6 deletions simpleble/src/plain/AdapterBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,17 @@ std::vector<std::shared_ptr<AdapterBase>> AdapterBase::get_adapters() {
return adapter_list;
}

bool AdapterBase::bluetooth_enabled() {
return true;
}
bool AdapterBase::bluetooth_enabled() { return true; }

AdapterBase::AdapterBase() {}

AdapterBase::~AdapterBase() { }
AdapterBase::~AdapterBase() {}

void* AdapterBase::underlying() const { return nullptr; }

std::string AdapterBase::identifier() { return "Plain Adapter"; }

BluetoothAddress AdapterBase::address() { return "00:00:00:00:00:00"; }
BluetoothAddress AdapterBase::address() { return "AA:BB:CC:DD:EE:FF"; }

void AdapterBase::scan_start() {
is_scanning_ = true;
Expand All @@ -34,7 +32,6 @@ void AdapterBase::scan_start() {
PeripheralBuilder peripheral_builder(std::make_shared<PeripheralBase>());
SAFE_CALLBACK_CALL(this->callback_on_scan_found_, peripheral_builder);
SAFE_CALLBACK_CALL(this->callback_on_scan_updated_, peripheral_builder);

}

void AdapterBase::scan_stop() {
Expand Down
2 changes: 1 addition & 1 deletion simpleble/src/plain/AdapterBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class AdapterBase {
static std::vector<std::shared_ptr<AdapterBase>> get_adapters();

private:
std::atomic_bool is_scanning_;
std::atomic_bool is_scanning_{false};

kvn::safe_callback<void()> callback_on_scan_start_;
kvn::safe_callback<void()> callback_on_scan_stop_;
Expand Down
6 changes: 4 additions & 2 deletions simpleble/src/plain/PeripheralBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ void* PeripheralBase::underlying() const { return nullptr; }

std::string PeripheralBase::identifier() { return "Plain Peripheral"; }

BluetoothAddress PeripheralBase::address() { return "00:00:00:00:00:00"; }
BluetoothAddress PeripheralBase::address() { return "11:22:33:44:55:66"; }

int16_t PeripheralBase::rssi() { return -127; }
int16_t PeripheralBase::rssi() { return -60; }

void PeripheralBase::connect() {
connected_ = true;
Expand All @@ -46,6 +46,8 @@ bool PeripheralBase::is_paired() { return paired_; }
void PeripheralBase::unpair() { paired_ = false; }

std::vector<Service> PeripheralBase::services() {
if (!connected_) return {};

std::vector<Service> service_list;

service_list.push_back(
Expand Down
7 changes: 3 additions & 4 deletions simpleble/src/plain/PeripheralBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

#include <atomic>
#include <condition_variable>
#include <memory>
#include <map>
#include <memory>

namespace SimpleBLE {

Expand Down Expand Up @@ -50,9 +50,8 @@ class PeripheralBase {
void set_callback_on_disconnected(std::function<void()> on_disconnected);

private:

std::atomic_bool connected_;
std::atomic_bool paired_;
std::atomic_bool connected_{false};
std::atomic_bool paired_{false};

kvn::safe_callback<void()> callback_on_connected_;
kvn::safe_callback<void()> callback_on_disconnected_;
Expand Down
4 changes: 4 additions & 0 deletions simplepyble/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
twine
wheel
ninja
pytest
pybind11
setuptools
cibuildwheel==2.9
17 changes: 17 additions & 0 deletions simplepyble/setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import pathlib
import sys
import setuptools
import argparse

argparser = argparse.ArgumentParser(add_help=False)
argparser.add_argument('--plain', help='Use Plain SimpleBLE', required=False, action='store_true')
args, unknown = argparser.parse_known_args()
sys.argv = [sys.argv[0]] + unknown

here = pathlib.Path(__file__).parent.resolve()
root = here.parent.resolve()
Expand All @@ -26,6 +32,9 @@
cmake_options.append(f"-DPYTHON_EXECUTABLE={sys.executable}")
cmake_options.append(f"-DSIMPLEPYBLE_VERSION={version_str}")

if args.plain:
cmake_options.append("-DSIMPLEBLE_PLAIN=ON")

# The information here can also be placed in setup.cfg - better separation of
# logic and declaration, and simpler if you include description/version in a file.
setuptools.setup(
Expand All @@ -51,6 +60,14 @@
"build_ext": cmake_build_extension.BuildExtension
},
zip_safe=False,
install_requires=[
"wheel",
"pybind11",
"ninja"
],
test_requires=[
"pytest",
],
extras_require={},
platforms="Windows, macOS, Linux",
python_requires=">=3.7",
Expand Down
62 changes: 62 additions & 0 deletions simplepyble/test/test_simpleble.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Note: This test suite is only evaluating the Python bindings, not the C++ library.
# The SimpleBLE implementation to test this on is the PLAIN version.
import simplepyble


def test_get_adapters():
assert simplepyble.Adapter.bluetooth_enabled() == True

adapters = simplepyble.Adapter.get_adapters()
assert len(adapters) == 1

adapter = adapters[0]
assert adapter.identifier() == "Plain Adapter"
assert adapter.address() == "AA:BB:CC:DD:EE:FF"


def test_scan_blocking():
adapter = simplepyble.Adapter.get_adapters()[0]

adapter.scan_for(1)
peripherals = adapter.scan_get_results()
assert len(peripherals) == 1

peripheral = peripherals[0]
assert peripheral.identifier() == "Plain Peripheral"
assert peripheral.address() == "11:22:33:44:55:66"
assert peripheral.rssi() == -60
assert peripheral.is_connected() == False
assert peripheral.is_paired() == False


def test_scan_async():
# TODO: Implement once we have proper callback and advertising emulation.
pass


def test_connect():
adapter = simplepyble.Adapter.get_adapters()[0]

adapter.scan_for(1)
peripherals = adapter.scan_get_results()
peripheral = peripherals[0]

peripheral.connect()
assert peripheral.is_connected() == True
assert peripheral.is_paired() == True

services = peripheral.services()
assert len(services) == 1

service = services[0]
assert service.uuid() == "0000180f-0000-1000-8000-00805f9b34fb"

characteristics = service.characteristics()
assert len(characteristics) == 1

characteristic = characteristics[0]
assert characteristic.uuid() == "00002a19-0000-1000-8000-00805f9b34fb"

peripheral.disconnect()
assert peripheral.is_connected() == False
assert peripheral.is_paired() == True
2 changes: 1 addition & 1 deletion utils/build_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ if [[ ! -z "$FLAG_CLEAN" ]]; then
rm -rf $EXAMPLE_BUILD_PATH
fi

cmake -H$SOURCE_PATH -B $BUILD_PATH $BUILD_TEST_ARG $BUILD_SANITIZE_ADDRESS_ARG $BUILD_SANITIZE_THREAD_ARG $BUILD_SHARED_ARG $EXTRA_BUILD_ARGS $BUILD_PLAIN
cmake -H$SOURCE_PATH -B $BUILD_PATH $BUILD_TEST_ARG $BUILD_SANITIZE_ADDRESS_ARG $BUILD_SANITIZE_THREAD_ARG $BUILD_SHARED_ARG $BUILD_PLAIN $EXTRA_BUILD_ARGS
cmake --build $BUILD_PATH -j7
cmake --install $BUILD_PATH --prefix "${INSTALL_PATH}"

Expand Down
27 changes: 24 additions & 3 deletions utils/build_py.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ while (( "$#" )); do
FLAG_CLEAN=0
shift
;;
-p|--plain)
FLAG_PLAIN=0
shift
;;
-i|--install)
FLAG_INSTALL=0
shift
;;
-*|--*=) # unsupported flags
echo "Error: Unsupported flag $1" >&2
exit 1
Expand All @@ -46,13 +54,26 @@ eval set -- "$PARAMS"

PROJECT_ROOT=$(realpath $(dirname `realpath $0`)/..)
SOURCE_PATH=$PROJECT_ROOT/simplepyble
BUILD_PATH=$PROJECT_ROOT/build # Note: setup.py will append the project name to the build path
BUILD_PATH=$PROJECT_ROOT/build_simplepyble # Note: setup.py will append the project name to the build path
DIST_PATH=$BUILD_PATH/dist

# If FLAG_CLEAN is set, clean the build directory
if [[ ! -z "$FLAG_CLEAN" ]]; then
rm -rf "$BUILD_PATH"_simplepyble
fi

if [[ ! -z "$FLAG_PLAIN" ]]; then
BUILD_PLAIN="--plain"
fi

SETUP_INSTRUCTIONS="build --build-base $BUILD_PATH"
SETUP_INSTRUCTIONS="$SETUP_INSTRUCTIONS egg_info --egg-base $BUILD_PATH"
SETUP_INSTRUCTIONS="$SETUP_INSTRUCTIONS bdist_wheel --dist-dir $DIST_PATH"

cd $SOURCE_PATH
python3 setup.py build --build-temp $BUILD_PATH
cd -
python3 setup.py $SETUP_INSTRUCTIONS $BUILD_PLAIN
cd -

if [[ ! -z "$FLAG_INSTALL" ]]; then
pip3 install $DIST_PATH/*.whl --force-reinstall
fi

0 comments on commit 86642a3

Please sign in to comment.