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