How to assert if a particular allocation was made in tests

I have a logic that conditionally allocates.

Is there a clean way to have a tests where I can confirm that allocation occurs in the path that should allocate?

I use the std.testing.allocator, and while testing the path that should not allocate, I do not call the necessary denit function in the test.

So if tests runs, and no leak is detected, I assume that means no allocation happened.

Not sure if there is a better/cleaner way

There is a std.testing.checkAllAllocationFailures(…) that you could use. This doesn’t do exactly what you want, but might be something to read and base a solution off it. Another option would be to write your own allocator that can track allocations like you want.
I am curious as to why you would need to assert that one particular allocation succeds. Of we had more context, there might be another option for what you are trying to verify.

If you only want to know if an allocation occured, you should be able to check that std.testing.allocator_instance.total_requested_bytes is non zero

1 Like

There is also std.testing.FailingAllocator. You can set fail_index to 1, call your function and then expect the next allocation to fail:

test {
    var failer = std.testing.FailingAllocator.init(std.testing.allocator, .{ .fail_index = 1 });
    const allocator = failer.allocator();

    const cond = true;
    // Your function that conditionally allocates
    foo(allocator, cond);

    try std.testing.expectError(error.OutOfMemory, allocator.create(u8));
}

failer also keeps track of allocated_bytes.

4 Likes

I like this strategy, but I think it might be more intuitive/readable to not set a fail point and just check the allocation count:

test {
    var failer = std.testing.FailingAllocator.init(std.testing.allocator, .{});
    const allocator = failer.allocator();

    const cond = true;
    // Your function that conditionally allocates
    foo(allocator, cond);

    try std.testing.expectEqual(failer.allocations, 1);
    // you could also do expect(failer.allocations > 0)
}
2 Likes

Yeah sure, that might be a better way to express intent here.

You could also use a pattern similiar to this test from std:

test {
    // Should allocate
    try testing.expectError(error.OutOfMemory, foo(std.testing.failing_allocator, true));

    // Should not allocate
    try foo(std.testing.failing_allocator, false);
}
1 Like

Yeah, I like that for the negative case (no allocation) because it gives an error trace pointing to where the allocation happened.

1 Like