diff --git a/tests/cpp/gen/ft/buffers.yml b/tests/cpp/gen/ft/buffers.yml new file mode 100644 index 00000000..a49a3a7f --- /dev/null +++ b/tests/cpp/gen/ft/buffers.yml @@ -0,0 +1,24 @@ +--- + +classes: + Buffers: + methods: + set_buffer: + buffers: + - { type: in, src: data, len: len } + get_buffer2: + buffers: + - { type: out, src: data, len: len } + get_buffer1: + buffers: + - { type: out, src: data, len: len } + + v_set_buffer: + buffers: + - { type: in, src: data, len: len } + v_get_buffer2: + buffers: + - { type: out, src: data, len: len } + v_get_buffer1: + buffers: + - { type: out, src: data, len: len } \ No newline at end of file diff --git a/tests/cpp/gen/ft/ignore.yml b/tests/cpp/gen/ft/ignore.yml index 29e8b570..0316fd62 100644 --- a/tests/cpp/gen/ft/ignore.yml +++ b/tests/cpp/gen/ft/ignore.yml @@ -36,6 +36,15 @@ classes: Param1: ignore: true methods: + ClassWithIgnored: + cpp_code: | + [](py::args) { + return std::make_shared(1); + } + keepalive: [] + param_override: + y: + ignore: true fnIgnore: ignore: true fnIgnoredParam: diff --git a/tests/cpp/gen/ft/inline_code.yml b/tests/cpp/gen/ft/inline_code.yml index e78e0271..5b65e848 100644 --- a/tests/cpp/gen/ft/inline_code.yml +++ b/tests/cpp/gen/ft/inline_code.yml @@ -2,12 +2,19 @@ classes: InlineCode: + constants: + - NS::inner::KONSTANT enums: MyE: inline_code: | .value("Value2", (InlineCode::MyE)2) methods: get2: + cpp_code_with_constant: + cpp_code: | + [](InlineCode *self) { + return KONSTANT; + } inline_code: | // you can even start with a comment .def("get4", [](InlineCode *self) { diff --git a/tests/cpp/gen/ft/virtual_xform.yml b/tests/cpp/gen/ft/virtual_xform.yml index 0d2a787f..ae6e0b64 100644 --- a/tests/cpp/gen/ft/virtual_xform.yml +++ b/tests/cpp/gen/ft/virtual_xform.yml @@ -5,6 +5,11 @@ functions: classes: VBase: methods: + different_cpp_and_py: + cpp_code: | + [](VBase * self, int x) { + return x + 2; + } pure_io: param_override: ss: diff --git a/tests/cpp/pyproject.toml.tmpl b/tests/cpp/pyproject.toml.tmpl index 99f90b27..11c5c818 100644 --- a/tests/cpp/pyproject.toml.tmpl +++ b/tests/cpp/pyproject.toml.tmpl @@ -44,6 +44,7 @@ generate = [ { abstract = "abstract.h" }, { base_qualname = "base_qualname.h" }, { base_qualname_hidden = "base_qualname_hidden.h" }, + { buffers = "buffers.h" }, { custom_type_caster = "custom_type_caster.h" }, { defaults = "defaults.h" }, { docstrings = "docstrings.h" }, @@ -56,6 +57,7 @@ generate = [ { inline_code = "inline_code.h" }, { lifetime = "lifetime.h" }, { nested = "nested.h" }, + { operators = "operators.h" }, { overloads = "overloads.h" }, { parameters = "parameters.h" }, { refqual = "refqual.h" }, diff --git a/tests/cpp/rpytest/ft/__init__.py b/tests/cpp/rpytest/ft/__init__.py index f6a6b872..c01766cc 100644 --- a/tests/cpp/rpytest/ft/__init__.py +++ b/tests/cpp/rpytest/ft/__init__.py @@ -3,6 +3,7 @@ # autogenerated by 'robotpy-build create-imports rpytest.ft rpytest.ft._rpytest_ft' from ._rpytest_ft import ( Abstract, + Buffers, ClassWithFields, ClassWithIgnored, ClassWithTrampoline, @@ -19,6 +20,7 @@ GEnum, GEnumMath, HasFactory, + HasOperator, IBase, IChild, IFinal, @@ -80,6 +82,7 @@ VChild, VirtualComma, checkConvertRpyintToInt, + check_different_cpp_and_py, check_impure_io, check_pure_io, convertRpyintToInt, @@ -107,6 +110,7 @@ __all__ = [ "Abstract", + "Buffers", "ClassWithFields", "ClassWithIgnored", "ClassWithTrampoline", @@ -123,6 +127,7 @@ "GEnum", "GEnumMath", "HasFactory", + "HasOperator", "IBase", "IChild", "IFinal", @@ -184,6 +189,7 @@ "VChild", "VirtualComma", "checkConvertRpyintToInt", + "check_different_cpp_and_py", "check_impure_io", "check_pure_io", "convertRpyintToInt", diff --git a/tests/cpp/rpytest/ft/include/buffers.h b/tests/cpp/rpytest/ft/include/buffers.h new file mode 100644 index 00000000..be7a2f69 --- /dev/null +++ b/tests/cpp/rpytest/ft/include/buffers.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +class Buffers { +public: + + // in + void set_buffer(const uint8_t *data, size_t len) { + m_buf.resize(len); + memcpy(m_buf.data(), data, len); + } + + // out + // - data is bytes + // - len is input_size and output size + void get_buffer2(uint8_t *data, size_t *len) { + *len = get_buffer1(data, *len); + } + + // out + // - data is bytes + // - len is input size + // - return value is output size + size_t get_buffer1(uint8_t *data, size_t len) { + size_t rlen = len < m_buf.size() ? len : m_buf.size(); + if (rlen) { + memcpy(data, m_buf.data(), rlen); + } + return rlen; + } + + // + // virtual functions -- trampolines are disabled but normal function + // calls work + // + + virtual void v_set_buffer(const uint8_t *data, size_t len) { + set_buffer(data, len); + } + + virtual void v_get_buffer2(uint8_t *data, size_t *len) { + get_buffer2(data, len); + } + + virtual size_t v_get_buffer1(uint8_t *data, size_t len) { + return get_buffer1(data, len); + } + +private: + + std::vector m_buf; +}; diff --git a/tests/cpp/rpytest/ft/include/ignore.h b/tests/cpp/rpytest/ft/include/ignore.h index 045d8c2e..1f94c2d8 100644 --- a/tests/cpp/rpytest/ft/include/ignore.h +++ b/tests/cpp/rpytest/ft/include/ignore.h @@ -19,6 +19,9 @@ struct IgnoredClassWithEnum { struct ClassWithIgnored { + // constructor with ignored param + ClassWithIgnored(int y) {} + // class function int fnIgnore() { return 0x2; } diff --git a/tests/cpp/rpytest/ft/include/inheritance/ibase.h b/tests/cpp/rpytest/ft/include/inheritance/ibase.h index 8c6a55bc..5eb050ff 100644 --- a/tests/cpp/rpytest/ft/include/inheritance/ibase.h +++ b/tests/cpp/rpytest/ft/include/inheritance/ibase.h @@ -11,26 +11,31 @@ struct IBase IBase() {} virtual ~IBase() {} + /** doc: base::baseOnly */ virtual std::string baseOnly() { return "base::baseOnly"; } + /** doc: base::baseAndGrandchild */ virtual std::string baseAndGrandchild() { return "base::baseAndGrandchild"; } + /** doc: base::baseAndChild */ virtual std::string baseAndChild() { return "base::baseAndChild"; } + /** doc: base::baseAndPyChild */ virtual std::string baseAndPyChild() { return "base::baseAndPyChild"; } + /** doc: base::baseAndChildFinal */ virtual std::string baseAndChildFinal() { return "base::baseAndChildFinal"; diff --git a/tests/cpp/rpytest/ft/include/inheritance/ichild.h b/tests/cpp/rpytest/ft/include/inheritance/ichild.h index f86964c9..0c5e56e8 100644 --- a/tests/cpp/rpytest/ft/include/inheritance/ichild.h +++ b/tests/cpp/rpytest/ft/include/inheritance/ichild.h @@ -10,11 +10,13 @@ struct IChild : IBase { IChild() : IBase(), i(42) {} + /** doc: child::baseAndChild */ std::string baseAndChild() override { return "child::baseAndChild"; } + /** doc: child::baseAndChildFinal */ std::string baseAndChildFinal() final { return "child::baseAndChildFinal"; diff --git a/tests/cpp/rpytest/ft/include/inheritance/igchild.h b/tests/cpp/rpytest/ft/include/inheritance/igchild.h index 0f576e4f..21c06349 100644 --- a/tests/cpp/rpytest/ft/include/inheritance/igchild.h +++ b/tests/cpp/rpytest/ft/include/inheritance/igchild.h @@ -7,6 +7,7 @@ namespace inheritance struct IGrandChild final : IChild { + /** doc: grandchild::baseAndGrandchild */ std::string baseAndGrandchild() override { return "grandchild::baseAndGrandchild"; diff --git a/tests/cpp/rpytest/ft/include/inheritance/imchild.h b/tests/cpp/rpytest/ft/include/inheritance/imchild.h index d92c36cf..1140c2cf 100644 --- a/tests/cpp/rpytest/ft/include/inheritance/imchild.h +++ b/tests/cpp/rpytest/ft/include/inheritance/imchild.h @@ -10,8 +10,10 @@ struct IMOther { // a child that does multiple inheritance struct IMChild : IBase, IMOther { + /** doc: mchild::baseAndChild */ std::string baseAndChild() override { return "mchild::baseAndChild"; } + /** doc: mchild::baseAndChildFinal */ std::string baseAndChildFinal() final { return "mchild::baseAndChildFinal"; } }; diff --git a/tests/cpp/rpytest/ft/include/inline_code.h b/tests/cpp/rpytest/ft/include/inline_code.h index af951cfa..ae10a6c4 100644 --- a/tests/cpp/rpytest/ft/include/inline_code.h +++ b/tests/cpp/rpytest/ft/include/inline_code.h @@ -1,6 +1,10 @@ #pragma once +namespace NS::inner { + static constexpr auto KONSTANT = 4; +} + class InlineCode { public: enum MyE { @@ -8,4 +12,6 @@ class InlineCode { }; int get2() const { return 2; } + + int cpp_code_with_constant() { return 3; } }; diff --git a/tests/cpp/rpytest/ft/include/operators.h b/tests/cpp/rpytest/ft/include/operators.h new file mode 100644 index 00000000..a91542f2 --- /dev/null +++ b/tests/cpp/rpytest/ft/include/operators.h @@ -0,0 +1,14 @@ +#pragma once + +class HasOperator { +public: + HasOperator() : m_i(0) {} + HasOperator(int i) : m_i(i) {} + + bool operator==(const HasOperator &o) const { + return m_i == o.m_i; + } + +private: + int m_i; +}; diff --git a/tests/cpp/rpytest/ft/include/overloads.h b/tests/cpp/rpytest/ft/include/overloads.h index 9bd9e393..fde7d06d 100644 --- a/tests/cpp/rpytest/ft/include/overloads.h +++ b/tests/cpp/rpytest/ft/include/overloads.h @@ -29,6 +29,11 @@ struct OverloadedObject return o; } + // This shows rtnType is inconsistent in CppHeaderParser + const OverloadedObject& overloaded() { + return *this; + } + constexpr int overloaded_constexpr(int a, int b) { return a + b; } diff --git a/tests/cpp/rpytest/ft/include/virtual_comma.h b/tests/cpp/rpytest/ft/include/virtual_comma.h index 0a149bad..f1898c3a 100644 --- a/tests/cpp/rpytest/ft/include/virtual_comma.h +++ b/tests/cpp/rpytest/ft/include/virtual_comma.h @@ -4,10 +4,19 @@ struct VirtualComma { + struct RVal {}; + virtual ~VirtualComma() {} virtual std::pair getTwoTwo() { return std::pair{1, 2}; } + + // ensures that RVal is recognized as VirtualComma::RVal + virtual RVal getRval() { + return RVal{}; + } + + int getRval(int) { return 1; } }; \ No newline at end of file diff --git a/tests/cpp/rpytest/ft/include/virtual_xform.h b/tests/cpp/rpytest/ft/include/virtual_xform.h index 44a3fb26..72d1c14e 100644 --- a/tests/cpp/rpytest/ft/include/virtual_xform.h +++ b/tests/cpp/rpytest/ft/include/virtual_xform.h @@ -5,6 +5,11 @@ struct VBase { + // overridden in yml but doesn't need vcheck + virtual int different_cpp_and_py(int x) { + return x + 1; + } + virtual void pure_io(std::stringstream &ss) = 0; virtual void impure_io(std::stringstream &ss) { @@ -39,3 +44,8 @@ std::string check_impure_io(VBase *base) base->impure_io(ss); return ss.str(); } + +int check_different_cpp_and_py(VBase *base, int x) +{ + return base->different_cpp_and_py(x); +} \ No newline at end of file diff --git a/tests/test_ft_inheritance.py b/tests/test_ft_inheritance.py index f0c4e749..37de6440 100644 --- a/tests/test_ft_inheritance.py +++ b/tests/test_ft_inheritance.py @@ -1,6 +1,16 @@ from rpytest import ft import pytest +import inspect + + +def _getdoc(f): + # ensures that the method is actually defined at the right + # place, not just being passed through the base virtual fn + line = inspect.getdoc(f).splitlines()[-1] + assert line.startswith("doc: ") + return line[5:] + # C++ check functions getBaseOnly = ft.IBase.getBaseOnly @@ -31,6 +41,13 @@ def test_inheritance_base(): assert getBaseAndChildFinal(b) == "base::baseAndChildFinal" assert getBaseAndGrandchild(b) == "base::baseAndGrandchild" + # docstring check + assert _getdoc(b.baseOnly) == "base::baseOnly" + assert _getdoc(b.baseAndChild) == "base::baseAndChild" + assert _getdoc(b.baseAndPyChild) == "base::baseAndPyChild" + assert _getdoc(b.baseAndChildFinal) == "base::baseAndChildFinal" + assert _getdoc(b.baseAndGrandchild) == "base::baseAndGrandchild" + def test_inheritance_pybase(): # Overridden version should be the same @@ -67,6 +84,13 @@ def test_inheritance_child(): assert getBaseAndChildFinal(c) == "child::baseAndChildFinal" assert getBaseAndGrandchild(c) == "base::baseAndGrandchild" + # docstring check + assert _getdoc(c.baseOnly) == "base::baseOnly" + assert _getdoc(c.baseAndChild) == "child::baseAndChild" + assert _getdoc(c.baseAndPyChild) == "base::baseAndPyChild" + assert _getdoc(c.baseAndChildFinal) == "child::baseAndChildFinal" + assert _getdoc(c.baseAndGrandchild) == "base::baseAndGrandchild" + class PyIChild(ft.IChild): def baseAndChild(self): @@ -118,6 +142,13 @@ def test_inheritance_grandchild(): assert getBaseAndChildFinal(g) == "child::baseAndChildFinal" assert getBaseAndGrandchild(g) == "grandchild::baseAndGrandchild" + # docstring check + assert _getdoc(g.baseOnly) == "base::baseOnly" + assert _getdoc(g.baseAndChild) == "child::baseAndChild" + assert _getdoc(g.baseAndPyChild) == "base::baseAndPyChild" + assert _getdoc(g.baseAndChildFinal) == "child::baseAndChildFinal" + assert _getdoc(g.baseAndGrandchild) == "grandchild::baseAndGrandchild" + def test_inheritance_pygrandchild(): # grandchild is final, so we cannot inherit from it @@ -143,6 +174,12 @@ def test_inheritance_mchild(): assert getBaseAndChildFinal(c) == "mchild::baseAndChildFinal" assert getBaseAndGrandchild(c) == "base::baseAndGrandchild" + # docstring check + assert _getdoc(c.baseOnly) == "base::baseOnly" + assert _getdoc(c.baseAndChild) == "mchild::baseAndChild" + assert _getdoc(c.baseAndChildFinal) == "mchild::baseAndChildFinal" + assert _getdoc(c.baseAndGrandchild) == "base::baseAndGrandchild" + class PyIMChild(ft.IMChild): def baseAndChild(self): diff --git a/tests/test_ft_misc.py b/tests/test_ft_misc.py index 5c4bd6bf..0dcc259a 100644 --- a/tests/test_ft_misc.py +++ b/tests/test_ft_misc.py @@ -80,6 +80,41 @@ def test_good_private_abstract(): assert ft.PrivateAbstract.getPrivateOverride(m) == 0x3 +# +# buffers.h +# + + +def test_buffers(): + o = ft.Buffers() + o.set_buffer(b"12345") + + b = bytearray(4) + l = o.get_buffer1(b) + assert b == b"1234" + assert l == 4 + + b = bytearray(4) + l = o.get_buffer2(b) + assert b == b"1234" + assert l == 4 + + +def test_buffers_v(): + o = ft.Buffers() + o.v_set_buffer(b"12345") + + b = bytearray(4) + l = o.v_get_buffer1(b) + assert b == b"1234" + assert l == 4 + + b = bytearray(4) + l = o.v_get_buffer2(b) + assert b == b"1234" + assert l == 4 + + # # factory.h # @@ -101,6 +136,25 @@ def test_inline_code(): assert o.get4() == 4 +def test_cpp_code_with_constant(): + o = ft.InlineCode() + assert o.cpp_code_with_constant() == 4 + + +# +# operators.h +# + + +def test_operators_eq(): + o1 = ft.HasOperator(1) + o1a = ft.HasOperator(1) + o2 = ft.HasOperator(2) + + assert o1 == o1a + assert not (o1 == o2) + + # # static_only.h # @@ -136,6 +190,9 @@ def test_virtual_xform(): assert base.impure_io() == "py vbase impure + c++ vbase impure" assert ft.check_impure_io(base) == "c++ vbase impure" + assert base.different_cpp_and_py(1) == 3 + assert ft.check_different_cpp_and_py(base, 1) == 2 + class PyChild(ft.VBase): def pure_io(self) -> str: return "pychild pure"