summaryrefslogtreecommitdiff
path: root/Homework/math4610/test
diff options
context:
space:
mode:
authorElizabeth Alexander Hunt <me@liz.coffee>2026-07-02 11:55:17 -0700
committerElizabeth Alexander Hunt <me@liz.coffee>2026-07-02 11:55:17 -0700
commit6bf4b90c90f15f4ab60833bddf5b5756d1a6b1f6 (patch)
treeed97e39ec77c5231ffd2c394493e68d00ddac5a4 /Homework/math4610/test
downloadmisc-undergrad-main.tar.gz
misc-undergrad-main.zip
Diffstat (limited to 'Homework/math4610/test')
-rw-r--r--Homework/math4610/test/approx_derivative.t.c32
-rw-r--r--Homework/math4610/test/eigen.t.c147
-rw-r--r--Homework/math4610/test/jacobi.t.c93
-rw-r--r--Homework/math4610/test/lin.t.c20
-rw-r--r--Homework/math4610/test/lizfcm.test.h8
-rw-r--r--Homework/math4610/test/maceps.t.c18
-rw-r--r--Homework/math4610/test/main.c12
-rw-r--r--Homework/math4610/test/matrix.t.c247
-rw-r--r--Homework/math4610/test/rand.t.c10
-rw-r--r--Homework/math4610/test/roots.t.c114
-rw-r--r--Homework/math4610/test/utest.h1668
-rw-r--r--Homework/math4610/test/vector.t.c115
12 files changed, 2484 insertions, 0 deletions
diff --git a/Homework/math4610/test/approx_derivative.t.c b/Homework/math4610/test/approx_derivative.t.c
new file mode 100644
index 0000000..6bcac79
--- /dev/null
+++ b/Homework/math4610/test/approx_derivative.t.c
@@ -0,0 +1,32 @@
+#include "lizfcm.test.h"
+
+double f(double x) { return x * x; }
+
+double f_prime(double x) { return 2 * x; }
+
+double H = 0.0001;
+double ACCEPTED_DERIVATIVE_ERROR = 0.0001;
+
+UTEST(derivative, central) {
+ double a = 3.0;
+ double expected = f_prime(a);
+ double f_prime_x = central_derivative_at(&f, a, H);
+
+ EXPECT_NEAR(expected, f_prime_x, ACCEPTED_DERIVATIVE_ERROR);
+}
+
+UTEST(derivative, forward) {
+ double a = 3.0;
+ double expected = f_prime(a);
+ double f_prime_x = forward_derivative_at(&f, a, H);
+
+ EXPECT_NEAR(expected, f_prime_x, ACCEPTED_DERIVATIVE_ERROR);
+}
+
+UTEST(derivative, backward) {
+ double a = 3.0;
+ double expected = f_prime(a);
+ double f_prime_x = backward_derivative_at(&f, a, H);
+
+ EXPECT_NEAR(expected, f_prime_x, ACCEPTED_DERIVATIVE_ERROR);
+}
diff --git a/Homework/math4610/test/eigen.t.c b/Homework/math4610/test/eigen.t.c
new file mode 100644
index 0000000..dc01aa7
--- /dev/null
+++ b/Homework/math4610/test/eigen.t.c
@@ -0,0 +1,147 @@
+#include "lizfcm.test.h"
+#include <math.h>
+
+Matrix_double *eigen_test_matrix() {
+ // produces a matrix that has eigenvalues [5 + sqrt{17}, 2, 5 - sqrt{17}]
+ Matrix_double *m = InitMatrixWithSize(double, 3, 3, 0.0);
+ m->data[0]->data[0] = 2.0;
+ m->data[0]->data[1] = 2.0;
+ m->data[0]->data[2] = 4.0;
+ m->data[1]->data[0] = 1.0;
+ m->data[1]->data[1] = 4.0;
+ m->data[1]->data[2] = 7.0;
+ m->data[2]->data[1] = 2.0;
+ m->data[2]->data[2] = 6.0;
+ return m;
+}
+
+UTEST(eigen, least_dominant_eigenvalue) {
+ Matrix_double *m = eigen_test_matrix();
+
+ double expected_least_dominant_eigenvalue = 0.87689; // 5 - sqrt(17)
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ Array_double *v_guess = InitArrayWithSize(double, 3, 1.0);
+ double approx_least_dominant_eigenvalue =
+ least_dominant_eigenvalue(m, v_guess, tolerance, max_iterations);
+
+ EXPECT_NEAR(expected_least_dominant_eigenvalue,
+ approx_least_dominant_eigenvalue, tolerance);
+}
+
+UTEST(eigen, dominant_eigenvalue) {
+ Matrix_double *m = InitMatrixWithSize(double, 2, 2, 0.0);
+ m->data[0]->data[0] = 2.0;
+ m->data[0]->data[1] = -12.0;
+ m->data[1]->data[0] = 1.0;
+ m->data[1]->data[1] = -5.0;
+
+ Array_double *v_guess = InitArrayWithSize(double, 2, 1.0);
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ double expect_dominant_eigenvalue = -2.0;
+
+ double approx_dominant_eigenvalue =
+ dominant_eigenvalue(m, v_guess, tolerance, max_iterations);
+
+ EXPECT_NEAR(expect_dominant_eigenvalue, approx_dominant_eigenvalue,
+ tolerance);
+ free_matrix(m);
+ free_vector(v_guess);
+}
+
+UTEST(eigen, shifted_eigenvalue) {
+ Matrix_double *m = eigen_test_matrix();
+
+ double least_dominant_eigenvalue = 0.87689; // 5 - sqrt{17}
+ double dominant_eigenvalue = 9.12311; // 5 + sqrt{17}
+ double expected_middle_eigenvalue = 2.0;
+ double shift = (dominant_eigenvalue + least_dominant_eigenvalue) / 2.0;
+
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+ Array_double *v_guess = InitArray(double, {0.5, 1.0, 0.75});
+
+ double approx_middle_eigenvalue = shift_inverse_power_eigenvalue(
+ m, v_guess, shift, tolerance, max_iterations);
+
+ EXPECT_NEAR(approx_middle_eigenvalue, expected_middle_eigenvalue, tolerance);
+}
+
+UTEST(eigen, partition_find_eigenvalues) {
+ Matrix_double *m = eigen_test_matrix();
+
+ double least_dominant_eigenvalue = 0.87689; // 5 - sqrt{17}
+ double dominant_eigenvalue = 9.12311; // 5 + sqrt{17}
+ double expected_middle_eigenvalue = 2.0;
+ double expected_eigenvalues[3] = {least_dominant_eigenvalue,
+ expected_middle_eigenvalue,
+ dominant_eigenvalue};
+
+ size_t partitions = 10;
+ Matrix_double *guesses = InitMatrixWithSize(double, partitions, 3, 0.0);
+ for (size_t y = 0; y < guesses->rows; y++) {
+ free_vector(guesses->data[y]);
+ guesses->data[y] = InitArray(double, {0.5, 1.0, 0.75});
+ }
+
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ int eigenvalues_found[3] = {false, false, false};
+ Array_double *partition_eigenvalues =
+ partition_find_eigenvalues(m, guesses, tolerance, max_iterations);
+
+ for (size_t i = 0; i < partition_eigenvalues->size; i++)
+ for (size_t eigenvalue_i = 0; eigenvalue_i < 3; eigenvalue_i++)
+ if (fabs(partition_eigenvalues->data[i] - expected_eigenvalues[i]) <=
+ tolerance)
+ eigenvalues_found[eigenvalue_i] = true;
+
+ for (size_t eigenvalue_i = 0; eigenvalue_i < 3; eigenvalue_i++)
+ EXPECT_TRUE(eigenvalues_found[eigenvalue_i]);
+}
+
+UTEST(eigen, leslie_matrix_dominant_eigenvalue) {
+ Array_double *felicity = InitArray(double, {0.0, 1.5, 0.8});
+ Array_double *survivor_ratios = InitArray(double, {0.8, 0.55});
+ Matrix_double *leslie = leslie_matrix(survivor_ratios, felicity);
+ Array_double *v_guess = InitArrayWithSize(double, 3, 2.0);
+ double tolerance = 0.0001;
+ uint64_t max_iterations = 64;
+
+ double expect_dominant_eigenvalue = 1.22005;
+
+ double approx_dominant_eigenvalue =
+ dominant_eigenvalue(leslie, v_guess, tolerance, max_iterations);
+
+ EXPECT_NEAR(expect_dominant_eigenvalue, approx_dominant_eigenvalue,
+ tolerance);
+
+ free_vector(v_guess);
+ free_vector(survivor_ratios);
+ free_vector(felicity);
+ free_matrix(leslie);
+}
+UTEST(eigen, leslie_matrix) {
+ Array_double *felicity = InitArray(double, {0.0, 1.5, 0.8});
+ Array_double *survivor_ratios = InitArray(double, {0.8, 0.55});
+
+ Matrix_double *m = InitMatrixWithSize(double, 3, 3, 0.0);
+ m->data[0]->data[0] = 0.0;
+ m->data[0]->data[1] = 1.5;
+ m->data[0]->data[2] = 0.8;
+ m->data[1]->data[0] = 0.8;
+ m->data[2]->data[1] = 0.55;
+
+ Matrix_double *leslie = leslie_matrix(survivor_ratios, felicity);
+
+ EXPECT_TRUE(matrix_equal(leslie, m));
+
+ free_matrix(leslie);
+ free_matrix(m);
+ free_vector(felicity);
+ free_vector(survivor_ratios);
+}
diff --git a/Homework/math4610/test/jacobi.t.c b/Homework/math4610/test/jacobi.t.c
new file mode 100644
index 0000000..94ed53a
--- /dev/null
+++ b/Homework/math4610/test/jacobi.t.c
@@ -0,0 +1,93 @@
+#include "lizfcm.test.h"
+#include <assert.h>
+#include <math.h>
+
+Matrix_double *generate_ddm(size_t n) {
+ Matrix_double *m = InitMatrixWithSize(double, n, n, rand_from(0.0, 1.0));
+
+ for (size_t y = 0; y < m->rows; y++) {
+ m->data[y]->data[y] += sum_v(m->data[y]);
+ }
+
+ return m;
+}
+
+UTEST(jacobi, jacobi_solve) {
+ Matrix_double *m = generate_ddm(2);
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+ Array_double *solution = jacobi_solve(m, b, tolerance, max_iter);
+
+ for (size_t y = 0; y < m->rows; y++) {
+ double dot = v_dot_v(m->data[y], solution);
+ EXPECT_NEAR(b->data[y], dot, 0.1);
+ }
+
+ free_matrix(m);
+ free_vector(b_1);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(jacobi, gauss_siedel_solve) {
+ Matrix_double *m = generate_ddm(2);
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+ Array_double *solution = gauss_siedel_solve(m, b, tolerance, max_iter);
+
+ for (size_t y = 0; y < m->rows; y++) {
+ double dot = v_dot_v(m->data[y], solution);
+ EXPECT_NEAR(b->data[y], dot, 0.1);
+ }
+
+ free_matrix(m);
+ free_vector(b_1);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(jacobi, leslie_solve) {
+ Array_double *felicity = InitArray(double, {0.0, 1.5, 0.8});
+ Array_double *survivor_ratios = InitArray(double, {0.8, 0.55});
+ Matrix_double *leslie = leslie_matrix(survivor_ratios, felicity);
+
+ Array_double *initial_pop = InitArray(double, {10.0, 20.0, 15.0});
+ Array_double *next = m_dot_v(leslie, initial_pop);
+
+ Matrix_double *augmented = add_column(leslie, next);
+ Matrix_double *leslie_augmented_echelon = gaussian_elimination(augmented);
+
+ Array_double *next_echelon =
+ col_v(leslie_augmented_echelon, leslie_augmented_echelon->cols - 1);
+ Matrix_double *leslie_echelon = slice_column(
+ leslie_augmented_echelon, leslie_augmented_echelon->cols - 1);
+
+ double tolerance = 0.001;
+ size_t max_iter = 400;
+ Array_double *initial_pop_guess =
+ jacobi_solve(leslie_echelon, next_echelon, tolerance, max_iter);
+
+ for (size_t y = 0; y < initial_pop->size; y++) {
+ EXPECT_NEAR(initial_pop_guess->data[y], initial_pop->data[y], 0.05);
+ }
+
+ free_matrix(leslie);
+ free_matrix(augmented);
+ free_matrix(leslie_augmented_echelon);
+ free_matrix(leslie_echelon);
+
+ free_vector(felicity);
+ free_vector(survivor_ratios);
+ free_vector(next);
+ free_vector(next_echelon);
+ free_vector(initial_pop);
+ free_vector(initial_pop_guess);
+}
diff --git a/Homework/math4610/test/lin.t.c b/Homework/math4610/test/lin.t.c
new file mode 100644
index 0000000..6ad1613
--- /dev/null
+++ b/Homework/math4610/test/lin.t.c
@@ -0,0 +1,20 @@
+#include "lizfcm.test.h"
+
+UTEST(Lin, least_squares_lin_reg_perfect) {
+ Array_double *x = InitArray(double, {0, 1, 2, 3, 4});
+ Array_double *y = InitArray(double, {1, 2, 3, 4, 5});
+
+ Line *line = least_squares_lin_reg(x, y);
+
+ EXPECT_EQ(line->m, 1.0);
+ EXPECT_EQ(line->a, 1.0);
+}
+
+UTEST(Lin, least_squares_lin_reg_estimate) {
+ Array_double *x = InitArray(double, {1, 2, 3, 4, 5, 6, 7});
+ Array_double *y = InitArray(double, {0.5, 3, 2, 3.5, 5, 6, 7.5});
+
+ Line *line = least_squares_lin_reg(x, y);
+
+ EXPECT_NEAR(line->m, 1.0, 0.2);
+}
diff --git a/Homework/math4610/test/lizfcm.test.h b/Homework/math4610/test/lizfcm.test.h
new file mode 100644
index 0000000..9819d46
--- /dev/null
+++ b/Homework/math4610/test/lizfcm.test.h
@@ -0,0 +1,8 @@
+#ifndef LIZFCM_TEST_H
+#define LIZFCM_TEST_H
+
+#include "lizfcm.h"
+
+#include "utest.h"
+
+#endif // LIZFCM_TEST_H
diff --git a/Homework/math4610/test/maceps.t.c b/Homework/math4610/test/maceps.t.c
new file mode 100644
index 0000000..9c45659
--- /dev/null
+++ b/Homework/math4610/test/maceps.t.c
@@ -0,0 +1,18 @@
+#include "lizfcm.test.h"
+#include <math.h>
+
+UTEST(maceps, smaceps) {
+ float epsilon = smaceps();
+ float one = 1.0;
+ float approx_one = one + epsilon;
+
+ EXPECT_LE(approx_one - one, 0);
+}
+
+UTEST(maceps, dmaceps) {
+ double epsilon = dmaceps();
+ double one = 1.0;
+ double approx_one = one + epsilon;
+
+ EXPECT_LE(approx_one - one, 0);
+}
diff --git a/Homework/math4610/test/main.c b/Homework/math4610/test/main.c
new file mode 100644
index 0000000..6a92d4a
--- /dev/null
+++ b/Homework/math4610/test/main.c
@@ -0,0 +1,12 @@
+#include "lizfcm.test.h"
+#include <stdlib.h>
+#include <time.h>
+
+UTEST(basic, unit_tests) { ASSERT_TRUE(1); }
+
+UTEST_STATE();
+int main(int argc, const char *const argv[]) {
+ srand(time(NULL));
+
+ return utest_main(argc, argv);
+}
diff --git a/Homework/math4610/test/matrix.t.c b/Homework/math4610/test/matrix.t.c
new file mode 100644
index 0000000..597d6e0
--- /dev/null
+++ b/Homework/math4610/test/matrix.t.c
@@ -0,0 +1,247 @@
+#include "lizfcm.test.h"
+
+UTEST(matrix, free) {
+ Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
+ uint64_t data_addr = (uint64_t)(m->data);
+ free_matrix(m);
+ EXPECT_NE(data_addr, (uint64_t)(m->data));
+}
+
+UTEST(matrix, add_column) {
+ Matrix_double *m = InitMatrixWithSize(double, 5, 5, 0.0);
+ Array_double *col = InitArray(double, {1.0, 2.0, 3.0, 4.0, 5.0});
+ Matrix_double *new_m = add_column(m, col);
+
+ for (size_t row = 0; row < m->rows; row++)
+ EXPECT_EQ(new_m->data[row]->data[m->cols], col->data[row]);
+ EXPECT_EQ(new_m->cols, m->cols + 1);
+
+ free_matrix(m);
+ free_matrix(new_m);
+ free_vector(col);
+}
+
+UTEST(matrix, slice_column) {
+ size_t slice = 1;
+
+ Matrix_double *m = InitMatrixWithSize(double, 5, 5, 1.0 * (rand() % 10));
+ Matrix_double *new_m = slice_column(m, slice);
+
+ for (size_t row = 0; row < m->rows; row++) {
+ Array_double *sliced_row = slice_element(m->data[row], slice);
+
+ EXPECT_TRUE(vector_equal(new_m->data[row], sliced_row));
+ free_vector(sliced_row);
+ }
+ EXPECT_EQ(new_m->cols, m->cols - 1);
+
+ free_matrix(m);
+ free_matrix(new_m);
+}
+
+UTEST(matrix, put_identity_diagonal) {
+ Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
+ Matrix_double *ident = put_identity_diagonal(m);
+
+ for (size_t y = 0; y < m->rows; ++y)
+ for (size_t x = 0; x < m->cols; ++x)
+ EXPECT_EQ(ident->data[y]->data[x], x == y ? 1.0 : 0.0);
+
+ free_matrix(m);
+ free_matrix(ident);
+}
+
+UTEST(matrix, copy) {
+ Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
+ Matrix_double *ident = put_identity_diagonal(m);
+
+ Matrix_double *copy = copy_matrix(ident);
+
+ EXPECT_TRUE(matrix_equal(ident, copy));
+
+ free_matrix(m);
+ free_matrix(ident);
+ free_matrix(copy);
+}
+
+UTEST(matrix, m_dot_v) {
+ Matrix_double *m = InitMatrixWithSize(double, 8, 8, 0.0);
+ Matrix_double *ident = put_identity_diagonal(m);
+
+ Array_double *x = InitArray(double, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0});
+ Array_double *dotted = m_dot_v(ident, x);
+
+ EXPECT_TRUE(vector_equal(dotted, x));
+
+ free_matrix(m);
+ free_matrix(ident);
+ free_vector(x);
+ free_vector(dotted);
+}
+
+UTEST(matrix, bsubst) {
+ Matrix_double *u = InitMatrixWithSize(double, 3, 3, 0.0);
+ u->data[0]->data[0] = 1.0;
+ u->data[0]->data[1] = 2.0;
+ u->data[0]->data[2] = 3.0;
+ u->data[1]->data[1] = 4.0;
+ u->data[1]->data[2] = 5.0;
+ u->data[2]->data[2] = 6.0;
+
+ Array_double *b = InitArray(double, {14.0, 29.0, 30.0});
+
+ Array_double *solution = bsubst(u, b);
+ EXPECT_NEAR(solution->data[0], -3.0, 0.0001);
+ EXPECT_NEAR(solution->data[1], 1.0, 0.0001);
+ EXPECT_NEAR(solution->data[2], 5.0, 0.0001);
+
+ free_matrix(u);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(matrix, fsubst) {
+ Matrix_double *l = InitMatrixWithSize(double, 3, 3, 0.0);
+ l->data[0]->data[0] = 1.0;
+ l->data[1]->data[0] = 2.0;
+ l->data[1]->data[1] = 3.0;
+ l->data[2]->data[0] = 4.0;
+ l->data[2]->data[1] = 5.0;
+ l->data[2]->data[2] = 6.0;
+
+ Array_double *b = InitArray(double, {14.0, 13.0, 32.0});
+
+ Array_double *solution = fsubst(l, b);
+ EXPECT_NEAR(solution->data[0], 14.0, 0.0001);
+ EXPECT_NEAR(solution->data[1], -5.0, 0.0001);
+ EXPECT_NEAR(solution->data[2], 0.16667, 0.0001);
+
+ free_matrix(l);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(matrix, lu_decomp) {
+ Matrix_double *m = InitMatrixWithSize(double, 10, 10, 0.0);
+ for (size_t y = 0; y < m->rows; ++y) {
+ for (size_t x = 0; x < m->cols; ++x)
+ m->data[y]->data[x] = x == y ? 20.0 : (100.0 - rand() % 100) / 100.0;
+ }
+
+ Matrix_double **ul = lu_decomp(m);
+ Matrix_double *u = ul[0];
+ Matrix_double *l = ul[1];
+ for (int y = 0; y < m->rows; y++) {
+ for (size_t x = 0; x < c_max(y - 1, 0); x++) {
+ double u_yx = u->data[y]->data[x];
+ EXPECT_NEAR(u_yx, 0.0, 0.0001);
+ }
+
+ for (size_t x = c_min(m->cols, y + 1); x < m->cols; ++x) {
+ double l_yx = l->data[y]->data[x];
+ EXPECT_NEAR(l_yx, 0.0, 0.0001);
+ }
+ }
+
+ free_matrix(m);
+ free_matrix(l);
+ free_matrix(u);
+ free(ul);
+}
+
+UTEST(matrix, solve_gaussian_elimination) {
+ Matrix_double *m = InitMatrixWithSize(double, 10, 10, 0.0);
+ for (size_t y = 0; y < m->rows; ++y) {
+ for (size_t x = 0; x < m->cols; ++x)
+ m->data[y]->data[x] = x == y ? 20.0 : (100.0 - rand() % 100) / 100.0;
+ }
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+
+ Array_double *solution = solve_matrix_gaussian(m, b);
+
+ for (size_t y = 0; y < m->rows; y++) {
+ double dot = v_dot_v(m->data[y], solution);
+ EXPECT_NEAR(b->data[y], dot, 0.0001);
+ }
+
+ free_vector(b_1);
+ free_matrix(m);
+ free_vector(b);
+ free_vector(solution);
+}
+
+UTEST(matrix, solve_matrix_lu_bsubst) {
+ Matrix_double *m = InitMatrixWithSize(double, 10, 10, 0.0);
+ for (size_t y = 0; y < m->rows; ++y) {
+ for (size_t x = 0; x < m->cols; ++x)
+ m->data[y]->data[x] = x == y ? 20.0 : (100.0 - rand() % 100) / 100.0;
+ }
+
+ Array_double *b_1 = InitArrayWithSize(double, m->rows, 1.0);
+ Array_double *b = m_dot_v(m, b_1);
+
+ Array_double *solution = solve_matrix_lu_bsubst(m, b);
+
+ for (size_t y = 0; y < m->rows; y++) {
+ double dot = v_dot_v(m->data[y], solution);
+ EXPECT_NEAR(b->data[y], dot, 0.0001);
+ }
+
+ free_matrix(m);
+ free_vector(b);
+ free_vector(b_1);
+ free_vector(solution);
+}
+
+UTEST(matrix, col_v) {
+ Matrix_double *m = InitMatrixWithSize(double, 2, 3, 0.0);
+ // set element to its column index
+ for (size_t y = 0; y < m->rows; y++) {
+ for (size_t x = 0; x < m->cols; x++) {
+ m->data[y]->data[x] = x;
+ }
+ }
+
+ Array_double *col, *expected;
+ for (size_t x = 0; x < m->cols; x++) {
+ col = col_v(m, x);
+ expected = InitArrayWithSize(double, m->rows, (double)x);
+ EXPECT_TRUE(vector_equal(expected, col));
+ free_vector(col);
+ free_vector(expected);
+ }
+
+ free_matrix(m);
+}
+
+UTEST(matrix, m_dot_m) {
+ Matrix_double *a = InitMatrixWithSize(double, 1, 3, 12.0);
+ Matrix_double *b = InitMatrixWithSize(double, 3, 1, 10.0);
+
+ Matrix_double *prod = m_dot_m(a, b);
+
+ EXPECT_EQ(prod->cols, 1);
+ EXPECT_EQ(prod->rows, 1);
+ EXPECT_EQ(12.0 * 10.0 * 3, prod->data[0]->data[0]);
+
+ free_matrix(a);
+ free_matrix(b);
+ free_matrix(prod);
+}
+
+UTEST(matrix, transpose) {
+ Matrix_double *a = InitMatrixWithSize(double, 1, 3, 12.0);
+ a->data[0]->data[1] = 13.0;
+ Matrix_double *b = InitMatrixWithSize(double, 3, 1, 12.0);
+ b->data[1]->data[0] = 13.0;
+
+ Matrix_double *a_t = transpose(a);
+
+ EXPECT_TRUE(matrix_equal(a_t, b));
+
+ free_matrix(a_t);
+ free_matrix(a);
+ free_matrix(b);
+}
diff --git a/Homework/math4610/test/rand.t.c b/Homework/math4610/test/rand.t.c
new file mode 100644
index 0000000..9ed2e9c
--- /dev/null
+++ b/Homework/math4610/test/rand.t.c
@@ -0,0 +1,10 @@
+#include "lizfcm.test.h"
+
+UTEST(rand, rand_from) {
+ double min = -2.0;
+ double max = 5.0;
+ for (size_t i = 0; i < 1000; i++) {
+ double r = rand_from(min, max);
+ ASSERT_TRUE(min <= r && r <= max);
+ }
+}
diff --git a/Homework/math4610/test/roots.t.c b/Homework/math4610/test/roots.t.c
new file mode 100644
index 0000000..c20f22e
--- /dev/null
+++ b/Homework/math4610/test/roots.t.c
@@ -0,0 +1,114 @@
+#include "lizfcm.test.h"
+#include <math.h>
+#include <stdio.h>
+
+double f1(double x) { return x * x - 9; }
+
+double f2(double x) { return x * x - 5 * x + 6; }
+double f2prime(double x) { return 2 * x - 5; }
+double g1(double x) { return x + f2(x); }
+double g2(double x) { return x - f2(x); }
+
+UTEST(ivt, find_interval) {
+ Array_double *range = find_ivt_range(&f1, -10.0, 0.10, 200);
+ EXPECT_LT(f1(range->data[0]) * f1(range->data[1]), 0);
+
+ free_vector(range);
+}
+
+UTEST(root, bisection_with_error_assumption) {
+ Array_double *range = find_ivt_range(&f2, 2.5, 0.10, 200);
+
+ double tolerance = 0.01;
+ double root1 = bisect_find_root_with_error_assumption(
+ &f2, range->data[0], range->data[1], tolerance);
+
+ free_vector(range);
+ range = find_ivt_range(&f2, 0, 0.01, 500);
+ double root2 = bisect_find_root_with_error_assumption(
+ &f2, range->data[0], range->data[1], tolerance);
+ free_vector(range);
+
+ EXPECT_NEAR(3.0, root1, tolerance);
+ EXPECT_NEAR(2.0, root2, tolerance);
+}
+
+UTEST(root, fixed_point_iteration_method) {
+ // x^2 - 5x + 6 = (x - 3)(x - 2)
+ double expect_x2 = 3.0;
+ double expect_x1 = 2.0;
+
+ double tolerance = 0.001;
+ uint64_t max_iterations = 10;
+
+ double x_0 = 1.55; // 1.5 < 1.55 < 2.5
+ // g1(x) = x + f(x)
+ double root1 =
+ fixed_point_iteration_method(&f2, &g1, x_0, tolerance, max_iterations);
+ EXPECT_NEAR(root1, expect_x1, tolerance);
+
+ // g2(x) = x - f(x)
+ x_0 = 3.4; // 2.5 < 3.4 < 3.5
+ double root2 =
+ fixed_point_iteration_method(&f2, &g2, x_0, tolerance, max_iterations);
+ EXPECT_NEAR(root2, expect_x2, tolerance);
+}
+
+UTEST(root, fixed_point_newton_method) {
+ // x^2 - 5x + 6 = (x - 3)(x - 2)
+ double expect_x2 = 3.0;
+ double expect_x1 = 2.0;
+
+ double tolerance = 0.01;
+ uint64_t max_iterations = 10;
+
+ double x_0 = 1.55; // 1.5 < 1.55 < 2.5
+ double root1 =
+ fixed_point_newton_method(&f2, &f2prime, x_0, tolerance, max_iterations);
+ EXPECT_NEAR(root1, expect_x1, tolerance);
+
+ x_0 = 3.4; // 2.5 < 3.4 < 3.5
+ double root2 =
+ fixed_point_newton_method(&f2, &f2prime, x_0, tolerance, max_iterations);
+ EXPECT_NEAR(root2, expect_x2, tolerance);
+}
+
+UTEST(root, fixed_point_secant_method) {
+ // x^2 - 5x + 6 = (x - 3)(x - 2)
+ double expect_x2 = 3.0;
+ double expect_x1 = 2.0;
+
+ double delta = 0.01;
+ double tolerance = 0.01;
+ uint64_t max_iterations = 10;
+
+ double x_0 = 1.55; // 1.5 < 1.55 < 2.5
+ double root1 = fixed_point_secant_method(&f2, x_0, x_0 + delta, tolerance,
+ max_iterations);
+ EXPECT_NEAR(root1, expect_x1, tolerance);
+
+ x_0 = 3.4; // 2.5 < 3.4 < 3.5
+ double root2 = fixed_point_secant_method(&f2, x_0, x_0 + delta, tolerance,
+ max_iterations);
+ EXPECT_NEAR(root2, expect_x2, tolerance);
+}
+
+UTEST(root, fixed_point_hybrid_method) {
+ // x^2 - 5x + 6 = (x - 3)(x - 2)
+ double expect_x2 = 3.0;
+ double expect_x1 = 2.0;
+
+ double delta = 1.0;
+ double tolerance = 0.01;
+ uint64_t max_iterations = 10;
+
+ double x_0 = 1.55;
+ double root1 = fixed_point_secant_bisection_method(&f2, x_0, x_0 + delta,
+ tolerance, max_iterations);
+ EXPECT_NEAR(root1, expect_x1, tolerance);
+
+ x_0 = 2.5;
+ double root2 = fixed_point_secant_bisection_method(&f2, x_0, x_0 + delta,
+ tolerance, max_iterations);
+ EXPECT_NEAR(root2, expect_x2, tolerance);
+}
diff --git a/Homework/math4610/test/utest.h b/Homework/math4610/test/utest.h
new file mode 100644
index 0000000..8767600
--- /dev/null
+++ b/Homework/math4610/test/utest.h
@@ -0,0 +1,1668 @@
+/*
+ The latest version of this library is available on GitHub;
+ https://github.com/sheredom/utest.h
+*/
+
+/*
+ This is free and unencumbered software released into the public domain.
+
+ Anyone is free to copy, modify, publish, use, compile, sell, or
+ distribute this software, either in source code form or as a compiled
+ binary, for any purpose, commercial or non-commercial, and by any
+ means.
+
+ In jurisdictions that recognize copyright laws, the author or authors
+ of this software dedicate any and all copyright interest in the
+ software to the public domain. We make this dedication for the benefit
+ of the public at large and to the detriment of our heirs and
+ successors. We intend this dedication to be an overt act of
+ relinquishment in perpetuity of all present and future rights to this
+ software under copyright law.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+
+ For more information, please refer to <http://unlicense.org/>
+*/
+
+#ifndef SHEREDOM_UTEST_H_INCLUDED
+#define SHEREDOM_UTEST_H_INCLUDED
+
+#ifdef _MSC_VER
+/*
+ Disable warning about not inlining 'inline' functions.
+*/
+#pragma warning(disable : 4710)
+
+/*
+ Disable warning about inlining functions that are not marked 'inline'.
+*/
+#pragma warning(disable : 4711)
+
+/*
+ Disable warning for alignment padding added
+*/
+#pragma warning(disable : 4820)
+
+#if _MSC_VER > 1900
+/*
+ Disable warning about preprocessor macros not being defined in MSVC headers.
+*/
+#pragma warning(disable : 4668)
+
+/*
+ Disable warning about no function prototype given in MSVC headers.
+*/
+#pragma warning(disable : 4255)
+
+/*
+ Disable warning about pointer or reference to potentially throwing function.
+*/
+#pragma warning(disable : 5039)
+
+/*
+ Disable warning about macro expansion producing 'defined' has undefined
+ behavior.
+*/
+#pragma warning(disable : 5105)
+#endif
+
+#if _MSC_VER > 1930
+/*
+ Disable warning about 'const' variable is not used.
+*/
+#pragma warning(disable : 5264)
+#endif
+
+#pragma warning(push, 1)
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1920)
+typedef __int64 utest_int64_t;
+typedef unsigned __int64 utest_uint64_t;
+typedef unsigned __int32 utest_uint32_t;
+#else
+#include <stdint.h>
+typedef int64_t utest_int64_t;
+typedef uint64_t utest_uint64_t;
+typedef uint32_t utest_uint32_t;
+#endif
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(__cplusplus)
+#if defined(_MSC_VER) && !defined(_CPPUNWIND)
+/* We're on MSVC and the compiler is compiling without exception support! */
+#elif !defined(_MSC_VER) && !defined(__EXCEPTIONS)
+/* We're on a GCC/Clang compiler that doesn't have exception support! */
+#else
+#define UTEST_HAS_EXCEPTIONS 1
+#endif
+#endif
+
+#if defined(UTEST_HAS_EXCEPTIONS)
+#include <stdexcept>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#if defined(__cplusplus)
+#define UTEST_C_FUNC extern "C"
+#else
+#define UTEST_C_FUNC
+#endif
+
+#define UTEST_TEST_PASSED (0)
+#define UTEST_TEST_FAILURE (1)
+#define UTEST_TEST_SKIPPED (2)
+
+#if defined(__TINYC__)
+#define UTEST_ATTRIBUTE(a) __attribute((a))
+#else
+#define UTEST_ATTRIBUTE(a) __attribute__((a))
+#endif
+
+#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
+
+#if defined(__MINGW64__) || defined(__MINGW32__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#endif
+
+#if defined(_WINDOWS_) || defined(_WINDOWS_H)
+typedef LARGE_INTEGER utest_large_integer;
+#else
+// use old QueryPerformanceCounter definitions (not sure is this needed in some
+// edge cases or not) on Win7 with VS2015 these extern declaration cause "second
+// C linkage of overloaded function not allowed" error
+typedef union {
+ struct {
+ unsigned long LowPart;
+ long HighPart;
+ } DUMMYSTRUCTNAME;
+ struct {
+ unsigned long LowPart;
+ long HighPart;
+ } u;
+ utest_int64_t QuadPart;
+} utest_large_integer;
+
+UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceCounter(
+ utest_large_integer *);
+UTEST_C_FUNC __declspec(dllimport) int __stdcall QueryPerformanceFrequency(
+ utest_large_integer *);
+
+#if defined(__MINGW64__) || defined(__MINGW32__)
+#pragma GCC diagnostic pop
+#endif
+#endif
+
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \
+ defined(__HAIKU__)
+/*
+ slightly obscure include here - we need to include glibc's features.h, but
+ we don't want to just include a header that might not be defined for other
+ c libraries like musl. Instead we include limits.h, which we know on all
+ glibc distributions includes features.h
+*/
+#include <limits.h>
+
+#if defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+#include <time.h>
+
+#if ((2 < __GLIBC__) || ((2 == __GLIBC__) && (17 <= __GLIBC_MINOR__)))
+/* glibc is version 2.17 or above, so we can just use clock_gettime */
+#define UTEST_USE_CLOCKGETTIME
+#else
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+#else // Other libc implementations
+#include <time.h>
+#define UTEST_USE_CLOCKGETTIME
+#endif
+
+#elif defined(__APPLE__)
+#include <time.h>
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER < 1920)
+#define UTEST_PRId64 "I64d"
+#define UTEST_PRIu64 "I64u"
+#else
+#include <inttypes.h>
+
+#define UTEST_PRId64 PRId64
+#define UTEST_PRIu64 PRIu64
+#endif
+
+#if defined(__cplusplus)
+#define UTEST_INLINE inline
+
+#if defined(__clang__)
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"")
+
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop")
+#else
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS
+#endif
+
+#define UTEST_INITIALIZER(f) \
+ struct f##_cpp_struct { \
+ f##_cpp_struct(); \
+ }; \
+ UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS static f##_cpp_struct \
+ f##_cpp_global UTEST_INITIALIZER_END_DISABLE_WARNINGS; \
+ f##_cpp_struct::f##_cpp_struct()
+#elif defined(_MSC_VER)
+#define UTEST_INLINE __forceinline
+
+#if defined(_WIN64)
+#define UTEST_SYMBOL_PREFIX
+#else
+#define UTEST_SYMBOL_PREFIX "_"
+#endif
+
+#if defined(__clang__)
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wmissing-variable-declarations\"")
+
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS _Pragma("clang diagnostic pop")
+#else
+#define UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS
+#define UTEST_INITIALIZER_END_DISABLE_WARNINGS
+#endif
+
+#pragma section(".CRT$XCU", read)
+#define UTEST_INITIALIZER(f) \
+ static void __cdecl f(void); \
+ UTEST_INITIALIZER_BEGIN_DISABLE_WARNINGS \
+ __pragma(comment(linker, "/include:" UTEST_SYMBOL_PREFIX #f "_")) \
+ UTEST_C_FUNC __declspec(allocate(".CRT$XCU")) void(__cdecl * \
+ f##_)(void) = f; \
+ UTEST_INITIALIZER_END_DISABLE_WARNINGS \
+ static void __cdecl f(void)
+#else
+#if defined(__linux__)
+#if defined(__clang__)
+#if __has_warning("-Wreserved-id-macro")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreserved-id-macro"
+#endif
+#endif
+
+#define __STDC_FORMAT_MACROS 1
+
+#if defined(__clang__)
+#if __has_warning("-Wreserved-id-macro")
+#pragma clang diagnostic pop
+#endif
+#endif
+#endif
+
+#define UTEST_INLINE inline
+
+#define UTEST_INITIALIZER(f) \
+ static void f(void) UTEST_ATTRIBUTE(constructor); \
+ static void f(void)
+#endif
+
+#if defined(__cplusplus)
+#define UTEST_CAST(type, x) static_cast<type>(x)
+#define UTEST_PTR_CAST(type, x) reinterpret_cast<type>(x)
+#define UTEST_EXTERN extern "C"
+#define UTEST_NULL NULL
+#else
+#define UTEST_CAST(type, x) ((type)(x))
+#define UTEST_PTR_CAST(type, x) ((type)(x))
+#define UTEST_EXTERN extern
+#define UTEST_NULL 0
+#endif
+
+#ifdef _MSC_VER
+/*
+ io.h contains definitions for some structures with natural padding. This is
+ uninteresting, but for some reason MSVC's behaviour is to warn about
+ including this system header. That *is* interesting
+*/
+#pragma warning(disable : 4820)
+#pragma warning(push, 1)
+#include <io.h>
+#pragma warning(pop)
+#define UTEST_COLOUR_OUTPUT() (_isatty(_fileno(stdout)))
+#else
+#if defined(__EMSCRIPTEN__)
+#include <emscripten/html5.h>
+#define UTEST_COLOUR_OUTPUT() false
+#else
+#include <unistd.h>
+#define UTEST_COLOUR_OUTPUT() (isatty(STDOUT_FILENO))
+#endif
+#endif
+
+static UTEST_INLINE void *utest_realloc(void *const pointer, size_t new_size) {
+ void *const new_pointer = realloc(pointer, new_size);
+
+ if (UTEST_NULL == new_pointer) {
+ free(new_pointer);
+ }
+
+ return new_pointer;
+}
+
+static UTEST_INLINE utest_int64_t utest_ns(void) {
+#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__)
+ utest_large_integer counter;
+ utest_large_integer frequency;
+ QueryPerformanceCounter(&counter);
+ QueryPerformanceFrequency(&frequency);
+ return UTEST_CAST(utest_int64_t,
+ (counter.QuadPart * 1000000000) / frequency.QuadPart);
+#elif defined(__linux__) && defined(__STRICT_ANSI__)
+ return UTEST_CAST(utest_int64_t, clock()) * 1000000000 / CLOCKS_PER_SEC;
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun__) || \
+ defined(__HAIKU__)
+ struct timespec ts;
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+ !defined(__HAIKU__)
+ timespec_get(&ts, TIME_UTC);
+#else
+ const clockid_t cid = CLOCK_REALTIME;
+#if defined(UTEST_USE_CLOCKGETTIME)
+ clock_gettime(cid, &ts);
+#else
+ syscall(SYS_clock_gettime, cid, &ts);
+#endif
+#endif
+ return UTEST_CAST(utest_int64_t, ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec;
+#elif __APPLE__
+ return UTEST_CAST(utest_int64_t, clock_gettime_nsec_np(CLOCK_UPTIME_RAW));
+#elif __EMSCRIPTEN__
+ return emscripten_performance_now() * 1000000.0;
+#else
+#error Unsupported platform!
+#endif
+}
+
+typedef void (*utest_testcase_t)(int *, size_t);
+
+struct utest_test_state_s {
+ utest_testcase_t func;
+ size_t index;
+ char *name;
+};
+
+struct utest_state_s {
+ struct utest_test_state_s *tests;
+ size_t tests_length;
+ FILE *output;
+};
+
+/* extern to the global state utest needs to execute */
+UTEST_EXTERN struct utest_state_s utest_state;
+
+#if defined(_MSC_VER)
+#define UTEST_WEAK __forceinline
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+#define UTEST_WEAK static UTEST_ATTRIBUTE(used)
+#elif defined(__clang__) || defined(__GNUC__) || defined(__TINYC__)
+#define UTEST_WEAK UTEST_ATTRIBUTE(weak)
+#else
+#error Non clang, non gcc, non MSVC, non tcc compiler found!
+#endif
+
+#if defined(_MSC_VER)
+#define UTEST_UNUSED
+#else
+#define UTEST_UNUSED UTEST_ATTRIBUTE(unused)
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+#define UTEST_PRINTF(...) \
+ if (utest_state.output) { \
+ fprintf(utest_state.output, __VA_ARGS__); \
+ } \
+ printf(__VA_ARGS__)
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+#ifdef _MSC_VER
+#define UTEST_SNPRINTF(BUFFER, N, ...) _snprintf_s(BUFFER, N, N, __VA_ARGS__)
+#else
+#define UTEST_SNPRINTF(...) snprintf(__VA_ARGS__)
+#endif
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#if defined(__cplusplus)
+/* if we are using c++ we can use overloaded methods (its in the language) */
+#define UTEST_OVERLOADABLE
+#elif defined(__clang__)
+/* otherwise, if we are using clang with c - use the overloadable attribute */
+#define UTEST_OVERLOADABLE UTEST_ATTRIBUTE(overloadable)
+#endif
+
+#if defined(__cplusplus) && (__cplusplus >= 201103L)
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+#include <type_traits>
+
+template <typename T, bool is_enum = std::is_enum<T>::value>
+struct utest_type_deducer final {
+ static void _(const T t);
+};
+
+template <> struct utest_type_deducer<signed char, false> {
+ static void _(const signed char c) {
+ UTEST_PRINTF("%d", static_cast<int>(c));
+ }
+};
+
+template <> struct utest_type_deducer<unsigned char, false> {
+ static void _(const unsigned char c) {
+ UTEST_PRINTF("%u", static_cast<unsigned int>(c));
+ }
+};
+
+template <> struct utest_type_deducer<short, false> {
+ static void _(const short s) { UTEST_PRINTF("%d", static_cast<int>(s)); }
+};
+
+template <> struct utest_type_deducer<unsigned short, false> {
+ static void _(const unsigned short s) {
+ UTEST_PRINTF("%u", static_cast<int>(s));
+ }
+};
+
+template <> struct utest_type_deducer<float, false> {
+ static void _(const float f) { UTEST_PRINTF("%f", static_cast<double>(f)); }
+};
+
+template <> struct utest_type_deducer<double, false> {
+ static void _(const double d) { UTEST_PRINTF("%f", d); }
+};
+
+template <> struct utest_type_deducer<long double, false> {
+ static void _(const long double d) {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ /* MINGW is weird - doesn't like LF at all?! */
+ UTEST_PRINTF("%f", (double)d);
+#else
+ UTEST_PRINTF("%Lf", d);
+#endif
+ }
+};
+
+template <> struct utest_type_deducer<int, false> {
+ static void _(const int i) { UTEST_PRINTF("%d", i); }
+};
+
+template <> struct utest_type_deducer<unsigned int, false> {
+ static void _(const unsigned int i) { UTEST_PRINTF("%u", i); }
+};
+
+template <> struct utest_type_deducer<long, false> {
+ static void _(const long i) { UTEST_PRINTF("%ld", i); }
+};
+
+template <> struct utest_type_deducer<unsigned long, false> {
+ static void _(const unsigned long i) { UTEST_PRINTF("%lu", i); }
+};
+
+template <> struct utest_type_deducer<long long, false> {
+ static void _(const long long i) { UTEST_PRINTF("%lld", i); }
+};
+
+template <> struct utest_type_deducer<unsigned long long, false> {
+ static void _(const unsigned long long i) { UTEST_PRINTF("%llu", i); }
+};
+
+template <typename T> struct utest_type_deducer<const T *, false> {
+ static void _(const T *t) {
+ UTEST_PRINTF("%p", static_cast<void *>(const_cast<T *>(t)));
+ }
+};
+
+template <typename T> struct utest_type_deducer<T *, false> {
+ static void _(T *t) { UTEST_PRINTF("%p", static_cast<void *>(t)); }
+};
+
+template <typename T> struct utest_type_deducer<T, true> {
+ static void _(const T t) {
+ UTEST_PRINTF("%llu", static_cast<unsigned long long>(t));
+ }
+};
+
+template <typename T>
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const T t) {
+ utest_type_deducer<T>::_(t);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#elif defined(UTEST_OVERLOADABLE)
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(signed char c);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(signed char c) {
+ UTEST_PRINTF("%d", UTEST_CAST(int, c));
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned char c);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned char c) {
+ UTEST_PRINTF("%u", UTEST_CAST(unsigned int, c));
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(float f) {
+ UTEST_PRINTF("%f", UTEST_CAST(double, f));
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(double d) {
+ UTEST_PRINTF("%f", d);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long double d) {
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ /* MINGW is weird - doesn't like LF at all?! */
+ UTEST_PRINTF("%f", (double)d);
+#else
+ UTEST_PRINTF("%Lf", d);
+#endif
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(int i) {
+ UTEST_PRINTF("%d", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(unsigned int i) {
+ UTEST_PRINTF("%u", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long int i) {
+ UTEST_PRINTF("%ld", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long unsigned int i) {
+ UTEST_PRINTF("%lu", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(const void *p) {
+ UTEST_PRINTF("%p", p);
+}
+
+/*
+ long long is a c++11 extension
+*/
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || \
+ defined(__cplusplus) && (__cplusplus >= 201103L) || \
+ (defined(__MINGW32__) || defined(__MINGW64__))
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i);
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long int i) {
+ UTEST_PRINTF("%lld", i);
+}
+
+UTEST_WEAK UTEST_OVERLOADABLE void utest_type_printer(long long unsigned int i);
+UTEST_WEAK UTEST_OVERLOADABLE void
+utest_type_printer(long long unsigned int i) {
+ UTEST_PRINTF("%llu", i);
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
+ !(defined(__MINGW32__) || defined(__MINGW64__)) || \
+ defined(__TINYC__)
+#define utest_type_printer(val) \
+ UTEST_PRINTF(_Generic((val), signed char \
+ : "%d", unsigned char \
+ : "%u", short \
+ : "%d", unsigned short \
+ : "%u", int \
+ : "%d", long \
+ : "%ld", long long \
+ : "%lld", unsigned \
+ : "%u", unsigned long \
+ : "%lu", unsigned long long \
+ : "%llu", float \
+ : "%f", double \
+ : "%f", long double \
+ : "%Lf", default \
+ : _Generic((val - val), ptrdiff_t \
+ : "%p", default \
+ : "undef")), \
+ (val))
+#else
+/*
+ we don't have the ability to print the values we got, so we create a macro
+ to tell our users we can't do anything fancy
+*/
+#define utest_type_printer(...) UTEST_PRINTF("undef")
+#endif
+
+#if defined(_MSC_VER)
+#define UTEST_SURPRESS_WARNING_BEGIN \
+ __pragma(warning(push)) __pragma(warning(disable : 4127)) \
+ __pragma(warning(disable : 4571)) __pragma(warning(disable : 4130))
+#define UTEST_SURPRESS_WARNING_END __pragma(warning(pop))
+#else
+#define UTEST_SURPRESS_WARNING_BEGIN
+#define UTEST_SURPRESS_WARNING_END
+#endif
+
+#if defined(__cplusplus) && (__cplusplus >= 201103L)
+#define UTEST_AUTO(x) auto
+#elif !defined(__cplusplus)
+
+#if defined(__clang__)
+/* clang-format off */
+/* had to disable clang-format here because it malforms the pragmas */
+#define UTEST_AUTO(x) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wgnu-auto-type\"") __auto_type \
+ _Pragma("clang diagnostic pop")
+/* clang-format on */
+#else
+#define UTEST_AUTO(x) __typeof__(x + 0)
+#endif
+
+#else
+#define UTEST_AUTO(x) typeof(x + 0)
+#endif
+
+#if defined(__clang__)
+#define UTEST_STRNCMP(x, y, size) \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wdisabled-macro-expansion\"") \
+ strncmp(x, y, size) _Pragma("clang diagnostic pop")
+#else
+#define UTEST_STRNCMP(x, y, size) strncmp(x, y, size)
+#endif
+
+#if defined(_MSC_VER)
+#define UTEST_STRNCPY(x, y, size) strcpy_s(x, size, y)
+#elif !defined(__clang__) && defined(__GNUC__)
+static UTEST_INLINE char *
+utest_strncpy_gcc(char *const dst, const char *const src, const size_t size) {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstringop-overflow"
+ return strncpy(dst, src, size);
+#pragma GCC diagnostic pop
+}
+
+#define UTEST_STRNCPY(x, y, size) utest_strncpy_gcc(x, y, size)
+#else
+#define UTEST_STRNCPY(x, y, size) strncpy(x, y, size)
+#endif
+
+#define UTEST_SKIP(msg) \
+ do { \
+ UTEST_PRINTF(" Skipped : '%s'\n", (msg)); \
+ *utest_result = UTEST_TEST_SKIPPED; \
+ return; \
+ } while (0)
+
+#if defined(__clang__)
+#define UTEST_COND(x, y, cond, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wlanguage-extension-token\"") \
+ _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"") \
+ _Pragma("clang diagnostic ignored \"-Wfloat-equal\"") \
+ UTEST_AUTO(x) xEval = (x); \
+ UTEST_AUTO(y) yEval = (y); \
+ if (!((xEval)cond(yEval))) { \
+ _Pragma("clang diagnostic pop") \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : ("); \
+ UTEST_PRINTF(#x ") " #cond " (" #y); \
+ UTEST_PRINTF(")\n"); \
+ UTEST_PRINTF(" Actual : "); \
+ utest_type_printer(xEval); \
+ UTEST_PRINTF(" vs "); \
+ utest_type_printer(yEval); \
+ UTEST_PRINTF("\n"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+#elif defined(__GNUC__) || defined(__TINYC__)
+#define UTEST_COND(x, y, cond, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ UTEST_AUTO(x) xEval = (x); \
+ UTEST_AUTO(y) yEval = (y); \
+ if (!((xEval)cond(yEval))) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : ("); \
+ UTEST_PRINTF(#x ") " #cond " (" #y); \
+ UTEST_PRINTF(")\n"); \
+ UTEST_PRINTF(" Actual : "); \
+ utest_type_printer(xEval); \
+ UTEST_PRINTF(" vs "); \
+ utest_type_printer(yEval); \
+ UTEST_PRINTF("\n"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+#else
+#define UTEST_COND(x, y, cond, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ if (!((x)cond(y))) { \
+ UTEST_PRINTF("%s:%i: Failure (Expected " #cond " Actual)", __FILE__, \
+ __LINE__); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s", msg); \
+ } \
+ UTEST_PRINTF("\n"); \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+#endif
+
+#define EXPECT_EQ(x, y) UTEST_COND(x, y, ==, "", 0)
+#define EXPECT_EQ_MSG(x, y, msg) UTEST_COND(x, y, ==, msg, 0)
+#define ASSERT_EQ(x, y) UTEST_COND(x, y, ==, "", 1)
+#define ASSERT_EQ_MSG(x, y, msg) UTEST_COND(x, y, ==, msg, 1)
+
+#define EXPECT_NE(x, y) UTEST_COND(x, y, !=, "", 0)
+#define EXPECT_NE_MSG(x, y, msg) UTEST_COND(x, y, !=, msg, 0)
+#define ASSERT_NE(x, y) UTEST_COND(x, y, !=, "", 1)
+#define ASSERT_NE_MSG(x, y, msg) UTEST_COND(x, y, !=, msg, 1)
+
+#define EXPECT_LT(x, y) UTEST_COND(x, y, <, "", 0)
+#define EXPECT_LT_MSG(x, y, msg) UTEST_COND(x, y, <, msg, 0)
+#define ASSERT_LT(x, y) UTEST_COND(x, y, <, "", 1)
+#define ASSERT_LT_MSG(x, y, msg) UTEST_COND(x, y, <, msg, 1)
+
+#define EXPECT_LE(x, y) UTEST_COND(x, y, <=, "", 0)
+#define EXPECT_LE_MSG(x, y, msg) UTEST_COND(x, y, <=, msg, 0)
+#define ASSERT_LE(x, y) UTEST_COND(x, y, <=, "", 1)
+#define ASSERT_LE_MSG(x, y, msg) UTEST_COND(x, y, <=, msg, 1)
+
+#define EXPECT_GT(x, y) UTEST_COND(x, y, >, "", 0)
+#define EXPECT_GT_MSG(x, y, msg) UTEST_COND(x, y, >, msg, 0)
+#define ASSERT_GT(x, y) UTEST_COND(x, y, >, "", 1)
+#define ASSERT_GT_MSG(x, y, msg) UTEST_COND(x, y, >, msg, 1)
+
+#define EXPECT_GE(x, y) UTEST_COND(x, y, >=, "", 0)
+#define EXPECT_GE_MSG(x, y, msg) UTEST_COND(x, y, >=, msg, 0)
+#define ASSERT_GE(x, y) UTEST_COND(x, y, >=, "", 1)
+#define ASSERT_GE_MSG(x, y, msg) UTEST_COND(x, y, >=, msg, 1)
+
+#define UTEST_TRUE(x, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const int xEval = !!(x); \
+ if (!(xEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : true\n"); \
+ UTEST_PRINTF(" Actual : %s\n", (xEval) ? "true" : "false"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_TRUE(x) UTEST_TRUE(x, "", 0)
+#define EXPECT_TRUE_MSG(x, msg) UTEST_TRUE(x, msg, 0)
+#define ASSERT_TRUE(x) UTEST_TRUE(x, "", 1)
+#define ASSERT_TRUE_MSG(x, msg) UTEST_TRUE(x, msg, 1)
+
+#define UTEST_FALSE(x, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const int xEval = !!(x); \
+ if (xEval) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : false\n"); \
+ UTEST_PRINTF(" Actual : %s\n", (xEval) ? "true" : "false"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_FALSE(x) UTEST_FALSE(x, "", 0)
+#define EXPECT_FALSE_MSG(x, msg) UTEST_FALSE(x, msg, 0)
+#define ASSERT_FALSE(x) UTEST_FALSE(x, "", 1)
+#define ASSERT_FALSE_MSG(x, msg) UTEST_FALSE(x, msg, 1)
+
+#define UTEST_STREQ(x, y, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 != strcmp(xEval, yEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%s\"\n", xEval); \
+ UTEST_PRINTF(" Actual : \"%s\"\n", yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STREQ(x, y) UTEST_STREQ(x, y, "", 0)
+#define EXPECT_STREQ_MSG(x, y, msg) UTEST_STREQ(x, y, msg, 0)
+#define ASSERT_STREQ(x, y) UTEST_STREQ(x, y, "", 1)
+#define ASSERT_STREQ_MSG(x, y, msg) UTEST_STREQ(x, y, msg, 1)
+
+#define UTEST_STRNE(x, y, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 == strcmp(xEval, yEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%s\"\n", xEval); \
+ UTEST_PRINTF(" Actual : \"%s\"\n", yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STRNE(x, y) UTEST_STRNE(x, y, "", 0)
+#define EXPECT_STRNE_MSG(x, y, msg) UTEST_STRNE(x, y, msg, 0)
+#define ASSERT_STRNE(x, y) UTEST_STRNE(x, y, "", 1)
+#define ASSERT_STRNE_MSG(x, y, msg) UTEST_STRNE(x, y, msg, 1)
+
+#define UTEST_STRNEQ(x, y, n, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ const size_t nEval = UTEST_CAST(size_t, n); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 != UTEST_STRNCMP(xEval, yEval, nEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, nEval), xEval); \
+ UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, nEval), yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STRNEQ(x, y, n) UTEST_STRNEQ(x, y, n, "", 0)
+#define EXPECT_STRNEQ_MSG(x, y, n, msg) UTEST_STRNEQ(x, y, n, msg, 0)
+#define ASSERT_STRNEQ(x, y, n) UTEST_STRNEQ(x, y, n, "", 1)
+#define ASSERT_STRNEQ_MSG(x, y, n, msg) UTEST_STRNEQ(x, y, n, msg, 1)
+
+#define UTEST_STRNNE(x, y, n, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const char *xEval = (x); \
+ const char *yEval = (y); \
+ const size_t nEval = UTEST_CAST(size_t, n); \
+ if (UTEST_NULL == xEval || UTEST_NULL == yEval || \
+ 0 == UTEST_STRNCMP(xEval, yEval, nEval)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : \"%.*s\"\n", UTEST_CAST(int, nEval), xEval); \
+ UTEST_PRINTF(" Actual : \"%.*s\"\n", UTEST_CAST(int, nEval), yEval); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_STRNNE(x, y, n) UTEST_STRNNE(x, y, n, "", 0)
+#define EXPECT_STRNNE_MSG(x, y, n, msg) UTEST_STRNNE(x, y, n, msg, 0)
+#define ASSERT_STRNNE(x, y, n) UTEST_STRNNE(x, y, n, "", 1)
+#define ASSERT_STRNNE_MSG(x, y, n, msg) UTEST_STRNNE(x, y, n, msg, 1)
+
+#define UTEST_NEAR(x, y, epsilon, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ const double diff = \
+ utest_fabs(UTEST_CAST(double, x) - UTEST_CAST(double, y)); \
+ if (diff > UTEST_CAST(double, epsilon) || utest_isnan(diff)) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %f\n", UTEST_CAST(double, x)); \
+ UTEST_PRINTF(" Actual : %f\n", UTEST_CAST(double, y)); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_NEAR(x, y, epsilon) UTEST_NEAR(x, y, epsilon, "", 0)
+#define EXPECT_NEAR_MSG(x, y, epsilon, msg) UTEST_NEAR(x, y, epsilon, msg, 0)
+#define ASSERT_NEAR(x, y, epsilon) UTEST_NEAR(x, y, epsilon, "", 1)
+#define ASSERT_NEAR_MSG(x, y, epsilon, msg) UTEST_NEAR(x, y, epsilon, msg, 1)
+
+#if defined(UTEST_HAS_EXCEPTIONS)
+#define UTEST_EXCEPTION(x, exception_type, msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ int exception_caught = 0; \
+ try { \
+ x; \
+ } catch (const exception_type &) { \
+ exception_caught = 1; \
+ } catch (...) { \
+ exception_caught = 2; \
+ } \
+ if (1 != exception_caught) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %s exception\n", #exception_type); \
+ UTEST_PRINTF(" Actual : %s\n", (2 == exception_caught) \
+ ? "Unexpected exception" \
+ : "No exception"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_EXCEPTION(x, exception_type) \
+ UTEST_EXCEPTION(x, exception_type, "", 0)
+#define EXPECT_EXCEPTION_MSG(x, exception_type, msg) \
+ UTEST_EXCEPTION(x, exception_type, msg, 0)
+#define ASSERT_EXCEPTION(x, exception_type) \
+ UTEST_EXCEPTION(x, exception_type, "", 1)
+#define ASSERT_EXCEPTION_MSG(x, exception_type, msg) \
+ UTEST_EXCEPTION(x, exception_type, msg, 1)
+
+#define UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, \
+ msg, is_assert) \
+ UTEST_SURPRESS_WARNING_BEGIN do { \
+ int exception_caught = 0; \
+ char *message_caught = UTEST_NULL; \
+ try { \
+ x; \
+ } catch (const exception_type &e) { \
+ const char *const what = e.what(); \
+ exception_caught = 1; \
+ if (0 != \
+ UTEST_STRNCMP(what, exception_message, strlen(exception_message))) { \
+ const size_t message_size = strlen(what) + 1; \
+ message_caught = UTEST_PTR_CAST(char *, malloc(message_size)); \
+ UTEST_STRNCPY(message_caught, what, message_size); \
+ } \
+ } catch (...) { \
+ exception_caught = 2; \
+ } \
+ if (1 != exception_caught) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %s exception\n", #exception_type); \
+ UTEST_PRINTF(" Actual : %s\n", (2 == exception_caught) \
+ ? "Unexpected exception" \
+ : "No exception"); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ if (is_assert) { \
+ return; \
+ } \
+ } else if (UTEST_NULL != message_caught) { \
+ UTEST_PRINTF("%s:%i: Failure\n", __FILE__, __LINE__); \
+ UTEST_PRINTF(" Expected : %s exception with message %s\n", \
+ #exception_type, exception_message); \
+ UTEST_PRINTF(" Actual message : %s\n", message_caught); \
+ if (strlen(msg) > 0) { \
+ UTEST_PRINTF(" Message : %s\n", msg); \
+ } \
+ *utest_result = UTEST_TEST_FAILURE; \
+ free(message_caught); \
+ if (is_assert) { \
+ return; \
+ } \
+ } \
+ } \
+ while (0) \
+ UTEST_SURPRESS_WARNING_END
+
+#define EXPECT_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, "", 0)
+#define EXPECT_EXCEPTION_WITH_MESSAGE_MSG(x, exception_type, \
+ exception_message, msg) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, msg, 0)
+#define ASSERT_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, "", 1)
+#define ASSERT_EXCEPTION_WITH_MESSAGE_MSG(x, exception_type, \
+ exception_message, msg) \
+ UTEST_EXCEPTION_WITH_MESSAGE(x, exception_type, exception_message, msg, 1)
+#endif
+
+#if defined(__clang__)
+#if __has_warning("-Wunsafe-buffer-usage")
+#define UTEST_SURPRESS_WARNINGS_BEGIN \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wunsafe-buffer-usage\"")
+#define UTEST_SURPRESS_WARNINGS_END _Pragma("clang diagnostic pop")
+#else
+#define UTEST_SURPRESS_WARNINGS_BEGIN
+#define UTEST_SURPRESS_WARNINGS_END
+#endif
+#elif defined(__GNUC__) && __GNUC__ >= 8 && defined(__cplusplus)
+#define UTEST_SURPRESS_WARNINGS_BEGIN \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
+#define UTEST_SURPRESS_WARNINGS_END _Pragma("GCC diagnostic pop")
+#else
+#define UTEST_SURPRESS_WARNINGS_BEGIN
+#define UTEST_SURPRESS_WARNINGS_END
+#endif
+
+#define UTEST(SET, NAME) \
+ UTEST_SURPRESS_WARNINGS_BEGIN \
+ UTEST_EXTERN struct utest_state_s utest_state; \
+ static void utest_run_##SET##_##NAME(int *utest_result); \
+ static void utest_##SET##_##NAME(int *utest_result, size_t utest_index) { \
+ (void)utest_index; \
+ utest_run_##SET##_##NAME(utest_result); \
+ } \
+ UTEST_INITIALIZER(utest_register_##SET##_##NAME) { \
+ const size_t index = utest_state.tests_length++; \
+ const char *name_part = #SET "." #NAME; \
+ const size_t name_size = strlen(name_part) + 1; \
+ char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
+ utest_state.tests = UTEST_PTR_CAST( \
+ struct utest_test_state_s *, \
+ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
+ sizeof(struct utest_test_state_s) * \
+ utest_state.tests_length)); \
+ if (utest_state.tests) { \
+ utest_state.tests[index].func = &utest_##SET##_##NAME; \
+ utest_state.tests[index].name = name; \
+ utest_state.tests[index].index = 0; \
+ UTEST_SNPRINTF(name, name_size, "%s", name_part); \
+ } else if (name) { \
+ free(name); \
+ } \
+ } \
+ UTEST_SURPRESS_WARNINGS_END \
+ void utest_run_##SET##_##NAME(int *utest_result)
+
+#define UTEST_F_SETUP(FIXTURE) \
+ static void utest_f_setup_##FIXTURE(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#define UTEST_F_TEARDOWN(FIXTURE) \
+ static void utest_f_teardown_##FIXTURE(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#define UTEST_F(FIXTURE, NAME) \
+ UTEST_SURPRESS_WARNINGS_BEGIN \
+ UTEST_EXTERN struct utest_state_s utest_state; \
+ static void utest_f_setup_##FIXTURE(int *, struct FIXTURE *); \
+ static void utest_f_teardown_##FIXTURE(int *, struct FIXTURE *); \
+ static void utest_run_##FIXTURE##_##NAME(int *, struct FIXTURE *); \
+ static void utest_f_##FIXTURE##_##NAME(int *utest_result, \
+ size_t utest_index) { \
+ struct FIXTURE fixture; \
+ (void)utest_index; \
+ memset(&fixture, 0, sizeof(fixture)); \
+ utest_f_setup_##FIXTURE(utest_result, &fixture); \
+ if (UTEST_TEST_PASSED != *utest_result) { \
+ return; \
+ } \
+ utest_run_##FIXTURE##_##NAME(utest_result, &fixture); \
+ utest_f_teardown_##FIXTURE(utest_result, &fixture); \
+ } \
+ UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME) { \
+ const size_t index = utest_state.tests_length++; \
+ const char *name_part = #FIXTURE "." #NAME; \
+ const size_t name_size = strlen(name_part) + 1; \
+ char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
+ utest_state.tests = UTEST_PTR_CAST( \
+ struct utest_test_state_s *, \
+ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
+ sizeof(struct utest_test_state_s) * \
+ utest_state.tests_length)); \
+ if (utest_state.tests) { \
+ utest_state.tests[index].func = &utest_f_##FIXTURE##_##NAME; \
+ utest_state.tests[index].name = name; \
+ UTEST_SNPRINTF(name, name_size, "%s", name_part); \
+ } else if (name) { \
+ free(name); \
+ } \
+ } \
+ UTEST_SURPRESS_WARNINGS_END \
+ void utest_run_##FIXTURE##_##NAME(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#define UTEST_I_SETUP(FIXTURE) \
+ static void utest_i_setup_##FIXTURE( \
+ int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index)
+
+#define UTEST_I_TEARDOWN(FIXTURE) \
+ static void utest_i_teardown_##FIXTURE( \
+ int *utest_result, struct FIXTURE *utest_fixture, size_t utest_index)
+
+#define UTEST_I(FIXTURE, NAME, INDEX) \
+ UTEST_SURPRESS_WARNINGS_BEGIN \
+ UTEST_EXTERN struct utest_state_s utest_state; \
+ static void utest_run_##FIXTURE##_##NAME##_##INDEX(int *, struct FIXTURE *); \
+ static void utest_i_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \
+ size_t index) { \
+ struct FIXTURE fixture; \
+ memset(&fixture, 0, sizeof(fixture)); \
+ utest_i_setup_##FIXTURE(utest_result, &fixture, index); \
+ if (UTEST_TEST_PASSED != *utest_result) { \
+ return; \
+ } \
+ utest_run_##FIXTURE##_##NAME##_##INDEX(utest_result, &fixture); \
+ utest_i_teardown_##FIXTURE(utest_result, &fixture, index); \
+ } \
+ UTEST_INITIALIZER(utest_register_##FIXTURE##_##NAME##_##INDEX) { \
+ size_t i; \
+ utest_uint64_t iUp; \
+ for (i = 0; i < (INDEX); i++) { \
+ const size_t index = utest_state.tests_length++; \
+ const char *name_part = #FIXTURE "." #NAME; \
+ const size_t name_size = strlen(name_part) + 32; \
+ char *name = UTEST_PTR_CAST(char *, malloc(name_size)); \
+ utest_state.tests = UTEST_PTR_CAST( \
+ struct utest_test_state_s *, \
+ utest_realloc(UTEST_PTR_CAST(void *, utest_state.tests), \
+ sizeof(struct utest_test_state_s) * \
+ utest_state.tests_length)); \
+ if (utest_state.tests) { \
+ utest_state.tests[index].func = &utest_i_##FIXTURE##_##NAME##_##INDEX; \
+ utest_state.tests[index].index = i; \
+ utest_state.tests[index].name = name; \
+ iUp = UTEST_CAST(utest_uint64_t, i); \
+ UTEST_SNPRINTF(name, name_size, "%s/%" UTEST_PRIu64, name_part, iUp); \
+ } else if (name) { \
+ free(name); \
+ } \
+ } \
+ } \
+ UTEST_SURPRESS_WARNINGS_END \
+ void utest_run_##FIXTURE##_##NAME##_##INDEX(int *utest_result, \
+ struct FIXTURE *utest_fixture)
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+UTEST_WEAK
+double utest_fabs(double d);
+UTEST_WEAK
+double utest_fabs(double d) {
+ union {
+ double d;
+ utest_uint64_t u;
+ } both;
+ both.d = d;
+ both.u &= 0x7fffffffffffffffu;
+ return both.d;
+}
+
+UTEST_WEAK
+int utest_isnan(double d);
+UTEST_WEAK
+int utest_isnan(double d) {
+ union {
+ double d;
+ utest_uint64_t u;
+ } both;
+ both.d = d;
+ both.u &= 0x7fffffffffffffffu;
+ return both.u > 0x7ff0000000000000u;
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#if defined(__clang__)
+#if __has_warning("-Wunsafe-buffer-usage")
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
+#endif
+#endif
+
+UTEST_WEAK
+int utest_should_filter_test(const char *filter, const char *testcase);
+UTEST_WEAK int utest_should_filter_test(const char *filter,
+ const char *testcase) {
+ if (filter) {
+ const char *filter_cur = filter;
+ const char *testcase_cur = testcase;
+ const char *filter_wildcard = UTEST_NULL;
+
+ while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) {
+ if ('*' == *filter_cur) {
+ /* store the position of the wildcard */
+ filter_wildcard = filter_cur;
+
+ /* skip the wildcard character */
+ filter_cur++;
+
+ while (('\0' != *filter_cur) && ('\0' != *testcase_cur)) {
+ if ('*' == *filter_cur) {
+ /*
+ we found another wildcard (filter is something like *foo*) so we
+ exit the current loop, and return to the parent loop to handle
+ the wildcard case
+ */
+ break;
+ } else if (*filter_cur != *testcase_cur) {
+ /* otherwise our filter didn't match, so reset it */
+ filter_cur = filter_wildcard;
+ }
+
+ /* move testcase along */
+ testcase_cur++;
+
+ /* move filter along */
+ filter_cur++;
+ }
+
+ if (('\0' == *filter_cur) && ('\0' == *testcase_cur)) {
+ return 0;
+ }
+
+ /* if the testcase has been exhausted, we don't have a match! */
+ if ('\0' == *testcase_cur) {
+ return 1;
+ }
+ } else {
+ if (*testcase_cur != *filter_cur) {
+ /* test case doesn't match filter */
+ return 1;
+ } else {
+ /* move our filter and testcase forward */
+ testcase_cur++;
+ filter_cur++;
+ }
+ }
+ }
+
+ if (('\0' != *filter_cur) ||
+ (('\0' != *testcase_cur) &&
+ ((filter == filter_cur) || ('*' != filter_cur[-1])))) {
+ /* we have a mismatch! */
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static UTEST_INLINE FILE *utest_fopen(const char *filename, const char *mode) {
+#ifdef _MSC_VER
+ FILE *file;
+ if (0 == fopen_s(&file, filename, mode)) {
+ return file;
+ } else {
+ return UTEST_NULL;
+ }
+#else
+ return fopen(filename, mode);
+#endif
+}
+
+static UTEST_INLINE int utest_main(int argc, const char *const argv[]);
+int utest_main(int argc, const char *const argv[]) {
+ utest_uint64_t failed = 0;
+ utest_uint64_t skipped = 0;
+ size_t index = 0;
+ size_t *failed_testcases = UTEST_NULL;
+ size_t failed_testcases_length = 0;
+ size_t *skipped_testcases = UTEST_NULL;
+ size_t skipped_testcases_length = 0;
+ const char *filter = UTEST_NULL;
+ utest_uint64_t ran_tests = 0;
+ int enable_mixed_units = 0;
+ int random_order = 0;
+ utest_uint32_t seed = 0;
+
+ enum colours { RESET, GREEN, RED, YELLOW };
+
+ const int use_colours = UTEST_COLOUR_OUTPUT();
+ const char *colours[] = {"\033[0m", "\033[32m", "\033[31m", "\033[33m"};
+
+ if (!use_colours) {
+ for (index = 0; index < sizeof colours / sizeof colours[0]; index++) {
+ colours[index] = "";
+ }
+ }
+ /* loop through all arguments looking for our options */
+ for (index = 1; index < UTEST_CAST(size_t, argc); index++) {
+ /* Informational switches */
+ const char help_str[] = "--help";
+ const char list_str[] = "--list-tests";
+ /* Test config switches */
+ const char filter_str[] = "--filter=";
+ const char output_str[] = "--output=";
+ const char enable_mixed_units_str[] = "--enable-mixed-units";
+ const char random_order_str[] = "--random-order";
+ const char random_order_with_seed_str[] = "--random-order=";
+
+ if (0 == UTEST_STRNCMP(argv[index], help_str, strlen(help_str))) {
+ printf("utest.h - the single file unit testing solution for C/C++!\n"
+ "Command line Options:\n"
+ " --help Show this message and exit.\n"
+ " --filter=<filter> Filter the test cases to run (EG. "
+ "MyTest*.a would run MyTestCase.a but not MyTestCase.b).\n"
+ " --list-tests List testnames, one per line. Output "
+ "names can be passed to --filter.\n");
+ printf(" --output=<output> Output an xunit XML file to the file "
+ "specified in <output>.\n"
+ " --enable-mixed-units Enable the per-test output to contain "
+ "mixed units (s/ms/us/ns).\n"
+ " --random-order[=<seed>] Randomize the order that the tests are "
+ "ran in. If the optional <seed> argument is not provided, then a "
+ "random starting seed is used.\n");
+ goto cleanup;
+ } else if (0 ==
+ UTEST_STRNCMP(argv[index], filter_str, strlen(filter_str))) {
+ /* user wants to filter what test cases run! */
+ filter = argv[index] + strlen(filter_str);
+ } else if (0 ==
+ UTEST_STRNCMP(argv[index], output_str, strlen(output_str))) {
+ utest_state.output = utest_fopen(argv[index] + strlen(output_str), "w+");
+ } else if (0 == UTEST_STRNCMP(argv[index], list_str, strlen(list_str))) {
+ for (index = 0; index < utest_state.tests_length; index++) {
+ UTEST_PRINTF("%s\n", utest_state.tests[index].name);
+ }
+ /* when printing the test list, don't actually run the tests */
+ return 0;
+ } else if (0 == UTEST_STRNCMP(argv[index], enable_mixed_units_str,
+ strlen(enable_mixed_units_str))) {
+ enable_mixed_units = 1;
+ } else if (0 == UTEST_STRNCMP(argv[index], random_order_with_seed_str,
+ strlen(random_order_with_seed_str))) {
+ seed =
+ UTEST_CAST(utest_uint32_t,
+ strtoul(argv[index] + strlen(random_order_with_seed_str),
+ UTEST_NULL, 10));
+ random_order = 1;
+ } else if (0 == UTEST_STRNCMP(argv[index], random_order_str,
+ strlen(random_order_str))) {
+ const utest_int64_t ns = utest_ns();
+
+ // Some really poor pseudo-random using the current time. I do this
+ // because I really want to avoid using C's rand() because that'd mean our
+ // random would be affected by any srand() usage by the user (which I
+ // don't want).
+ seed = UTEST_CAST(utest_uint32_t, ns >> 32) * 31 +
+ UTEST_CAST(utest_uint32_t, ns & 0xffffffff);
+ random_order = 1;
+ }
+ }
+
+ if (random_order) {
+ // Use Fisher-Yates with the Durstenfield's version to randomly re-order the
+ // tests.
+ for (index = utest_state.tests_length; index > 1; index--) {
+ // For the random order we'll use PCG.
+ const utest_uint32_t state = seed;
+ const utest_uint32_t word =
+ ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
+ const utest_uint32_t next =
+ ((word >> 22u) ^ word) % UTEST_CAST(utest_uint32_t, index);
+
+ // Swap the randomly chosen element into the last location.
+ const struct utest_test_state_s copy = utest_state.tests[index - 1];
+ utest_state.tests[index - 1] = utest_state.tests[next];
+ utest_state.tests[next] = copy;
+
+ // Move the seed onwards.
+ seed = seed * 747796405u + 2891336453u;
+ }
+ }
+
+ for (index = 0; index < utest_state.tests_length; index++) {
+ if (utest_should_filter_test(filter, utest_state.tests[index].name)) {
+ continue;
+ }
+
+ ran_tests++;
+ }
+
+ printf("%s[==========]%s Running %" UTEST_PRIu64 " test cases.\n",
+ colours[GREEN], colours[RESET], UTEST_CAST(utest_uint64_t, ran_tests));
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(utest_state.output,
+ "<testsuites tests=\"%" UTEST_PRIu64 "\" name=\"All\">\n",
+ UTEST_CAST(utest_uint64_t, ran_tests));
+ fprintf(utest_state.output,
+ "<testsuite name=\"Tests\" tests=\"%" UTEST_PRIu64 "\">\n",
+ UTEST_CAST(utest_uint64_t, ran_tests));
+ }
+
+ for (index = 0; index < utest_state.tests_length; index++) {
+ int result = UTEST_TEST_PASSED;
+ utest_int64_t ns = 0;
+
+ if (utest_should_filter_test(filter, utest_state.tests[index].name)) {
+ continue;
+ }
+
+ printf("%s[ RUN ]%s %s\n", colours[GREEN], colours[RESET],
+ utest_state.tests[index].name);
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "<testcase name=\"%s\">",
+ utest_state.tests[index].name);
+ }
+
+ ns = utest_ns();
+ errno = 0;
+#if defined(UTEST_HAS_EXCEPTIONS)
+ UTEST_SURPRESS_WARNING_BEGIN
+ try {
+ utest_state.tests[index].func(&result, utest_state.tests[index].index);
+ } catch (const std::exception &err) {
+ printf(" Exception : %s\n", err.what());
+ result = UTEST_TEST_FAILURE;
+ } catch (...) {
+ printf(" Exception : Unknown\n");
+ result = UTEST_TEST_FAILURE;
+ }
+ UTEST_SURPRESS_WARNING_END
+#else
+ utest_state.tests[index].func(&result, utest_state.tests[index].index);
+#endif
+ ns = utest_ns() - ns;
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "</testcase>\n");
+ }
+
+ // Record the failing test.
+ if (UTEST_TEST_FAILURE == result) {
+ const size_t failed_testcase_index = failed_testcases_length++;
+ failed_testcases = UTEST_PTR_CAST(
+ size_t *, utest_realloc(UTEST_PTR_CAST(void *, failed_testcases),
+ sizeof(size_t) * failed_testcases_length));
+ if (UTEST_NULL != failed_testcases) {
+ failed_testcases[failed_testcase_index] = index;
+ }
+ failed++;
+ } else if (UTEST_TEST_SKIPPED == result) {
+ const size_t skipped_testcase_index = skipped_testcases_length++;
+ skipped_testcases = UTEST_PTR_CAST(
+ size_t *, utest_realloc(UTEST_PTR_CAST(void *, skipped_testcases),
+ sizeof(size_t) * skipped_testcases_length));
+ if (UTEST_NULL != skipped_testcases) {
+ skipped_testcases[skipped_testcase_index] = index;
+ }
+ skipped++;
+ }
+
+ {
+ const char *const units[] = {"ns", "us", "ms", "s", UTEST_NULL};
+ unsigned int unit_index = 0;
+ utest_int64_t time = ns;
+
+ if (enable_mixed_units) {
+ for (unit_index = 0; UTEST_NULL != units[unit_index]; unit_index++) {
+ if (10000 > time) {
+ break;
+ }
+
+ time /= 1000;
+ }
+ }
+
+ if (UTEST_TEST_FAILURE == result) {
+ printf("%s[ FAILED ]%s %s (%" UTEST_PRId64 "%s)\n", colours[RED],
+ colours[RESET], utest_state.tests[index].name, time,
+ units[unit_index]);
+ } else if (UTEST_TEST_SKIPPED == result) {
+ printf("%s[ SKIPPED ]%s %s (%" UTEST_PRId64 "%s)\n", colours[YELLOW],
+ colours[RESET], utest_state.tests[index].name, time,
+ units[unit_index]);
+ } else {
+ printf("%s[ OK ]%s %s (%" UTEST_PRId64 "%s)\n", colours[GREEN],
+ colours[RESET], utest_state.tests[index].name, time,
+ units[unit_index]);
+ }
+ }
+ }
+
+ printf("%s[==========]%s %" UTEST_PRIu64 " test cases ran.\n", colours[GREEN],
+ colours[RESET], ran_tests);
+ printf("%s[ PASSED ]%s %" UTEST_PRIu64 " tests.\n", colours[GREEN],
+ colours[RESET], ran_tests - failed - skipped);
+
+ if (0 != skipped) {
+ printf("%s[ SKIPPED ]%s %" UTEST_PRIu64 " tests, listed below:\n",
+ colours[YELLOW], colours[RESET], skipped);
+ for (index = 0; index < skipped_testcases_length; index++) {
+ printf("%s[ SKIPPED ]%s %s\n", colours[YELLOW], colours[RESET],
+ utest_state.tests[skipped_testcases[index]].name);
+ }
+ }
+
+ if (0 != failed) {
+ printf("%s[ FAILED ]%s %" UTEST_PRIu64 " tests, listed below:\n",
+ colours[RED], colours[RESET], failed);
+ for (index = 0; index < failed_testcases_length; index++) {
+ printf("%s[ FAILED ]%s %s\n", colours[RED], colours[RESET],
+ utest_state.tests[failed_testcases[index]].name);
+ }
+ }
+
+ if (utest_state.output) {
+ fprintf(utest_state.output, "</testsuite>\n</testsuites>\n");
+ }
+
+cleanup:
+ for (index = 0; index < utest_state.tests_length; index++) {
+ free(UTEST_PTR_CAST(void *, utest_state.tests[index].name));
+ }
+
+ free(UTEST_PTR_CAST(void *, skipped_testcases));
+ free(UTEST_PTR_CAST(void *, failed_testcases));
+ free(UTEST_PTR_CAST(void *, utest_state.tests));
+
+ if (utest_state.output) {
+ fclose(utest_state.output);
+ }
+
+ return UTEST_CAST(int, failed);
+}
+
+#if defined(__clang__)
+#if __has_warning("-Wunsafe-buffer-usage")
+#pragma clang diagnostic pop
+#endif
+#endif
+
+/*
+ we need, in exactly one source file, define the global struct that will hold
+ the data we need to run utest. This macro allows the user to declare the
+ data without having to use the UTEST_MAIN macro, thus allowing them to write
+ their own main() function.
+*/
+#define UTEST_STATE() struct utest_state_s utest_state = {0, 0, 0}
+
+/*
+ define a main() function to call into utest.h and start executing tests! A
+ user can optionally not use this macro, and instead define their own main()
+ function and manually call utest_main. The user must, in exactly one source
+ file, use the UTEST_STATE macro to declare a global struct variable that
+ utest requires.
+*/
+#define UTEST_MAIN() \
+ UTEST_STATE(); \
+ int main(int argc, const char *const argv[]) { \
+ return utest_main(argc, argv); \
+ }
+
+#endif /* SHEREDOM_UTEST_H_INCLUDED */
diff --git a/Homework/math4610/test/vector.t.c b/Homework/math4610/test/vector.t.c
new file mode 100644
index 0000000..4811113
--- /dev/null
+++ b/Homework/math4610/test/vector.t.c
@@ -0,0 +1,115 @@
+#include "lizfcm.test.h"
+#include <math.h>
+
+UTEST(vector, copy_vector) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ Array_double *w = copy_vector(v);
+ EXPECT_TRUE(vector_equal(v, w));
+
+ free_vector(v);
+ free_vector(w);
+}
+
+UTEST(vector, add_element) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ Array_double *w = add_element(v, -2);
+ Array_double *w_expect = InitArray(double, {3, 1, -4, -2});
+ EXPECT_TRUE(vector_equal(w, w_expect));
+
+ free_vector(v);
+ free_vector(w);
+ free_vector(w_expect);
+}
+
+UTEST(vector, slice_element) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ Array_double *w = slice_element(v, 1);
+ Array_double *w_expect = InitArray(double, {3, -4});
+ EXPECT_TRUE(vector_equal(w, w_expect));
+
+ free_vector(v);
+ free_vector(w);
+ free_vector(w_expect);
+}
+
+UTEST(vector, free_vector) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ uint64_t arr_addr = (uint64_t)v->data;
+ free_vector(v);
+ EXPECT_NE((uint64_t)v->data, arr_addr);
+}
+
+UTEST(vector, sum_vector) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ EXPECT_EQ(0.0, sum_v(v));
+ free_vector(v);
+}
+
+UTEST(vector, add_v) {
+ Array_double *a = InitArray(double, {1.0, 3.0, -4.0});
+ Array_double *b = InitArray(double, {2.0, -1.0, 0});
+ Array_double *expected_sum = InitArray(double, {3.0, 2.0, -4.0});
+ Array_double *sum = add_v(a, b);
+
+ EXPECT_TRUE(vector_equal(sum, expected_sum));
+
+ free_vector(a);
+ free_vector(b);
+ free_vector(expected_sum);
+ free_vector(sum);
+}
+
+UTEST(vector, minus_v) {
+ Array_double *a = InitArray(double, {1.0, 3.0, -4.0});
+ Array_double *b = InitArray(double, {2.0, -1.0, 0});
+ Array_double *expected_sub = InitArray(double, {-1.0, 4.0, -4.0});
+ Array_double *sub = minus_v(a, b);
+
+ EXPECT_TRUE(vector_equal(sub, expected_sub));
+
+ free_vector(a);
+ free_vector(b);
+ free_vector(expected_sub);
+ free_vector(sub);
+}
+
+UTEST(vector, scale_v) {
+ double factor = 3.0;
+ Array_double *a = InitArray(double, {1.0, 3.0, -4.0});
+ Array_double *expected_scaled = InitArray(double, {3.0, 9.0, -12.0});
+ Array_double *scaled = scale_v(a, factor);
+
+ EXPECT_TRUE(vector_equal(scaled, expected_scaled));
+
+ free_vector(a);
+ free_vector(expected_scaled);
+ free_vector(scaled);
+}
+
+UTEST(vector, l1_norm) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ EXPECT_EQ(l1_norm(v), 8.0);
+ free_vector(v);
+}
+
+UTEST(vector, l2_norm) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ EXPECT_EQ(l2_norm(v), sqrt(3 * 3 + 1 * 1 + 4 * 4));
+ free_vector(v);
+}
+
+UTEST(vector, linf_norm) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ EXPECT_EQ(linf_norm(v), c_max(c_max(3.0, 1.0), -4.0));
+ free_vector(v);
+}
+
+UTEST(vector, vector_distance) {
+ Array_double *v = InitArray(double, {3, 1, -4});
+ Array_double *w = InitArray(double, {3, 1, -4});
+ Array_double *minus = minus_v(v, w);
+ EXPECT_EQ(vector_distance(v, w, &l2_norm), l2_norm(minus));
+ free_vector(v);
+ free_vector(w);
+ free_vector(minus);
+}