From 22d3f0c80400b6a2dcfb0b36cfea19148df66d7e Mon Sep 17 00:00:00 2001 From: Andreas Gieriet Date: Sun, 1 Mar 2020 05:02:24 +0100 Subject: [PATCH] P03 lab code added --- P03_Bounding_Box/bounding-box/Makefile | 8 + P03_Bounding_Box/bounding-box/mainpage.dox | 8 + P03_Bounding_Box/bounding-box/src/main.c | 209 ++++++++++++++++++ P03_Bounding_Box/bounding-box/tab2svg.sh | 40 ++++ P03_Bounding_Box/bounding-box/tests/tests.c | 109 +++++++++ .../wochentag-berechnung/Makefile | 7 + .../wochentag-berechnung/mainpage.dox | 8 + .../wochentag-berechnung/src/main.c | 121 ++++++++++ .../wochentag-berechnung/tests/tests.c | 196 ++++++++++++++++ 9 files changed, 706 insertions(+) create mode 100644 P03_Bounding_Box/bounding-box/Makefile create mode 100644 P03_Bounding_Box/bounding-box/mainpage.dox create mode 100644 P03_Bounding_Box/bounding-box/src/main.c create mode 100755 P03_Bounding_Box/bounding-box/tab2svg.sh create mode 100755 P03_Bounding_Box/bounding-box/tests/tests.c create mode 100644 P03_Bounding_Box/wochentag-berechnung/Makefile create mode 100644 P03_Bounding_Box/wochentag-berechnung/mainpage.dox create mode 100644 P03_Bounding_Box/wochentag-berechnung/src/main.c create mode 100755 P03_Bounding_Box/wochentag-berechnung/tests/tests.c diff --git a/P03_Bounding_Box/bounding-box/Makefile b/P03_Bounding_Box/bounding-box/Makefile new file mode 100644 index 0000000..caa3e7e --- /dev/null +++ b/P03_Bounding_Box/bounding-box/Makefile @@ -0,0 +1,8 @@ +SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk") + +TARGET := bin/boundinbox +SOURCES := src/main.c +TSTSOURCES := tests/tests.c +LIBS := -lm + +include $(SNP_SHARED_MAKEFILE) diff --git a/P03_Bounding_Box/bounding-box/mainpage.dox b/P03_Bounding_Box/bounding-box/mainpage.dox new file mode 100644 index 0000000..c142211 --- /dev/null +++ b/P03_Bounding_Box/bounding-box/mainpage.dox @@ -0,0 +1,8 @@ +/** + * @mainpage SNP - P03 Calculate bounding box + * + * @section Purpose + * + * This is a lab to calculate the bounding box of some triangle and to compare the boxes + * + */ diff --git a/P03_Bounding_Box/bounding-box/src/main.c b/P03_Bounding_Box/bounding-box/src/main.c new file mode 100644 index 0000000..e66f245 --- /dev/null +++ b/P03_Bounding_Box/bounding-box/src/main.c @@ -0,0 +1,209 @@ +/* ---------------------------------------------------------------------------- + * -- _____ ______ _____ - + * -- |_ _| | ____|/ ____| - + * -- | | _ __ | |__ | (___ Institute of Embedded Systems - + * -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur - + * -- _| |_| | | | |____ ____) | (University of Applied Sciences) - + * -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland - + * ---------------------------------------------------------------------------- + */ +/** + * @file + * @brief Lab P03 weekday + */ +#include +#include +#include +#include + + +/// @brief point of two coordinate axes +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + +/// @brief box with an origin point and a dimension w and h +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + +/// @brief triangle given by three points a, b, and c +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + +/** + * @brief Compares two double values with a given hard coded tolerance. + * @param [in] a the first value + * @param [in] b the second value + * @returns 0 if fabs(a-b) <= tolerance, -1 if a < b, 1 otherwise + * @remark the tolerance is expected to be 0.05 (internally hard coded) + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + + +/** + * @brief Compares two box parameters for their area (w * h of the box). + * @param [in] a the first box + * @param [in] b the second box + * @returns the return value from compare_double() when given the areas of both boxes as parameter to compare_double() + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + + +/** + * @brief Compares the area of the parameter against 0. + * @param [in] box the box to check against area 0 + * @returns compare_double() == 0 with the boxes area and 0 as parameters + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + + +/** + * @brief Calculates the bounding box of a triangle + * @param [in] t the trinagle for which the baounding box is to be calculated + * @returns the bounding box of the triangle + * @remark calculates first the point with the minimum x and y of the triangle's points, + * plus as second point the one with the max coordinates of all points + * @remark the minial point is the origin of the bounding box, the width and hight is the x/y delta of the two points + * + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + + +// END-STUDENTS-TO-ADD-CODE + + +// forward declaration of used functions in main() +static box_t get_match(box_t board, triangle_t t); +static triangle_t triangle_rotate(triangle_t t, double degree); +static void write_data(box_t board, triangle_t t, int degree); + + +/** + * @brief main function + * @param argc [in] number of entries in argv + * @param argv [in] program name plus command line arguments + * @returns returns success if valid date is given, failure otherwise + */ +int main(int argc, const char *argv[]) +{ + int x1, x2, x3, y1, y2, y3; + if (argc < 2 || sscanf(argv[1], "%d/%d-%d/%d-%d/%d", &x1, &y1, &x2, &y2, &x3, &y3) != 6) { + fprintf(stderr, "Usage: %s x1/y1-x2/y2-x3/y3\ne.g. 0/0-100/0-50/50\n", argv[0]); + return EXIT_FAILURE; + + } + + box_t board = { { 0, 0 }, 100, 200 }; + + // rotate the triangle in steps of 1 degree to find the "best position" of the triangle in the board + triangle_t t = { { x1, y1 }, { x2, y2 }, { x3, y3 } }; + int degree_best = -1; + box_t best; + for(int degree = 0; degree < 360; degree++) { + box_t match = get_match(board, triangle_rotate(t, degree)); + if (!is_zero_area(match)) { + if (degree_best == -1 || compare_area(match, best) < 0) { + degree_best = degree; + best = match; + } + } + } + + // write as tabular file + write_data(board, t, degree_best); + + return EXIT_SUCCESS; +} + + +/****************** internal functions ********************/ + +// forward declarations +static point_t point_rotate(point_t p, double degree); +static point_t point_move(point_t p, double dx, double dy); +static triangle_t triangle_move(triangle_t t, double dx, double dy); + + +static box_t get_match(box_t board, triangle_t t) +{ + box_t b = triangle_bounding_box(t); + if (compare_double(board.w, b.w) < 0) return (box_t){ board.p, 0, 0 }; + if (compare_double(board.h, b.h) < 0) return (box_t){ board.p, 0, 0 }; + return (box_t){ board.p, b.w, b.h }; +} + +static triangle_t triangle_rotate(triangle_t t, double degree) +{ + return (triangle_t){ point_rotate(t.a, degree), point_rotate(t.b, degree), point_rotate(t.c, degree) }; +} + +static triangle_t triangle_move(triangle_t t, double dx, double dy) +{ + return (triangle_t){ point_move(t.a, dx, dy), point_move(t.b, dx, dy), point_move(t.c, dx, dy) }; +} + +static point_t point_rotate(point_t p, double degree) +{ + double rad = fmod(degree, 360.0) * acos(-1.0) / 180.0; + double s = sin(rad); + double c = cos(rad); + + return (point_t){ c*p.x - s*p.y, s*p.x + c*p.y }; +} + +static point_t point_move(point_t p, double dx, double dy) +{ + return (point_t) { p.x+dx, p.y+dy }; +} + +static void write_data(box_t board, triangle_t t, int degree) +{ + double border = 10.0; + double gap = 2*border; + + // move board to origin + board.p.x = 0.0; + board.p.y = 0.0; + + // move original triangle to above the board + box_t tbb = triangle_bounding_box(t); + t = triangle_move(t, -tbb.p.x, -tbb.p.y + board.h + gap); + tbb.p.x = 0.0; + tbb.p.y = board.h + gap; + + // view box + box_t view = { { -border, -border }, fmax(board.w, tbb.w) + 2 * border, board.h + gap + tbb.h + 2 * border }; + printf("viewbox:%.1f:%.1f:%.1f:%.1f\n", view.p.x, view.p.y, view.w, view.h); + + printf("rect:%.1f:%.1f:%.1f:%.1f:%s\n", board.p.x, board.p.y, board.w, board.h, "gray"); + printf("polygon:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%s\n", t.a.x, t.a.y, t.b.x, t.b.y, t.c.x, t.c.y, "green"); + + // there was a match, show it + if (degree >= 0) { + triangle_t rotated = triangle_rotate(t, degree); + box_t rbb = triangle_bounding_box(rotated); + t = triangle_move(rotated, -rbb.p.x, -rbb.p.y); // move to origin + printf("polygon:%.1f:%.1f:%.1f:%.1f:%.1f:%.1f:%s\n", t.a.x, t.a.y, t.b.x, t.b.y, t.c.x, t.c.y, "yellow"); + } +} diff --git a/P03_Bounding_Box/bounding-box/tab2svg.sh b/P03_Bounding_Box/bounding-box/tab2svg.sh new file mode 100755 index 0000000..a74dbf6 --- /dev/null +++ b/P03_Bounding_Box/bounding-box/tab2svg.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +#!/bin/bash + +# produces a crude HTML embedded SVG drawing from a tabular file (given on stdin) with columns separated by ":" +# usage: tab2svg < inbut.txt > output.html + +awk $* -- ' +BEGIN { + FS=":" # field-separator: which character separats fields in a record (i.e. in a line) + print "" + print "" + print " " + print " SVG Data" + print " " + print " " +} +/^viewbox/ { + x = $2 + y = $3 + w = $4 + h = $5 +} +/^rect/ { + if (h > 0) { + printf " board = %dmm x %dmm\n

