|
18 | 18 | #include <gtest/gtest.h> |
19 | 19 |
|
20 | 20 | using namespace ::testing; |
21 | | -using executorch::extension::BufferDataLoader; |
22 | | -using executorch::extension::FileDataLoader; |
23 | | -using executorch::extension::FlatTensorDataMap; |
24 | | -using executorch::runtime::DataLoader; |
25 | | -using executorch::runtime::Error; |
26 | | -using executorch::runtime::FreeableBuffer; |
27 | | -using executorch::runtime::Result; |
28 | | -using executorch::runtime::TensorLayout; |
| 21 | +using namespace executorch::extension; |
| 22 | +using namespace executorch::runtime; |
29 | 23 |
|
30 | 24 | class FlatTensorDataMapTest : public ::testing::Test { |
31 | 25 | protected: |
@@ -181,3 +175,94 @@ TEST_F(FlatTensorDataMapTest, LoadAndCheckSize) { |
181 | 175 | FlatTensorDataMap::load(&truncated_loader); |
182 | 176 | ASSERT_EQ(truncated_program.error(), Error::InvalidExternalData); |
183 | 177 | } |
| 178 | + |
| 179 | +namespace { |
| 180 | + |
| 181 | +constexpr size_t kAlignment = 16; |
| 182 | + |
| 183 | +size_t aligned_up(size_t size) { |
| 184 | + return (size + kAlignment - 1) & ~(kAlignment - 1); |
| 185 | +} |
| 186 | + |
| 187 | +// Builds the smallest PTD file that FlatTensorDataMap::load() accepts, stamped |
| 188 | +// with the given schema version and holding no data. Follows the layout written |
| 189 | +// by save_ptd(): the header is embedded in the flatbuffer region, so the offset |
| 190 | +// to the root table shifts by the size of the header. |
| 191 | +std::vector<uint8_t> CreateDataWithVersion(uint32_t version) { |
| 192 | + flatbuffers::FlatBufferBuilder builder; |
| 193 | + auto flat_tensor = flat_tensor_flatbuffer::CreateFlatTensor( |
| 194 | + builder, |
| 195 | + version, |
| 196 | + builder.CreateVector( |
| 197 | + std::vector< |
| 198 | + flatbuffers::Offset<flat_tensor_flatbuffer::DataSegment>>{}), |
| 199 | + builder.CreateVector( |
| 200 | + std::vector< |
| 201 | + flatbuffers::Offset<flat_tensor_flatbuffer::NamedData>>{})); |
| 202 | + builder.Finish(flat_tensor, flat_tensor_flatbuffer::FlatTensorIdentifier()); |
| 203 | + |
| 204 | + const uint8_t* flatbuffer = builder.GetBufferPointer(); |
| 205 | + const size_t flatbuffer_size = builder.GetSize(); |
| 206 | + const size_t header_size = |
| 207 | + aligned_up(FlatTensorHeader::kHeaderExpectedLength); |
| 208 | + |
| 209 | + std::vector<uint8_t> data; |
| 210 | + auto append = [&data](const void* bytes, size_t size) { |
| 211 | + const uint8_t* begin = static_cast<const uint8_t*>(bytes); |
| 212 | + data.insert(data.end(), begin, begin + size); |
| 213 | + }; |
| 214 | + |
| 215 | + uint32_t root_table_offset = *reinterpret_cast<const uint32_t*>(flatbuffer) + |
| 216 | + static_cast<uint32_t>(header_size); |
| 217 | + append(&root_table_offset, sizeof(root_table_offset)); |
| 218 | + append(flatbuffer + sizeof(root_table_offset), 4); // File identifier. |
| 219 | + |
| 220 | + append(FlatTensorHeader::kMagic, sizeof(FlatTensorHeader::kMagic)); |
| 221 | + uint32_t header_length = FlatTensorHeader::kHeaderExpectedLength; |
| 222 | + append(&header_length, sizeof(header_length)); |
| 223 | + uint64_t header_fields[] = { |
| 224 | + header_size, // Offset to the flatbuffer. |
| 225 | + flatbuffer_size, |
| 226 | + header_size + aligned_up(flatbuffer_size), // Offset to the segments. |
| 227 | + 0, // Segment data size. |
| 228 | + }; |
| 229 | + append(header_fields, sizeof(header_fields)); |
| 230 | + data.resize(sizeof(root_table_offset) + 4 + header_size, 0); |
| 231 | + |
| 232 | + // The first eight bytes of the flatbuffer were written above, before the |
| 233 | + // header. |
| 234 | + append(flatbuffer + 8, flatbuffer_size - 8); |
| 235 | + data.resize(header_size + aligned_up(flatbuffer_size), 0); |
| 236 | + |
| 237 | + return data; |
| 238 | +} |
| 239 | + |
| 240 | +} // namespace |
| 241 | + |
| 242 | +TEST_F(FlatTensorDataMapTest, SupportedSchemaVersionLoads) { |
| 243 | + std::vector<uint8_t> data = |
| 244 | + CreateDataWithVersion(FlatTensorDataMap::kMaxSupportedSchemaVersion); |
| 245 | + |
| 246 | + alignas(16) uint8_t aligned_buffer[512]; |
| 247 | + ASSERT_LE(data.size(), sizeof(aligned_buffer)); |
| 248 | + memcpy(aligned_buffer, data.data(), data.size()); |
| 249 | + |
| 250 | + BufferDataLoader loader(aligned_buffer, data.size()); |
| 251 | + Result<FlatTensorDataMap> data_map = FlatTensorDataMap::load(&loader); |
| 252 | + |
| 253 | + EXPECT_EQ(data_map.error(), Error::Ok); |
| 254 | +} |
| 255 | + |
| 256 | +TEST_F(FlatTensorDataMapTest, NewerSchemaVersionFailsToLoad) { |
| 257 | + std::vector<uint8_t> data = |
| 258 | + CreateDataWithVersion(FlatTensorDataMap::kMaxSupportedSchemaVersion + 1); |
| 259 | + |
| 260 | + alignas(16) uint8_t aligned_buffer[512]; |
| 261 | + ASSERT_LE(data.size(), sizeof(aligned_buffer)); |
| 262 | + memcpy(aligned_buffer, data.data(), data.size()); |
| 263 | + |
| 264 | + BufferDataLoader loader(aligned_buffer, data.size()); |
| 265 | + Result<FlatTensorDataMap> data_map = FlatTensorDataMap::load(&loader); |
| 266 | + |
| 267 | + EXPECT_EQ(data_map.error(), Error::InvalidExternalData); |
| 268 | +} |
0 commit comments