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