\n", $4, $5 + printf " \n", $4, x, y, w, h + h = 0 + } + printf " \n", $6, $2, $3, $4, $5 +} +/^polygon/ { + printf " \n", $8, $2, $3, $4, $5, $6, $7 +} +END { + print " " + print " " + print "" +} +' diff --git a/P03_Bounding_Box/bounding-box/tests/tests.c b/P03_Bounding_Box/bounding-box/tests/tests.c new file mode 100755 index 0000000..51844a0 --- /dev/null +++ b/P03_Bounding_Box/bounding-box/tests/tests.c @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------------- + * -- _____ ______ _____ - + * -- |_ _| | ____|/ ____| - + * -- | | _ __ | |__ | (___ Institute of Embedded Systems - + * -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur - + * -- _| |_| | | | |____ ____) | (University of Applied Sciences) - + * -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland - + * ---------------------------------------------------------------------------- + */ +/** + * @file + * @brief Test suite for the given package. + */ +#include +#include +#include +#include +#include +#include +#include "test_utils.h" + +#ifndef TARGET // must be given by the make file --> see test target +#error missing TARGET define +#endif + +/// @brief alias for EXIT_SUCCESS +#define OK EXIT_SUCCESS +/// @brief alias for EXIT_FAILURE +#define FAIL EXIT_FAILURE + +/// @brief The name of the STDOUT text file. +#define OUTFILE "stdout.txt" +/// @brief The name of the STDERR text file. +#define ERRFILE "stderr.txt" + +// setup & cleanup +static int setup(void) +{ + remove_file_if_exists(OUTFILE); + remove_file_if_exists(ERRFILE); + return 0; // success +} + +static int teardown(void) +{ + // Do nothing. + // Especially: do not remove result files - they are removed in int setup(void) *before* running a test. + return 0; // success +} + +// tests +static void test_no_match(void) +{ + // arrange + const char *out_txt[] = { + "viewbox:-10.0:-10.0:250.0:290.0\n", + "rect:0.0:0.0:100.0:200.0:gray\n", + "polygon:0.0:220.0:230.0:220.0:100.0:270.0:green\n", + }; + + // act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 0/0-230/0-100/50 >" OUTFILE " 2>" ERRFILE)), OK); + assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt)); +} + +static void test_initial_match(void) +{ + // arrange + const char *out_txt[] = { + "viewbox:-10.0:-10.0:120.0:340.0\n", + "rect:0.0:0.0:100.0:200.0:gray\n", + "polygon:0.0:220.0:100.0:220.0:100.0:320.0:green\n", + "polygon:0.0:0.0:100.0:0.0:100.0:100.0:yellow\n", + }; + + // act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 0/0-100/0-100/100 >" OUTFILE " 2>" ERRFILE)), OK); + assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt)); +} + +static void test_tight_match(void) +{ + // arrange + const char *out_txt[] = { + "viewbox:-10.0:-10.0:225.0:290.0\n", + "rect:0.0:0.0:100.0:200.0:gray\n", + "polygon:0.0:220.0:205.0:220.0:205.0:270.0:green\n", + "polygon:94.8:0.0:48.7:199.7:0.0:188.5:yellow\n", + }; + + // act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 0/0-205/0-205/50 >" OUTFILE " 2>" ERRFILE)), OK); + assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt)); +} + + +/** + * @brief Registers and runs the tests. + * @returns success (0) or one of the CU_ErrorCode (>0) + */ +int main(void) +{ + // setup, run, teardown + TestMainBasic("lab test", setup, teardown + , test_no_match + , test_initial_match + , test_tight_match + ); +} diff --git a/P03_Bounding_Box/wochentag-berechnung/Makefile b/P03_Bounding_Box/wochentag-berechnung/Makefile new file mode 100644 index 0000000..b3a1fea --- /dev/null +++ b/P03_Bounding_Box/wochentag-berechnung/Makefile @@ -0,0 +1,7 @@ +SNP_SHARED_MAKEFILE := $(if $(SNP_SHARED_MAKEFILE),$(SNP_SHARED_MAKEFILE),"~/snp/shared.mk") + +TARGET := bin/weekday +SOURCES := src/main.c +TSTSOURCES := tests/tests.c + +include $(SNP_SHARED_MAKEFILE) diff --git a/P03_Bounding_Box/wochentag-berechnung/mainpage.dox b/P03_Bounding_Box/wochentag-berechnung/mainpage.dox new file mode 100644 index 0000000..79fdc99 --- /dev/null +++ b/P03_Bounding_Box/wochentag-berechnung/mainpage.dox @@ -0,0 +1,8 @@ +/** + * @mainpage SNP - P03 Calculate the week day + * + * @section Purpose + * + * This is a lab to calculate the week day from a given Gregorian date. + * + */ diff --git a/P03_Bounding_Box/wochentag-berechnung/src/main.c b/P03_Bounding_Box/wochentag-berechnung/src/main.c new file mode 100644 index 0000000..131f587 --- /dev/null +++ b/P03_Bounding_Box/wochentag-berechnung/src/main.c @@ -0,0 +1,121 @@ + /* ---------------------------------------------------------------------------- + * -- _____ ______ _____ - + * -- |_ _| | ____|/ ____| - + * -- | | _ __ | |__ | (___ Institute of Embedded Systems - + * -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur - + * -- _| |_| | | | |____ ____) | (University of Applied Sciences) - + * -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland - + * ---------------------------------------------------------------------------- + */ +/** + * @file + * @brief Lab P03 weekday + */ +#include +#include +#include + + +// *** TASK1: typedef enum types for month_t (Jan=1,...Dec} *** +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + + + +// *** TASK1: typedef struct for date_t *** +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + + + +// *** TASK2: typedef enum weekday_t (Sun=0, Mon, ...Sat) *** +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + +/** + * @brief TASK1: Checks if the given date is a leap year. + * @returns 0 = is not leap year, 1 = is leap year + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + + +/** + * @brief TASK1: Calculates the length of the month given by the data parameter + * @returns 28, 29, 30, 31 if a valid month, else 0 + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + +/** + * @brief TASK1: Checks if the given date is in the gregorian date range + * @returns 0 = no, 1 = yes + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + + +/** + * @brief TASK1: Checks if the given date is a valid date. + * @returns 0 = is not valid date, 1 = is valid date + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + + +/** + * @brief TASK2: calculated from a valid date the weekday + * @returns returns a weekday in the range Sun...Sat + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + + + +/** + * @brief TASK2: print weekday as 3-letter abreviated English day name + */ +// BEGIN-STUDENTS-TO-ADD-CODE + + +// END-STUDENTS-TO-ADD-CODE + +/** + * @brief main function + * @param argc [in] number of entries in argv + * @param argv [in] program name plus command line arguments + * @returns returns success if valid date is given, failure otherwise + */ +int main(int argc, const char *argv[]) +{ + // TASK1: parse the mandatory argument into a date_t variable and check if the date is valid + // BEGIN-STUDENTS-TO-ADD-CODE + + + // END-STUDENTS-TO-ADD-CODE + + + // TASK2: calculate the weekday and print it in this format: "%04d-%02d-%02d is a %s\n" + // BEGIN-STUDENTS-TO-ADD-CODE + + + // END-STUDENTS-TO-ADD-CODE + + return EXIT_SUCCESS; +} diff --git a/P03_Bounding_Box/wochentag-berechnung/tests/tests.c b/P03_Bounding_Box/wochentag-berechnung/tests/tests.c new file mode 100755 index 0000000..3a784db --- /dev/null +++ b/P03_Bounding_Box/wochentag-berechnung/tests/tests.c @@ -0,0 +1,196 @@ +/* ---------------------------------------------------------------------------- + * -- _____ ______ _____ - + * -- |_ _| | ____|/ ____| - + * -- | | _ __ | |__ | (___ Institute of Embedded Systems - + * -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur - + * -- _| |_| | | | |____ ____) | (University of Applied Sciences) - + * -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland - + * ---------------------------------------------------------------------------- + */ +/** + * @file + * @brief Test suite for the given package. + */ +#include +#include +#include +#include +#include +#include +#include "test_utils.h" + +#ifndef TARGET // must be given by the make file --> see test target +#error missing TARGET define +#endif + +/// @brief alias for EXIT_SUCCESS +#define OK EXIT_SUCCESS +/// @brief alias for EXIT_FAILURE +#define FAIL EXIT_FAILURE + +/// @brief The name of the STDOUT text file. +#define OUTFILE "stdout.txt" +/// @brief The name of the STDERR text file. +#define ERRFILE "stderr.txt" + +// setup & cleanup +static int setup(void) +{ + remove_file_if_exists(OUTFILE); + remove_file_if_exists(ERRFILE); + return 0; // success +} + +static int teardown(void) +{ + // Do nothing. + // Especially: do not remove result files - they are removed in int setup(void) *before* running a test. + return 0; // success +} + +static struct tm now() +{ + time_t t = time(NULL); + return *localtime(&t); +} + +static const char* weekday_name(int wday) +{ + assert(0 <= wday && wday <= 6); + static const char* days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + return days[wday]; +} + +// tests +static void test_task1_fail_no_arg(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " >" OUTFILE " 2>" ERRFILE)), FAIL); +} + +static void test_task1_fail_not_gregorian(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1291-08-01 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-14 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1583-10-14 >" OUTFILE " 2>" ERRFILE)), OK); +} + +static void test_task1_fail_month_out_of_range(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-13-13 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-00-13 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-12-13 >" OUTFILE " 2>" ERRFILE)), OK); +} + +static void test_task1_fail_day_out_of_range(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-29 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-28 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2019-02-28 >" OUTFILE " 2>" ERRFILE)), OK); +} + +static void test_task1_fail_leap_year(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1900-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1900-02-28 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2000-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2000-02-29 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2001-02-29 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2001-02-28 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2004-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2004-02-29 >" OUTFILE " 2>" ERRFILE)), OK); +} + +static void test_task1_valid_date(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-01 >" OUTFILE " 2>" ERRFILE)), OK); + + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-29 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-03-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-04-30 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-05-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-06-30 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-07-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-08-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-09-30 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-10-31 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-11-30 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-12-31 >" OUTFILE " 2>" ERRFILE)), OK); + + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-01-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-02-30 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-03-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-04-31 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-05-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-06-31 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-07-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-08-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-09-31 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-10-32 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-11-31 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 2020-12-32 >" OUTFILE " 2>" ERRFILE)), FAIL); +} + +static void test_task2_start_gregorian(void) +{ + // arrange & act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1581-10-14 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1581-10-15 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-14 >" OUTFILE " 2>" ERRFILE)), FAIL); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-15 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1583-10-14 >" OUTFILE " 2>" ERRFILE)), OK); + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1583-10-15 >" OUTFILE " 2>" ERRFILE)), OK); + + const char *out_txt[] = { "1582-10-15 is a Fri\n" }; + CU_ASSERT_EQUAL(WEXITSTATUS(system(XSTR(TARGET) " 1582-10-15 >" OUTFILE " 2>" ERRFILE)), OK); + assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt)); +} + +static void test_task2_today(void) +{ + // arrange + const size_t SIZE = 1000; + char command[SIZE]; + struct tm t = now(); + snprintf(command, SIZE, "%s %04d-%02d-%02d 2>%s | tail -1 >%s", XSTR(TARGET), t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, ERRFILE, OUTFILE); + + char buffer[SIZE]; + snprintf(buffer, SIZE, "%04d-%02d-%02d is a %s\n", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, weekday_name(t.tm_wday)); + const char *out_txt[] = { buffer }; + const char *err_txt[] = { NULL }; + + // act & assert + CU_ASSERT_EQUAL(WEXITSTATUS(system(command)), OK); + assert_lines(OUTFILE, out_txt, sizeof(out_txt)/sizeof(*out_txt)); + assert_lines(ERRFILE, err_txt, sizeof(err_txt)/sizeof(*err_txt)); +} + +/** + * @brief Registers and runs the tests. + * @returns success (0) or one of the CU_ErrorCode (>0) + */ +int main(void) +{ + // setup, run, teardown + TestMainBasic("lab test", setup, teardown + , test_task1_fail_no_arg + , test_task1_fail_not_gregorian + , test_task1_fail_month_out_of_range + , test_task1_fail_day_out_of_range + , test_task1_fail_leap_year + , test_task1_valid_date + , test_task2_start_gregorian + , test_task2_today + ); +}