test_lang_c.cc
Go to the documentation of this file.
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 


typelib
Author(s): Sylvain Joyeux/sylvain.joyeux@m4x.org
autogenerated on Thu Jan 2 2014 11:38:41