Skip to content

Commit 85d6868

Browse files
Pascal's Triangle tests checkAllAllocationFailures (#487)
We verify there are no memory leaks in the event of memory allocation failure. Update the example solution as it previously leaked if any allocation (other than the first) failed.
1 parent 306952e commit 85d6868

File tree

2 files changed

+65
-77
lines changed

2 files changed

+65
-77
lines changed

exercises/practice/pascals-triangle/.meta/example.zig

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,23 @@ const mem = std.mem;
33

44
pub fn rows(allocator: mem.Allocator, count: usize) mem.Allocator.Error![][]u128 {
55
var result = try allocator.alloc([]u128, count);
6-
for (0..count) |i| {
6+
var i: usize = 0;
7+
errdefer {
8+
while (i > 0) {
9+
i -= 1;
10+
allocator.free(result[i]);
11+
}
12+
allocator.free(result);
13+
}
14+
15+
while (i < count) : (i += 1) {
716
result[i] = try allocator.alloc(u128, i + 1);
817
result[i][0] = 1;
918
result[i][i] = 1;
10-
if (i == 0) {
19+
if (i < 2) {
1120
continue;
1221
}
22+
1323
for (1..i) |j| {
1424
result[i][j] = result[i - 1][j - 1] + result[i - 1][j];
1525
}

exercises/practice/pascals-triangle/test_pascals_triangle.zig

Lines changed: 53 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,8 @@ fn free(slices: [][]u128) void {
1010
testing.allocator.free(slices);
1111
}
1212

13-
test "zero rows" {
14-
const expected = try testing.allocator.alloc([]const u128, 0);
15-
defer testing.allocator.free(expected);
16-
17-
const actual = try pascals_triangle.rows(testing.allocator, 0);
13+
fn rowsTest(allocator: std.mem.Allocator, count: usize, expected: [][]const u128) anyerror!void {
14+
const actual = try pascals_triangle.rows(allocator, count);
1815
defer free(actual);
1916

2017
try testing.expectEqual(expected.len, actual.len);
@@ -23,107 +20,92 @@ test "zero rows" {
2320
}
2421
}
2522

23+
test "zero rows" {
24+
const expected: [0][]const u128 = undefined;
25+
try std.testing.checkAllAllocationFailures(
26+
std.testing.allocator,
27+
rowsTest,
28+
.{ 0, &expected },
29+
);
30+
}
31+
2632
test "single row" {
27-
var expected = try testing.allocator.alloc([]const u128, 1);
33+
var expected: [1][]const u128 = undefined;
2834
expected[0] = &.{1};
29-
defer testing.allocator.free(expected);
30-
31-
const actual = try pascals_triangle.rows(testing.allocator, 1);
32-
defer free(actual);
33-
34-
try testing.expectEqual(expected.len, actual.len);
35-
for (expected, actual) |expected_slice, actual_slice| {
36-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
37-
}
35+
try std.testing.checkAllAllocationFailures(
36+
std.testing.allocator,
37+
rowsTest,
38+
.{ 1, &expected },
39+
);
3840
}
3941

4042
test "two rows" {
41-
var expected = try testing.allocator.alloc([]const u128, 2);
43+
var expected: [2][]const u128 = undefined;
4244
expected[0] = &.{1};
4345
expected[1] = &.{ 1, 1 };
44-
defer testing.allocator.free(expected);
45-
46-
const actual = try pascals_triangle.rows(testing.allocator, 2);
47-
defer free(actual);
48-
49-
try testing.expectEqual(expected.len, actual.len);
50-
for (expected, actual) |expected_slice, actual_slice| {
51-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
52-
}
46+
try std.testing.checkAllAllocationFailures(
47+
std.testing.allocator,
48+
rowsTest,
49+
.{ 2, &expected },
50+
);
5351
}
5452

5553
test "three rows" {
56-
var expected = try testing.allocator.alloc([]const u128, 3);
54+
var expected: [3][]const u128 = undefined;
5755
expected[0] = &.{1};
5856
expected[1] = &.{ 1, 1 };
5957
expected[2] = &.{ 1, 2, 1 };
60-
defer testing.allocator.free(expected);
61-
62-
const actual = try pascals_triangle.rows(testing.allocator, 3);
63-
defer free(actual);
64-
65-
try testing.expectEqual(expected.len, actual.len);
66-
for (expected, actual) |expected_slice, actual_slice| {
67-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
68-
}
58+
try std.testing.checkAllAllocationFailures(
59+
std.testing.allocator,
60+
rowsTest,
61+
.{ 3, &expected },
62+
);
6963
}
7064

7165
test "four rows" {
72-
var expected = try testing.allocator.alloc([]const u128, 4);
66+
var expected: [4][]const u128 = undefined;
7367
expected[0] = &.{1};
7468
expected[1] = &.{ 1, 1 };
7569
expected[2] = &.{ 1, 2, 1 };
7670
expected[3] = &.{ 1, 3, 3, 1 };
77-
defer testing.allocator.free(expected);
78-
79-
const actual = try pascals_triangle.rows(testing.allocator, 4);
80-
defer free(actual);
81-
82-
try testing.expectEqual(expected.len, actual.len);
83-
for (expected, actual) |expected_slice, actual_slice| {
84-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
85-
}
71+
try std.testing.checkAllAllocationFailures(
72+
std.testing.allocator,
73+
rowsTest,
74+
.{ 4, &expected },
75+
);
8676
}
8777

8878
test "five rows" {
89-
var expected = try testing.allocator.alloc([]const u128, 5);
79+
var expected: [5][]const u128 = undefined;
9080
expected[0] = &.{1};
9181
expected[1] = &.{ 1, 1 };
9282
expected[2] = &.{ 1, 2, 1 };
9383
expected[3] = &.{ 1, 3, 3, 1 };
9484
expected[4] = &.{ 1, 4, 6, 4, 1 };
95-
defer testing.allocator.free(expected);
96-
97-
const actual = try pascals_triangle.rows(testing.allocator, 5);
98-
defer free(actual);
99-
100-
try testing.expectEqual(expected.len, actual.len);
101-
for (expected, actual) |expected_slice, actual_slice| {
102-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
103-
}
85+
try std.testing.checkAllAllocationFailures(
86+
std.testing.allocator,
87+
rowsTest,
88+
.{ 5, &expected },
89+
);
10490
}
10591

10692
test "six rows" {
107-
var expected = try testing.allocator.alloc([]const u128, 6);
93+
var expected: [6][]const u128 = undefined;
10894
expected[0] = &.{1};
10995
expected[1] = &.{ 1, 1 };
11096
expected[2] = &.{ 1, 2, 1 };
11197
expected[3] = &.{ 1, 3, 3, 1 };
11298
expected[4] = &.{ 1, 4, 6, 4, 1 };
11399
expected[5] = &.{ 1, 5, 10, 10, 5, 1 };
114-
defer testing.allocator.free(expected);
115-
116-
const actual = try pascals_triangle.rows(testing.allocator, 6);
117-
defer free(actual);
118-
119-
try testing.expectEqual(expected.len, actual.len);
120-
for (expected, actual) |expected_slice, actual_slice| {
121-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
122-
}
100+
try std.testing.checkAllAllocationFailures(
101+
std.testing.allocator,
102+
rowsTest,
103+
.{ 6, &expected },
104+
);
123105
}
124106

125107
test "ten rows" {
126-
var expected = try testing.allocator.alloc([]const u128, 10);
108+
var expected: [10][]const u128 = undefined;
127109
expected[0] = &.{1};
128110
expected[1] = &.{ 1, 1 };
129111
expected[2] = &.{ 1, 2, 1 };
@@ -134,15 +116,11 @@ test "ten rows" {
134116
expected[7] = &.{ 1, 7, 21, 35, 35, 21, 7, 1 };
135117
expected[8] = &.{ 1, 8, 28, 56, 70, 56, 28, 8, 1 };
136118
expected[9] = &.{ 1, 9, 36, 84, 126, 126, 84, 36, 9, 1 };
137-
defer testing.allocator.free(expected);
138-
139-
const actual = try pascals_triangle.rows(testing.allocator, 10);
140-
defer free(actual);
141-
142-
try testing.expectEqual(expected.len, actual.len);
143-
for (expected, actual) |expected_slice, actual_slice| {
144-
try testing.expectEqualSlices(u128, expected_slice, actual_slice);
145-
}
119+
try std.testing.checkAllAllocationFailures(
120+
std.testing.allocator,
121+
rowsTest,
122+
.{ 10, &expected },
123+
);
146124
}
147125

148126
test "seventy-five rows" {

0 commit comments

Comments
 (0)