mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-23 01:21:42 +00:00
[bazel][robotpy] Add mirror for robotpy's wpiuil and wpinet libraries (#8062)
Project import generated by Copybara. GitOrigin-RevId: 92ea93d1b47a82667044bd0af05f7fdb34d2c2c2
This commit is contained in:
1
wpiutil/src/test/python/conftest.py
Normal file
1
wpiutil/src/test/python/conftest.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
11
wpiutil/src/test/python/cpp/pyproject.toml
Normal file
11
wpiutil/src/test/python/cpp/pyproject.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[build-system]
|
||||
build-backend = "hatchling.build"
|
||||
requires = [
|
||||
"hatch-meson", "hatchling"
|
||||
]
|
||||
|
||||
[project]
|
||||
name = "wpiutil_test"
|
||||
version = "0.0.1"
|
||||
|
||||
[tool.hatch.build.hooks.meson]
|
||||
1
wpiutil/src/test/python/cpp/wpiutil_test/__init__.py
Normal file
1
wpiutil/src/test/python/cpp/wpiutil_test/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
import wpiutil
|
||||
195
wpiutil/src/test/python/cpp/wpiutil_test/module.cpp
Normal file
195
wpiutil/src/test/python/cpp/wpiutil_test/module.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
// clang-format off
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
#include <wpi_array_type_caster.h>
|
||||
#include <wpi_span_type_caster.h>
|
||||
#include <wpi_smallset_type_caster.h>
|
||||
#include <wpi_smallvector_type_caster.h>
|
||||
#include <wpi_smallvectorimpl_type_caster.h>
|
||||
#include <wpi_string_map_caster.h>
|
||||
#include <wpi_json_type_caster.h>
|
||||
#include <wpi_ct_string_type_caster.h>
|
||||
|
||||
#include <limits>
|
||||
#include <functional>
|
||||
|
||||
#include <pybind11/functional.h>
|
||||
|
||||
/*
|
||||
array tests
|
||||
*/
|
||||
wpi::array<int, 4> load_array_int(wpi::array<int, 4> data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
wpi::array<int, 1> load_array_int1(wpi::array<int, 1> data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
/*
|
||||
span Tests
|
||||
*/
|
||||
std::span<const int> load_span_int(std::span<const int> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::span<const bool> load_span_bool(std::span<const bool> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::span<std::string> load_span_string(std::span<std::string> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::span<const std::string> load_span_string_const(std::span<const std::string> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::span<std::string_view> load_span_string_view(std::span<std::string_view> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::span<std::vector<std::string>> load_span_vector(std::span<std::vector<std::string>> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::span<const double, 3> load_span_fixed_double(std::span<const double, 3> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
std::span<int> cast_span() {
|
||||
static std::vector<int> vec{1, 2, 3};
|
||||
return vec;
|
||||
}
|
||||
|
||||
std::span<const std::string> make_string_span() {
|
||||
static std::vector<std::string> vec{"hi", "there"};
|
||||
return vec;
|
||||
}
|
||||
|
||||
py::object cast_string_span() {
|
||||
return py::cast(make_string_span());
|
||||
}
|
||||
|
||||
std::span<const uint8_t> load_span_bytes(std::span<const uint8_t> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
void modify_span_buffer(std::span<uint8_t> ref) {
|
||||
ref[0] = 0x4;
|
||||
}
|
||||
|
||||
/*
|
||||
SmallSet tests
|
||||
*/
|
||||
|
||||
wpi::SmallSet<int, 4> load_smallset_int(wpi::SmallSet<int, 4> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
wpi::SmallSet<int, 4> cast_smallset() {
|
||||
static wpi::SmallSet<int, 4> set;
|
||||
set.insert(1);
|
||||
set.insert(2);
|
||||
set.insert(3);
|
||||
set.insert(4);
|
||||
return set;
|
||||
}
|
||||
|
||||
/*
|
||||
SmallVector tests
|
||||
*/
|
||||
|
||||
wpi::SmallVector<int, 4> load_smallvec_int(wpi::SmallVector<int, 4> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
wpi::SmallVector<int, 4> cast_smallvec() {
|
||||
static wpi::SmallVector<int, 4> set;
|
||||
set.append({1, 2, 3, 4});
|
||||
return set;
|
||||
}
|
||||
|
||||
/*
|
||||
SmallVectorImpl tests
|
||||
|
||||
.. seems like references are the only useful things to do with them
|
||||
*/
|
||||
|
||||
wpi::SmallVectorImpl<int>& load_smallvecimpl_int(wpi::SmallVectorImpl<int>& ref) {
|
||||
static wpi::SmallVector<int, 4> set(ref.begin(), ref.end());
|
||||
return set;
|
||||
}
|
||||
|
||||
/*
|
||||
StringMap tests
|
||||
*/
|
||||
wpi::StringMap<int> load_stringmap_int(wpi::StringMap<int> ref) {
|
||||
return ref;
|
||||
}
|
||||
|
||||
wpi::StringMap<int> cast_stringmap() {
|
||||
static wpi::StringMap<int> m;
|
||||
m["one"] = 1;
|
||||
m["two"] = 2;
|
||||
return m;
|
||||
}
|
||||
|
||||
/* JSON tests */
|
||||
wpi::json cast_json_arg(const wpi::json &j) {
|
||||
return j;
|
||||
}
|
||||
|
||||
wpi::json cast_json_val(std::function<wpi::json()> fn) {
|
||||
return fn();
|
||||
}
|
||||
|
||||
constexpr auto const_string() {
|
||||
return wpi::ct_string<char, std::char_traits<char>, 3>{{'#', '1', '2'}};
|
||||
}
|
||||
|
||||
void sendable_test(py::module &m);
|
||||
void struct_test(py::module &m);
|
||||
|
||||
|
||||
PYBIND11_MODULE(module, m) {
|
||||
|
||||
sendable_test(m);
|
||||
struct_test(m);
|
||||
|
||||
// array
|
||||
m.def("load_array_int", &load_array_int);
|
||||
m.def("load_array_int1", &load_array_int1);
|
||||
// span
|
||||
m.def("load_span_int", &load_span_int);
|
||||
m.def("load_span_bool", &load_span_bool);
|
||||
m.def("load_span_fixed_double", &load_span_fixed_double);
|
||||
m.def("load_span_string", &load_span_string);
|
||||
m.def("load_span_string_const", &load_span_string_const);
|
||||
m.def("load_span_string_view", &load_span_string_view);
|
||||
m.def("load_span_vector", &load_span_vector);
|
||||
m.def("cast_span", &cast_span);
|
||||
m.def("cast_string_span", &cast_string_span);
|
||||
m.def("load_span_bytes", &load_span_bytes);
|
||||
m.def("modify_span_buffer", &modify_span_buffer);
|
||||
// SmallSet
|
||||
m.def("load_smallset_int", &load_smallset_int);
|
||||
m.def("cast_smallset", &cast_smallset);
|
||||
// SmallVector
|
||||
m.def("load_smallvec_int", &load_smallvec_int);
|
||||
m.def("cast_smallvec", &cast_smallvec);
|
||||
// SmallVectorImpl
|
||||
m.def("load_smallvecimpl_int", &load_smallvecimpl_int);
|
||||
// StringMap
|
||||
m.def("load_stringmap_int", &load_stringmap_int);
|
||||
m.def("cast_stringmap", &cast_stringmap);
|
||||
// JSON
|
||||
m.def("cast_json_arg", &cast_json_arg);
|
||||
m.def("cast_json_val", &cast_json_val);
|
||||
m.attr("max_uint64") = std::numeric_limits<uint64_t>::max();
|
||||
m.attr("max_int64") = std::numeric_limits<int64_t>::max();
|
||||
m.attr("min_int64") = std::numeric_limits<int64_t>::min();
|
||||
// ct_string
|
||||
m.def("const_string", &const_string);
|
||||
};
|
||||
154
wpiutil/src/test/python/cpp/wpiutil_test/sendable_test.cpp
Normal file
154
wpiutil/src/test/python/cpp/wpiutil_test/sendable_test.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
|
||||
#include <pybind11/functional.h>
|
||||
#include <pybind11/stl.h>
|
||||
#include <semiwrap.h>
|
||||
#include <wpi/sendable/SendableBuilder.h>
|
||||
#include <wpi/sendable/SendableRegistry.h>
|
||||
|
||||
class MySendableBuilder : public wpi::SendableBuilder {
|
||||
public:
|
||||
MySendableBuilder(py::dict keys) : keys(keys) {}
|
||||
|
||||
~MySendableBuilder() {
|
||||
// leak this so the python interpreter doesn't crash on shutdown
|
||||
keys.release();
|
||||
}
|
||||
|
||||
void SetSmartDashboardType(std::string_view type) override {}
|
||||
|
||||
void SetActuator(bool value) override {}
|
||||
|
||||
void AddBooleanProperty(std::string_view key, std::function<bool()> getter,
|
||||
std::function<void(bool)> setter) override {}
|
||||
|
||||
void PublishConstBoolean(std::string_view key, bool value) override {}
|
||||
|
||||
void AddIntegerProperty(std::string_view key, std::function<int64_t()> getter,
|
||||
std::function<void(int64_t)> setter) override {}
|
||||
|
||||
void PublishConstInteger(std::string_view key, int64_t value) override {}
|
||||
|
||||
void AddFloatProperty(std::string_view key, std::function<float()> getter,
|
||||
std::function<void(float)> setter) override {}
|
||||
|
||||
void PublishConstFloat(std::string_view key, float value) override {}
|
||||
|
||||
void AddDoubleProperty(std::string_view key, std::function<double()> getter,
|
||||
std::function<void(double)> setter) override {
|
||||
py::gil_scoped_acquire gil;
|
||||
py::object pykey = py::cast(key);
|
||||
keys[pykey] = std::make_tuple(getter, setter);
|
||||
}
|
||||
|
||||
void PublishConstDouble(std::string_view key, double value) override {}
|
||||
|
||||
void
|
||||
AddStringProperty(std::string_view key, std::function<std::string()> getter,
|
||||
std::function<void(std::string_view)> setter) override {}
|
||||
|
||||
void PublishConstString(std::string_view key,
|
||||
std::string_view value) override {}
|
||||
|
||||
void AddBooleanArrayProperty(
|
||||
std::string_view key, std::function<std::vector<int>()> getter,
|
||||
std::function<void(std::span<const int>)> setter) override {}
|
||||
|
||||
void PublishConstBooleanArray(std::string_view key,
|
||||
std::span<const int> value) override {}
|
||||
|
||||
void AddIntegerArrayProperty(
|
||||
std::string_view key, std::function<std::vector<int64_t>()> getter,
|
||||
std::function<void(std::span<const int64_t>)> setter) override {}
|
||||
|
||||
void PublishConstIntegerArray(std::string_view key,
|
||||
std::span<const int64_t> value) override {}
|
||||
|
||||
void AddFloatArrayProperty(
|
||||
std::string_view key, std::function<std::vector<float>()> getter,
|
||||
std::function<void(std::span<const float>)> setter) override {}
|
||||
|
||||
void PublishConstFloatArray(std::string_view key,
|
||||
std::span<const float> value) override {}
|
||||
|
||||
void AddDoubleArrayProperty(
|
||||
std::string_view key, std::function<std::vector<double>()> getter,
|
||||
std::function<void(std::span<const double>)> setter) override {}
|
||||
|
||||
void PublishConstDoubleArray(std::string_view key,
|
||||
std::span<const double> value) override {}
|
||||
|
||||
void AddStringArrayProperty(
|
||||
std::string_view key, std::function<std::vector<std::string>()> getter,
|
||||
std::function<void(std::span<const std::string>)> setter) override {}
|
||||
|
||||
void PublishConstStringArray(std::string_view key,
|
||||
std::span<const std::string> value) override {}
|
||||
|
||||
void AddRawProperty(
|
||||
std::string_view key, std::string_view typeString,
|
||||
std::function<std::vector<uint8_t>()> getter,
|
||||
std::function<void(std::span<const uint8_t>)> setter) override {}
|
||||
|
||||
void PublishConstRaw(std::string_view key, std::string_view typeString,
|
||||
std::span<const uint8_t> value) override {}
|
||||
|
||||
void AddSmallStringProperty(
|
||||
std::string_view key,
|
||||
std::function<std::string_view(wpi::SmallVectorImpl<char> &buf)> getter,
|
||||
std::function<void(std::string_view)> setter) override {}
|
||||
|
||||
void AddSmallBooleanArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<std::span<const int>(wpi::SmallVectorImpl<int> &buf)>
|
||||
getter,
|
||||
std::function<void(std::span<const int>)> setter) override {}
|
||||
|
||||
void AddSmallIntegerArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<
|
||||
std::span<const int64_t>(wpi::SmallVectorImpl<int64_t> &buf)>
|
||||
getter,
|
||||
std::function<void(std::span<const int64_t>)> setter) override {}
|
||||
|
||||
void AddSmallFloatArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<std::span<const float>(wpi::SmallVectorImpl<float> &buf)>
|
||||
getter,
|
||||
std::function<void(std::span<const float>)> setter) override {}
|
||||
|
||||
void AddSmallDoubleArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<std::span<const double>(wpi::SmallVectorImpl<double> &buf)>
|
||||
getter,
|
||||
std::function<void(std::span<const double>)> setter) override {}
|
||||
|
||||
void AddSmallStringArrayProperty(
|
||||
std::string_view key,
|
||||
std::function<
|
||||
std::span<const std::string>(wpi::SmallVectorImpl<std::string> &buf)>
|
||||
getter,
|
||||
std::function<void(std::span<const std::string>)> setter) override {}
|
||||
|
||||
void AddSmallRawProperty(
|
||||
std::string_view key, std::string_view typeString,
|
||||
std::function<std::span<uint8_t>(wpi::SmallVectorImpl<uint8_t> &buf)>
|
||||
getter,
|
||||
std::function<void(std::span<const uint8_t>)> setter) override {}
|
||||
|
||||
wpi::SendableBuilder::BackendKind GetBackendKind() const override {
|
||||
return wpi::SendableBuilder::BackendKind::kUnknown;
|
||||
}
|
||||
|
||||
bool IsPublished() const override { return false; }
|
||||
void Update() override {}
|
||||
void ClearProperties() override {}
|
||||
|
||||
py::dict keys;
|
||||
};
|
||||
|
||||
void Publish(wpi::SendableRegistry::UID sendableUid, py::dict keys) {
|
||||
auto builder = std::make_unique<MySendableBuilder>(keys);
|
||||
wpi::SendableRegistry::Publish(sendableUid, std::move(builder));
|
||||
}
|
||||
|
||||
void sendable_test(py::module &m) { m.def("publish", Publish); }
|
||||
84
wpiutil/src/test/python/cpp/wpiutil_test/struct_test.cpp
Normal file
84
wpiutil/src/test/python/cpp/wpiutil_test/struct_test.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
#include <pybind11/operators.h>
|
||||
#include <wpystruct.h>
|
||||
|
||||
//
|
||||
// Thing to serialize
|
||||
//
|
||||
|
||||
struct ThingA {
|
||||
ThingA() = default;
|
||||
ThingA(int x) : x(x) {}
|
||||
|
||||
const int x = 0;
|
||||
|
||||
bool operator==(const ThingA &other) const { return x == other.x; }
|
||||
};
|
||||
|
||||
template <> struct wpi::Struct<ThingA> {
|
||||
static constexpr std::string_view GetTypeName() { return "ThingA"; }
|
||||
static constexpr size_t GetSize() { return 1; }
|
||||
static constexpr std::string_view GetSchema() { return "uint8 value"; }
|
||||
static ThingA Unpack(std::span<const uint8_t> data) {
|
||||
return ThingA{data[0]};
|
||||
}
|
||||
static void Pack(std::span<uint8_t> data, const ThingA &value) {
|
||||
data[0] = value.x;
|
||||
}
|
||||
};
|
||||
|
||||
struct Outer {
|
||||
Outer() = default;
|
||||
Outer(const ThingA &t, int c) : inner(t), c(c) {}
|
||||
|
||||
ThingA inner;
|
||||
int c = 0;
|
||||
|
||||
bool operator==(const Outer &other) const {
|
||||
return inner == other.inner && c == other.c;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct wpi::Struct<Outer> {
|
||||
static constexpr std::string_view GetTypeName() { return "Outer"; }
|
||||
static constexpr size_t GetSize() { return wpi::GetStructSize<ThingA>() + 4; }
|
||||
static constexpr std::string_view GetSchema() {
|
||||
return "ThingA inner; int32 c";
|
||||
}
|
||||
|
||||
static Outer Unpack(std::span<const uint8_t> data) {
|
||||
constexpr size_t innerSize = wpi::GetStructSize<ThingA>();
|
||||
return {wpi::UnpackStruct<ThingA, 0>(data),
|
||||
wpi::UnpackStruct<int32_t, innerSize>(data)};
|
||||
}
|
||||
static void Pack(std::span<uint8_t> data, const Outer& value) {
|
||||
constexpr size_t innerSize = wpi::GetStructSize<ThingA>();
|
||||
wpi::PackStruct<0>(data, value.inner);
|
||||
wpi::PackStruct<innerSize>(data, value.c);
|
||||
}
|
||||
static void ForEachNested(
|
||||
std::invocable<std::string_view, std::string_view> auto fn) {
|
||||
wpi::ForEachStructSchema<ThingA>(fn);
|
||||
}
|
||||
};
|
||||
|
||||
void struct_test(py::module &m) {
|
||||
|
||||
py::class_<ThingA> thingCls(m, "ThingA");
|
||||
thingCls.def(py::init<>());
|
||||
thingCls.def(py::init<int>());
|
||||
thingCls.def_readonly("x", &ThingA::x);
|
||||
thingCls.def(py::self == py::self);
|
||||
|
||||
SetupWPyStruct<ThingA>(thingCls);
|
||||
|
||||
py::class_<Outer> outerCls(m, "Outer");
|
||||
outerCls.def(py::init<>());
|
||||
outerCls.def(py::init<ThingA, int>());
|
||||
outerCls.def_readonly("inner", &Outer::inner);
|
||||
outerCls.def_readwrite("c", &Outer::c);
|
||||
outerCls.def(py::self == py::self);
|
||||
|
||||
SetupWPyStruct<Outer>(outerCls);
|
||||
}
|
||||
26
wpiutil/src/test/python/run_tests.py
Executable file
26
wpiutil/src/test/python/run_tests.py
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
from os.path import abspath, dirname
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
if __name__ == "__main__":
|
||||
root = abspath(dirname(__file__))
|
||||
os.chdir(root)
|
||||
|
||||
subprocess.check_call(
|
||||
[
|
||||
sys.executable,
|
||||
"-m",
|
||||
"pip",
|
||||
"--disable-pip-version-check",
|
||||
"install",
|
||||
"-v",
|
||||
"--force-reinstall",
|
||||
"--no-build-isolation",
|
||||
"./cpp",
|
||||
],
|
||||
)
|
||||
|
||||
subprocess.check_call([sys.executable, "-m", "pytest"])
|
||||
17
wpiutil/src/test/python/test_array.py
Normal file
17
wpiutil/src/test/python/test_array.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from wpiutil_test import module
|
||||
|
||||
|
||||
def test_load_array_int():
|
||||
assert module.load_array_int((1, 2, 3, 4)) == (1, 2, 3, 4)
|
||||
assert module.load_array_int([1, 2, 3, 4]) == (1, 2, 3, 4)
|
||||
|
||||
|
||||
def test_load_array_annotation():
|
||||
assert (
|
||||
module.load_array_int.__doc__
|
||||
== "load_array_int(arg0: Tuple[typing.SupportsInt, typing.SupportsInt, typing.SupportsInt, typing.SupportsInt]) -> Tuple[int, int, int, int]\n"
|
||||
)
|
||||
assert (
|
||||
module.load_array_int1.__doc__
|
||||
== "load_array_int1(arg0: Tuple[typing.SupportsInt]) -> Tuple[int]\n"
|
||||
)
|
||||
5
wpiutil/src/test/python/test_ct_string.py
Normal file
5
wpiutil/src/test/python/test_ct_string.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from wpiutil_test import module
|
||||
|
||||
|
||||
def test_const_string():
|
||||
assert module.const_string() == "#12"
|
||||
71
wpiutil/src/test/python/test_json.py
Normal file
71
wpiutil/src/test/python/test_json.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from wpiutil_test.module import (
|
||||
cast_json_arg,
|
||||
cast_json_val,
|
||||
max_int64,
|
||||
min_int64,
|
||||
max_uint64,
|
||||
)
|
||||
import pytest
|
||||
import math
|
||||
|
||||
|
||||
def test_json_invalid():
|
||||
with pytest.raises(TypeError):
|
||||
cast_json_val(lambda: object())
|
||||
|
||||
|
||||
def test_json_none():
|
||||
assert cast_json_arg(None) == None
|
||||
|
||||
|
||||
def test_json_bool():
|
||||
assert cast_json_arg(True) == True
|
||||
assert cast_json_arg(False) == False
|
||||
|
||||
|
||||
def test_json_int():
|
||||
assert cast_json_arg(36) == 36
|
||||
|
||||
assert cast_json_arg(min_int64) == min_int64
|
||||
with pytest.raises(ValueError):
|
||||
cast_json_arg(min_int64 - 1)
|
||||
|
||||
assert cast_json_arg(max_int64) == max_int64
|
||||
assert cast_json_arg(max_uint64) == max_uint64
|
||||
with pytest.raises(ValueError):
|
||||
cast_json_arg(max_uint64 + 1)
|
||||
|
||||
|
||||
def test_json_float():
|
||||
assert cast_json_arg(36.37) == 36.37
|
||||
assert cast_json_arg(math.inf) == math.inf
|
||||
assert math.isnan(cast_json_arg(math.nan))
|
||||
|
||||
|
||||
def test_json_string():
|
||||
assert cast_json_arg("hi") == "hi"
|
||||
|
||||
|
||||
def test_json_list():
|
||||
v = [36, "hello", False]
|
||||
assert cast_json_arg(v) == v
|
||||
|
||||
assert cast_json_arg([]) == []
|
||||
|
||||
tv = (36, "hello", False)
|
||||
assert cast_json_arg(tv) == v
|
||||
|
||||
|
||||
def test_json_dict():
|
||||
d = {"number": 1234, "hello": "world"}
|
||||
assert cast_json_arg(d) == d
|
||||
|
||||
assert cast_json_arg({}) == {}
|
||||
|
||||
assert cast_json_arg({1: 2}) == {"1": 2}
|
||||
assert cast_json_arg({None: 2}) == {"None": 2}
|
||||
assert cast_json_arg({1.2: 2}) == {"1.2": 2}
|
||||
assert cast_json_arg({False: 2}) == {"False": 2}
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
cast_json_arg({object(): 2})
|
||||
35
wpiutil/src/test/python/test_sendable.py
Normal file
35
wpiutil/src/test/python/test_sendable.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import typing
|
||||
import wpiutil
|
||||
from wpiutil_test import module
|
||||
|
||||
|
||||
class MySendable(wpiutil.Sendable):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
wpiutil.SendableRegistry.add(self, "Test", 1)
|
||||
self.value = 0
|
||||
|
||||
def initSendable(self, builder: wpiutil.SendableBuilder):
|
||||
builder.addDoubleProperty("key", self._get, self._set)
|
||||
|
||||
def _set(self, value: float):
|
||||
self.value = value
|
||||
|
||||
def _get(self) -> float:
|
||||
return self.value
|
||||
|
||||
|
||||
def test_custom_sendable():
|
||||
ms = MySendable()
|
||||
|
||||
uid = wpiutil.SendableRegistry.getUniqueId(ms)
|
||||
keys = {}
|
||||
|
||||
module.publish(uid, keys)
|
||||
assert ms.value == 0
|
||||
|
||||
getter, setter = keys["key"]
|
||||
assert getter() == 0
|
||||
setter(1)
|
||||
assert getter() == 1
|
||||
assert ms.value == 1
|
||||
18
wpiutil/src/test/python/test_smallset.py
Normal file
18
wpiutil/src/test/python/test_smallset.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from wpiutil_test import module
|
||||
|
||||
|
||||
def test_smallset_load():
|
||||
assert module.load_smallset_int({1, 2, 3, 4}) == {1, 2, 3, 4}
|
||||
|
||||
|
||||
def test_smallsetbool_load():
|
||||
assert module.load_smallset_int({True, True, False, True}) == {
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
}
|
||||
|
||||
|
||||
def test_smallset_cast():
|
||||
assert module.cast_smallset() == {1, 2, 3, 4}
|
||||
22
wpiutil/src/test/python/test_smallvector.py
Normal file
22
wpiutil/src/test/python/test_smallvector.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from wpiutil_test import module
|
||||
|
||||
|
||||
def test_smallvec_load():
|
||||
assert module.load_smallvec_int([1, 2, 3, 4]) == [1, 2, 3, 4]
|
||||
|
||||
|
||||
def test_smallvecbool_load():
|
||||
assert module.load_smallvec_int([True, True, False, True]) == [
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
True,
|
||||
]
|
||||
|
||||
|
||||
def test_smallvec_cast():
|
||||
assert module.cast_smallvec() == [1, 2, 3, 4]
|
||||
|
||||
|
||||
def test_smallvecimpl_load():
|
||||
assert module.load_smallvecimpl_int([1, 2, 3, 4]) == [1, 2, 3, 4]
|
||||
75
wpiutil/src/test/python/test_span.py
Normal file
75
wpiutil/src/test/python/test_span.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import pytest
|
||||
from wpiutil_test import module
|
||||
import array
|
||||
|
||||
|
||||
def test_span_load_int():
|
||||
assert module.load_span_int([1, 2, 3, 4]) == [1, 2, 3, 4]
|
||||
|
||||
|
||||
def test_span_load_int():
|
||||
assert module.load_span_int([1, 2, 3]) == [1, 2, 3]
|
||||
|
||||
|
||||
def test_span_load_bool():
|
||||
assert module.load_span_bool([True, False, True]) == [True, False, True]
|
||||
|
||||
|
||||
def test_span_load_string():
|
||||
assert module.load_span_string(["a", "b", "c"]) == ["a", "b", "c"]
|
||||
|
||||
|
||||
def test_span_load_string_const():
|
||||
assert module.load_span_string_const(["a", "b", "c"]) == ["a", "b", "c"]
|
||||
|
||||
|
||||
def test_span_load_stringview():
|
||||
assert module.load_span_string_view(["a", "b", "c"]) == ["a", "b", "c"]
|
||||
|
||||
|
||||
def test_span_load_vector():
|
||||
assert module.load_span_vector([["a"], ["b"], ["c"]]) == [["a"], ["b"], ["c"]]
|
||||
|
||||
|
||||
def test_span_load_buffer_bytes():
|
||||
assert module.load_span_bytes(b"abc") == b"abc"
|
||||
|
||||
|
||||
def test_span_modify_buffer_bytes():
|
||||
b = b"abc"
|
||||
with pytest.raises(BufferError):
|
||||
module.modify_span_buffer(b)
|
||||
|
||||
|
||||
def test_span_load_buffer_bytearray():
|
||||
assert module.load_span_bytes(bytearray([1, 2, 3])) == b"\x01\x02\x03"
|
||||
|
||||
|
||||
def test_span_modify_buffer_bytearray():
|
||||
b = bytearray([1, 2, 3])
|
||||
module.modify_span_buffer(b)
|
||||
assert b == bytearray([4, 2, 3])
|
||||
|
||||
|
||||
def test_span_load_buffer_array():
|
||||
a = array.array("l")
|
||||
a.append(1)
|
||||
a2 = array.array("l")
|
||||
a2.frombytes(module.load_span_bytes(a))
|
||||
assert len(a2) == 1
|
||||
assert a2[0] == 1
|
||||
|
||||
|
||||
def test_span_cast():
|
||||
assert module.cast_span() == [1, 2, 3]
|
||||
|
||||
|
||||
def test_string_span():
|
||||
assert module.cast_string_span() == ["hi", "there"]
|
||||
|
||||
|
||||
def test_fixed_double_span():
|
||||
assert module.load_span_fixed_double([1, 2, 3]) == (1, 2, 3)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
assert module.load_span_fixed_double([1, 2, 3, 4])
|
||||
9
wpiutil/src/test/python/test_stacktrace.py
Normal file
9
wpiutil/src/test/python/test_stacktrace.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import wpiutil
|
||||
|
||||
|
||||
def test_python_stack_trace():
|
||||
st = wpiutil._wpiutil.getStackTrace(0)
|
||||
assert __file__ in st
|
||||
|
||||
st = wpiutil._wpiutil.getStackTraceDefault(0)
|
||||
assert __file__ not in st
|
||||
13
wpiutil/src/test/python/test_stringmap.py
Normal file
13
wpiutil/src/test/python/test_stringmap.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from wpiutil_test import module
|
||||
|
||||
|
||||
def test_stringmap_load():
|
||||
assert module.load_stringmap_int({"one": 11, "two": 22, "three": 33}) == {
|
||||
"one": 11,
|
||||
"two": 22,
|
||||
"three": 33,
|
||||
}
|
||||
|
||||
|
||||
def test_stringmap_cast():
|
||||
assert module.cast_stringmap() == {"one": 1, "two": 2}
|
||||
242
wpiutil/src/test/python/test_struct.py
Normal file
242
wpiutil/src/test/python/test_struct.py
Normal file
@@ -0,0 +1,242 @@
|
||||
import dataclasses
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from wpiutil import wpistruct
|
||||
from wpiutil_test import module
|
||||
|
||||
#
|
||||
# Static serialization
|
||||
#
|
||||
|
||||
|
||||
# ensure that a type that doesn't work has a sane error message
|
||||
def test_invalid_type():
|
||||
with pytest.raises(
|
||||
TypeError,
|
||||
match=re.escape("str is not struct serializable (does not have WPIStruct)"),
|
||||
):
|
||||
wpistruct.getSchema(str)
|
||||
|
||||
|
||||
def test_for_each_nested():
|
||||
l = []
|
||||
|
||||
def _fn(*args):
|
||||
l.append(args)
|
||||
|
||||
wpistruct.forEachNested(module.ThingA, _fn)
|
||||
assert l == [("struct:ThingA", "uint8 value")]
|
||||
|
||||
|
||||
def test_get_type_string():
|
||||
assert wpistruct.getTypeName(module.ThingA) == "ThingA"
|
||||
|
||||
|
||||
def test_get_schema():
|
||||
assert wpistruct.getSchema(module.ThingA) == "uint8 value"
|
||||
|
||||
|
||||
def test_get_size():
|
||||
assert wpistruct.getSize(module.ThingA) == 1
|
||||
|
||||
|
||||
def test_pack():
|
||||
assert wpistruct.pack(module.ThingA(1)) == b"\x01"
|
||||
|
||||
|
||||
def test_pack_array():
|
||||
assert wpistruct.packArray([module.ThingA(1), module.ThingA(2)]) == b"\x01\x02"
|
||||
|
||||
|
||||
def test_pack_into():
|
||||
buf = bytearray(1)
|
||||
wpistruct.packInto(module.ThingA(1), buf)
|
||||
assert buf == b"\x01"
|
||||
|
||||
|
||||
def test_pack_into_err():
|
||||
buf = bytearray(2)
|
||||
with pytest.raises(ValueError, match=re.escape("buffer must be 1 bytes")):
|
||||
wpistruct.packInto(module.ThingA(1), buf)
|
||||
|
||||
|
||||
def test_unpack():
|
||||
assert wpistruct.unpack(module.ThingA, b"\x01") == module.ThingA(1)
|
||||
|
||||
|
||||
def test_unpack_array():
|
||||
assert wpistruct.unpackArray(module.ThingA, b"\x01\x02") == [
|
||||
module.ThingA(1),
|
||||
module.ThingA(2),
|
||||
]
|
||||
|
||||
|
||||
# def test_unpack_into():
|
||||
# r1 = module.ThingA(1)
|
||||
# r2 = module.ThingA(2)
|
||||
# assert r1 != r2
|
||||
# wpistruct.unpackInto(b"\x01", r2)
|
||||
# assert r1 == r2
|
||||
|
||||
|
||||
#
|
||||
# Nested struct
|
||||
#
|
||||
|
||||
|
||||
def test_nested_for_each_nested():
|
||||
l = []
|
||||
|
||||
def _fn(*args):
|
||||
l.append(args)
|
||||
|
||||
wpistruct.forEachNested(module.Outer, _fn)
|
||||
assert l == [
|
||||
("struct:ThingA", "uint8 value"),
|
||||
("struct:Outer", "ThingA inner; int32 c"),
|
||||
]
|
||||
|
||||
|
||||
def test_nested_get_type_string():
|
||||
assert wpistruct.getTypeName(module.ThingA) == "ThingA"
|
||||
|
||||
|
||||
def test_nested_get_schema():
|
||||
assert wpistruct.getSchema(module.Outer) == "ThingA inner; int32 c"
|
||||
|
||||
|
||||
def test_nested_get_size():
|
||||
assert wpistruct.getSize(module.Outer) == 5
|
||||
|
||||
|
||||
def test_nested_pack():
|
||||
v = module.Outer(module.ThingA(2), 4)
|
||||
assert wpistruct.pack(v) == b"\x02\x04\x00\x00\x00"
|
||||
|
||||
|
||||
def test_nested_pack_into():
|
||||
v = module.Outer(module.ThingA(3), 5)
|
||||
buf = bytearray(5)
|
||||
wpistruct.packInto(v, buf)
|
||||
assert buf == b"\x03\x05\x00\x00\x00"
|
||||
|
||||
|
||||
def test_nested_unpack():
|
||||
assert wpistruct.unpack(module.ThingA, b"\x01") == module.ThingA(1)
|
||||
|
||||
|
||||
#
|
||||
# User defined serialization
|
||||
#
|
||||
|
||||
|
||||
@wpistruct.make_wpistruct(name="mystruct")
|
||||
@dataclasses.dataclass
|
||||
class MyStruct:
|
||||
x: int
|
||||
y: bool
|
||||
z: float
|
||||
|
||||
|
||||
def test_user_for_each_nested():
|
||||
l = []
|
||||
|
||||
def _fn(*args):
|
||||
l.append(args)
|
||||
|
||||
wpistruct.forEachNested(MyStruct, _fn)
|
||||
assert l == [("struct:mystruct", "int32 x; bool y; float z")]
|
||||
|
||||
|
||||
def test_user_get_type_string():
|
||||
assert wpistruct.getTypeName(MyStruct) == "mystruct"
|
||||
|
||||
|
||||
def test_user_get_schema():
|
||||
assert wpistruct.getSchema(MyStruct) == "int32 x; bool y; float z"
|
||||
|
||||
|
||||
def test_user_get_size():
|
||||
assert wpistruct.getSize(MyStruct) == 9
|
||||
|
||||
|
||||
def test_user_pack():
|
||||
v = MyStruct(2, True, 3.5)
|
||||
assert wpistruct.pack(v) == b"\x02\x00\x00\x00\x01\x00\x00\x60\x40"
|
||||
|
||||
|
||||
def test_user_pack_into():
|
||||
v = MyStruct(2, True, 3.5)
|
||||
buf = bytearray(9)
|
||||
wpistruct.packInto(v, buf)
|
||||
assert buf == b"\x02\x00\x00\x00\x01\x00\x00\x60\x40"
|
||||
|
||||
|
||||
def test_user_unpack():
|
||||
v = MyStruct(2, True, 3.5)
|
||||
assert wpistruct.unpack(MyStruct, b"\x02\x00\x00\x00\x01\x00\x00\x60\x40") == v
|
||||
|
||||
|
||||
# def test_user_unpack_into():
|
||||
# v1 = MyStruct(2, True, 3.5)
|
||||
# v2 = MyStruct(3, True, 4.5)
|
||||
# assert v1 != v2
|
||||
# wpistruct.unpackInto(b"\x02\x00\x00\x00\x01\x00\x00\x60\x40", v2)
|
||||
# assert v1 == v2
|
||||
|
||||
|
||||
#
|
||||
# User defined serialization (nested)
|
||||
#
|
||||
|
||||
|
||||
@wpistruct.make_wpistruct
|
||||
@dataclasses.dataclass
|
||||
class Outer:
|
||||
x: int
|
||||
inner: MyStruct
|
||||
|
||||
|
||||
def test_user_nested_for_each_nested():
|
||||
l = []
|
||||
|
||||
def _fn(*args):
|
||||
l.append(args)
|
||||
|
||||
wpistruct.forEachNested(Outer, _fn)
|
||||
assert l == [
|
||||
("struct:mystruct", "int32 x; bool y; float z"),
|
||||
("struct:Outer", "int32 x; mystruct inner"),
|
||||
]
|
||||
|
||||
|
||||
def test_user_nested_get_type_string():
|
||||
assert wpistruct.getTypeName(Outer) == "Outer"
|
||||
|
||||
|
||||
def test_user_nested_get_schema():
|
||||
assert wpistruct.getSchema(Outer) == "int32 x; mystruct inner"
|
||||
|
||||
|
||||
def test_user_nested_get_size():
|
||||
assert wpistruct.getSize(Outer) == 4 + 9
|
||||
|
||||
|
||||
def test_user_nested_pack():
|
||||
v = Outer(2, MyStruct(3, True, 4.0))
|
||||
assert wpistruct.pack(v) == b"\x02\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x80\x40"
|
||||
|
||||
|
||||
def test_user_nested_pack_into():
|
||||
v = Outer(2, MyStruct(3, True, 4.0))
|
||||
buf = bytearray(4 + 9)
|
||||
wpistruct.packInto(v, buf)
|
||||
assert buf == b"\x02\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x80\x40"
|
||||
|
||||
|
||||
def test_user_nested_unpack():
|
||||
assert wpistruct.unpack(
|
||||
Outer, b"\x02\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x80\x40"
|
||||
) == Outer(2, MyStruct(3, True, 4.0))
|
||||
Reference in New Issue
Block a user