aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorChris Boesch <chrboesch@noreply.codeberg.org>2023-05-15 01:00:28 +0200
committerGitHub <noreply@github.com>2023-05-15 01:00:28 +0200
commit5cbaa0441f1a52532ac68899bb5b64d3595e5a06 (patch)
treedb9710577e27321a7a69b9d8133dddf13c14f8de
parent76ee4eb043ae290102d3fb19375931990f2a9824 (diff)
parentc3a73b8e2b3a276dd87ee27528a1dd52db77e3b8 (diff)
Merge pull request #304 from chrboesch/testing_exercise
Added testing exercise.
-rw-r--r--build.zig3
-rw-r--r--exercises/102_testing.zig106
-rw-r--r--patches/patches/102_testing.patch8
-rw-r--r--test/tests.zig17
4 files changed, 129 insertions, 5 deletions
diff --git a/build.zig b/build.zig
index 9113240..a13b016 100644
--- a/build.zig
+++ b/build.zig
@@ -1219,9 +1219,8 @@ const exercises = [_]Exercise{
},
.{
.main_file = "102_testing.zig",
- .output = "All 1 tests passed.",
+ .output = "",
.run_test = true,
- .skip = true,
},
.{
.main_file = "999_the_end.zig",
diff --git a/exercises/102_testing.zig b/exercises/102_testing.zig
index dc1da59..89a0ee8 100644
--- a/exercises/102_testing.zig
+++ b/exercises/102_testing.zig
@@ -1,10 +1,112 @@
+//
+// A big advantage of Zig is the integration of its own test system.
+// This allows the philosophy of Test Driven Development (TDD) to be
+// implemented perfectly. Zig even goes one step further than other
+// languages, the tests can be included directly in the source file.
+//
+// This has several advantages. On the one hand it is much clearer to
+// have everything in one file, both the source code and the associated
+// test code. On the other hand, it is much easier for third parties
+// to understand what exactly a function is supposed to do if they can
+// simply look at the test inside the source and compare both.
+//
+// Especially if you want to understand how e.g. the standard library
+// of Zig works, this approach is very helpful. Furthermore it is very
+// practical, if you want to report a bug to the Zig community, to
+// illustrate it with a small example including a test.
+//
+// Therefore, in this exercise we will deal with the basics of testing
+// in Zig. Basically, tests work as follows: you pass certain parameters
+// to a function, for which you get a return - the result. This is then
+// compared with the EXPECTED value. If both values match, the test is
+// passed, otherwise an error message is displayed.
+//
+// testing.expect(foo(param1, param2) == expected);
+//
+// Also other comparisons are possible, deviations or also errors can
+// be provoked, which must lead to an appropriate behavior of the
+// function, so that the test is passed.
+//
+// Tests can be run via Zig build system or applied directly to
+// individual modules using "zig test xyz.zig".
+//
+// Both can be used script-driven to execute tests automatically, e.g.
+// after checking into a Git repository. Something we also make extensive
+// use of here at Ziglings.
+//
const std = @import("std");
const testing = std.testing;
-fn add(a: u16, b: u16) u16 {
+// This is a simple function
+// that builds a sum from the
+// passed parameters and returns.
+fn add(a: f16, b: f16) f16 {
return a + b;
}
-test "simple test" {
+// The associated test.
+// It always starts with the keyword "test",
+// followed by a description of the tasks
+// of the test. This is followed by the
+// test cases in curly brackets.
+test "add" {
+
+ // The first test checks if the sum
+ // of '41' and '1' gives '42', which
+ // is correct.
try testing.expect(add(41, 1) == 42);
+
+ // Another way to perform this test
+ // is as follows:
+ try testing.expectEqual(add(41, 1), 42);
+
+ // This time a test with the addition
+ // of a negative number:
+ try testing.expect(add(5, -4) == 1);
+
+ // And a floating point operation:
+ try testing.expect(add(1.5, 1.5) == 3);
+}
+
+// Another simple function
+// that returns the result
+// of subtracting the two
+// parameters.
+fn sub(a: f16, b: f16) f16 {
+ return a - b;
+}
+
+// The corresponding test
+// is not much different
+// from the previous one.
+// Except that it contains
+// an error that you need
+// to correct.
+test "sub" {
+ try testing.expect(sub(10, 5) == 6);
+
+ try testing.expect(sub(3, 1.5) == 1.5);
+}
+
+// This function divides the
+// numerator by the denominator.
+// Here it is important that the
+// denominator must not be zero.
+// This is checked and if it
+// occurs an error is returned.
+fn divide(a: f16, b: f16) !f16 {
+ if (b == 0) return error.DivisionByZero;
+ return a / b;
+}
+
+test "divide" {
+ try testing.expect(divide(2, 2) catch unreachable == 1);
+ try testing.expect(divide(-1, -1) catch unreachable == 1);
+ try testing.expect(divide(10, 2) catch unreachable == 5);
+ try testing.expect(divide(1, 3) catch unreachable == 0.3333333333333333);
+
+ // Now we test if the function returns an error
+ // if we pass a zero as denominator.
+ // But which error needs to be tested?
+ try testing.expectError(error.???, divide(15, 0));
}
diff --git a/patches/patches/102_testing.patch b/patches/patches/102_testing.patch
new file mode 100644
index 0000000..49daf0c
--- /dev/null
+++ b/patches/patches/102_testing.patch
@@ -0,0 +1,8 @@
+86c86
+< try testing.expect(sub(10, 5) == 6);
+---
+> try testing.expect(sub(10, 5) == 5);
+111c111
+< try testing.expectError(error.???, divide(15, 0));
+---
+> try testing.expectError(error.DivisionByZero, divide(15, 0));
diff --git a/test/tests.zig b/test/tests.zig
index f5c3960..b25b29c 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -93,7 +93,7 @@ pub fn addCliTests(b: *std.Build, exercises: []const Exercise) *Step {
const case_step = createCase(b, "case-3");
for (exercises[0 .. exercises.len - 1]) |ex| {
- if (ex.skip) continue;
+ if (ex.skip or ex.run_test) continue;
if (ex.hint) |hint| {
const n = ex.number();
@@ -249,6 +249,21 @@ fn check_output(step: *Step, exercise: Exercise, reader: Reader) !void {
return;
}
+ if (exercise.run_test) {
+ {
+ const actual = try readLine(reader, &buf) orelse "EOF";
+ const expect = b.fmt("Testing {s}...", .{exercise.main_file});
+ try check(step, exercise, expect, actual);
+ }
+
+ {
+ const actual = try readLine(reader, &buf) orelse "EOF";
+ try check(step, exercise, "", actual);
+ }
+
+ return;
+ }
+
{
const actual = try readLine(reader, &buf) orelse "EOF";
const expect = b.fmt("Compiling {s}...", .{exercise.main_file});