Skip to content

Commit e30dfd2

Browse files
committed
feat: Add unit tests for object and nested array equality and containment assertions
1 parent b058ecf commit e30dfd2

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

source/fluentasserts/core/memory/heapequable.d

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,18 +331,34 @@ void copyHeapEquableArray(
331331
foreach (i; 0 .. count) {
332332
dst[i]._serialized = src[i]._serialized;
333333
dst[i]._kind = src[i]._kind;
334-
dst[i]._elementCount = src[i]._elementCount;
335-
dst[i]._elements = cast(HeapEquableValue*) src[i]._elements;
336334
dst[i]._serialized.incrementRefCount();
335+
dst[i]._objectRef = cast(Object) src[i]._objectRef;
336+
337+
// Deep copy nested elements
338+
if (src[i]._elements !is null && src[i]._elementCount > 0) {
339+
dst[i]._elements = duplicateHeapEquableArray(src[i]._elements, src[i]._elementCount);
340+
dst[i]._elementCount = (dst[i]._elements !is null) ? src[i]._elementCount : 0;
341+
} else {
342+
dst[i]._elements = null;
343+
dst[i]._elementCount = 0;
344+
}
337345
}
338346
}
339347

340348
void copyHeapEquableElement(HeapEquableValue* dst, ref HeapEquableValue src) @trusted @nogc nothrow {
341349
dst._serialized = src._serialized;
342350
dst._kind = src._kind;
343-
dst._elementCount = src._elementCount;
344-
dst._elements = src._elements;
345351
dst._serialized.incrementRefCount();
352+
dst._objectRef = src._objectRef;
353+
354+
// Deep copy nested elements
355+
if (src._elements !is null && src._elementCount > 0) {
356+
dst._elements = duplicateHeapEquableArray(src._elements, src._elementCount);
357+
dst._elementCount = (dst._elements !is null) ? src._elementCount : 0;
358+
} else {
359+
dst._elements = null;
360+
dst._elementCount = 0;
361+
}
346362
}
347363

348364
HeapEquableValue* duplicateHeapEquableArray(
@@ -377,6 +393,10 @@ HeapEquableValue[] allocateSingleGCElement(ref const HeapEquableValue value) @tr
377393
try {
378394
auto result = new HeapEquableValue[1];
379395
result[0] = value;
396+
// Clear the nested elements pointer so GC won't try to free malloc'd memory.
397+
// The copy still has valid serialized data for comparison.
398+
result[0]._elements = null;
399+
result[0]._elementCount = 0;
380400
return result;
381401
} catch (Exception) {
382402
return [];
@@ -388,6 +408,10 @@ HeapEquableValue[] copyToGCArray(const HeapEquableValue* elements, size_t count)
388408
auto result = new HeapEquableValue[count];
389409
foreach (i; 0 .. count) {
390410
result[i] = elements[i];
411+
// Clear the nested elements pointer so GC won't try to free malloc'd memory.
412+
// The copy still has valid serialized data for comparison.
413+
result[i]._elements = null;
414+
result[i]._elementCount = 0;
391415
}
392416
return result;
393417
} catch (Exception) {

source/fluentasserts/operations/equality/equal.d

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,3 +1007,25 @@ unittest {
10071007
assert(a1 != a2, "D's != operator should use opEquals");
10081008
a1.should.not.equal(a2);
10091009
}
1010+
1011+
@("Object array equal itself passes")
1012+
unittest {
1013+
Object[] l = [new Object(), new Object()];
1014+
l.should.equal(l);
1015+
}
1016+
1017+
@("associative array equal itself passes")
1018+
unittest {
1019+
string[string] al = ["k1": "v1", "k2": "v2"];
1020+
al.should.equal(al);
1021+
}
1022+
1023+
@("nested int array equal passes")
1024+
unittest {
1025+
import std.range : iota;
1026+
import std.algorithm : map;
1027+
import std.array : array;
1028+
1029+
auto ll = iota(1, 4).map!iota;
1030+
ll.map!array.array.should.equal([[0], [0, 1], [0, 1, 2]]);
1031+
}

source/fluentasserts/operations/string/arraycontainonly.d

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,19 @@ unittest {
8282
unittest {
8383
expect([1, 2, 3, 4]).to.not.containOnly([1, 2, 3]);
8484
}
85+
86+
@("Object array containOnly itself passes")
87+
unittest {
88+
Object[] l = [new Object(), new Object()];
89+
l.should.containOnly(l);
90+
}
91+
92+
@("nested int array containOnly passes")
93+
unittest {
94+
import std.range : iota;
95+
import std.algorithm : map;
96+
import std.array : array;
97+
98+
auto ll = iota(1, 4).map!iota;
99+
ll.map!array.array.should.containOnly([[0], [0, 1], [0, 1, 2]]);
100+
}

0 commit comments

Comments
 (0)