00001 #include <boost/test/auto_unit_test.hpp>
00002
00003 #include <test/testsuite.hh>
00004 #include <utilmm/configfile/configset.hh>
00005 #include <utilmm/stringtools.hh>
00006 #include <typelib/pluginmanager.hh>
00007 #include <typelib/importer.hh>
00008 #include <typelib/typemodel.hh>
00009 #include <typelib/registry.hh>
00010 #include <typelib/typedisplay.hh>
00011 #include <typesolver.hh>
00012 #include "test_cimport.1"
00013 #include <iostream>
00014
00015 #include <antlr/ANTLRException.hpp>
00016 using namespace Typelib;
00017 using namespace std;
00018 using utilmm::split;
00019 using utilmm::join;
00020
00021 static void import_test_types(Registry& registry)
00022 {
00023 static const char* test_file = TEST_DATA_PATH("test_cimport.h");
00024
00025 utilmm::config_set config;
00026 PluginManager::self manager;
00027 auto_ptr<Importer> importer(manager->importer("c"));
00028 config.set("include", TEST_DATA_PATH(".."));
00029 config.set("define", "GOOD");
00030 importer->load(test_file, config, registry);
00031 }
00032
00033 BOOST_AUTO_TEST_CASE( test_strict_c_import )
00034 {
00035 static const char* test_file = TEST_DATA_PATH("test_cimport.h");
00036 PluginManager::self manager;
00037 auto_ptr<Importer> importer(manager->importer("c"));
00038
00039 utilmm::config_set config;
00040 config.set("cxx", "false");
00041 config.set("include", TEST_DATA_PATH(".."));
00042 config.set("define", "GOOD");
00043 config.insert("define", "VALID_STRICT_C");
00044 Registry registry;
00045 importer->load(test_file, config, registry);
00046
00047 BOOST_CHECK( !registry.has("/NS1/NS2/Test") );
00048 BOOST_CHECK( !registry.has("/NS1/Test") );
00049 BOOST_CHECK( !registry.has("/NS1/Bla/Test") );
00050 BOOST_CHECK( registry.has("/NS1/NS2/struct Test") );
00051 BOOST_CHECK( registry.has("/NS1/struct Test") );
00052 BOOST_CHECK( registry.has("/NS1/Bla/struct Test") );
00053
00054 BOOST_CHECK( registry.has("/enum INPUT_OUTPUT_MODE") );
00055 BOOST_CHECK( registry.has("/INPUT_OUTPUT_MODE") );
00056 BOOST_CHECK_EQUAL( "/enum INPUT_OUTPUT_MODE", registry.get("/INPUT_OUTPUT_MODE")->getName() );
00057 }
00058
00059 static Type const& check_type(Registry const& registry, string const& name, size_t expected_size)
00060 {
00061
00062 string const typelib_name = join(split(name, "::"), "/");
00063
00064 Type const* object = registry.get(typelib_name);
00065 BOOST_REQUIRE_MESSAGE(object, name << " is not defined");
00066 BOOST_REQUIRE_MESSAGE(object->getSize() == expected_size, "size mismatch for " << name << " " << object->getSize() << " != (expected) " << expected_size << ": " << *object);
00067 return *object;
00068 }
00069 #define CHECK_TYPE(type) check_type(registry, #type, sizeof(type))
00070
00071 static void check_field(Registry const& registry, string const& compound_name, string const& field_name,
00072 size_t expected_offset, string const& expected_type, size_t expected_size)
00073 {
00074 string const typelib_compound_name = join(split(compound_name, "::"), "/");
00075 string const typelib_expected_name = join(split(expected_type, "::"), "/");
00076
00077 Compound const& compound_object = dynamic_cast<Compound const&>(*registry.get(typelib_compound_name));
00078 Field const* field_object = compound_object.getField(field_name);
00079 BOOST_REQUIRE(field_object);
00080 BOOST_REQUIRE_EQUAL(field_object->getOffset(), expected_offset);
00081 BOOST_REQUIRE_MESSAGE(
00082 (&(field_object->getType()) == registry.get(typelib_expected_name)),
00083 "expecting " << typelib_expected_name << ", got " <<
00084 field_object->getType().getName() << " for " << compound_name << "." << field_name);
00085 BOOST_REQUIRE_EQUAL(field_object->getType().getSize(), expected_size);
00086 }
00087
00088 #define CHECK_FIELD(compound, field, expected_type, expected_name) \
00089 { compound v; \
00090 size_t offset = reinterpret_cast<uint8_t*>(&v.field) - reinterpret_cast<uint8_t*>(&v); \
00091 check_field(registry, #compound, #field, offset, (expected_name ? expected_name : #expected_type), sizeof(expected_type)); }
00092
00093 BOOST_AUTO_TEST_CASE( test_c_import )
00094 {
00095 Registry registry;
00096 static const char* test_file = TEST_DATA_PATH("test_cimport.h");
00097
00098 PluginManager::self manager;
00099 auto_ptr<Importer> importer(manager->importer("c"));
00100
00101 {
00102 Registry temp_registry;
00103 utilmm::config_set config;
00104 config.set("include", TEST_DATA_PATH(".."));
00105 config.set("define", "GOOD");
00106 importer->load(test_file, config, temp_registry);
00107 }
00108 {
00109 Registry temp_registry;
00110 utilmm::config_set config;
00111 config.insert("rawflag", "-I" TEST_DATA_PATH(".."));
00112 config.insert("rawflag", "-DGOOD");
00113 importer->load(test_file, config, temp_registry);
00114 }
00115
00116 utilmm::config_set config;
00117
00118 BOOST_CHECK_THROW( importer->load("does_not_exist", config, registry), ImportError);
00119 BOOST_CHECK_THROW( importer->load(test_file, config, registry), ImportError );
00120 config.set("include", TEST_DATA_PATH(".."));
00121 config.set("define", "GOOD");
00122 importer->load(test_file, config, registry);
00123
00124
00125 CHECK_TYPE(struct A);
00126 CHECK_TYPE(struct B);
00127 CHECK_TYPE(ADef);
00128 CHECK_TYPE(B);
00129 CHECK_TYPE( struct A );
00130 CHECK_TYPE( struct B );
00131 CHECK_TYPE( ADef );
00132 Compound const& b = dynamic_cast<Compound const&>(CHECK_TYPE( B ));
00133 CHECK_TYPE( OPAQUE_TYPE );
00134 CHECK_TYPE( NS1::NS2::Test );
00135 CHECK_TYPE( NS1::Bla::Test );
00136 CHECK_FIELD(NS1::Test, b, NS1::Bla::Test, 0);
00137 CHECK_TYPE( NS1::Test );
00138 CHECK_TYPE( NS1::NS2::Test );
00139 CHECK_TYPE( NS1::Test );
00140 CHECK_TYPE( NS1::Bla::Test );
00141
00142
00143 BOOST_CHECK_EQUAL( "/NS1/NS2/Test", registry.get("/NS1/NS2/struct Test")->getName());
00144
00145
00146 CHECK_FIELD(B, a, ADef, 0);
00147
00148
00149 CHECK_FIELD(B, c, float[100], 0);
00150
00151
00152 CHECK_FIELD(B, d, float[1], 0);
00153 CHECK_FIELD(B, e, float[1], 0);
00154 CHECK_FIELD(B, f, float[3], 0);
00155 CHECK_FIELD(B, g, float[2], 0);
00156 CHECK_FIELD(B, h, A[4], 0);
00157 CHECK_FIELD(B, i, float[20][10], 0);
00158 CHECK_FIELD(B, x, float, 0);
00159 CHECK_FIELD(B, y, float, 0);
00160 CHECK_FIELD(B, z, float, 0);
00161
00162
00163
00164
00165
00166 Field const* b_i = b.getField("i");
00167 BOOST_CHECK_EQUAL( &(b_i->getType()), registry.get("/float[20][10]") );
00168
00169 Compound const* c = static_cast<Compound const*>(registry.get("/C"));
00170 Field const* c_x = c->getField("x");
00171 BOOST_CHECK_EQUAL( &(c_x->getType()), registry.get("/float[4]") );
00172 Field const* c_y = c->getField("y");
00173 BOOST_CHECK_EQUAL( &(c_y->getType()), registry.get("/float*") );
00174 Field const* c_z = c->getField("z");
00175 BOOST_CHECK_EQUAL( &(c_z->getType()), registry.get("/float") );
00176
00177
00178 Array const& b_c_array(dynamic_cast<Array const&>(b.getField("c")->getType()));
00179 BOOST_CHECK_EQUAL( &b_c_array.getIndirection(), registry.get("/float") );
00180 BOOST_CHECK_EQUAL( b_c_array.getDimension(), 100UL );
00181
00182
00183 BOOST_CHECK( registry.has("/DEFINE_STR") );
00184 BOOST_CHECK( registry.has("/DEFINE_ID") );
00185 BOOST_CHECK_EQUAL(Type::Compound, registry.get("/DEFINE_STR")->getCategory());
00186 BOOST_CHECK_EQUAL(Type::Pointer, registry.get("/DEFINE_ID")->getCategory());
00187 BOOST_CHECK( *registry.get("/DEFINE_STR") == static_cast<Pointer const*>(registry.get("/DEFINE_ID"))->getIndirection());
00188
00189
00190 BOOST_CHECK( registry.has("/Recursive") );
00191 BOOST_CHECK_EQUAL(Type::Compound, registry.get("/Recursive")->getCategory());
00192 Type const& recursive_ptr = static_cast<Compound const*>(registry.get("/Recursive"))->getField("next")->getType();
00193 BOOST_CHECK_EQUAL(Type::Pointer, recursive_ptr.getCategory());
00194 BOOST_CHECK( *registry.get("/Recursive") == static_cast<Pointer const&>(recursive_ptr).getIndirection());
00195
00196
00197 BOOST_CHECK( registry.has("/ANONYMOUS_ENUM") );
00198 BOOST_CHECK( registry.has("/ANONYMOUS_ENUM_PTR") );
00199 BOOST_CHECK_EQUAL(Type::Enum, registry.get("/ANONYMOUS_ENUM")->getCategory());
00200 BOOST_CHECK_EQUAL(Type::Pointer, registry.get("/ANONYMOUS_ENUM_PTR")->getCategory());
00201 BOOST_CHECK( *registry.get("/ANONYMOUS_ENUM") == static_cast<Pointer const*>(registry.get("/ANONYMOUS_ENUM_PTR"))->getIndirection());
00202
00203
00204 BOOST_CHECK( registry.has("/E") );
00205 BOOST_CHECK_EQUAL(registry.get("/E")->getCategory(), Type::Enum);
00206 Enum const& e(dynamic_cast<Enum const&>(*registry.get("/E")));
00207 Enum::ValueMap const& map = e.values();
00208
00209
00210 struct ExpectedValue
00211 {
00212 char const* name;
00213 int value;
00214 };
00215 ExpectedValue expected[] = {
00216 { "E_FIRST", E_FIRST },
00217 { "E_SECOND", E_SECOND },
00218 { "E_SET", E_SET },
00219 { "E_PARENS", E_PARENS },
00220 { "E_HEX", E_HEX },
00221 { "E_OCT", E_OCT },
00222 { "LAST", LAST },
00223 { "E_FROM_SYMBOL", E_FIRST + E_HEX },
00224 { "E_FROM_SIZEOF_STD", sizeof(int32_t) },
00225 { "E_FROM_SIZEOF_SPEC", sizeof(B) },
00226 { 0, 0 }
00227 };
00228
00229 for (ExpectedValue* exp_it = expected; exp_it->name; ++exp_it)
00230 {
00231 Enum::ValueMap::const_iterator it = map.find(exp_it->name);
00232 BOOST_REQUIRE( it != map.end() );
00233 BOOST_CHECK_EQUAL(exp_it->value, it->second);
00234 }
00235 }
00236
00237 BOOST_AUTO_TEST_CASE( test_std_collections )
00238 {
00239 Registry registry;
00240 import_test_types(registry);
00241
00242 CHECK_TYPE(StdCollections);
00243 CHECK_FIELD(StdCollections, iv, int, 0);
00244 CHECK_FIELD(StdCollections, dbl_vector, std::vector<double>, "/std/vector</double>");
00245 CHECK_FIELD(StdCollections, v8, int8_t, 0);
00246
00247 CHECK_FIELD(StdCollections, v16, int16_t, 0);
00248 CHECK_FIELD(StdCollections, v64, int64_t, 0);
00249
00250 Compound const& type = dynamic_cast<Compound const&>(*registry.get("/StdCollections"));
00251 StdCollections value;
00252 int padding = sizeof(StdCollections) -
00253 (reinterpret_cast<uint8_t*>(&value.padding) + sizeof(value.padding) - reinterpret_cast<uint8_t*>(&value));
00254 BOOST_REQUIRE_EQUAL(padding, type.getTrailingPadding());
00255
00256
00257
00258
00259
00260
00261
00262
00263 }
00264
00265 BOOST_AUTO_TEST_CASE( test_string_handling )
00266 {
00267 Registry registry;
00268 import_test_types(registry);
00269
00270 CHECK_TYPE(StringHandling);
00271 CHECK_FIELD(StringHandling, a, char, 0);
00272 CHECK_FIELD(StringHandling, b, std::string, "/std/string");
00273 CHECK_FIELD(StringHandling, c, short, 0);
00274 }
00275
00276 BOOST_AUTO_TEST_CASE( test_c_array_typedefs )
00277 {
00278 Registry registry;
00279 import_test_types(registry);
00280
00281 BOOST_REQUIRE(( registry.get("array_typedef") ));
00282 Array const* array_t = dynamic_cast<Typelib::Array const*>(registry.get("array_typedef"));
00283 BOOST_REQUIRE(( array_t ));
00284 BOOST_REQUIRE_EQUAL(256, array_t->getDimension());
00285 BOOST_REQUIRE_EQUAL(registry.get("int"), &array_t->getIndirection());
00286
00287 BOOST_REQUIRE(( registry.get("multi_array_typedef") ));
00288 array_t = dynamic_cast<Typelib::Array const*>(registry.get("multi_array_typedef"));
00289 BOOST_REQUIRE(( array_t ));
00290 BOOST_REQUIRE_EQUAL(256, array_t->getDimension());
00291 array_t = dynamic_cast<Typelib::Array const*>(&array_t->getIndirection());
00292 BOOST_REQUIRE_EQUAL(512, array_t->getDimension());
00293 BOOST_REQUIRE_EQUAL(registry.get("int"), &array_t->getIndirection());
00294 }
00295
00296 typedef double double_array10[10];
00297 typedef NS1::Test struct_array10[10];
00298 typedef std::vector<double> vector_double_array10[10];
00299 typedef std::vector<NS1::Test> vector_struct_array10[10];
00300
00301 BOOST_AUTO_TEST_CASE( test_arrays_of_containers )
00302 {
00303 Registry registry;
00304 import_test_types(registry);
00305
00306 Compound const& arrays_t =
00307 *dynamic_cast<Typelib::Compound const*>(registry.get("Arrays"));
00308 Array const& a_v_numeric_t =
00309 *dynamic_cast<Typelib::Array const*>(registry.get("/std/vector</double>[10]"));
00310 Array const& a_v_struct_t =
00311 *dynamic_cast<Typelib::Array const*>(registry.get("/std/vector</NS1/Test>[10]"));
00312
00313 BOOST_REQUIRE(&a_v_numeric_t);
00314 BOOST_REQUIRE(&a_v_struct_t);
00315 BOOST_REQUIRE(arrays_t.getField("a_v_numeric")->getType() == a_v_numeric_t);
00316 BOOST_REQUIRE(arrays_t.getField("a_v_struct")->getType() == a_v_struct_t);
00317
00318 CHECK_FIELD(Arrays, a_numeric, double_array10, "/double[10]");
00319 CHECK_FIELD(Arrays, a_struct, struct_array10, "/NS1::Test[10]");
00320 CHECK_FIELD(Arrays, a_v_numeric, vector_double_array10, "/std/vector</double>[10]");
00321 CHECK_FIELD(Arrays, a_v_struct, vector_struct_array10, "/std/vector</NS1/Test>[10]");
00322 }
00323
00324 BOOST_AUTO_TEST_CASE( test_import_validation )
00325 {
00326 utilmm::config_set config;
00327 PluginManager::self manager;
00328
00329 static const char* test1 = TEST_DATA_PATH("data/nested_types/struct_in_struct.h");
00330 BOOST_REQUIRE_THROW( manager->load("c", test1, config), TypeSolver::NestedTypeDefinition );
00331 static const char* test2 = TEST_DATA_PATH("data/nested_types/enum_in_struct.h");
00332 BOOST_REQUIRE_THROW( manager->load("c", test2, config), TypeSolver::NestedTypeDefinition );
00333 }
00334
00335 BOOST_AUTO_TEST_CASE( test_import_problematic_headers )
00336 {
00337 utilmm::config_set config;
00338 PluginManager::self manager;
00339
00340 {
00341 static const char* test_file = TEST_DATA_PATH("data/posterLib.h");
00342 delete manager->load("c", test_file, config);
00343 }
00344
00345
00346
00347
00348
00349 }
00350
00351 BOOST_AUTO_TEST_CASE( test_import_and_merge )
00352 {
00353 static const char* test_file = TEST_DATA_PATH("test_cimport.h");
00354
00355 utilmm::config_set config;
00356 config.set("include", TEST_DATA_PATH(".."));
00357 config.set("define", "GOOD");
00358 PluginManager::self manager;
00359
00360 { std::auto_ptr<Registry> r1(manager->load("c", test_file, config));
00361 std::auto_ptr<Registry> r2(manager->load("c", test_file, config));
00362 r1->merge(*r2);
00363 }
00364 { Registry target;
00365 std::auto_ptr<Registry> r1(manager->load("c", test_file, config));
00366 std::auto_ptr<Registry> r2(manager->load("c", test_file, config));
00367 target.merge(*r1);
00368 target.merge(*r2);
00369 }
00370 }
00371