[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:
PJ Reiniger
2025-08-30 14:55:11 -04:00
committed by GitHub
parent 96004f9bb5
commit bd1dcc4358
96 changed files with 7271 additions and 64 deletions

View File

@@ -0,0 +1 @@

View 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]

View File

@@ -0,0 +1 @@
import wpiutil

View 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);
};

View 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); }

View 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);
}

View 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"])

View 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"
)

View File

@@ -0,0 +1,5 @@
from wpiutil_test import module
def test_const_string():
assert module.const_string() == "#12"

View 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})

View 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

View 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}

View 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]

View 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])

View 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

View 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}

View 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))