duid_factory_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcp/dhcp4.h>
  16. #include <dhcp/duid_factory.h>
  17. #include <dhcp/tests/iface_mgr_test_config.h>
  18. #include <testutils/io_utils.h>
  19. #include <util/encode/hex.h>
  20. #include <util/range_utilities.h>
  21. #include <boost/algorithm/string.hpp>
  22. #include <gtest/gtest.h>
  23. #include <ctime>
  24. #include <fstream>
  25. #include <iomanip>
  26. #include <sstream>
  27. #include <stdio.h>
  28. #include <string>
  29. #include <vector>
  30. using namespace isc;
  31. using namespace isc::dhcp;
  32. using namespace isc::dhcp::test;
  33. using namespace isc::util;
  34. namespace {
  35. /// @brief Name of the file holding DUID generated during a test.
  36. const std::string DEFAULT_DUID_FILE = "duid-factory-test.duid";
  37. /// @brief Test fixture class for @c DUIDFactory.
  38. class DUIDFactoryTest : public ::testing::Test {
  39. public:
  40. /// @brief Constructor.
  41. ///
  42. /// Creates fake interface configuration. It also creates an instance
  43. /// of the @c DUIDFactory object used throughout the tests.
  44. DUIDFactoryTest();
  45. /// @brief Destructor.
  46. virtual ~DUIDFactoryTest();
  47. /// @brief Returns absolute path to a test DUID storage.
  48. ///
  49. /// @param duid_file_name Name of the file holding test DUID.
  50. std::string absolutePath(const std::string& duid_file_name) const;
  51. /// @brief Removes default DUID file used in the tests.
  52. ///
  53. /// This method is called from both constructor and destructor.
  54. void removeDefaultFile() const;
  55. /// @brief Returns contents of the DUID file.
  56. std::string readDefaultFile() const;
  57. /// @brief Converts string of hexadecimal digits to vector.
  58. ///
  59. /// @param hex String representation.
  60. /// @return Vector created from the converted string.
  61. std::vector<uint8_t> toVector(const std::string& hex) const;
  62. /// @brief Converts vector to string of hexadecimal digits.
  63. ///
  64. /// @param vec Input vector.
  65. /// @return String of hexadecimal digits converted from vector.
  66. std::string toString(const std::vector<uint8_t>& vec) const;
  67. /// @brief Converts current time to a string of hexadecimal digits.
  68. ///
  69. /// @return Time represented as text.
  70. std::string timeAsHexString() const;
  71. /// @brief Tests creation of a DUID-LLT.
  72. ///
  73. /// @param expected_htype Expected link layer type as string.
  74. /// @param expected_time Expected time as string.
  75. /// @param time_equal Indicates if @c expected time should be
  76. /// compared for equality with the time being part of a DUID
  77. /// (if true), or the time being part of the DUID should be
  78. /// less or equal current time (if false).
  79. /// @param expected_hwaddr Expected link layer type as string.
  80. void testLLT(const std::string& expected_htype,
  81. const std::string& expected_time,
  82. const bool time_equal,
  83. const std::string& expected_hwaddr);
  84. /// @brief Tests creation of a DUID-LLT.
  85. ///
  86. /// @param expected_htype Expected link layer type as string.
  87. /// @param expected_time Expected time as string.
  88. /// @param time_equal Indicates if @c expected time should be
  89. /// compared for equality with the time being part of a DUID
  90. /// (if true), or the time being part of the DUID should be
  91. /// less or equal current time (if false).
  92. /// @param expected_hwaddr Expected link layer type as string.
  93. /// @param factory_ref Reference to DUID factory.
  94. void testLLT(const std::string& expected_htype,
  95. const std::string& expected_time,
  96. const bool time_equal,
  97. const std::string& expected_hwaddr,
  98. DUIDFactory& factory_ref);
  99. /// @brief Tests creation of a DUID-EN.
  100. ///
  101. /// @param expected_enterprise_id Expected enterprise id as string.
  102. /// @param expected_identifier Expected variable length identifier
  103. /// as string. If empty string specified the test method only checks
  104. /// that generated identifier consists of some random values.
  105. void testEN(const std::string& expected_enterprise_id,
  106. const std::string& expected_identifier = "");
  107. /// @brief Tests creation of a DUID-EN.
  108. ///
  109. /// @param expected_enterprise_id Expected enterprise id as string.
  110. /// @param expected_identifier Expected variable length identifier
  111. /// as string. If empty string specified the test method only checks
  112. /// that generated identifier consists of some random values.
  113. /// @param factory_ref Reference to DUID factory.
  114. void testEN(const std::string& expected_enterprise_id,
  115. const std::string& expected_identifier,
  116. DUIDFactory& factory_ref);
  117. /// @brief Tests creation of a DUID-LL.
  118. ///
  119. /// @param expected_htype Expected link layer type as string.
  120. /// @param expected_hwaddr Expected link layer type as string.
  121. void testLL(const std::string& expected_htype,
  122. const std::string& expected_hwaddr);
  123. /// @brief Tests creation of a DUID-LL.
  124. ///
  125. /// @param expected_htype Expected link layer type as string.
  126. /// @param expected_hwaddr Expected link layer type as string.
  127. /// @param factory_ref Reference to DUID factory.
  128. void testLL(const std::string& expected_htype,
  129. const std::string& expected_hwaddr,
  130. DUIDFactory& factory_ref);
  131. /// @brief Returns reference to a default factory.
  132. DUIDFactory& factory() {
  133. return (factory_);
  134. }
  135. private:
  136. /// @brief Creates fake interface configuration.
  137. IfaceMgrTestConfig iface_mgr_test_config_;
  138. /// @brief Holds default instance of the @c DUIDFactory class, being
  139. /// used throughout the tests.
  140. DUIDFactory factory_;
  141. };
  142. DUIDFactoryTest::DUIDFactoryTest()
  143. : iface_mgr_test_config_(true),
  144. factory_(absolutePath(DEFAULT_DUID_FILE)) {
  145. removeDefaultFile();
  146. }
  147. DUIDFactoryTest::~DUIDFactoryTest() {
  148. removeDefaultFile();
  149. }
  150. std::string
  151. DUIDFactoryTest::absolutePath(const std::string& duid_file_name) const {
  152. std::ostringstream s;
  153. s << TEST_DATA_BUILDDIR << "/" << duid_file_name;
  154. return (s.str());
  155. }
  156. void
  157. DUIDFactoryTest::removeDefaultFile() const {
  158. static_cast<void>(remove(absolutePath(DEFAULT_DUID_FILE).c_str()));
  159. }
  160. std::string
  161. DUIDFactoryTest::readDefaultFile() const {
  162. return (dhcp::test::readFile(absolutePath(DEFAULT_DUID_FILE)));
  163. }
  164. std::vector<uint8_t>
  165. DUIDFactoryTest::toVector(const std::string& hex) const {
  166. std::vector<uint8_t> vec;
  167. try {
  168. util::encode::decodeHex(hex, vec);
  169. } catch (...) {
  170. ADD_FAILURE() << "toVector: the following string " << hex
  171. << " is not a valid hex string";
  172. }
  173. return (vec);
  174. }
  175. std::string
  176. DUIDFactoryTest::toString(const std::vector<uint8_t>& vec) const {
  177. try {
  178. return (util::encode::encodeHex(vec));
  179. } catch (...) {
  180. ADD_FAILURE() << "toString: unable to encode vector to"
  181. " hexadecimal string";
  182. }
  183. return ("");
  184. }
  185. std::string
  186. DUIDFactoryTest::timeAsHexString() const {
  187. time_t current_time = time(NULL) - DUID_TIME_EPOCH;
  188. std::ostringstream s;
  189. s << std::hex << std::setw(8) << std::setfill('0') << current_time;
  190. return (boost::to_upper_copy<std::string>(s.str()));
  191. }
  192. void
  193. DUIDFactoryTest::testLLT(const std::string& expected_htype,
  194. const std::string& expected_time,
  195. const bool time_equal,
  196. const std::string& expected_hwaddr) {
  197. testLLT(expected_htype, expected_time, time_equal, expected_hwaddr,
  198. factory());
  199. }
  200. void
  201. DUIDFactoryTest::testLLT(const std::string& expected_htype,
  202. const std::string& expected_time,
  203. const bool time_equal,
  204. const std::string& expected_hwaddr,
  205. DUIDFactory& factory_ref) {
  206. DuidPtr duid = factory_ref.get();
  207. ASSERT_TRUE(duid);
  208. ASSERT_GE(duid->getDuid().size(), 14);
  209. std::string duid_text = toString(duid->getDuid());
  210. // DUID type LLT
  211. EXPECT_EQ("0001", duid_text.substr(0, 4));
  212. // Link layer type HTYPE_ETHER
  213. EXPECT_EQ(expected_htype, duid_text.substr(4, 4));
  214. // Verify if time is correct.
  215. if (time_equal) {
  216. // Strict time check.
  217. EXPECT_EQ(expected_time, duid_text.substr(8, 8));
  218. } else {
  219. // Timestamp equal or less current time.
  220. EXPECT_LE(duid_text.substr(8, 8), expected_time);
  221. }
  222. // MAC address of the interface.
  223. EXPECT_EQ(expected_hwaddr, duid_text.substr(16));
  224. // Compare DUID with the one stored in the file.
  225. EXPECT_EQ(duid->toText(), readDefaultFile());
  226. }
  227. void
  228. DUIDFactoryTest::testEN(const std::string& expected_enterprise_id,
  229. const std::string& expected_identifier) {
  230. testEN(expected_enterprise_id, expected_identifier, factory());
  231. }
  232. void
  233. DUIDFactoryTest::testEN(const std::string& expected_enterprise_id,
  234. const std::string& expected_identifier,
  235. DUIDFactory& factory_ref) {
  236. DuidPtr duid = factory_ref.get();
  237. ASSERT_TRUE(duid);
  238. ASSERT_GE(duid->getDuid().size(), 8);
  239. std::string duid_text = toString(duid->getDuid());
  240. // DUID type EN.
  241. EXPECT_EQ("0002", duid_text.substr(0, 4));
  242. // Verify enterprise ID.
  243. EXPECT_EQ(expected_enterprise_id, duid_text.substr(4, 8));
  244. // If no expected identifier, we should at least check that the
  245. // generated identifier contains some random non-zero digits.
  246. if (expected_identifier.empty()) {
  247. EXPECT_FALSE(isRangeZero(duid->getDuid().begin(),
  248. duid->getDuid().end()));
  249. } else {
  250. // Check if identifier matches.
  251. EXPECT_EQ(expected_identifier, duid_text.substr(12));
  252. }
  253. // Compare DUID with the one stored in the file.
  254. EXPECT_EQ(duid->toText(), readDefaultFile());
  255. }
  256. void
  257. DUIDFactoryTest::testLL(const std::string& expected_htype,
  258. const std::string& expected_hwaddr) {
  259. testLL(expected_htype, expected_hwaddr, factory());
  260. }
  261. void
  262. DUIDFactoryTest::testLL(const std::string& expected_htype,
  263. const std::string& expected_hwaddr,
  264. DUIDFactory& factory_ref) {
  265. DuidPtr duid = factory_ref.get();
  266. ASSERT_TRUE(duid);
  267. ASSERT_GE(duid->getDuid().size(), 8);
  268. std::string duid_text = toString(duid->getDuid());
  269. // DUID type LL
  270. EXPECT_EQ("0003", duid_text.substr(0, 4));
  271. // Link layer type.
  272. EXPECT_EQ(expected_htype, duid_text.substr(4, 4));
  273. // MAC address of the interface.
  274. EXPECT_EQ(expected_hwaddr, duid_text.substr(8));
  275. // Compare DUID with the one stored in the file.
  276. EXPECT_EQ(duid->toText(), readDefaultFile());
  277. }
  278. // This test verifies that the factory class will generate the entire
  279. // DUID-LLT if there are no explicit values specified for the
  280. // time, link layer type and link layer address.
  281. TEST_F(DUIDFactoryTest, createLLT) {
  282. // Use 0 values for time and link layer type and empty vector for
  283. // the link layer address. The createLLT function will need to
  284. // use current time, HTYPE_ETHER and MAC address of one of the
  285. // interfaces.
  286. ASSERT_NO_THROW(factory().createLLT(0, 0, std::vector<uint8_t>()));
  287. testLLT("0001", timeAsHexString(), false, "080808080808");
  288. }
  289. // This test verifies that the factory class creates a DUID-LLT from
  290. // the explicitly specified time, when link layer type and address are
  291. // generated.
  292. TEST_F(DUIDFactoryTest, createLLTExplicitTime) {
  293. ASSERT_NO_THROW(factory().createLLT(0, 0xABCDEF, std::vector<uint8_t>()));
  294. testLLT("0001", "00ABCDEF", true, "080808080808");
  295. }
  296. // This test verifies that the factory class creates DUID-LLT with
  297. // the link layer type of the interface which link layer address
  298. // is used to generate the DUID.
  299. TEST_F(DUIDFactoryTest, createLLTExplicitHtype) {
  300. ASSERT_NO_THROW(factory().createLLT(HTYPE_FDDI, 0, std::vector<uint8_t>()));
  301. testLLT("0001", timeAsHexString(), false, "080808080808");
  302. }
  303. // This test verifies that the factory class creates DUID-LLT from
  304. // explcitly specified link layer address, when other parameters
  305. // are generated.
  306. TEST_F(DUIDFactoryTest, createLLTExplicitLinkLayerAddress) {
  307. ASSERT_NO_THROW(factory().createLLT(0, 0, toVector("121212121212")));
  308. testLLT("0001", timeAsHexString(), false, "121212121212");
  309. }
  310. // This test verifies that the factory function creates DUID-LLT from
  311. // all values explicitly specified.
  312. TEST_F(DUIDFactoryTest, createLLTAllExplcitParameters) {
  313. ASSERT_NO_THROW(factory().createLLT(HTYPE_FDDI, 0xFAFAFAFA,
  314. toVector("24242424242424242424")));
  315. testLLT("0008", "FAFAFAFA", true, "24242424242424242424");
  316. }
  317. // This test verifies that the createLLT function will try to reuse existing
  318. // DUID for the non-explicitly specified values.
  319. TEST_F(DUIDFactoryTest, createLLTReuse) {
  320. // Create DUID-LLT and store it in a file.
  321. ASSERT_NO_THROW(factory().createLLT(HTYPE_FDDI, 0xFAFAFAFA,
  322. toVector("242424242424")));
  323. // Create another factory class, which uses the same file.
  324. DUIDFactory factory2(absolutePath(DEFAULT_DUID_FILE));
  325. // Create DUID-LLT without specifying hardware type, time and
  326. // link layer address. The factory function should use the
  327. // values in the existing DUID.
  328. ASSERT_NO_THROW(factory2.createLLT(0, 0, std::vector<uint8_t>()));
  329. testLLT("0008", "FAFAFAFA", true, "242424242424", factory2);
  330. // Try to reuse only a time value.
  331. DUIDFactory factory3(absolutePath(DEFAULT_DUID_FILE));
  332. ASSERT_NO_THROW(factory3.createLLT(HTYPE_ETHER, 0,
  333. toVector("121212121212")));
  334. testLLT("0001", "FAFAFAFA", true, "121212121212", factory3);
  335. // Reuse only a hardware type.
  336. DUIDFactory factory4(absolutePath(DEFAULT_DUID_FILE));
  337. ASSERT_NO_THROW(factory4.createLLT(0, 0x23432343,
  338. toVector("455445544554")));
  339. testLLT("0001", "23432343", true, "455445544554", factory4);
  340. // Reuse link layer address. Note that in this case the hardware
  341. // type is set to the type of the interface from which hardware
  342. // address is obtained and the explicit value is ignored.
  343. DUIDFactory factory5(absolutePath(DEFAULT_DUID_FILE));
  344. ASSERT_NO_THROW(factory5.createLLT(HTYPE_FDDI, 0x11111111,
  345. std::vector<uint8_t>()));
  346. testLLT("0001", "11111111", true, "455445544554", factory5);
  347. }
  348. // This test verifies that the DUID-EN can be generated entirely. Such
  349. // generated DUID contains ISC enterprise id and the random identifier.
  350. TEST_F(DUIDFactoryTest, createEN) {
  351. ASSERT_NO_THROW(factory().createEN(0, std::vector<uint8_t>()));
  352. testEN("000009BF");
  353. }
  354. // This test verifies that the DUID-EN may contain custom enterprise id.
  355. TEST_F(DUIDFactoryTest, createENExplicitEnterpriseId) {
  356. ASSERT_NO_THROW(factory().createEN(0xABCDEFAB, std::vector<uint8_t>()));
  357. testEN("ABCDEFAB");
  358. }
  359. // This test verifies that DUID-EN may contain custom variable length
  360. // identifier and default enterprise id.
  361. TEST_F(DUIDFactoryTest, createENExplicitIdentifier) {
  362. ASSERT_NO_THROW(factory().createEN(0, toVector("1212121212121212")));
  363. testEN("000009BF", "1212121212121212");
  364. }
  365. // This test verifies that DUID-EN can be created from explicit enterprise id
  366. // and identifier.
  367. TEST_F(DUIDFactoryTest, createENAllExplicitParameters) {
  368. ASSERT_NO_THROW(factory().createEN(0x01020304, toVector("ABCD")));
  369. testEN("01020304", "ABCD");
  370. }
  371. // This test verifies that the createEN function will try to reuse existing
  372. // DUID for the non-explicitly specified values.
  373. TEST_F(DUIDFactoryTest, createENReuse) {
  374. // Create DUID-EN and store it in a file.
  375. ASSERT_NO_THROW(factory().createEN(0xFAFAFAFA, toVector("242424242424")));
  376. // Create another factory class, which uses the same file.
  377. DUIDFactory factory2(absolutePath(DEFAULT_DUID_FILE));
  378. ASSERT_NO_THROW(factory2.createEN(0, std::vector<uint8_t>()));
  379. testEN("FAFAFAFA", "242424242424", factory2);
  380. // Reuse only enterprise id.
  381. DUIDFactory factory3(absolutePath(DEFAULT_DUID_FILE));
  382. ASSERT_NO_THROW(factory3.createEN(0, toVector("121212121212")));
  383. testEN("FAFAFAFA", "121212121212", factory3);
  384. // Reuse only variable length identifier.
  385. DUIDFactory factory4(absolutePath(DEFAULT_DUID_FILE));
  386. ASSERT_NO_THROW(factory4.createEN(0x1234, std::vector<uint8_t>()));
  387. testEN("00001234", "121212121212", factory4);
  388. }
  389. // This test verifies that the DUID-LL is generated when neither link layer
  390. // type nor address is specified.
  391. TEST_F(DUIDFactoryTest, createLL) {
  392. ASSERT_NO_THROW(factory().createLL(0, std::vector<uint8_t>()));
  393. testLL("0001", "080808080808");
  394. }
  395. // This test verifies that the DUID-LL is generated and the link layer type
  396. // used is taken from the interface used to generate link layer address.
  397. TEST_F(DUIDFactoryTest, createLLExplicitHtype) {
  398. ASSERT_NO_THROW(factory().createLL(HTYPE_FDDI, std::vector<uint8_t>()));
  399. testLL("0001", "080808080808");
  400. }
  401. // This test verifies that DUID-LL is created from explicitly provided
  402. // link layer type and address.
  403. TEST_F(DUIDFactoryTest, createLLAllExplicitParameters) {
  404. ASSERT_NO_THROW(factory().createLL(HTYPE_FDDI, toVector("242424242424")));
  405. testLL("0008", "242424242424");
  406. }
  407. // This test verifies that DUID-LLT is created when caller wants to obtain
  408. // it and it doesn't exist.
  409. TEST_F(DUIDFactoryTest, createLLTIfNotExists) {
  410. DuidPtr duid;
  411. ASSERT_NO_THROW(duid = factory().get());
  412. ASSERT_TRUE(duid);
  413. EXPECT_EQ(DUID::DUID_LLT, duid->getType());
  414. }
  415. // This test verifies that DUID-EN when there is no suitable interface to
  416. // use to create DUID-LLT.
  417. TEST_F(DUIDFactoryTest, createENIfNotExists) {
  418. // Remove interfaces. The DUID-LLT is a default type but it requires
  419. // that an interface with a suitable link-layer address is present
  420. // in the system. By removing the interfaces we cause the factory
  421. // to fail to generate DUID-LLT. It should fall back to DUID-EN.
  422. IfaceMgr::instance().clearIfaces();
  423. DuidPtr duid;
  424. ASSERT_NO_THROW(duid = factory().get());
  425. ASSERT_TRUE(duid);
  426. EXPECT_EQ(DUID::DUID_EN, duid->getType());
  427. }
  428. // This test verifies that the createLL function will try to reuse existing
  429. // DUID for the non-explicitly specified values.
  430. TEST_F(DUIDFactoryTest, createLLReuse) {
  431. // Create DUID-EN and store it in a file.
  432. ASSERT_NO_THROW(factory().createLL(HTYPE_FDDI, toVector("242424242424")));
  433. // Create another factory class, which uses the same file.
  434. DUIDFactory factory2(absolutePath(DEFAULT_DUID_FILE));
  435. // Create DUID-LL without specifying hardware type, time and
  436. // link layer address. The factory function should use the
  437. // values in the existing DUID.
  438. ASSERT_NO_THROW(factory2.createLL(0, std::vector<uint8_t>()));
  439. testLL("0008", "242424242424", factory2);
  440. // Reuse only hardware type
  441. DUIDFactory factory3(absolutePath(DEFAULT_DUID_FILE));
  442. ASSERT_NO_THROW(factory3.createLL(0, toVector("121212121212")));
  443. testLL("0008", "121212121212", factory3);
  444. // Reuse link layer address. Note that when the link layer address is
  445. // reused, the explicit value of hardware type is reused too and the
  446. // explicit value of hardware type is ignored.
  447. DUIDFactory factory4(absolutePath(DEFAULT_DUID_FILE));
  448. ASSERT_NO_THROW(factory4.createLL(HTYPE_ETHER, std::vector<uint8_t>()));
  449. testLL("0008", "121212121212", factory4);
  450. }
  451. // This test verifies that it is possible to override a DUID.
  452. TEST_F(DUIDFactoryTest, override) {
  453. // Create default DUID-LLT.
  454. ASSERT_NO_THROW(static_cast<void>(factory().get()));
  455. testLLT("0001", timeAsHexString(), false, "080808080808");
  456. ASSERT_NO_THROW(factory().createEN(0, toVector("12131415")));
  457. testEN("000009BF", "12131415");
  458. }
  459. } // End anonymous namespace