1 module memutils.tests; 2 import memutils.all; 3 import core.thread : Fiber; 4 import std.conv : to; 5 6 version(MemutilsTests): 7 static if (!SkipUnitTests && !DisableDebugAllocations): 8 9 // Test hashmap, freelists 10 void hashmapFreeListTest(ALLOC)() { 11 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 12 { 13 HashMapRef!(string, string, ALLOC) hm; 14 hm["hey"] = "you"; 15 assert(getAllocator!(ALLOC.ident)().bytesAllocated() > 0); 16 void hello(HashMapRef!(string, string, ALLOC) map) { 17 assert(map["hey"] == "you"); 18 map["you"] = "hey"; 19 } 20 hello(hm); 21 assert(hm["you"] == "hey"); 22 destroy(hm); 23 assert(hm.empty); 24 } 25 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 26 27 } 28 29 // Test Vector, FreeLists & Array 30 void vectorArrayTest(ALLOC)() { 31 { 32 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 33 Vector!(ubyte, ALLOC) data; 34 data ~= "Hello there"; 35 assert(getAllocator!(ALLOC.ident)().bytesAllocated() > 0); 36 assert(data[] == "Hello there"); 37 38 Vector!(Array!(ubyte, ALLOC), ALLOC) arr; 39 arr ~= data.dupr; 40 assert(arr[0] == data && arr[0][] == "Hello there"); 41 42 { 43 Vector!(ubyte, ALLOC) outbuf_; 44 ubyte[] reference; 45 int i; 46 for (i = 0; i < 4096; i++) { 47 string abc = "abcdefghijklmnop"; 48 outbuf_ ~= cast(ubyte[])abc; 49 reference ~= cast(ubyte[]) abc; 50 51 assert(outbuf_[] == reference, "realloc error"); 52 } 53 } 54 } 55 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 56 } 57 58 // Test HashMap, FreeLists & Array 59 void hashmapComplexTest(ALLOC)() { 60 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 61 { 62 HashMap!(string, Array!dchar, ALLOC) hm; 63 hm["hey"] = array("you"d); 64 hm["hello"] = hm["hey"]; 65 assert(*hm["hello"] is *hm["hey"]); 66 hm["hello"] = hm["hey"].dupr; 67 assert(*hm["hello"] !is *hm["hey"]); 68 auto vec = hm["hey"].dup; 69 assert(vec[] == hm["hey"][]); 70 71 72 assert(!__traits(compiles, { void handler(HashMap!(string, Array!dchar, ALLOC) hm) { } handler(hm); })); 73 } 74 75 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 76 } 77 78 // Test RBTree 79 void rbTreeTest(ALLOC)() { 80 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 81 { 82 RBTree!(int, "a < b", true, ALLOC) rbtree; 83 84 rbtree.insert( [50, 51, 52, 53, 54] ); 85 auto vec = rbtree.lowerBoundRange(52).vector(); 86 assert(vec[] == [50, 51]); 87 } 88 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 89 } 90 91 // Test Unique 92 void uniqueTest(ALLOC)() { 93 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 94 { 95 class A { int a; } 96 Unique!(A, ALLOC) a; 97 auto inst = ObjectAllocator!(A, ALLOC).alloc(); 98 A a_check = inst; 99 inst.a = 10; 100 auto bytes = getAllocator!(ALLOC.ident)().bytesAllocated(); 101 assert(bytes > 0); 102 a = inst; 103 assert(!inst); 104 assert(a.a == 10); 105 a.free(); 106 } 107 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 108 } 109 110 // Test FreeList casting 111 void refCountedCastTest(ALLOC)() { 112 class A { 113 this() { a=0; } 114 protected int a; 115 protected void incr() { 116 a += 1; 117 } 118 public final int get() { 119 return a; 120 } 121 } 122 class B : A { 123 int c; 124 int d; 125 long e; 126 override protected void incr() { 127 a += 3; 128 } 129 } 130 131 alias ARef = RefCounted!(A, ALLOC); 132 alias BRef = RefCounted!(B, ALLOC); 133 134 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 135 { 136 ARef a; 137 a = ARef(); 138 a.incr(); 139 assert(a.get() == 1); 140 destroy(a); /// destruction test 141 assert(!a); 142 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 143 144 { /// cast test 145 BRef b = BRef(); 146 a = cast(ARef) b; 147 static void doIncr(ARef a_ref) { a_ref.incr(); } 148 doIncr(a); 149 assert(a.get() == 3); 150 } 151 ARef c = a; 152 assert(c.get() == 3); 153 destroy(c); 154 assert(a); 155 } 156 // The B object allocates a lot more. If A destructor called B's dtor we get 0 here. 157 assert(getAllocator!(ALLOC.ident)().bytesAllocated() == 0); 158 } 159 160 /// test Circular buffer 161 void circularBufferTest(ALLOC)() { 162 auto buf1 = CircularBuffer!(ubyte, 0, ALLOC)(65536); 163 ubyte[] data = new ubyte[150]; 164 data[50] = 'b'; 165 buf1.put(data); 166 assert(buf1.length == 150); 167 assert(buf1[50] == 'b'); 168 169 // pulled from vibe.d - vibe.utils.array 170 auto buf = CircularBuffer!(int, 0, ALLOC)(5); 171 assert(buf.length == 0 && buf.freeSpace == 5); buf.put(1); // |1 . . . . 172 assert(buf.length == 1 && buf.freeSpace == 4); buf.put(2); // |1 2 . . . 173 assert(buf.length == 2 && buf.freeSpace == 3); buf.put(3); // |1 2 3 . . 174 assert(buf.length == 3 && buf.freeSpace == 2); buf.put(4); // |1 2 3 4 . 175 assert(buf.length == 4 && buf.freeSpace == 1); buf.put(5); // |1 2 3 4 5 176 assert(buf.length == 5 && buf.freeSpace == 0); 177 assert(buf.front == 1); 178 buf.popFront(); // .|2 3 4 5 179 assert(buf.front == 2); 180 buf.popFrontN(2); // . . .|4 5 181 assert(buf.front == 4); 182 assert(buf.length == 2 && buf.freeSpace == 3); 183 buf.put([6, 7, 8]); // 6 7 8|4 5 184 assert(buf.length == 5 && buf.freeSpace == 0); 185 int[5] dst; 186 buf.read(dst); // . . .|. . 187 assert(dst == [4, 5, 6, 7, 8]); 188 assert(buf.length == 0 && buf.freeSpace == 5); 189 buf.put([1, 2]); // . . .|1 2 190 assert(buf.length == 2 && buf.freeSpace == 3); 191 buf.read(dst[0 .. 2]); //|. . . . . 192 assert(dst[0 .. 2] == [1, 2]); 193 } 194 195 void dictionaryListTest(ALLOC)() 196 { 197 DictionaryList!(string, int, ALLOC) a; 198 a.insert("a", 1); 199 a.insert("a", 2); 200 assert(a["a"] == 1); 201 assert(a.getValuesAt("a") == [1, 2]); 202 //logTrace("Done getValuesAt"); 203 a["a"] = 3; 204 assert(a["a"] == 3); 205 assert(a.getValuesAt("a") == [3, 2]); 206 a.removeAll("a"); 207 assert(a.getValuesAt("a").length == 0); 208 assert(a.get("a", 4) == 4); 209 a.insert("b", 2); 210 a.insert("b", 1); 211 a.remove("b"); 212 assert(a.getValuesAt("b") == [1]); 213 214 DictionaryList!(string, int, ALLOC, false) b; 215 b.insert("a", 1); 216 b.insert("A", 2); 217 assert(b["A"] == 1); 218 assert(b.getValuesAt("a") == [1, 2]); 219 220 foreach (int i; 0 .. 15_000) { 221 b.insert("a", i); 222 } 223 224 // TODO: Fix case insensitive comparison on x86 225 assert(b.getValuesAt("a").length >= 15_001, "Found " ~ b.getValuesAt("a").length.to!string); 226 227 } 228 229 void propagateTests(alias fct)() { 230 logDebug("Testing ", fct.stringof); 231 fct!AppMem(); 232 fct!SecureMem(); 233 fct!ThreadMem(); 234 } 235 236 void highLevelAllocTest() { 237 logDebug("Testing High Level Allocators"); 238 class A { 239 int a; 240 241 ~this() { 242 a = 0; 243 } 244 } 245 A a = ThreadMem.alloc!A(); 246 a.a = 10; 247 ThreadMem.free(a); 248 assert(!a); 249 250 A appAllocated() { 251 A c = AppMem.alloc!A(); 252 c.a = 10; 253 return c; 254 } 255 256 assert(appAllocated().a == 10); 257 258 ubyte[] ub = ThreadMem.alloc!(ubyte[])(150); 259 260 assert(ub.length == 150); 261 ub[50] = 'a'; 262 ThreadMem.free(ub); 263 assert(ub is null); 264 } 265 struct A { 266 int a; 267 268 ~this() { 269 //logDebug("Dtor called"); 270 a = 0; 271 } 272 } 273 274 void scopedTest() { 275 276 277 logDebug("Testing ScopedPool"); 278 279 A* num; 280 { 281 PoolStack.push(); 282 num = alloc!A(0); 283 num.a = 2; 284 //logDebug("Freezing"); 285 PoolStack.disable(); PoolStack.enable(); 286 PoolStack.freeze(1); 287 //logDebug("Frozen"); 288 assert(PoolStack.empty, "Stack is not empty"); 289 PoolStack.pop(); 290 assert(num.a == 0, "Dtor not called"); 291 } 292 { 293 auto pool1 = ScopedPool(); 294 num = alloc!A(0); 295 } 296 297 298 Fiber f; 299 f = new Fiber(delegate { auto pool = ScopedPool(); pool.freeze(); pool.unfreeze(); PoolStack.disable(); PoolStack.enable(); }); 300 f.call(); 301 } 302 303 unittest { 304 propagateTests!hashmapFreeListTest(); 305 propagateTests!vectorArrayTest(); 306 propagateTests!hashmapComplexTest(); 307 propagateTests!rbTreeTest(); 308 propagateTests!uniqueTest(); 309 propagateTests!refCountedCastTest(); 310 propagateTests!circularBufferTest(); 311 propagateTests!dictionaryListTest(); 312 313 scopedTest(); 314 315 highLevelAllocTest(); 316 }