Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 15 additions & 45 deletions exercises/practice/binary-search/test_binary_search.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,81 +2,51 @@ const std = @import("std");
const testing = std.testing;

const binary_search = @import("binary_search.zig");
const binarySearch = binary_search.binarySearch;

fn testBinarySearch(comptime T: type, target: T, items: []const T, expected: ?usize) !void {
try testing.expectEqual(expected, binary_search.binarySearch(T, target, items));
}

test "finds a value in an array with one element" {
const expected: ?usize = 0;
const array = [_]i4{6};
const actual = binarySearch(i4, 6, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(i4, 6, &[_]i4{6}, 0);
}

test "finds a value in the middle of an array" {
const expected: ?usize = 3;
const array = [_]u4{ 1, 3, 4, 6, 8, 9, 11 };
const actual = binarySearch(u4, 6, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(u4, 6, &[_]u4{ 1, 3, 4, 6, 8, 9, 11 }, 3);
}

test "finds a value at the beginning of an array" {
const expected: ?usize = 0;
const array = [_]i8{ 1, 3, 4, 6, 8, 9, 11 };
const actual = binarySearch(i8, 1, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(i8, 1, &[_]i8{ 1, 3, 4, 6, 8, 9, 11 }, 0);
}

test "finds a value at the end of an array" {
const expected: ?usize = 6;
const array = [_]u8{ 1, 3, 4, 6, 8, 9, 11 };
const actual = binarySearch(u8, 11, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(u8, 11, &[_]u8{ 1, 3, 4, 6, 8, 9, 11 }, 6);
}

test "finds a value in an array of odd length" {
const expected: ?usize = 5;
const array = [_]i16{ 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634 };
const actual = binarySearch(i16, 21, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(i16, 144, &[_]i16{ 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634 }, 9);
}

test "finds a value in an array of even length" {
const expected: ?usize = 5;
const array = [_]u16{ 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377 };
const actual = binarySearch(u16, 21, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(u16, 21, &[_]u16{ 1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377 }, 5);
}

test "identifies that a value is not included in the array" {
const expected: ?usize = null;
const array = [_]i32{ 1, 3, 4, 6, 8, 9, 11 };
const actual = binarySearch(i32, 7, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(i32, 7, &[_]i32{ 1, 3, 4, 6, 8, 9, 11 }, null);
}

test "a value smaller than the array's smallest value is not found" {
const expected: ?usize = null;
const array = [_]u32{ 1, 3, 4, 6, 8, 9, 11 };
const actual = binarySearch(u32, 0, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(u32, 0, &[_]u32{ 1, 3, 4, 6, 8, 9, 11 }, null);
}

test "a value larger than the array's largest value is not found" {
const expected: ?usize = null;
const array = [_]i64{ 1, 3, 4, 6, 8, 9, 11 };
const actual = binarySearch(i64, 13, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(i64, 13, &[_]i64{ 1, 3, 4, 6, 8, 9, 11 }, null);
}

test "nothing is found in an empty array" {
const expected: ?usize = null;
const array = [_]u64{};
const actual = binarySearch(u64, 13, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(u64, 13, &[_]u64{}, null);
}

test "nothing is found when the left and right bounds cross" {
const expected: ?usize = null;
const array = [_]isize{ 1, 2 };
const actual = binarySearch(isize, 13, &array);
try testing.expectEqual(expected, actual);
try testBinarySearch(isize, 13, &[_]isize{ 1, 2 }, null);
}
50 changes: 24 additions & 26 deletions exercises/practice/triangle/test_triangle.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,108 +2,106 @@ const std = @import("std");
const testing = std.testing;

const triangle = @import("triangle.zig");
fn makeTriangle(a: f64, b: f64, c: f64) triangle.TriangleError!triangle.Triangle {
return triangle.Triangle.init(a, b, c);
}

test "equilateral all sides are equal" {
const actual = try triangle.Triangle.init(2, 2, 2);
const actual = try makeTriangle(2, 2, 2);
try testing.expect(actual.isEquilateral());
}

test "equilateral any side is unequal" {
const actual = try triangle.Triangle.init(2, 3, 2);
const actual = try makeTriangle(2, 3, 2);
try testing.expect(!actual.isEquilateral());
}

test "equilateral no sides are equal" {
const actual = try triangle.Triangle.init(5, 4, 6);
const actual = try makeTriangle(5, 4, 6);
try testing.expect(!actual.isEquilateral());
}

test "equilateral all zero sides is not a triangle" {
const actual = triangle.Triangle.init(0, 0, 0);
try testing.expectError(triangle.TriangleError.Invalid, actual);
try testing.expectError(triangle.TriangleError.Invalid, makeTriangle(0, 0, 0));
}

test "equilateral sides may be floats" {
const actual = try triangle.Triangle.init(0.5, 0.5, 0.5);
const actual = try makeTriangle(0.5, 0.5, 0.5);
try testing.expect(actual.isEquilateral());
}

test "isosceles last two sides are equal" {
const actual = try triangle.Triangle.init(3, 4, 4);
const actual = try makeTriangle(3, 4, 4);
try testing.expect(actual.isIsosceles());
}

test "isosceles first two sides are equal" {
const actual = try triangle.Triangle.init(4, 4, 3);
const actual = try makeTriangle(4, 4, 3);
try testing.expect(actual.isIsosceles());
}

test "isosceles first and last sides are equal" {
const actual = try triangle.Triangle.init(4, 3, 4);
const actual = try makeTriangle(4, 3, 4);
try testing.expect(actual.isIsosceles());
}

test "equilateral triangles are also isosceles" {
const actual = try triangle.Triangle.init(4, 3, 4);
const actual = try makeTriangle(4, 4, 4);
try testing.expect(actual.isIsosceles());
}

test "isosceles no sides are equal" {
const actual = try triangle.Triangle.init(2, 3, 4);
const actual = try makeTriangle(2, 3, 4);
try testing.expect(!actual.isIsosceles());
}

test "isosceles first triangle inequality violation" {
const actual = triangle.Triangle.init(1, 1, 3);
try testing.expectError(triangle.TriangleError.Invalid, actual);
try testing.expectError(triangle.TriangleError.Invalid, makeTriangle(1, 1, 3));
}

test "isosceles second triangle inequality violation" {
const actual = triangle.Triangle.init(1, 3, 1);
try testing.expectError(triangle.TriangleError.Invalid, actual);
try testing.expectError(triangle.TriangleError.Invalid, makeTriangle(1, 3, 1));
}

test "isosceles third triangle inequality violation" {
const actual = triangle.Triangle.init(3, 1, 1);
try testing.expectError(triangle.TriangleError.Invalid, actual);
try testing.expectError(triangle.TriangleError.Invalid, makeTriangle(3, 1, 1));
}

test "isosceles sides may be floats" {
const actual = try triangle.Triangle.init(0.5, 0.4, 0.5);
const actual = try makeTriangle(0.5, 0.4, 0.5);
try testing.expect(actual.isIsosceles());
}

test "scalene no sides are equal" {
const actual = try triangle.Triangle.init(5, 4, 6);
const actual = try makeTriangle(5, 4, 6);
try testing.expect(actual.isScalene());
}

test "scalene all sides are equal" {
const actual = try triangle.Triangle.init(4, 4, 4);
const actual = try makeTriangle(4, 4, 4);
try testing.expect(!actual.isScalene());
}

test "scalene first and second sides are equal" {
const actual = try triangle.Triangle.init(4, 4, 3);
const actual = try makeTriangle(4, 4, 3);
try testing.expect(!actual.isScalene());
}

test "scalene first and third sides are equal" {
const actual = try triangle.Triangle.init(3, 4, 3);
const actual = try makeTriangle(3, 4, 3);
try testing.expect(!actual.isScalene());
}

test "scalene second and third sides are equal" {
const actual = try triangle.Triangle.init(4, 3, 3);
const actual = try makeTriangle(4, 3, 3);
try testing.expect(!actual.isScalene());
}

test "scalene may not violate triangle inequality" {
const actual = triangle.Triangle.init(7, 3, 2);
try testing.expectError(triangle.TriangleError.Invalid, actual);
try testing.expectError(triangle.TriangleError.Invalid, makeTriangle(7, 3, 2));
}

test "scalene sides may be floats" {
const actual = try triangle.Triangle.init(0.5, 0.4, 0.6);
const actual = try makeTriangle(0.5, 0.4, 0.6);
try testing.expect(actual.isScalene());
}
59 changes: 59 additions & 0 deletions generators/exercises/binary_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from lib import zarray

IMPORT_SELF = True

# Inputs are passed through `testBinarySearch`'s runtime parameters, so a solution that
# declares `binarySearch`'s value parameters `comptime` is rejected at compile time.
# See https://forum.exercism.org/t/zig-track-needs-tests-against-comptime-abuse-and-other-kinds-of-cheating/59830/
HEADER = """
fn testBinarySearch(comptime T: type, target: T, items: []const T, expected: ?usize) !void {
try testing.expectEqual(expected, binary_search.binarySearch(T, target, items));
}
"""

# The committed target cycles a different integer type through each case, in order.
_TYPE_BY_DESC = {
"finds a value in an array with one element": "i4",
"finds a value in the middle of an array": "u4",
"finds a value at the beginning of an array": "i8",
"finds a value at the end of an array": "u8",
"finds a value in an array of odd length": "i16",
"finds a value in an array of even length": "u16",
"identifies that a value is not included in the array": "i32",
"a value smaller than the array's smallest value is not found": "u32",
"a value larger than the array's largest value is not found": "i64",
"nothing is found in an empty array": "u64",
"nothing is found when the left and right bounds cross": "isize",
}

_ORDER = list(_TYPE_BY_DESC.keys())

# The committed target searches for 13 in the not-found "empty array" and
# "bounds cross" cases (canonical uses 1 and 0 respectively).
_VALUE_OVERRIDE = {
"nothing is found in an empty array": 13,
"nothing is found when the left and right bounds cross": 13,
}


def order_key(case):
try:
return _ORDER.index(case["description"])
except ValueError:
return len(_ORDER)


def gen_case(case):
desc = case["description"]
ty = _TYPE_BY_DESC[desc]
inp = case["input"]
array = zarray([str(v) for v in inp["array"]], ty)
value = _VALUE_OVERRIDE.get(desc, inp["value"])
expected = case["expected"]

if isinstance(expected, dict) and "error" in expected:
idx = "null"
else:
idx = str(expected)

return f" try testBinarySearch({ty}, {value}, &{array}, {idx});\n"
47 changes: 47 additions & 0 deletions generators/exercises/triangle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
_METHODS = {
"equilateral": "isEquilateral",
"isosceles": "isIsosceles",
"scalene": "isScalene",
}

# Sides are passed through `makeTriangle`'s runtime parameters, so a solution that declares
# `Triangle.init`'s parameters `comptime` is rejected at compile time.
# See https://forum.exercism.org/t/zig-track-needs-tests-against-comptime-abuse-and-other-kinds-of-cheating/59830/
HEADER = """fn makeTriangle(a: f64, b: f64, c: f64) triangle.TriangleError!triangle.Triangle {
return triangle.Triangle.init(a, b, c);
}
"""


def describe(case, parent):
desc = case.get("description")
prop = case.get("property")
if prop and prop not in desc:
return f"{prop} {desc}"
return desc


def _fmt(n):
# Integers stay integral (2 -> "2"); floats keep their literal form (0.5 -> "0.5").
if isinstance(n, float) and not n.is_integer():
return repr(n)
return str(int(n))


def _is_valid(a, b, c):
return not (a + b <= c or a + c <= b or b + c <= a)


def gen_case(case):
a, b, c = case["input"]["sides"]
method = _METHODS[case["property"]]
args = f"{_fmt(a)}, {_fmt(b)}, {_fmt(c)}"
if not _is_valid(a, b, c):
return (
f" try testing.expectError(triangle.TriangleError.Invalid, makeTriangle({args}));\n"
)
bang = "" if case["expected"] else "!"
return (
f" const actual = try makeTriangle({args});\n"
f" try testing.expect({bang}actual.{method}());\n"
)
Loading