$search
00001 #include <boost/test/auto_unit_test.hpp> 00002 00003 #include <test/testsuite.hh> 00004 #include <utilmm/configfile/configset.hh> 00005 #include <typelib/pluginmanager.hh> 00006 #include <typelib/importer.hh> 00007 #include <typelib/typemodel.hh> 00008 #include <typelib/registry.hh> 00009 #include <typelib/value.hh> 00010 #include <typelib/value_ops.hh> 00011 00012 #include <test/test_cimport.1> 00013 #include <string.h> 00014 00015 using namespace Typelib; 00016 using namespace std; 00017 00018 BOOST_AUTO_TEST_CASE( test_marshalling_simple ) 00019 { 00020 // Get the test file into repository 00021 Registry registry; 00022 PluginManager::self manager; 00023 auto_ptr<Importer> importer(manager->importer("tlb")); 00024 utilmm::config_set config; 00025 BOOST_REQUIRE_NO_THROW( importer->load(TEST_DATA_PATH("test_cimport.tlb"), config, registry) ); 00026 00027 /* Check a simple structure which translates into MEMCPY */ 00028 { 00029 Type const& type = *registry.get("/A"); 00030 A a; 00031 memset(&a, 1, sizeof(A)); 00032 a.a = 10000; 00033 a.b = 1000; 00034 a.c = 100; 00035 a.d = 10; 00036 vector<uint8_t> buffer = dump(Value(&a, type)); 00037 00038 size_t expected_dump_size = offsetof(A, d) + sizeof(a.d); 00039 BOOST_REQUIRE_EQUAL( buffer.size(), expected_dump_size); 00040 BOOST_REQUIRE( !memcmp(&buffer[0], &a, expected_dump_size) ); 00041 00042 A reloaded; 00043 load(Value(&reloaded, type), buffer); 00044 BOOST_REQUIRE( !memcmp(&reloaded, &a, expected_dump_size) ); 00045 00046 // Try (in order) 00047 // - smaller type 00048 // - bigger type 00049 // - bigger buffer 00050 // - smaller buffer 00051 BOOST_REQUIRE_THROW(load(Value(&reloaded, *registry.build("/int[200]")), buffer), std::runtime_error); 00052 BOOST_REQUIRE_THROW(load(Value(&reloaded, *registry.get("/int")), buffer), std::runtime_error); 00053 buffer.resize(buffer.size() + 2); 00054 BOOST_REQUIRE_THROW(load(Value(&reloaded, type), buffer), std::runtime_error); 00055 buffer.resize(buffer.size() - 4); 00056 BOOST_REQUIRE_THROW(load(Value(&reloaded, type), buffer), std::runtime_error); 00057 } 00058 00059 /* Now, insert SKIPS into it */ 00060 { 00061 A a; 00062 int align1 = offsetof(A, b) - sizeof(a.a); 00063 int align2 = offsetof(A, c) - sizeof(a.b) - offsetof(A, b); 00064 int align3 = offsetof(A, d) - sizeof(a.c) - offsetof(A, c); 00065 int align4 = sizeof(A) - sizeof(a.d) - offsetof(A, d); 00066 size_t raw_ops[] = { 00067 MemLayout::FLAG_MEMCPY, sizeof(long long), 00068 MemLayout::FLAG_SKIP, align1, 00069 MemLayout::FLAG_MEMCPY, sizeof(int), 00070 MemLayout::FLAG_SKIP, align2, 00071 MemLayout::FLAG_MEMCPY, sizeof(char), 00072 MemLayout::FLAG_SKIP, align3, 00073 MemLayout::FLAG_MEMCPY, sizeof(short) 00074 }; 00075 00076 MemoryLayout ops; 00077 ops.insert(ops.end(), raw_ops, raw_ops + 14); 00078 00079 Type const& type = *registry.get("/A"); 00080 memset(&a, 1, sizeof(A)); 00081 a.a = 10000; 00082 a.b = 1000; 00083 a.c = 100; 00084 a.d = 10; 00085 vector<uint8_t> buffer; 00086 dump(Value(&a, type), buffer, ops); 00087 BOOST_REQUIRE_EQUAL( sizeof(A) - align1 - align2 - align3 - align4, buffer.size()); 00088 BOOST_REQUIRE_EQUAL( *reinterpret_cast<long long*>(&buffer[0]), a.a ); 00089 00090 A reloaded; 00091 memset(&reloaded, 2, sizeof(A)); 00092 load(Value(&reloaded, type), buffer, ops); 00093 BOOST_REQUIRE_EQUAL(-1, memcmp(&a, &reloaded, sizeof(A))); 00094 BOOST_REQUIRE_EQUAL(a.a, reloaded.a); 00095 BOOST_REQUIRE_EQUAL(a.b, reloaded.b); 00096 BOOST_REQUIRE_EQUAL(a.c, reloaded.c); 00097 BOOST_REQUIRE_EQUAL(a.d, reloaded.d); 00098 } 00099 00100 // And now check the array semantics 00101 { 00102 B b; 00103 for (unsigned int i = 0; i < sizeof(b); ++i) 00104 reinterpret_cast<uint8_t*>(&b)[i] = rand(); 00105 00106 size_t raw_ops[] = { 00107 MemLayout::FLAG_MEMCPY, offsetof(B, c), 00108 MemLayout::FLAG_ARRAY, 100, 00109 MemLayout::FLAG_MEMCPY, sizeof(b.c[0]), 00110 MemLayout::FLAG_END, 00111 MemLayout::FLAG_MEMCPY, sizeof(B) - offsetof(B, d) 00112 }; 00113 00114 MemoryLayout ops; 00115 ops.insert(ops.end(), raw_ops, raw_ops + 9); 00116 00117 Type const& type = *registry.get("/B"); 00118 vector<uint8_t> buffer; 00119 dump(Value(&b, type), buffer, ops); 00120 BOOST_REQUIRE_EQUAL( sizeof(B), buffer.size()); 00121 BOOST_REQUIRE(!memcmp(&buffer[0], &b, sizeof(B))); 00122 00123 B reloaded; 00124 load(Value(&reloaded, type), buffer, ops); 00125 BOOST_REQUIRE(!memcmp(&b, &reloaded, sizeof(B))); 00126 } 00127 } 00128 00129 template<typename T> 00130 size_t CHECK_SIMPLE_VALUE(vector<uint8_t> const& buffer, size_t offset, T value) 00131 { 00132 BOOST_REQUIRE_EQUAL(value, *reinterpret_cast<T const*>(&buffer[offset])); 00133 return offset + sizeof(T); 00134 } 00135 00136 template<typename T> 00137 size_t CHECK_VECTOR_VALUE(vector<uint8_t> const& buffer, size_t offset, vector<T> const& value) 00138 { 00139 // First, check for the size 00140 offset = CHECK_SIMPLE_VALUE(buffer, offset, static_cast<uint64_t>(value.size())); 00141 // Then for the elements 00142 for (size_t i = 0; i < value.size(); ++i) 00143 offset = CHECK_SIMPLE_VALUE(buffer, offset, value[i]); 00144 return offset; 00145 } 00146 00147 BOOST_AUTO_TEST_CASE(test_marshalapply_containers) 00148 { 00149 // Get the test file into repository 00150 Registry registry; 00151 PluginManager::self manager; 00152 auto_ptr<Importer> importer(manager->importer("tlb")); 00153 utilmm::config_set config; 00154 BOOST_REQUIRE_NO_THROW( importer->load(TEST_DATA_PATH("test_cimport.tlb"), config, registry) ); 00155 00156 StdCollections offset_discovery; 00157 uint8_t* base_ptr = reinterpret_cast<uint8_t*>(&offset_discovery); 00158 size_t off_dbl_vector = reinterpret_cast<uint8_t*>(&offset_discovery.dbl_vector) - base_ptr; 00159 size_t off_v8 = reinterpret_cast<uint8_t*>(&offset_discovery.v8) - base_ptr; 00160 size_t off_v_of_v = reinterpret_cast<uint8_t*>(&offset_discovery.v_of_v) - base_ptr; 00161 00162 { 00163 StdCollections data; 00164 data.iv = 10; 00165 data.dbl_vector.resize(5); 00166 for (int i = 0; i < 5; ++i) 00167 data.dbl_vector[i] = 0.01 * i; 00168 data.v8 = -106; 00169 data.v_of_v.resize(5); 00170 for (int i = 0; i < 5; ++i) 00171 { 00172 data.v_of_v[i].resize(3); 00173 for (int j = 0; j < 3; ++j) 00174 data.v_of_v[i][j] = i * 10 + j; 00175 } 00176 data.v16 = 5235; 00177 data.v64 = 5230971546LL; 00178 00179 Type const& type = *registry.get("/StdCollections"); 00180 vector<uint8_t> buffer = dump(Value(&data, type)); 00181 00182 size_t size_without_trailing_padding = 00183 reinterpret_cast<uint8_t const*>(&data.padding) + sizeof(data.padding) - reinterpret_cast<uint8_t const*>(&data) 00184 - sizeof(std::vector<double>) - sizeof (std::vector< std::vector<double> >) 00185 + sizeof(double) * 20 // elements 00186 + 7 * sizeof(uint64_t); 00187 00188 BOOST_REQUIRE_EQUAL( buffer.size(), size_without_trailing_padding ); 00189 00190 CHECK_SIMPLE_VALUE(buffer, 0, data.iv); 00191 size_t pos = CHECK_VECTOR_VALUE(buffer, off_dbl_vector, data.dbl_vector); 00192 CHECK_SIMPLE_VALUE(buffer, pos, data.v8); 00193 00194 pos = CHECK_SIMPLE_VALUE(buffer, pos + off_v_of_v - off_v8, static_cast<uint64_t>(data.v_of_v.size())); 00195 for (int i = 0; i < 5; ++i) 00196 pos = CHECK_VECTOR_VALUE(buffer, pos, data.v_of_v[i]); 00197 00198 StdCollections reloaded; 00199 load(Value(&reloaded, type), buffer); 00200 BOOST_REQUIRE( data.iv == reloaded.iv ); 00201 BOOST_REQUIRE( data.dbl_vector == reloaded.dbl_vector ); 00202 BOOST_REQUIRE( data.v8 == reloaded.v8 ); 00203 BOOST_REQUIRE( data.v16 == reloaded.v16 ); 00204 BOOST_REQUIRE( data.v64 == reloaded.v64 ); 00205 BOOST_REQUIRE( data.padding == reloaded.padding ); 00206 00207 // Now, add the trailing bytes back. The load method should be OK with 00208 // it 00209 size_t size_with_trailing_padding = 00210 sizeof(StdCollections) 00211 - sizeof(std::vector<double>) - sizeof (std::vector< std::vector<double> >) 00212 + sizeof(double) * 20 // elements 00213 + 7 * sizeof(uint64_t); // element counts 00214 00215 buffer.insert(buffer.end(), size_with_trailing_padding - size_without_trailing_padding, 0); 00216 { 00217 StdCollections reloaded; 00218 load(Value(&reloaded, type), buffer); 00219 BOOST_REQUIRE( data.iv == reloaded.iv ); 00220 BOOST_REQUIRE( data.dbl_vector == reloaded.dbl_vector ); 00221 BOOST_REQUIRE( data.v8 == reloaded.v8 ); 00222 BOOST_REQUIRE( data.v16 == reloaded.v16 ); 00223 BOOST_REQUIRE( data.v64 == reloaded.v64 ); 00224 BOOST_REQUIRE( data.padding == reloaded.padding ); 00225 } 00226 } 00227 00228 { 00229 StdCollections data; 00230 00231 data.iv = 0; 00232 data.v8 = 1; 00233 data.v_of_v.resize(5); 00234 data.v16 = 2; 00235 data.v64 = 3; 00236 00237 Type const& type = *registry.get("/StdCollections"); 00238 vector<uint8_t> buffer = dump(Value(&data, type)); 00239 size_t size_without_trailing_padding = 00240 reinterpret_cast<uint8_t const*>(&data.padding) + sizeof(data.padding) - reinterpret_cast<uint8_t const*>(&data); 00241 BOOST_REQUIRE_EQUAL( buffer.size(), 00242 size_without_trailing_padding - sizeof(std::vector<double>) - sizeof (std::vector< std::vector<double> >) 00243 + 7 * sizeof(uint64_t)); // element counts 00244 00245 CHECK_SIMPLE_VALUE(buffer, 0, data.iv); 00246 size_t pos = CHECK_VECTOR_VALUE(buffer, off_dbl_vector, data.dbl_vector); 00247 CHECK_SIMPLE_VALUE(buffer, pos, data.v8); 00248 00249 pos = CHECK_SIMPLE_VALUE(buffer, pos + off_v_of_v - off_v8, static_cast<uint64_t>(data.v_of_v.size())); 00250 for (int i = 0; i < 5; ++i) 00251 pos = CHECK_VECTOR_VALUE(buffer, pos, data.v_of_v[i]); 00252 } 00253 } 00254