read_test.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * libnbt++ - A library for the Minecraft Named Binary Tag format.
  3. * Copyright (C) 2013, 2015 ljfa-ag
  4. *
  5. * This file is part of libnbt++.
  6. *
  7. * libnbt++ is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * libnbt++ is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with libnbt++. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <cxxtest/TestSuite.h>
  21. #include "io/stream_reader.h"
  22. #ifdef NBT_HAVE_ZLIB
  23. #include "io/izlibstream.h"
  24. #endif
  25. #include "nbt_tags.h"
  26. #include <iostream>
  27. #include <fstream>
  28. #include <sstream>
  29. using namespace nbt;
  30. #include "data.h"
  31. class read_test : public CxxTest::TestSuite
  32. {
  33. public:
  34. void test_stream_reader_big()
  35. {
  36. std::string input{
  37. 1, //tag_type::Byte
  38. 0, //tag_type::End
  39. 11, //tag_type::Int_Array
  40. 0x0a, 0x0b, 0x0c, 0x0d, //0x0a0b0c0d in Big Endian
  41. 0x00, 0x06, //String length in Big Endian
  42. 'f', 'o', 'o', 'b', 'a', 'r',
  43. 0 //tag_type::End (invalid with allow_end = false)
  44. };
  45. std::istringstream is(input);
  46. nbt::io::stream_reader reader(is);
  47. TS_ASSERT_EQUALS(&reader.get_istr(), &is);
  48. TS_ASSERT_EQUALS(reader.get_endian(), endian::big);
  49. TS_ASSERT_EQUALS(reader.read_type(), tag_type::Byte);
  50. TS_ASSERT_EQUALS(reader.read_type(true), tag_type::End);
  51. TS_ASSERT_EQUALS(reader.read_type(false), tag_type::Int_Array);
  52. int32_t i;
  53. reader.read_num(i);
  54. TS_ASSERT_EQUALS(i, 0x0a0b0c0d);
  55. TS_ASSERT_EQUALS(reader.read_string(), "foobar");
  56. TS_ASSERT_THROWS(reader.read_type(false), io::input_error);
  57. TS_ASSERT(!is);
  58. is.clear();
  59. //Test for invalid tag type 13
  60. is.str("\x0d");
  61. TS_ASSERT_THROWS(reader.read_type(), io::input_error);
  62. TS_ASSERT(!is);
  63. is.clear();
  64. //Test for unexpcted EOF on numbers (input too short for int32_t)
  65. is.str("\x03\x04");
  66. reader.read_num(i);
  67. TS_ASSERT(!is);
  68. }
  69. void test_stream_reader_little()
  70. {
  71. std::string input{
  72. 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, //0x0d0c0b0a09080706 in Little Endian
  73. 0x06, 0x00, //String length in Little Endian
  74. 'f', 'o', 'o', 'b', 'a', 'r',
  75. 0x10, 0x00, //String length (intentionally too large)
  76. 'a', 'b', 'c', 'd' //unexpected EOF
  77. };
  78. std::istringstream is(input);
  79. nbt::io::stream_reader reader(is, endian::little);
  80. TS_ASSERT_EQUALS(reader.get_endian(), endian::little);
  81. int64_t i;
  82. reader.read_num(i);
  83. TS_ASSERT_EQUALS(i, 0x0d0c0b0a09080706);
  84. TS_ASSERT_EQUALS(reader.read_string(), "foobar");
  85. TS_ASSERT_THROWS(reader.read_string(), io::input_error);
  86. TS_ASSERT(!is);
  87. }
  88. //Tests if comp equals an extended variant of Notch's bigtest NBT
  89. void verify_bigtest_structure(const tag_compound& comp)
  90. {
  91. TS_ASSERT_EQUALS(comp.size(), 13u);
  92. TS_ASSERT(comp.at("byteTest") == tag_byte(127));
  93. TS_ASSERT(comp.at("shortTest") == tag_short(32767));
  94. TS_ASSERT(comp.at("intTest") == tag_int(2147483647));
  95. TS_ASSERT(comp.at("longTest") == tag_long(9223372036854775807));
  96. TS_ASSERT(comp.at("floatTest") == tag_float(std::stof("0xff1832p-25"))); //0.4982315
  97. TS_ASSERT(comp.at("doubleTest") == tag_double(std::stod("0x1f8f6bbbff6a5ep-54"))); //0.493128713218231
  98. //From bigtest.nbt: "the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...)"
  99. tag_byte_array byteArrayTest;
  100. for(int n = 0; n < 1000; ++n)
  101. byteArrayTest.push_back((n*n*255 + n*7) % 100);
  102. TS_ASSERT(comp.at("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))") == byteArrayTest);
  103. TS_ASSERT(comp.at("stringTest") == tag_string("HELLO WORLD THIS IS A TEST STRING \u00C5\u00C4\u00D6!"));
  104. TS_ASSERT(comp.at("listTest (compound)") == tag_list::of<tag_compound>({
  105. {{"created-on", tag_long(1264099775885)}, {"name", "Compound tag #0"}},
  106. {{"created-on", tag_long(1264099775885)}, {"name", "Compound tag #1"}}
  107. }));
  108. TS_ASSERT(comp.at("listTest (long)") == tag_list::of<tag_long>({11, 12, 13, 14, 15}));
  109. TS_ASSERT(comp.at("listTest (end)") == tag_list());
  110. TS_ASSERT((comp.at("nested compound test") == tag_compound{
  111. {"egg", tag_compound{{"value", 0.5f}, {"name", "Eggbert"}}},
  112. {"ham", tag_compound{{"value", 0.75f}, {"name", "Hampus"}}}
  113. }));
  114. TS_ASSERT(comp.at("intArrayTest") == tag_int_array(
  115. {0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f}));
  116. }
  117. void test_read_bigtest()
  118. {
  119. //Uses an extended variant of Notch's original bigtest file
  120. std::string input(__binary_bigtest_uncompr_start, __binary_bigtest_uncompr_end);
  121. std::istringstream file(input, std::ios::binary);
  122. auto pair = nbt::io::read_compound(file);
  123. TS_ASSERT_EQUALS(pair.first, "Level");
  124. verify_bigtest_structure(*pair.second);
  125. }
  126. void test_read_littletest()
  127. {
  128. //Same as bigtest, but little endian
  129. std::string input(__binary_littletest_uncompr_start, __binary_littletest_uncompr_end);
  130. std::istringstream file(input, std::ios::binary);
  131. auto pair = nbt::io::read_compound(file, endian::little);
  132. TS_ASSERT_EQUALS(pair.first, "Level");
  133. TS_ASSERT_EQUALS(pair.second->get_type(), tag_type::Compound);
  134. verify_bigtest_structure(*pair.second);
  135. }
  136. void test_read_eof1()
  137. {
  138. std::string input(__binary_errortest_eof1_start, __binary_errortest_eof1_end);
  139. std::istringstream file(input, std::ios::binary);
  140. nbt::io::stream_reader reader(file);
  141. //EOF within a tag_double payload
  142. TS_ASSERT(file);
  143. TS_ASSERT_THROWS(reader.read_tag(), io::input_error);
  144. TS_ASSERT(!file);
  145. }
  146. void test_read_eof2()
  147. {
  148. std::string input(__binary_errortest_eof2_start, __binary_errortest_eof2_end);
  149. std::istringstream file(input, std::ios::binary);
  150. nbt::io::stream_reader reader(file);
  151. //EOF within a key in a compound
  152. TS_ASSERT(file);
  153. TS_ASSERT_THROWS(reader.read_tag(), io::input_error);
  154. TS_ASSERT(!file);
  155. }
  156. void test_read_errortest_noend()
  157. {
  158. std::string input(__binary_errortest_noend_start, __binary_errortest_noend_end);
  159. std::istringstream file(input, std::ios::binary);
  160. nbt::io::stream_reader reader(file);
  161. //Missing tag_end
  162. TS_ASSERT(file);
  163. TS_ASSERT_THROWS(reader.read_tag(), io::input_error);
  164. TS_ASSERT(!file);
  165. }
  166. void test_read_errortest_neg_length()
  167. {
  168. std::string input(__binary_errortest_neg_length_start, __binary_errortest_neg_length_end);
  169. std::istringstream file(input, std::ios::binary);
  170. nbt::io::stream_reader reader(file);
  171. //Negative list length
  172. TS_ASSERT(file);
  173. TS_ASSERT_THROWS(reader.read_tag(), io::input_error);
  174. TS_ASSERT(!file);
  175. }
  176. void test_read_misc()
  177. {
  178. std::string input(__binary_toplevel_string_start, __binary_toplevel_string_end);
  179. std::istringstream file(input, std::ios::binary);
  180. nbt::io::stream_reader reader(file);
  181. //Toplevel tag other than compound
  182. TS_ASSERT(file);
  183. TS_ASSERT_THROWS(reader.read_compound(), io::input_error);
  184. TS_ASSERT(!file);
  185. //Rewind and try again with read_tag
  186. file.clear();
  187. TS_ASSERT(file.seekg(0));
  188. auto pair = reader.read_tag();
  189. TS_ASSERT_EQUALS(pair.first, "Test (toplevel tag_string)");
  190. TS_ASSERT(*pair.second == tag_string(
  191. "Even though unprovided for by NBT, the library should also handle "
  192. "the case where the file consists of something else than tag_compound"));
  193. }
  194. void test_read_gzip()
  195. {
  196. #ifdef NBT_HAVE_ZLIB
  197. std::string input(__binary_bigtest_nbt_start, __binary_bigtest_nbt_end);
  198. std::istringstream file(input, std::ios::binary);
  199. zlib::izlibstream igzs(file);
  200. TS_ASSERT(file && igzs);
  201. auto pair = nbt::io::read_compound(igzs);
  202. TS_ASSERT(igzs);
  203. TS_ASSERT_EQUALS(pair.first, "Level");
  204. verify_bigtest_structure(*pair.second);
  205. #endif
  206. }
  207. };