""" GTSAM Copyright 2010-2020, Georgia Tech Research Corporation, Atlanta, Georgia 30332-0415 All Rights Reserved See LICENSE for the license information Tests for interface_parser. Author: Varun Agrawal """ # pylint: disable=import-error,wrong-import-position import os import sys import unittest sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from gtwrap.interface_parser import ( ArgumentList, Class, Constructor, ForwardDeclaration, GlobalFunction, Include, Method, Module, Namespace, Operator, ReturnType, StaticMethod, TemplatedType, Type, TypedefTemplateInstantiation, Typename, Variable) class TestInterfaceParser(unittest.TestCase): """Test driver for all classes in interface_parser.py.""" def test_typename(self): """Test parsing of Typename.""" typename = Typename.rule.parseString("size_t")[0] self.assertEqual("size_t", typename.name) def test_basic_type(self): """Tests for BasicType.""" # Check basis type t = Type.rule.parseString("int x")[0] self.assertEqual("int", t.typename.name) self.assertTrue(t.is_basic) # Check const t = Type.rule.parseString("const int x")[0] self.assertEqual("int", t.typename.name) self.assertTrue(t.is_basic) self.assertTrue(t.is_const) # Check shared pointer t = Type.rule.parseString("int* x")[0] self.assertEqual("int", t.typename.name) self.assertTrue(t.is_shared_ptr) # Check raw pointer t = Type.rule.parseString("int@ x")[0] self.assertEqual("int", t.typename.name) self.assertTrue(t.is_ptr) # Check reference t = Type.rule.parseString("int& x")[0] self.assertEqual("int", t.typename.name) self.assertTrue(t.is_ref) # Check const reference t = Type.rule.parseString("const int& x")[0] self.assertEqual("int", t.typename.name) self.assertTrue(t.is_const) self.assertTrue(t.is_ref) def test_custom_type(self): """Tests for CustomType.""" # Check qualified type t = Type.rule.parseString("gtsam::Pose3 x")[0] self.assertEqual("Pose3", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertTrue(not t.is_basic) # Check const t = Type.rule.parseString("const gtsam::Pose3 x")[0] self.assertEqual("Pose3", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertTrue(t.is_const) # Check shared pointer t = Type.rule.parseString("gtsam::Pose3* x")[0] self.assertEqual("Pose3", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertTrue(t.is_shared_ptr) self.assertEqual("std::shared_ptr", t.to_cpp(use_boost=False)) self.assertEqual("boost::shared_ptr", t.to_cpp(use_boost=True)) # Check raw pointer t = Type.rule.parseString("gtsam::Pose3@ x")[0] self.assertEqual("Pose3", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertTrue(t.is_ptr) # Check reference t = Type.rule.parseString("gtsam::Pose3& x")[0] self.assertEqual("Pose3", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertTrue(t.is_ref) # Check const reference t = Type.rule.parseString("const gtsam::Pose3& x")[0] self.assertEqual("Pose3", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertTrue(t.is_const) self.assertTrue(t.is_ref) def test_templated_type(self): """Test a templated type.""" t = TemplatedType.rule.parseString("Eigen::Matrix")[0] self.assertEqual("Matrix", t.typename.name) self.assertEqual(["Eigen"], t.typename.namespaces) self.assertEqual("double", t.typename.instantiations[0].name) self.assertEqual("3", t.typename.instantiations[1].name) self.assertEqual("4", t.typename.instantiations[2].name) t = TemplatedType.rule.parseString( "gtsam::PinholeCamera")[0] self.assertEqual("PinholeCamera", t.typename.name) self.assertEqual(["gtsam"], t.typename.namespaces) self.assertEqual("Cal3S2", t.typename.instantiations[0].name) self.assertEqual(["gtsam"], t.typename.instantiations[0].namespaces) t = TemplatedType.rule.parseString("PinholeCamera")[0] self.assertEqual("PinholeCamera", t.typename.name) self.assertEqual("Cal3S2", t.typename.instantiations[0].name) self.assertTrue(t.template_params[0].is_shared_ptr) def test_empty_arguments(self): """Test no arguments.""" empty_args = ArgumentList.rule.parseString("")[0] self.assertEqual(0, len(empty_args)) def test_argument_list(self): """Test arguments list for a method/function.""" arg_string = "int a, C1 c1, C2& c2, C3* c3, "\ "const C4 c4, const C5& c5,"\ "const C6* c6" args = ArgumentList.rule.parseString(arg_string)[0] self.assertEqual(7, len(args.args_list)) self.assertEqual(['a', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6'], args.args_names()) def test_argument_list_qualifiers(self): """ Test arguments list where the arguments are qualified with `const` and can be either raw pointers, shared pointers or references. """ arg_string = "double x1, double* x2, double& x3, double@ x4, " \ "const double x5, const double* x6, const double& x7, const double@ x8" args = ArgumentList.rule.parseString(arg_string)[0].args_list self.assertEqual(8, len(args)) self.assertFalse(args[1].ctype.is_ptr and args[1].ctype.is_shared_ptr and args[1].ctype.is_ref) self.assertTrue(args[1].ctype.is_shared_ptr) self.assertTrue(args[2].ctype.is_ref) self.assertTrue(args[3].ctype.is_ptr) self.assertTrue(args[4].ctype.is_const) self.assertTrue(args[5].ctype.is_shared_ptr and args[5].ctype.is_const) self.assertTrue(args[6].ctype.is_ref and args[6].ctype.is_const) self.assertTrue(args[7].ctype.is_ptr and args[7].ctype.is_const) def test_argument_list_templated(self): """Test arguments list where the arguments can be templated.""" arg_string = "std::pair steps, vector vector_of_pointers" args = ArgumentList.rule.parseString(arg_string)[0] args_list = args.args_list self.assertEqual(2, len(args_list)) self.assertEqual("std::pair", args_list[0].ctype.to_cpp(False)) self.assertEqual("vector>", args_list[1].ctype.to_cpp(False)) self.assertEqual("vector>", args_list[1].ctype.to_cpp(True)) def test_default_arguments(self): """Tests any expression that is a valid default argument""" args = ArgumentList.rule.parseString( "string s=\"hello\", int a=3, " "int b, double pi = 3.1415, " "gtsam::KeyFormatter kf = gtsam::DefaultKeyFormatter, " "std::vector p = std::vector(), " "std::vector l = (1, 2, 'name', \"random\", 3.1415)" )[0].args_list # Test for basic types self.assertEqual(args[0].default, "hello") self.assertEqual(args[1].default, 3) # '' is falsy so we can check against it self.assertEqual(args[2].default, '') self.assertFalse(args[2].default) self.assertEqual(args[3].default, 3.1415) # Test non-basic type self.assertEqual(repr(args[4].default.typename), 'gtsam::DefaultKeyFormatter') # Test templated type self.assertEqual(repr(args[5].default.typename), 'std::vector') # Test for allowing list as default argument print(args) self.assertEqual(args[6].default, (1, 2, 'name', "random", 3.1415)) def test_return_type(self): """Test ReturnType""" # Test void return_type = ReturnType.rule.parseString("void")[0] self.assertEqual("void", return_type.type1.typename.name) self.assertTrue(return_type.type1.is_basic) # Test basis type return_type = ReturnType.rule.parseString("size_t")[0] self.assertEqual("size_t", return_type.type1.typename.name) self.assertTrue(not return_type.type2) self.assertTrue(return_type.type1.is_basic) # Test with qualifiers return_type = ReturnType.rule.parseString("int&")[0] self.assertEqual("int", return_type.type1.typename.name) self.assertTrue(return_type.type1.is_basic and return_type.type1.is_ref) return_type = ReturnType.rule.parseString("const int")[0] self.assertEqual("int", return_type.type1.typename.name) self.assertTrue(return_type.type1.is_basic and return_type.type1.is_const) # Test pair return return_type = ReturnType.rule.parseString("pair")[0] self.assertEqual("char", return_type.type1.typename.name) self.assertEqual("int", return_type.type2.typename.name) def test_method(self): """Test for a class method.""" ret = Method.rule.parseString("int f();")[0] self.assertEqual("f", ret.name) self.assertEqual(0, len(ret.args)) self.assertTrue(not ret.is_const) ret = Method.rule.parseString("int f() const;")[0] self.assertEqual("f", ret.name) self.assertEqual(0, len(ret.args)) self.assertTrue(ret.is_const) ret = Method.rule.parseString( "int f(const int x, const Class& c, Class* t) const;")[0] self.assertEqual("f", ret.name) self.assertEqual(3, len(ret.args)) def test_static_method(self): """Test for static methods.""" ret = StaticMethod.rule.parseString("static int f();")[0] self.assertEqual("f", ret.name) self.assertEqual(0, len(ret.args)) ret = StaticMethod.rule.parseString( "static int f(const int x, const Class& c, Class* t);")[0] self.assertEqual("f", ret.name) self.assertEqual(3, len(ret.args)) def test_constructor(self): """Test for class constructor.""" ret = Constructor.rule.parseString("f();")[0] self.assertEqual("f", ret.name) self.assertEqual(0, len(ret.args)) ret = Constructor.rule.parseString( "f(const int x, const Class& c, Class* t);")[0] self.assertEqual("f", ret.name) self.assertEqual(3, len(ret.args)) def test_operator_overload(self): """Test for operator overloading.""" # Unary operator wrap_string = "gtsam::Vector2 operator-() const;" ret = Operator.rule.parseString(wrap_string)[0] self.assertEqual("operator", ret.name) self.assertEqual("-", ret.operator) self.assertEqual("Vector2", ret.return_type.type1.typename.name) self.assertEqual("gtsam::Vector2", ret.return_type.type1.typename.to_cpp()) self.assertTrue(len(ret.args) == 0) self.assertTrue(ret.is_unary) # Binary operator wrap_string = "gtsam::Vector2 operator*(const gtsam::Vector2 &v) const;" ret = Operator.rule.parseString(wrap_string)[0] self.assertEqual("operator", ret.name) self.assertEqual("*", ret.operator) self.assertEqual("Vector2", ret.return_type.type1.typename.name) self.assertEqual("gtsam::Vector2", ret.return_type.type1.typename.to_cpp()) self.assertTrue(len(ret.args) == 1) self.assertEqual("const gtsam::Vector2 &", repr(ret.args.args_list[0].ctype)) self.assertTrue(not ret.is_unary) def test_typedef_template_instantiation(self): """Test for typedef'd instantiation of a template.""" typedef = TypedefTemplateInstantiation.rule.parseString(""" typedef gtsam::BearingFactor BearingFactor2D; """)[0] self.assertEqual("BearingFactor2D", typedef.new_name) self.assertEqual("BearingFactor", typedef.typename.name) self.assertEqual(["gtsam"], typedef.typename.namespaces) self.assertEqual(3, len(typedef.typename.instantiations)) def test_base_class(self): """Test a base class.""" ret = Class.rule.parseString(""" virtual class Base { }; """)[0] self.assertEqual("Base", ret.name) self.assertEqual(0, len(ret.ctors)) self.assertEqual(0, len(ret.methods)) self.assertEqual(0, len(ret.static_methods)) self.assertEqual(0, len(ret.properties)) self.assertTrue(ret.is_virtual) def test_empty_class(self): """Test an empty class declaration.""" ret = Class.rule.parseString(""" class FactorIndices {}; """)[0] self.assertEqual("FactorIndices", ret.name) self.assertEqual(0, len(ret.ctors)) self.assertEqual(0, len(ret.methods)) self.assertEqual(0, len(ret.static_methods)) self.assertEqual(0, len(ret.properties)) self.assertTrue(not ret.is_virtual) def test_class(self): """Test a non-trivial class.""" ret = Class.rule.parseString(""" class SymbolicFactorGraph { SymbolicFactorGraph(); SymbolicFactorGraph(const gtsam::SymbolicBayesNet& bayesNet); SymbolicFactorGraph(const gtsam::SymbolicBayesTree& bayesTree); // Dummy static method static gtsam::SymbolidFactorGraph CreateGraph(); void push_back(gtsam::SymbolicFactor* factor); void print(string s) const; bool equals(const gtsam::SymbolicFactorGraph& rhs, double tol) const; size_t size() const; bool exists(size_t idx) const; // Standard interface gtsam::KeySet keys() const; void push_back(const gtsam::SymbolicFactorGraph& graph); void push_back(const gtsam::SymbolicBayesNet& bayesNet); void push_back(const gtsam::SymbolicBayesTree& bayesTree); /* Advanced interface */ void push_factor(size_t key); void push_factor(size_t key1, size_t key2); void push_factor(size_t key1, size_t key2, size_t key3); void push_factor(size_t key1, size_t key2, size_t key3, size_t key4); gtsam::SymbolicBayesNet* eliminateSequential(); gtsam::SymbolicBayesNet* eliminateSequential( const gtsam::Ordering& ordering); gtsam::SymbolicBayesTree* eliminateMultifrontal(); gtsam::SymbolicBayesTree* eliminateMultifrontal( const gtsam::Ordering& ordering); pair eliminatePartialSequential(const gtsam::Ordering& ordering); pair eliminatePartialSequential(const gtsam::KeyVector& keys); pair eliminatePartialMultifrontal(const gtsam::Ordering& ordering); gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet( const gtsam::Ordering& ordering); gtsam::SymbolicBayesNet* marginalMultifrontalBayesNet( const gtsam::KeyVector& key_vector, const gtsam::Ordering& marginalizedVariableOrdering); gtsam::SymbolicFactorGraph* marginal(const gtsam::KeyVector& key_vector); }; """)[0] self.assertEqual("SymbolicFactorGraph", ret.name) self.assertEqual(3, len(ret.ctors)) self.assertEqual(23, len(ret.methods)) self.assertEqual(1, len(ret.static_methods)) self.assertEqual(0, len(ret.properties)) self.assertTrue(not ret.is_virtual) def test_class_inheritance(self): """Test for class inheritance.""" ret = Class.rule.parseString(""" virtual class Null: gtsam::noiseModel::mEstimator::Base { Null(); void print(string s) const; static gtsam::noiseModel::mEstimator::Null* Create(); // enabling serialization functionality void serializable() const; }; """)[0] self.assertEqual("Null", ret.name) self.assertEqual(1, len(ret.ctors)) self.assertEqual(2, len(ret.methods)) self.assertEqual(1, len(ret.static_methods)) self.assertEqual(0, len(ret.properties)) self.assertEqual("Base", ret.parent_class.name) self.assertEqual(["gtsam", "noiseModel", "mEstimator"], ret.parent_class.namespaces) self.assertTrue(ret.is_virtual) ret = Class.rule.parseString( "class ForwardKinematicsFactor : gtsam::BetweenFactor {};" )[0] self.assertEqual("ForwardKinematicsFactor", ret.name) self.assertEqual("BetweenFactor", ret.parent_class.name) self.assertEqual(["gtsam"], ret.parent_class.namespaces) self.assertEqual("Pose3", ret.parent_class.instantiations[0].name) self.assertEqual(["gtsam"], ret.parent_class.instantiations[0].namespaces) def test_include(self): """Test for include statements.""" include = Include.rule.parseString( "#include ")[0] self.assertEqual("gtsam/slam/PriorFactor.h", include.header) def test_forward_declaration(self): """Test for forward declarations.""" fwd = ForwardDeclaration.rule.parseString( "virtual class Test:gtsam::Point3;")[0] fwd_name = fwd.name self.assertEqual("Test", fwd_name.name) self.assertTrue(fwd.is_virtual) def test_function(self): """Test for global/free function.""" func = GlobalFunction.rule.parseString(""" gtsam::Values localToWorld(const gtsam::Values& local, const gtsam::Pose2& base, const gtsam::KeyVector& keys); """)[0] self.assertEqual("localToWorld", func.name) self.assertEqual("Values", func.return_type.type1.typename.name) self.assertEqual(3, len(func.args)) def test_global_variable(self): """Test for global variable.""" variable = Variable.rule.parseString("string kGravity;")[0] self.assertEqual(variable.name, "kGravity") self.assertEqual(variable.ctype.typename.name, "string") variable = Variable.rule.parseString("string kGravity = 9.81;")[0] self.assertEqual(variable.name, "kGravity") self.assertEqual(variable.ctype.typename.name, "string") self.assertEqual(variable.default, 9.81) variable = Variable.rule.parseString("const string kGravity = 9.81;")[0] self.assertEqual(variable.name, "kGravity") self.assertEqual(variable.ctype.typename.name, "string") self.assertTrue(variable.ctype.is_const) self.assertEqual(variable.default, 9.81) def test_namespace(self): """Test for namespace parsing.""" namespace = Namespace.rule.parseString(""" namespace gtsam { #include class Point2 { Point2(); Point2(double x, double y); double x() const; double y() const; int dim() const; char returnChar() const; void argChar(char a) const; void argUChar(unsigned char a) const; }; #include class Point3 { Point3(double x, double y, double z); double norm() const; // static functions - use static keyword and uppercase static double staticFunction(); static gtsam::Point3 StaticFunctionRet(double z); // enabling serialization functionality void serialize() const; // Just triggers a flag internally }; }""")[0] self.assertEqual("gtsam", namespace.name) def test_module(self): """Test module parsing.""" module = Module.parseString(""" namespace one { namespace two { namespace three { class Class123 { }; } class Class12a { }; } namespace two_dummy { namespace three_dummy{ } namespace fourth_dummy{ } } namespace two { class Class12b { }; } int oneVar; } class Global{ }; int globalVar; """) # print("module: ", module) # print(dir(module.content[0].name)) self.assertEqual(["one", "Global", "globalVar"], [x.name for x in module.content]) self.assertEqual(["two", "two_dummy", "two", "oneVar"], [x.name for x in module.content[0].content]) if __name__ == '__main__': unittest.main()