$search
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 // Replace the '::' in +name+ by '/' 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 // Load the file in registry 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 // Check that the types are defined 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 // In C++ mode, the main type is without any leading prefix 00143 BOOST_CHECK_EQUAL( "/NS1/NS2/Test", registry.get("/NS1/NS2/struct Test")->getName()); 00144 00145 // Check that the size of B.a is the same as A 00146 CHECK_FIELD(B, a, ADef, 0); 00147 00148 // Check the type of c (array of floats) 00149 CHECK_FIELD(B, c, float[100], 0); 00150 00151 // Check the sizes for various ways of defining integer constants 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 // order of indexes of multi-dimensional arrays are reverse than the 00163 // ones in C because we always read dimensions from right to left 00164 // (i.e. b.i is supposed to be a (array of 10 elements of (array of 00165 // 20 elements of floats)) 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 // Check the array indirection 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 // Test the forms of DEFINE_STR and DEFINE_ID (anonymous structure and pointer-to-struct) 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 // Test definition of recursive structures 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 // Test the forms of ANONYMOUS_ENUM and ANONYMOUS_ENUM_PTR 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 // Check the enum behaviour 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 // Check that the values in Enum are the ones we are expecting 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 //CHECK_FIELD(StdCollections, float_set, std::set<float>, "/std/set</float>"); 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 // Unfortunately, cannot check this one automatically 00257 // Compound const& collections = dynamic_cast<Compound const&>(*registry.get("StdCollections")); 00258 // Field const* field = collections.getField("int_map"); 00259 // BOOST_REQUIRE(field); 00260 00261 // BOOST_REQUIRE_MESSAGE(&field->getType() == registry.get("/std/map</int,/int>"), 00262 // field->getType().getName()); 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 // static const char* test_file = TEST_DATA_PATH("data/stdheaders.h"); 00347 // delete manager->load("c", test_file, config); 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