]> git.lizzy.rs Git - dragonfireclient.git/blob - src/test.cpp
Resource file handling for exe icon for MinGW
[dragonfireclient.git] / src / test.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "test.h"
21 #include "common_irrlicht.h"
22 #include "debug.h"
23 #include "map.h"
24 #include "player.h"
25 #include "main.h"
26 #include "socket.h"
27 #include "connection.h"
28 #include "utility.h"
29 #include "serialization.h"
30 #include "voxel.h"
31 #include <sstream>
32 #include "porting.h"
33 #include "content_mapnode.h"
34 #include "mapsector.h"
35 #include "settings.h"
36
37 /*
38         Asserts that the exception occurs
39 */
40 #define EXCEPTION_CHECK(EType, code)\
41 {\
42         bool exception_thrown = false;\
43         try{ code; }\
44         catch(EType &e) { exception_thrown = true; }\
45         assert(exception_thrown);\
46 }
47
48 struct TestUtilities
49 {
50         void Run()
51         {
52                 /*dstream<<"wrapDegrees(100.0) = "<<wrapDegrees(100.0)<<std::endl;
53                 dstream<<"wrapDegrees(720.5) = "<<wrapDegrees(720.5)<<std::endl;
54                 dstream<<"wrapDegrees(-0.5) = "<<wrapDegrees(-0.5)<<std::endl;*/
55                 assert(fabs(wrapDegrees(100.0) - 100.0) < 0.001);
56                 assert(fabs(wrapDegrees(720.5) - 0.5) < 0.001);
57                 assert(fabs(wrapDegrees(-0.5) - (-0.5)) < 0.001);
58                 assert(fabs(wrapDegrees(-365.5) - (-5.5)) < 0.001);
59                 assert(lowercase("Foo bAR") == "foo bar");
60                 assert(is_yes("YeS") == true);
61                 assert(is_yes("") == false);
62                 assert(is_yes("FAlse") == false);
63         }
64 };
65
66 struct TestSettings
67 {
68         void Run()
69         {
70                 Settings s;
71                 // Test reading of settings
72                 s.parseConfigLine("leet = 1337");
73                 s.parseConfigLine("leetleet = 13371337");
74                 s.parseConfigLine("leetleet_neg = -13371337");
75                 s.parseConfigLine("floaty_thing = 1.1");
76                 s.parseConfigLine("stringy_thing = asd /( ¤%&(/\" BLÖÄRP");
77                 s.parseConfigLine("coord = (1, 2, 4.5)");
78                 assert(s.getS32("leet") == 1337);
79                 assert(s.getS16("leetleet") == 32767);
80                 assert(s.getS16("leetleet_neg") == -32768);
81                 // Not sure if 1.1 is an exact value as a float, but doesn't matter
82                 assert(fabs(s.getFloat("floaty_thing") - 1.1) < 0.001);
83                 assert(s.get("stringy_thing") == "asd /( ¤%&(/\" BLÖÄRP");
84                 assert(fabs(s.getV3F("coord").X - 1.0) < 0.001);
85                 assert(fabs(s.getV3F("coord").Y - 2.0) < 0.001);
86                 assert(fabs(s.getV3F("coord").Z - 4.5) < 0.001);
87                 // Test the setting of settings too
88                 s.setFloat("floaty_thing_2", 1.2);
89                 s.setV3F("coord2", v3f(1, 2, 3.3));
90                 assert(s.get("floaty_thing_2").substr(0,3) == "1.2");
91                 assert(fabs(s.getFloat("floaty_thing_2") - 1.2) < 0.001);
92                 assert(fabs(s.getV3F("coord2").X - 1.0) < 0.001);
93                 assert(fabs(s.getV3F("coord2").Y - 2.0) < 0.001);
94                 assert(fabs(s.getV3F("coord2").Z - 3.3) < 0.001);
95         }
96 };
97                 
98 struct TestCompress
99 {
100         void Run()
101         {
102                 { // ver 0
103
104                 SharedBuffer<u8> fromdata(4);
105                 fromdata[0]=1;
106                 fromdata[1]=5;
107                 fromdata[2]=5;
108                 fromdata[3]=1;
109                 
110                 std::ostringstream os(std::ios_base::binary);
111                 compress(fromdata, os, 0);
112
113                 std::string str_out = os.str();
114                 
115                 dstream<<"str_out.size()="<<str_out.size()<<std::endl;
116                 dstream<<"TestCompress: 1,5,5,1 -> ";
117                 for(u32 i=0; i<str_out.size(); i++)
118                 {
119                         dstream<<(u32)str_out[i]<<",";
120                 }
121                 dstream<<std::endl;
122
123                 assert(str_out.size() == 10);
124
125                 assert(str_out[0] == 0);
126                 assert(str_out[1] == 0);
127                 assert(str_out[2] == 0);
128                 assert(str_out[3] == 4);
129                 assert(str_out[4] == 0);
130                 assert(str_out[5] == 1);
131                 assert(str_out[6] == 1);
132                 assert(str_out[7] == 5);
133                 assert(str_out[8] == 0);
134                 assert(str_out[9] == 1);
135
136                 std::istringstream is(str_out, std::ios_base::binary);
137                 std::ostringstream os2(std::ios_base::binary);
138
139                 decompress(is, os2, 0);
140                 std::string str_out2 = os2.str();
141
142                 dstream<<"decompress: ";
143                 for(u32 i=0; i<str_out2.size(); i++)
144                 {
145                         dstream<<(u32)str_out2[i]<<",";
146                 }
147                 dstream<<std::endl;
148
149                 assert(str_out2.size() == fromdata.getSize());
150
151                 for(u32 i=0; i<str_out2.size(); i++)
152                 {
153                         assert(str_out2[i] == fromdata[i]);
154                 }
155
156                 }
157
158                 { // ver HIGHEST
159
160                 SharedBuffer<u8> fromdata(4);
161                 fromdata[0]=1;
162                 fromdata[1]=5;
163                 fromdata[2]=5;
164                 fromdata[3]=1;
165                 
166                 std::ostringstream os(std::ios_base::binary);
167                 compress(fromdata, os, SER_FMT_VER_HIGHEST);
168
169                 std::string str_out = os.str();
170                 
171                 dstream<<"str_out.size()="<<str_out.size()<<std::endl;
172                 dstream<<"TestCompress: 1,5,5,1 -> ";
173                 for(u32 i=0; i<str_out.size(); i++)
174                 {
175                         dstream<<(u32)str_out[i]<<",";
176                 }
177                 dstream<<std::endl;
178
179                 /*assert(str_out.size() == 10);
180
181                 assert(str_out[0] == 0);
182                 assert(str_out[1] == 0);
183                 assert(str_out[2] == 0);
184                 assert(str_out[3] == 4);
185                 assert(str_out[4] == 0);
186                 assert(str_out[5] == 1);
187                 assert(str_out[6] == 1);
188                 assert(str_out[7] == 5);
189                 assert(str_out[8] == 0);
190                 assert(str_out[9] == 1);*/
191
192                 std::istringstream is(str_out, std::ios_base::binary);
193                 std::ostringstream os2(std::ios_base::binary);
194
195                 decompress(is, os2, SER_FMT_VER_HIGHEST);
196                 std::string str_out2 = os2.str();
197
198                 dstream<<"decompress: ";
199                 for(u32 i=0; i<str_out2.size(); i++)
200                 {
201                         dstream<<(u32)str_out2[i]<<",";
202                 }
203                 dstream<<std::endl;
204
205                 assert(str_out2.size() == fromdata.getSize());
206
207                 for(u32 i=0; i<str_out2.size(); i++)
208                 {
209                         assert(str_out2[i] == fromdata[i]);
210                 }
211
212                 }
213         }
214 };
215
216 struct TestMapNode
217 {
218         void Run()
219         {
220                 MapNode n;
221
222                 // Default values
223                 assert(n.getContent() == CONTENT_AIR);
224                 assert(n.getLight(LIGHTBANK_DAY) == 0);
225                 assert(n.getLight(LIGHTBANK_NIGHT) == 0);
226                 
227                 // Transparency
228                 n.setContent(CONTENT_AIR);
229                 assert(n.light_propagates() == true);
230                 n.setContent(CONTENT_STONE);
231                 assert(n.light_propagates() == false);
232         }
233 };
234
235 struct TestVoxelManipulator
236 {
237         void Run()
238         {
239                 /*
240                         VoxelArea
241                 */
242
243                 VoxelArea a(v3s16(-1,-1,-1), v3s16(1,1,1));
244                 assert(a.index(0,0,0) == 1*3*3 + 1*3 + 1);
245                 assert(a.index(-1,-1,-1) == 0);
246                 
247                 VoxelArea c(v3s16(-2,-2,-2), v3s16(2,2,2));
248                 // An area that is 1 bigger in x+ and z-
249                 VoxelArea d(v3s16(-2,-2,-3), v3s16(3,2,2));
250                 
251                 core::list<VoxelArea> aa;
252                 d.diff(c, aa);
253                 
254                 // Correct results
255                 core::array<VoxelArea> results;
256                 results.push_back(VoxelArea(v3s16(-2,-2,-3),v3s16(3,2,-3)));
257                 results.push_back(VoxelArea(v3s16(3,-2,-2),v3s16(3,2,2)));
258
259                 assert(aa.size() == results.size());
260                 
261                 dstream<<"Result of diff:"<<std::endl;
262                 for(core::list<VoxelArea>::Iterator
263                                 i = aa.begin(); i != aa.end(); i++)
264                 {
265                         i->print(dstream);
266                         dstream<<std::endl;
267                         
268                         s32 j = results.linear_search(*i);
269                         assert(j != -1);
270                         results.erase(j, 1);
271                 }
272
273
274                 /*
275                         VoxelManipulator
276                 */
277                 
278                 VoxelManipulator v;
279
280                 v.print(dstream);
281
282                 dstream<<"*** Setting (-1,0,-1)=2 ***"<<std::endl;
283                 
284                 v.setNodeNoRef(v3s16(-1,0,-1), MapNode(2));
285
286                 v.print(dstream);
287
288                 assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
289
290                 dstream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
291
292                 EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,0,-1)));
293
294                 v.print(dstream);
295
296                 dstream<<"*** Adding area ***"<<std::endl;
297
298                 v.addArea(a);
299                 
300                 v.print(dstream);
301
302                 assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
303                 EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1)));
304
305 #if 0
306                 /*
307                         Water stuff
308                 */
309
310                 v.clear();
311
312                 const char *content =
313                         "#...######  "
314                         "#...##..##  "
315                         "#........ .."
316                         "############"
317
318                         "#...######  "
319                         "#...##..##  "
320                         "#........#  "
321                         "############"
322                 ;
323
324                 v3s16 size(12, 4, 2);
325                 VoxelArea area(v3s16(0,0,0), size-v3s16(1,1,1));
326                 
327                 const char *p = content;
328                 for(s16 z=0; z<size.Z; z++)
329                 for(s16 y=size.Y-1; y>=0; y--)
330                 for(s16 x=0; x<size.X; x++)
331                 {
332                         MapNode n;
333                         //n.pressure = size.Y - y;
334                         if(*p == '#')
335                                 n.setContent(CONTENT_STONE);
336                         else if(*p == '.')
337                                 n.setContent(CONTENT_WATER);
338                         else if(*p == ' ')
339                                 n.setContent(CONTENT_AIR);
340                         else
341                                 assert(0);
342                         v.setNode(v3s16(x,y,z), n);
343                         p++;
344                 }
345
346                 v.print(dstream, VOXELPRINT_WATERPRESSURE);
347                 
348                 core::map<v3s16, u8> active_nodes;
349                 v.updateAreaWaterPressure(area, active_nodes);
350
351                 v.print(dstream, VOXELPRINT_WATERPRESSURE);
352                 
353                 //s16 highest_y = -32768;
354                 /*
355                         NOTE: These are commented out because this behaviour is changed
356                               all the time
357                 */
358                 //assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == -1);
359                 //assert(highest_y == 3);
360                 /*assert(v.getWaterPressure(v3s16(7, 1, 1), highest_y, 0) == 3);
361                 //assert(highest_y == 3);*/
362                 
363                 active_nodes.clear();
364                 active_nodes[v3s16(9,1,0)] = 1;
365                 //v.flowWater(active_nodes, 0, true, 1000);
366                 v.flowWater(active_nodes, 0, false, 1000);
367                 
368                 dstream<<"Final result of flowWater:"<<std::endl;
369                 v.print(dstream, VOXELPRINT_WATERPRESSURE);
370 #endif
371                 
372                 //assert(0);
373         }
374 };
375
376 /*
377         NOTE: These tests became non-working then NodeContainer was removed.
378               These should be redone, utilizing some kind of a virtual
379                   interface for Map (IMap would be fine).
380 */
381 #if 0
382 struct TestMapBlock
383 {
384         class TC : public NodeContainer
385         {
386         public:
387
388                 MapNode node;
389                 bool position_valid;
390                 core::list<v3s16> validity_exceptions;
391
392                 TC()
393                 {
394                         position_valid = true;
395                 }
396
397                 virtual bool isValidPosition(v3s16 p)
398                 {
399                         //return position_valid ^ (p==position_valid_exception);
400                         bool exception = false;
401                         for(core::list<v3s16>::Iterator i=validity_exceptions.begin();
402                                         i != validity_exceptions.end(); i++)
403                         {
404                                 if(p == *i)
405                                 {
406                                         exception = true;
407                                         break;
408                                 }
409                         }
410                         return exception ? !position_valid : position_valid;
411                 }
412
413                 virtual MapNode getNode(v3s16 p)
414                 {
415                         if(isValidPosition(p) == false)
416                                 throw InvalidPositionException();
417                         return node;
418                 }
419
420                 virtual void setNode(v3s16 p, MapNode & n)
421                 {
422                         if(isValidPosition(p) == false)
423                                 throw InvalidPositionException();
424                 };
425
426                 virtual u16 nodeContainerId() const
427                 {
428                         return 666;
429                 }
430         };
431
432         void Run()
433         {
434                 TC parent;
435                 
436                 MapBlock b(&parent, v3s16(1,1,1));
437                 v3s16 relpos(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
438
439                 assert(b.getPosRelative() == relpos);
440
441                 assert(b.getBox().MinEdge.X == MAP_BLOCKSIZE);
442                 assert(b.getBox().MaxEdge.X == MAP_BLOCKSIZE*2-1);
443                 assert(b.getBox().MinEdge.Y == MAP_BLOCKSIZE);
444                 assert(b.getBox().MaxEdge.Y == MAP_BLOCKSIZE*2-1);
445                 assert(b.getBox().MinEdge.Z == MAP_BLOCKSIZE);
446                 assert(b.getBox().MaxEdge.Z == MAP_BLOCKSIZE*2-1);
447                 
448                 assert(b.isValidPosition(v3s16(0,0,0)) == true);
449                 assert(b.isValidPosition(v3s16(-1,0,0)) == false);
450                 assert(b.isValidPosition(v3s16(-1,-142,-2341)) == false);
451                 assert(b.isValidPosition(v3s16(-124,142,2341)) == false);
452                 assert(b.isValidPosition(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1)) == true);
453                 assert(b.isValidPosition(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE,MAP_BLOCKSIZE-1)) == false);
454
455                 /*
456                         TODO: this method should probably be removed
457                         if the block size isn't going to be set variable
458                 */
459                 /*assert(b.getSizeNodes() == v3s16(MAP_BLOCKSIZE,
460                                 MAP_BLOCKSIZE, MAP_BLOCKSIZE));*/
461                 
462                 // Changed flag should be initially set
463                 assert(b.getChangedFlag() == true);
464                 b.resetChangedFlag();
465                 assert(b.getChangedFlag() == false);
466
467                 // All nodes should have been set to
468                 // .d=CONTENT_IGNORE and .getLight() = 0
469                 for(u16 z=0; z<MAP_BLOCKSIZE; z++)
470                 for(u16 y=0; y<MAP_BLOCKSIZE; y++)
471                 for(u16 x=0; x<MAP_BLOCKSIZE; x++)
472                 {
473                         //assert(b.getNode(v3s16(x,y,z)).getContent() == CONTENT_AIR);
474                         assert(b.getNode(v3s16(x,y,z)).getContent() == CONTENT_IGNORE);
475                         assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0);
476                         assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0);
477                 }
478                 
479                 {
480                         MapNode n(CONTENT_AIR);
481                         for(u16 z=0; z<MAP_BLOCKSIZE; z++)
482                         for(u16 y=0; y<MAP_BLOCKSIZE; y++)
483                         for(u16 x=0; x<MAP_BLOCKSIZE; x++)
484                         {
485                                 b.setNode(v3s16(x,y,z), n);
486                         }
487                 }
488                         
489                 /*
490                         Parent fetch functions
491                 */
492                 parent.position_valid = false;
493                 parent.node.setContent(5);
494
495                 MapNode n;
496                 
497                 // Positions in the block should still be valid
498                 assert(b.isValidPositionParent(v3s16(0,0,0)) == true);
499                 assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1)) == true);
500                 n = b.getNodeParent(v3s16(0,MAP_BLOCKSIZE-1,0));
501                 assert(n.getContent() == CONTENT_AIR);
502
503                 // ...but outside the block they should be invalid
504                 assert(b.isValidPositionParent(v3s16(-121,2341,0)) == false);
505                 assert(b.isValidPositionParent(v3s16(-1,0,0)) == false);
506                 assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE)) == false);
507                 
508                 {
509                         bool exception_thrown = false;
510                         try{
511                                 // This should throw an exception
512                                 MapNode n = b.getNodeParent(v3s16(0,0,-1));
513                         }
514                         catch(InvalidPositionException &e)
515                         {
516                                 exception_thrown = true;
517                         }
518                         assert(exception_thrown);
519                 }
520
521                 parent.position_valid = true;
522                 // Now the positions outside should be valid
523                 assert(b.isValidPositionParent(v3s16(-121,2341,0)) == true);
524                 assert(b.isValidPositionParent(v3s16(-1,0,0)) == true);
525                 assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE)) == true);
526                 n = b.getNodeParent(v3s16(0,0,MAP_BLOCKSIZE));
527                 assert(n.getContent() == 5);
528
529                 /*
530                         Set a node
531                 */
532                 v3s16 p(1,2,0);
533                 n.setContent(4);
534                 b.setNode(p, n);
535                 assert(b.getNode(p).getContent() == 4);
536                 //TODO: Update to new system
537                 /*assert(b.getNodeTile(p) == 4);
538                 assert(b.getNodeTile(v3s16(-1,-1,0)) == 5);*/
539                 
540                 /*
541                         propagateSunlight()
542                 */
543                 // Set lighting of all nodes to 0
544                 for(u16 z=0; z<MAP_BLOCKSIZE; z++){
545                         for(u16 y=0; y<MAP_BLOCKSIZE; y++){
546                                 for(u16 x=0; x<MAP_BLOCKSIZE; x++){
547                                         MapNode n = b.getNode(v3s16(x,y,z));
548                                         n.setLight(LIGHTBANK_DAY, 0);
549                                         n.setLight(LIGHTBANK_NIGHT, 0);
550                                         b.setNode(v3s16(x,y,z), n);
551                                 }
552                         }
553                 }
554                 {
555                         /*
556                                 Check how the block handles being a lonely sky block
557                         */
558                         parent.position_valid = true;
559                         b.setIsUnderground(false);
560                         parent.node.setContent(CONTENT_AIR);
561                         parent.node.setLight(LIGHTBANK_DAY, LIGHT_SUN);
562                         parent.node.setLight(LIGHTBANK_NIGHT, 0);
563                         core::map<v3s16, bool> light_sources;
564                         // The bottom block is invalid, because we have a shadowing node
565                         assert(b.propagateSunlight(light_sources) == false);
566                         assert(b.getNode(v3s16(1,4,0)).getLight(LIGHTBANK_DAY) == LIGHT_SUN);
567                         assert(b.getNode(v3s16(1,3,0)).getLight(LIGHTBANK_DAY) == LIGHT_SUN);
568                         assert(b.getNode(v3s16(1,2,0)).getLight(LIGHTBANK_DAY) == 0);
569                         assert(b.getNode(v3s16(1,1,0)).getLight(LIGHTBANK_DAY) == 0);
570                         assert(b.getNode(v3s16(1,0,0)).getLight(LIGHTBANK_DAY) == 0);
571                         assert(b.getNode(v3s16(1,2,3)).getLight(LIGHTBANK_DAY) == LIGHT_SUN);
572                         assert(b.getFaceLight2(1000, p, v3s16(0,1,0)) == LIGHT_SUN);
573                         assert(b.getFaceLight2(1000, p, v3s16(0,-1,0)) == 0);
574                         assert(b.getFaceLight2(0, p, v3s16(0,-1,0)) == 0);
575                         // According to MapBlock::getFaceLight,
576                         // The face on the z+ side should have double-diminished light
577                         //assert(b.getFaceLight(p, v3s16(0,0,1)) == diminish_light(diminish_light(LIGHT_MAX)));
578                         // The face on the z+ side should have diminished light
579                         assert(b.getFaceLight2(1000, p, v3s16(0,0,1)) == diminish_light(LIGHT_MAX));
580                 }
581                 /*
582                         Check how the block handles being in between blocks with some non-sunlight
583                         while being underground
584                 */
585                 {
586                         // Make neighbours to exist and set some non-sunlight to them
587                         parent.position_valid = true;
588                         b.setIsUnderground(true);
589                         parent.node.setLight(LIGHTBANK_DAY, LIGHT_MAX/2);
590                         core::map<v3s16, bool> light_sources;
591                         // The block below should be valid because there shouldn't be
592                         // sunlight in there either
593                         assert(b.propagateSunlight(light_sources, true) == true);
594                         // Should not touch nodes that are not affected (that is, all of them)
595                         //assert(b.getNode(v3s16(1,2,3)).getLight() == LIGHT_SUN);
596                         // Should set light of non-sunlighted blocks to 0.
597                         assert(b.getNode(v3s16(1,2,3)).getLight(LIGHTBANK_DAY) == 0);
598                 }
599                 /*
600                         Set up a situation where:
601                         - There is only air in this block
602                         - There is a valid non-sunlighted block at the bottom, and
603                         - Invalid blocks elsewhere.
604                         - the block is not underground.
605
606                         This should result in bottom block invalidity
607                 */
608                 {
609                         b.setIsUnderground(false);
610                         // Clear block
611                         for(u16 z=0; z<MAP_BLOCKSIZE; z++){
612                                 for(u16 y=0; y<MAP_BLOCKSIZE; y++){
613                                         for(u16 x=0; x<MAP_BLOCKSIZE; x++){
614                                                 MapNode n;
615                                                 n.setContent(CONTENT_AIR);
616                                                 n.setLight(LIGHTBANK_DAY, 0);
617                                                 b.setNode(v3s16(x,y,z), n);
618                                         }
619                                 }
620                         }
621                         // Make neighbours invalid
622                         parent.position_valid = false;
623                         // Add exceptions to the top of the bottom block
624                         for(u16 x=0; x<MAP_BLOCKSIZE; x++)
625                         for(u16 z=0; z<MAP_BLOCKSIZE; z++)
626                         {
627                                 parent.validity_exceptions.push_back(v3s16(MAP_BLOCKSIZE+x, MAP_BLOCKSIZE-1, MAP_BLOCKSIZE+z));
628                         }
629                         // Lighting value for the valid nodes
630                         parent.node.setLight(LIGHTBANK_DAY, LIGHT_MAX/2);
631                         core::map<v3s16, bool> light_sources;
632                         // Bottom block is not valid
633                         assert(b.propagateSunlight(light_sources) == false);
634                 }
635         }
636 };
637
638 struct TestMapSector
639 {
640         class TC : public NodeContainer
641         {
642         public:
643
644                 MapNode node;
645                 bool position_valid;
646
647                 TC()
648                 {
649                         position_valid = true;
650                 }
651
652                 virtual bool isValidPosition(v3s16 p)
653                 {
654                         return position_valid;
655                 }
656
657                 virtual MapNode getNode(v3s16 p)
658                 {
659                         if(position_valid == false)
660                                 throw InvalidPositionException();
661                         return node;
662                 }
663
664                 virtual void setNode(v3s16 p, MapNode & n)
665                 {
666                         if(position_valid == false)
667                                 throw InvalidPositionException();
668                 };
669                 
670                 virtual u16 nodeContainerId() const
671                 {
672                         return 666;
673                 }
674         };
675         
676         void Run()
677         {
678                 TC parent;
679                 parent.position_valid = false;
680                 
681                 // Create one with no heightmaps
682                 ServerMapSector sector(&parent, v2s16(1,1));
683                 
684                 assert(sector.getBlockNoCreateNoEx(0) == 0);
685                 assert(sector.getBlockNoCreateNoEx(1) == 0);
686
687                 MapBlock * bref = sector.createBlankBlock(-2);
688                 
689                 assert(sector.getBlockNoCreateNoEx(0) == 0);
690                 assert(sector.getBlockNoCreateNoEx(-2) == bref);
691                 
692                 //TODO: Check for AlreadyExistsException
693
694                 /*bool exception_thrown = false;
695                 try{
696                         sector.getBlock(0);
697                 }
698                 catch(InvalidPositionException &e){
699                         exception_thrown = true;
700                 }
701                 assert(exception_thrown);*/
702
703         }
704 };
705 #endif
706
707 struct TestSocket
708 {
709         void Run()
710         {
711                 const int port = 30003;
712                 UDPSocket socket;
713                 socket.Bind(port);
714
715                 const char sendbuffer[] = "hello world!";
716                 socket.Send(Address(127,0,0,1,port), sendbuffer, sizeof(sendbuffer));
717
718                 sleep_ms(50);
719
720                 char rcvbuffer[256];
721                 memset(rcvbuffer, 0, sizeof(rcvbuffer));
722                 Address sender;
723                 for(;;)
724                 {
725                         int bytes_read = socket.Receive(sender, rcvbuffer, sizeof(rcvbuffer));
726                         if(bytes_read < 0)
727                                 break;
728                 }
729                 //FIXME: This fails on some systems
730                 assert(strncmp(sendbuffer, rcvbuffer, sizeof(sendbuffer))==0);
731                 assert(sender.getAddress() == Address(127,0,0,1, 0).getAddress());
732         }
733 };
734
735 struct TestConnection
736 {
737         void TestHelpers()
738         {
739                 /*
740                         Test helper functions
741                 */
742
743                 // Some constants for testing
744                 u32 proto_id = 0x12345678;
745                 u16 peer_id = 123;
746                 u8 channel = 2;
747                 SharedBuffer<u8> data1(1);
748                 data1[0] = 100;
749                 Address a(127,0,0,1, 10);
750                 u16 seqnum = 34352;
751
752                 con::BufferedPacket p1 = con::makePacket(a, data1,
753                                 proto_id, peer_id, channel);
754                 /*
755                         We should now have a packet with this data:
756                         Header:
757                                 [0] u32 protocol_id
758                                 [4] u16 sender_peer_id
759                                 [6] u8 channel
760                         Data:
761                                 [7] u8 data1[0]
762                 */
763                 assert(readU32(&p1.data[0]) == proto_id);
764                 assert(readU16(&p1.data[4]) == peer_id);
765                 assert(readU8(&p1.data[6]) == channel);
766                 assert(readU8(&p1.data[7]) == data1[0]);
767                 
768                 //dstream<<"initial data1[0]="<<((u32)data1[0]&0xff)<<std::endl;
769
770                 SharedBuffer<u8> p2 = con::makeReliablePacket(data1, seqnum);
771
772                 /*dstream<<"p2.getSize()="<<p2.getSize()<<", data1.getSize()="
773                                 <<data1.getSize()<<std::endl;
774                 dstream<<"readU8(&p2[3])="<<readU8(&p2[3])
775                                 <<" p2[3]="<<((u32)p2[3]&0xff)<<std::endl;
776                 dstream<<"data1[0]="<<((u32)data1[0]&0xff)<<std::endl;*/
777
778                 assert(p2.getSize() == 3 + data1.getSize());
779                 assert(readU8(&p2[0]) == TYPE_RELIABLE);
780                 assert(readU16(&p2[1]) == seqnum);
781                 assert(readU8(&p2[3]) == data1[0]);
782         }
783
784         struct Handler : public con::PeerHandler
785         {
786                 Handler(const char *a_name)
787                 {
788                         count = 0;
789                         last_id = 0;
790                         name = a_name;
791                 }
792                 void peerAdded(con::Peer *peer)
793                 {
794                         dstream<<"Handler("<<name<<")::peerAdded(): "
795                                         "id="<<peer->id<<std::endl;
796                         last_id = peer->id;
797                         count++;
798                 }
799                 void deletingPeer(con::Peer *peer, bool timeout)
800                 {
801                         dstream<<"Handler("<<name<<")::deletingPeer(): "
802                                         "id="<<peer->id
803                                         <<", timeout="<<timeout<<std::endl;
804                         last_id = peer->id;
805                         count--;
806                 }
807
808                 s32 count;
809                 u16 last_id;
810                 const char *name;
811         };
812
813         void Run()
814         {
815                 DSTACK("TestConnection::Run");
816
817                 TestHelpers();
818
819                 /*
820                         Test some real connections
821                 */
822                 u32 proto_id = 0xad26846a;
823
824                 Handler hand_server("server");
825                 Handler hand_client("client");
826                 
827                 dstream<<"** Creating server Connection"<<std::endl;
828                 con::Connection server(proto_id, 512, 5.0, &hand_server);
829                 server.Serve(30001);
830                 
831                 dstream<<"** Creating client Connection"<<std::endl;
832                 con::Connection client(proto_id, 512, 5.0, &hand_client);
833
834                 assert(hand_server.count == 0);
835                 assert(hand_client.count == 0);
836                 
837                 sleep_ms(50);
838                 
839                 Address server_address(127,0,0,1, 30001);
840                 dstream<<"** running client.Connect()"<<std::endl;
841                 client.Connect(server_address);
842
843                 sleep_ms(50);
844                 
845                 // Client should have added server now
846                 assert(hand_client.count == 1);
847                 assert(hand_client.last_id == 1);
848                 // But server should not have added client
849                 assert(hand_server.count == 0);
850
851                 try
852                 {
853                         u16 peer_id;
854                         u8 data[100];
855                         dstream<<"** running server.Receive()"<<std::endl;
856                         u32 size = server.Receive(peer_id, data, 100);
857                         dstream<<"** Server received: peer_id="<<peer_id
858                                         <<", size="<<size
859                                         <<std::endl;
860                 }
861                 catch(con::NoIncomingDataException &e)
862                 {
863                         // No actual data received, but the client has
864                         // probably been connected
865                 }
866                 
867                 // Client should be the same
868                 assert(hand_client.count == 1);
869                 assert(hand_client.last_id == 1);
870                 // Server should have the client
871                 assert(hand_server.count == 1);
872                 assert(hand_server.last_id == 2);
873                 
874                 //sleep_ms(50);
875
876                 while(client.Connected() == false)
877                 {
878                         try
879                         {
880                                 u16 peer_id;
881                                 u8 data[100];
882                                 dstream<<"** running client.Receive()"<<std::endl;
883                                 u32 size = client.Receive(peer_id, data, 100);
884                                 dstream<<"** Client received: peer_id="<<peer_id
885                                                 <<", size="<<size
886                                                 <<std::endl;
887                         }
888                         catch(con::NoIncomingDataException &e)
889                         {
890                         }
891                         sleep_ms(50);
892                 }
893
894                 sleep_ms(50);
895                 
896                 try
897                 {
898                         u16 peer_id;
899                         u8 data[100];
900                         dstream<<"** running server.Receive()"<<std::endl;
901                         u32 size = server.Receive(peer_id, data, 100);
902                         dstream<<"** Server received: peer_id="<<peer_id
903                                         <<", size="<<size
904                                         <<std::endl;
905                 }
906                 catch(con::NoIncomingDataException &e)
907                 {
908                 }
909
910                 {
911                         /*u8 data[] = "Hello World!";
912                         u32 datasize = sizeof(data);*/
913                         SharedBuffer<u8> data = SharedBufferFromString("Hello World!");
914
915                         dstream<<"** running client.Send()"<<std::endl;
916                         client.Send(PEER_ID_SERVER, 0, data, true);
917
918                         sleep_ms(50);
919
920                         u16 peer_id;
921                         u8 recvdata[100];
922                         dstream<<"** running server.Receive()"<<std::endl;
923                         u32 size = server.Receive(peer_id, recvdata, 100);
924                         dstream<<"** Server received: peer_id="<<peer_id
925                                         <<", size="<<size
926                                         <<", data="<<*data
927                                         <<std::endl;
928                         assert(memcmp(*data, recvdata, data.getSize()) == 0);
929                 }
930                 
931                 u16 peer_id_client = 2;
932
933                 {
934                         /*
935                                 Send consequent packets in different order
936                         */
937                         //u8 data1[] = "hello1";
938                         //u8 data2[] = "hello2";
939                         SharedBuffer<u8> data1 = SharedBufferFromString("hello1");
940                         SharedBuffer<u8> data2 = SharedBufferFromString("Hello2");
941
942                         Address client_address =
943                                         server.GetPeer(peer_id_client)->address;
944                         
945                         dstream<<"*** Sending packets in wrong order (2,1,2)"
946                                         <<std::endl;
947                         
948                         u8 chn = 0;
949                         con::Channel *ch = &server.GetPeer(peer_id_client)->channels[chn];
950                         u16 sn = ch->next_outgoing_seqnum;
951                         ch->next_outgoing_seqnum = sn+1;
952                         server.Send(peer_id_client, chn, data2, true);
953                         ch->next_outgoing_seqnum = sn;
954                         server.Send(peer_id_client, chn, data1, true);
955                         ch->next_outgoing_seqnum = sn+1;
956                         server.Send(peer_id_client, chn, data2, true);
957
958                         sleep_ms(50);
959
960                         dstream<<"*** Receiving the packets"<<std::endl;
961
962                         u16 peer_id;
963                         u8 recvdata[20];
964                         u32 size;
965
966                         dstream<<"** running client.Receive()"<<std::endl;
967                         peer_id = 132;
968                         size = client.Receive(peer_id, recvdata, 20);
969                         dstream<<"** Client received: peer_id="<<peer_id
970                                         <<", size="<<size
971                                         <<", data="<<recvdata
972                                         <<std::endl;
973                         assert(size == data1.getSize());
974                         assert(memcmp(*data1, recvdata, data1.getSize()) == 0);
975                         assert(peer_id == PEER_ID_SERVER);
976                         
977                         dstream<<"** running client.Receive()"<<std::endl;
978                         peer_id = 132;
979                         size = client.Receive(peer_id, recvdata, 20);
980                         dstream<<"** Client received: peer_id="<<peer_id
981                                         <<", size="<<size
982                                         <<", data="<<recvdata
983                                         <<std::endl;
984                         assert(size == data2.getSize());
985                         assert(memcmp(*data2, recvdata, data2.getSize()) == 0);
986                         assert(peer_id == PEER_ID_SERVER);
987                         
988                         bool got_exception = false;
989                         try
990                         {
991                                 dstream<<"** running client.Receive()"<<std::endl;
992                                 peer_id = 132;
993                                 size = client.Receive(peer_id, recvdata, 20);
994                                 dstream<<"** Client received: peer_id="<<peer_id
995                                                 <<", size="<<size
996                                                 <<", data="<<recvdata
997                                                 <<std::endl;
998                         }
999                         catch(con::NoIncomingDataException &e)
1000                         {
1001                                 dstream<<"** No incoming data for client"<<std::endl;
1002                                 got_exception = true;
1003                         }
1004                         assert(got_exception);
1005                 }
1006                 {
1007                         const int datasize = 30000;
1008                         SharedBuffer<u8> data1(datasize);
1009                         for(u16 i=0; i<datasize; i++){
1010                                 data1[i] = i/4;
1011                         }
1012
1013                         dstream<<"Sending data (size="<<datasize<<"):";
1014                         for(int i=0; i<datasize && i<20; i++){
1015                                 if(i%2==0) DEBUGPRINT(" ");
1016                                 DEBUGPRINT("%.2X", ((int)((const char*)*data1)[i])&0xff);
1017                         }
1018                         if(datasize>20)
1019                                 dstream<<"...";
1020                         dstream<<std::endl;
1021                         
1022                         server.Send(peer_id_client, 0, data1, true);
1023
1024                         sleep_ms(50);
1025                         
1026                         u8 recvdata[datasize + 1000];
1027                         dstream<<"** running client.Receive()"<<std::endl;
1028                         u16 peer_id = 132;
1029                         u16 size = client.Receive(peer_id, recvdata, datasize + 1000);
1030                         dstream<<"** Client received: peer_id="<<peer_id
1031                                         <<", size="<<size
1032                                         <<std::endl;
1033
1034                         dstream<<"Received data (size="<<size<<"):";
1035                         for(int i=0; i<size && i<20; i++){
1036                                 if(i%2==0) DEBUGPRINT(" ");
1037                                 DEBUGPRINT("%.2X", ((int)((const char*)recvdata)[i])&0xff);
1038                         }
1039                         if(size>20)
1040                                 dstream<<"...";
1041                         dstream<<std::endl;
1042
1043                         assert(memcmp(*data1, recvdata, data1.getSize()) == 0);
1044                         assert(peer_id == PEER_ID_SERVER);
1045                 }
1046                 
1047                 // Check peer handlers
1048                 assert(hand_client.count == 1);
1049                 assert(hand_client.last_id == 1);
1050                 assert(hand_server.count == 1);
1051                 assert(hand_server.last_id == 2);
1052                 
1053                 //assert(0);
1054         }
1055 };
1056
1057 #define TEST(X)\
1058 {\
1059         X x;\
1060         dstream<<"Running " #X <<std::endl;\
1061         x.Run();\
1062 }
1063
1064 void run_tests()
1065 {
1066         DSTACK(__FUNCTION_NAME);
1067         dstream<<"run_tests() started"<<std::endl;
1068         TEST(TestUtilities);
1069         TEST(TestSettings);
1070         TEST(TestCompress);
1071         TEST(TestMapNode);
1072         TEST(TestVoxelManipulator);
1073         //TEST(TestMapBlock);
1074         //TEST(TestMapSector);
1075         if(INTERNET_SIMULATOR == false){
1076                 TEST(TestSocket);
1077                 dout_con<<"=== BEGIN RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
1078                 TEST(TestConnection);
1079                 dout_con<<"=== END RUNNING UNIT TESTS FOR CONNECTION ==="<<std::endl;
1080         }
1081         dstream<<"run_tests() passed"<<std::endl;
1082 }
1083