paizaラーニングレベルアップ問題集の数列の最小値をやってみました。
前回
「一番小さい値」の入力チェック・テストコードを考えてみた。
前回の入力値は5個固定でしたが、今回は1個以上100個以下の入力値が想定されています。
問題
提出コード
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
int min;
scanf("%d", &min);
for (int i = 1; i < n; i++) {
int a;
scanf("%d", &a);
if (a < min) {
min = a;
}
}
printf("%d\n", min);
return 0;
}
提出しないコード
リファクタリング
提出コードを、入出力部分とロジック(数列の最小値を求める)部分に分けます。入力時には入力チェックを行います。
入力チェック
今回は、制約条件が
- $1\le N\le 100$
- $0\le a_i \le 100$
と与えられていますので、この制約条件を満たすかどうかチェックします。その際、“社内標準”を使ライブラリutil.hを使うことにします(実際に使われている社内標準関数ではありません、というか、実際のものはお見せできません)。
#ifndef UTIL_H_
#define UTIL_H_
#include <stdint.h>
#include <stdbool.h>
char* chomp(char*);
bool parse_ubyte(const char*, uint8_t*);
bool parse_ulong(const char*, size_t*);
#endif /* UTIL_H_ */
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include "util.h"
char* chomp(char *str) {
if (!str) return NULL;
size_t len = strlen(str);
while (len--) {
if (isspace(str[len])) {
str[len] = '\0';
} else {
break;
}
}
return str;
}
static bool is_positive_number(const char *s) {
if (!(s && *s)) return false;
for (const char *c = s; *c; c++) {
if (!isdigit(*c)) return false;
}
return true;
}
static bool parse_unsigned(const char *str, uintmax_t *n, uintmax_t max) {
errno = 0;
if (!is_positive_number(str)) {
errno = EINVAL;
return false;
}
char *s = NULL;
unsigned long long ull = strtoull(str, &s, 10);
if (errno) {
return false;
} else if (s && *s) {
errno = EINVAL;
return false;
} else if (ull > max) {
errno = ERANGE;
return false;
}
*n = (uintmax_t)ull;
return true;
}
bool parse_ubyte(const char *str, uint8_t *n) {
uintmax_t m = 0;
if (!parse_unsigned(str, &m, UINT8_MAX)) return false;
*n = (uint8_t)m;
return true;
}
bool parse_ulong(const char *str, size_t *n) {
uintmax_t m = 0;
if (!parse_unsigned(str, &m, SIZE_MAX)) return false;
*n = (size_t)m;
return true;
}
#ifndef INPUT_H_
#define INPUT_H_
#include <stdbool.h>
#include <stdint.h>
bool read_size(const char*, size_t*);
bool read_elements(const char*, size_t, uint8_t*);
#endif /* INPUT_H_ */
$a_1,\dots,a_N$のうち1個でも制約条件外の値が入力された場合は、直ちに入力エラーとしてエラーコードを設定し、関数の戻り値としてfalseを返します。
文字列バッファは401バイトあれば十分なはずですが、実際は何が入ってくるか分からないので、余裕を見て512バイト確保しておきます。(但し、'\0'含めて401バイトを超える文字列は確実にfalse)
#include <string.h>
#include <errno.h>
#include "input.h"
#include "util.h"
bool read_size(const char *str, size_t *n) {
errno = 0;
if (!parse_ulong(str, n)) {
return false;
}
if (*n < 1 || 100 < *n) {
errno = ERANGE;
return false;
}
return true;
}
bool read_elements(const char* str, size_t size, uint8_t* array) {
errno = 0;
if (!(str && array)) {
errno = EINVAL;
return false;
}
char s[512];
strncpy(s, str, sizeof(s));
char *tok = strtok(s, " ");
for (size_t i = 0; i < size; i++) {
if (tok == NULL) {
errno = EINVAL;
return false;
}
if (!parse_ubyte(tok, &array[i])) {
errno = EINVAL;
return false;
}
if (array[i] > 100) {
errno = ERANGE;
return false;
}
tok = strtok(NULL, " ");
}
if (tok) {
errno = EINVAL;
return false;
}
return true;
}
ロジック部分
今回の問題の主要部分「数列の最小値を求める」部分を切り出し、関数化します。
このように切り出すことにより、「ヨコ入力(半角空白区切りで入力)だったのをタテ入力(改行区切りで入力)にして!」のように入力仕様が変更になっても、切り出した部分は影響を受けずに済みます。
#ifndef SEQ_MIN_H_
#define SEQ_MIN_H_
#include <stdint.h>
uint8_t minimum(size_t, const uint8_t*);
#endif /* SEQ_MIN_H_ */
配列引数にnullや、要素数$0$が渡された場合は、符号なし8bit整数の最大値を返すことにします。(逆に、最大値関数の場合は0または符号あり整数の最小値を返す)
#include "seq_min.h"
uint8_t minimum(size_t size, const uint8_t* array) {
if (!(size && array)) {
return UINT8_MAX;
}
uint8_t min = array[0];
for (size_t i = 1; i < size; i++) {
if (array[i] < min) {
min = array[i];
}
}
return min;
}
エントリポイント
最後に、main関数を実装します。
最初にmain関数を実装すると、「minimumという名前は定義されていません」という赤線が出て、たまたま後ろを通りかかった先輩から「赤線出てるよ。大丈夫? 本当に大丈夫?」と言われます。この時、間違っても「右クリック」⇒「関数を自動生成する」は職場でしないでください。
標準入力から受け取った値は入力チェックを済ませたあと、直ちにロジック部(関数)に渡すようにします。文字列バッファは401バイトあれば十分ですが、余裕を見て512バイト確保しておきます。
#include <stdio.h>
#include <errno.h>
#include "seq_min.h"
#include "input.h"
#include "util.h"
int main(void) {
size_t n;
char s[512];
if (!read_size(chomp(fgets(s, sizeof(s), stdin)), &n)) {
int e = errno;
perror("The number of elements must be an integer between 1 and 100.");
return e;
}
uint8_t A[n];
if (!read_elements(chomp(fgets(s, sizeof(s), stdin)), n, A)) {
int e = errno;
perror("Each element must be an integer between 0 and 100.");
return e;
}
printf("%d\n", minimum(n, A));
return 0;
}
テストコード
詳細設計のレビューが通った段階で、今まで書いてきたような実装担当者と、これから書いていくテスト担当者と分担します。テスト担当者は詳細設計書からテストケースを起こし、必要に応じてテストコードを作成します。※テスト担当者はイジワルになるのがバグを世に出さないコツ。
入力チェック
入力チェックでは、以下の点を意識してテストを実施します。
- 要素数
- 数字かどうか
- 1以上100以下か
- 各要素
- 数字かどうか
- 0以上100以下か
- 1行目の入力値である要素数と一致しているか
メモリが確保されているかどうかは、関数内では知る由もないので、テストケースからは外します。
尚、単体テストフレームワークとして、minunit.hを使います。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include "minunit.h"
#include "input.h"
int tests_run = 0;
char msg[80];
size_t n;
static char* message_hhu(uint8_t expected, uint8_t actual) {
snprintf(msg, sizeof(msg), "Error: expected: <%hhu> but was: <%hhu>", expected, actual);
return msg;
}
static char* message_d(int expected, int actual) {
snprintf(msg, sizeof(msg), "Error: expected: <%d> but was: <%d>", expected, actual);
return msg;
}
static char* message_zu(size_t expected, size_t actual) {
snprintf(msg, sizeof(msg), "Error: expected: <%zu> but was: <%zu>", expected, actual);
return msg;
}
static char* test_read_size(const char *str, size_t expected) {
mu_assert("Error: expected: <true> but was: <false>", read_size(str, &n));
mu_assert(message_d(errno, 0), errno == 0);
mu_assert(message_zu(expected, n), n == expected);
return 0;
}
static char* test_read_size_null() {
mu_assert("Error: expected: <false> but was: <true>", !read_size(NULL, &n));
mu_assert(message_d(EINVAL, errno), errno == EINVAL);
return 0;
}
static char* test_read_size_invalid(const char *str) {
mu_assert("Error: expected: <false> but was: <true>", !read_size(str, &n));
mu_assert(message_d(EINVAL, errno), errno == EINVAL);
return 0;
}
static char* test_read_size_out_of_range(const char *str) {
mu_assert("Error: expected: <false> but was: <true>", !read_size(str, &n));
mu_assert(message_d(ERANGE, errno), errno == ERANGE);
return 0;
}
static char* test_read_size_0() {return test_read_size_null();}
static char* test_read_size_1() {return test_read_size_invalid("");}
static char* test_read_size_2() {return test_read_size_invalid("-1");}
static char* test_read_size_3() {return test_read_size_out_of_range("0");}
static char* test_read_size_4() {return test_read_size("1", 1);}
static char* test_read_size_5() {return test_read_size("100", 100);}
static char* test_read_size_6() {return test_read_size_out_of_range("101");}
static char* test_read_elements(const char *str, size_t size, ...) {
uint8_t expected[size];
va_list args;
va_start(args, size);
for (size_t i = 0; i < size; i++) {
expected[i] = (uint8_t) va_arg(args, int);
}
va_end(args);
uint8_t actual[size];
mu_assert("Error: expected: <true> but was: <false>", read_elements(str, size, actual));
mu_assert(message_d(0, errno), errno == 0);
for (size_t i = 0; i < size; i++) {
mu_assert(message_hhu(expected[i], actual[i]), actual[i] == expected[i]);
}
return 0;
}
static char* test_read_elements_null() {
mu_assert("Error: expected: <false> but was: <true>", !read_elements(NULL, 0, NULL));
mu_assert(message_d(EINVAL, errno), errno == EINVAL);
return 0;
}
static char* test_read_elements_invalid(const char *str, size_t size) {
uint8_t array[size];
mu_assert("Error: expected: <false> but was: <true>", !read_elements(str, size, array));
mu_assert(message_d(EINVAL, errno), errno == EINVAL);
return 0;
}
static char* test_read_elements_out_of_range(const char *str, size_t size) {
uint8_t array[size];
mu_assert("Error: expected: <false> but was: <true>", !read_elements(str, size, array));
mu_assert(message_d(ERANGE, errno), errno == ERANGE);
return 0;
}
static char* test_read_elements_0() {return test_read_elements_null();}
static char* test_read_elements_1() {return test_read_elements("", 0);}
static char* test_read_elements_2() {return test_read_elements_invalid("-1", 1);}
static char* test_read_elements_3() {return test_read_elements("0", 1, 0);}
static char* test_read_elements_4() {return test_read_elements("100", 1, 100);}
static char* test_read_elements_5() {return test_read_elements_out_of_range("101", 1);}
static char* test_read_elements_6() {return test_read_elements("1 2", 2, 1, 2);}
static char* test_read_elements_7() {return test_read_elements("10 11", 2, 10, 11);}
static char* test_read_elements_8() {return test_read_elements_invalid("-1 0", 2);}
static char* test_read_elements_9() {return test_read_elements_out_of_range("101 100", 2);}
static char* test_read_elements_10() {return test_read_elements_invalid("0 -1", 2);}
static char* test_read_elements_11() {return test_read_elements_out_of_range("100 101", 2);}
static char* test_read_elements_12() {return test_read_elements("7 8 9", 3, 7, 8, 9);}
static char* test_read_elements_13() {return test_read_elements("97 98 99", 3, 97, 98, 99);}
static char* test_read_elements_14() {return test_read_elements_invalid("-1 0 1", 3);}
static char* test_read_elements_15() {return test_read_elements_out_of_range("101 100 99", 3);}
static char* test_read_elements_16() {return test_read_elements_invalid("0 -1 0", 3);}
static char* test_read_elements_17() {return test_read_elements_out_of_range("100 101 100", 3);}
static char* test_read_elements_18() {return test_read_elements_invalid("1 0 -1", 3);}
static char* test_read_elements_19() {return test_read_elements_out_of_range("99 100 101", 3);}
static char* test_read_elements_20() {return test_read_elements_invalid("", 1);}
static char* test_read_elements_21() {return test_read_elements_invalid("1", 0);}
static char* all_tests() {
mu_run_test(test_read_size_0);
mu_run_test(test_read_size_1);
mu_run_test(test_read_size_2);
mu_run_test(test_read_size_3);
mu_run_test(test_read_size_4);
mu_run_test(test_read_size_5);
mu_run_test(test_read_size_6);
mu_run_test(test_read_elements_0);
mu_run_test(test_read_elements_1);
mu_run_test(test_read_elements_2);
mu_run_test(test_read_elements_3);
mu_run_test(test_read_elements_4);
mu_run_test(test_read_elements_5);
mu_run_test(test_read_elements_6);
mu_run_test(test_read_elements_7);
mu_run_test(test_read_elements_8);
mu_run_test(test_read_elements_9);
mu_run_test(test_read_elements_10);
mu_run_test(test_read_elements_11);
mu_run_test(test_read_elements_12);
mu_run_test(test_read_elements_13);
mu_run_test(test_read_elements_14);
mu_run_test(test_read_elements_15);
mu_run_test(test_read_elements_16);
mu_run_test(test_read_elements_17);
mu_run_test(test_read_elements_18);
mu_run_test(test_read_elements_19);
mu_run_test(test_read_elements_20);
mu_run_test(test_read_elements_21);
return 0;
}
int main() {
char *result = all_tests();
if (result != 0) {
fprintf(stderr, "%s\n", result);
fprintf(stderr, "Tests run: %d\n", tests_run);
} else {
fprintf(stdout, "ALL TESTS PASSED\n");
fprintf(stdout, "Tests run: %d\n", tests_run);
}
return result != 0;
}
で、Windows環境であれば、以下のようなバッチファイルを作っておくと楽にテストできると思います。
echo off
gcc -Wall -Wextra -Werror -std=c99 inputTest.c input.c util.c -o inputTest 1>inputTest.txt 2>&1
if exist inputTest.exe (
.\inputTest
echo %ERRORLEVEL%
del inputTest.exe
del inputTest.txt
) else (
type inputTest.txt
)
pause
ロジック部
今回のキモである「最小値を求める関数」のテストをします。最低でも配列長3のテストはするとよいでしょう。配列長3のテストをすることにより
- 配列の先頭
- 配列の途中
- 配列の末尾
についてチェックすることができます。今回の場合は、配列の先頭、途中、末尾が最小値の場合をテストすることができます。
また、null配列、空配列(両者は異なります)のテストケースも必須です。
- NULL配列(
int *A = NULL;) - 要素数0(空配列:
size_t n = 0; int A[n];) - 要素数1
- 入力されうる最小値(0)
- 入力されうる最大値(100)
- 要素数2
- 前者が最小値
- 後者が最小値
- 等しい値
- 要素数3
- 先頭が最小値
- 途中が最小値
- 末尾が最小値
- 第1要素と第2要素が最小値
- 第1要素と第3要素が最小値
- 第2要素と第3要素が最小値
- すべて等しい値
#include <stdio.h>
#include <stdarg.h>
#include "minunit.h"
#include "seq_min.h"
int tests_run = 0;
char msg[80];
static char* message_hhu(uint8_t expected, uint8_t actual) {
snprintf(msg, sizeof(msg), "Error: expected: <%hhu> but was: <%hhu>", expected, actual);
return msg;
}
static char* test_minimum(uint8_t expected, size_t size, ...) {
uint8_t array[size];
va_list args;
va_start(args, size);
for (size_t i = 0; i < size; i++) {
array[i] = (uint8_t) va_arg(args, int);
}
va_end(args);
uint8_t actual = minimum(size, array);
mu_assert(message_hhu(expected, actual), actual == expected);
return 0;
}
static char* test_minimum_null() {
uint8_t actual = minimum(0, NULL);
mu_assert(message_hhu(255, actual), actual == 255);
return 0;
}
static char* test_minimum_0() {return test_minimum(255, 0);}
static char* test_minimum_1() {return test_minimum(0, 1, 0);}
static char* test_minimum_2() {return test_minimum(100, 1, 100);}
static char* test_minimum_3() {return test_minimum(1, 2, 1, 2);}
static char* test_minimum_4() {return test_minimum(3, 2, 4, 3);}
static char* test_minimum_5() {return test_minimum(5, 2, 5, 5);}
static char* test_minimum_6() {return test_minimum(6, 3, 6, 7, 8);}
static char* test_minimum_7() {return test_minimum(9, 3, 10, 9, 10);}
static char* test_minimum_8() {return test_minimum(11, 3, 13, 12, 11);}
static char* test_minimum_9() {return test_minimum(14, 3, 14, 14, 15);}
static char* test_minimum_10() {return test_minimum(16, 3, 16, 17, 16);}
static char* test_minimum_11() {return test_minimum(18, 3, 19, 18, 18);}
static char* test_minimum_12() {return test_minimum(20, 3, 20, 20, 20);}
static char* all_tests() {
mu_run_test(test_minimum_null);
mu_run_test(test_minimum_0);
mu_run_test(test_minimum_1);
mu_run_test(test_minimum_2);
mu_run_test(test_minimum_3);
mu_run_test(test_minimum_4);
mu_run_test(test_minimum_5);
mu_run_test(test_minimum_6);
mu_run_test(test_minimum_7);
mu_run_test(test_minimum_8);
mu_run_test(test_minimum_9);
mu_run_test(test_minimum_10);
mu_run_test(test_minimum_11);
mu_run_test(test_minimum_12);
return 0;
}
int main() {
char *result = all_tests();
if (result != 0) {
fprintf(stderr, "%s\n", result);
fprintf(stderr, "Tests run: %d\n", tests_run);
} else {
fprintf(stdout, "ALL TESTS PASSED\n");
fprintf(stdout, "Tests run: %d\n", tests_run);
}
return result != 0;
}
echo off
gcc -Wall -Wextra -Werror -std=c99 seqMinTest.c seq_min.c -o seqMinTest 1>seqMinTest.txt 2>&1
if exist seqMinTest.exe (
.\seqMinTest
echo %ERRORLEVEL%
del seqMinTest.exe
del seqMinTest.txt
) else (
type seqMinTest.txt
)
pause
エントリポイント
最後にmain関数のテストをします。これは関数の観点で見ると「単体」ではなく「結合」ですが(環境の観点から言うと「単体」の最終段階とも言えますが)。
- 入力例1~3に対する出力が期待通りか
- 制約条件境界値
- 文字種(数字以外はNG)
- 整数の個数(1以上100以下ならOK)
- 各要素(0以上100以下ならOK)
- 1行目と2行目の入力に整合性は取れているか
に関するテストを行います。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include "minunit.h"
#define SOURCE "main"
#define IN_FILE "in.txt"
#define OUT_FILE "out.txt"
#define ERR_FILE "err.txt"
int tests_run = 0;
char msg[80];
char result[1][8];
static char* message_zu(size_t expected, size_t actual) {
sprintf(msg, "Error: expected: <%zu> but was: <%zu>", expected, actual);
return msg;
}
static char* message_s(const char *expected, const char *actual) {
sprintf(msg, "Error: expected: <%s> but was: <%s>", expected, actual);
return msg;
}
static char* message_d(int expected, int actual) {
sprintf(msg, "Error: expected: <%d> but was: <%d>", expected, actual);
return msg;
}
static size_t test(size_t n, const char *lines[]) {
static unsigned k = 0;
FILE *file;
if (!(file = fopen(IN_FILE, "w"))) {
fprintf(stderr, "%s\n", strerror(errno));
exit(errno);
}
for (size_t i = 0; i < n; i++) {
fputs(lines[i], file);
fputc('\n', file);
}
fclose(file);
clock_t start = clock();
if (!!(errno = system(".\\" SOURCE " <" IN_FILE " 1>" OUT_FILE " 2>" ERR_FILE))) {
fprintf(stderr, "%s\n", strerror(errno));
exit(errno);
}
fprintf(stderr, "#%u %f sec\n", ++k, (float) (clock() - start) / CLOCKS_PER_SEC);
fflush(stderr);
if (!(file = fopen(OUT_FILE, "r"))) {
fprintf(stderr, "%s\n", strerror(errno));
exit(errno);
}
size_t m = 0;
while (fgets(result[m], sizeof(result[m]), file)) m++;
fclose(file);
return m;
}
static int test_err(size_t n, const char *lines[]) {
FILE *file;
if (!(file = fopen(IN_FILE, "w"))) {
fprintf(stderr, "%s\n", strerror(errno));
exit(errno);
}
if (lines) {
for (size_t i = 0; i < n; i++) {
if (lines[i]) {
fputs(lines[i], file);
}
fputc('\n', file);
}
}
fclose(file);
return system(".\\" SOURCE " <" IN_FILE " 1>" OUT_FILE " 2>" ERR_FILE);
}
static char* test0() {
const char *lines[] = { "0", "" };
int e = test_err(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_d(ERANGE, e), e == ERANGE);
return 0;
}
static char* test1() {
const char *lines[] = { "5", "1 2 3 4 5" };
size_t n = test(sizeof(lines) / sizeof(lines[0]), (const char**) lines);
mu_assert(message_zu(1, n), n == 1);
mu_assert(message_s("1\n", result[0]), !strcmp(result[0], "1\n"));
return 0;
}
static char* test2() {
const char *lines[] = { "5", "5 1 4 3 2" };
size_t n = test(sizeof(lines) / sizeof(lines[0]), (const char**) lines);
mu_assert(message_zu(1, n), n == 1);
mu_assert(message_s("1\n", result[0]), !strcmp(result[0], "1\n"));
return 0;
}
static char* test3() {
const char *lines[] = { "6", "8 2 3 8 3 3" };
size_t n = test(sizeof(lines) / sizeof(lines[0]), (const char**) lines);
mu_assert(message_zu(1, n), n == 1);
mu_assert(message_s("2\n", result[0]), !strcmp(result[0], "2\n"));
return 0;
}
static char* test4() {
const char *lines[] = { "1", "0" };
size_t n = test(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_zu(1, n), n == 1);
mu_assert(message_s("0\n", result[0]), !strcmp(result[0], "0\n"));
return 0;
}
static char* test5() {
const char *lines[] = { "1", "100" };
size_t n = test(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_zu(1, n), n == 1);
mu_assert(message_s("100\n", result[0]), !strcmp(result[0], "100\n"));
return 0;
}
static char* test6() {
char chars[2][400] = { "100", "" };
for (size_t i = 0; i < 100; i++) {
if (i) strcat(chars[1], " ");
strcat(chars[1], "100");
}
char *lines[2];
for (size_t i = 0; i < 2; i++) {
lines[i] = chars[i];
}
size_t n = test(sizeof(lines) / sizeof(lines[0]), (const char**) lines);
mu_assert(message_zu(1, n), n == 1);
mu_assert(message_s("100\n", result[0]), !strcmp(result[0], "100\n"));
return 0;
}
static char* test7() {
char chars[2][404] = { "101", "" };
for (size_t i = 0; i < 101; i++) {
if (i) strcat(chars[1], " ");
strcat(chars[1], "100");
}
char *lines[2];
for (size_t i = 0; i < 2; i++) {
lines[i] = chars[i];
}
int e = test_err(sizeof(lines) / sizeof(lines[0]), (const char**) lines);
mu_assert(message_d(ERANGE, e), e == ERANGE);
return 0;
}
static char* test8() {
const char *lines[] = { "1", "-1" };
int e = test_err(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_d(EINVAL, e), e == EINVAL);
return 0;
}
static char* test9() {
const char *lines[] = { "1", "101" };
int e = test_err(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_d(ERANGE, e), e == ERANGE);
return 0;
}
static char* test10() {
const char *lines[] = { "6", "5 1 4 3 2" };
int e = test_err(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_d(EINVAL, e), e == EINVAL);
return 0;
}
static char* test11() {
const char *lines[] = { "5", "8 2 3 8 3 3" };
int e = test_err(sizeof(lines) / sizeof(lines[0]), lines);
mu_assert(message_d(EINVAL, e), e == EINVAL);
return 0;
}
static char* all_tests() {
mu_run_test(test0);
mu_run_test(test1);
mu_run_test(test2);
mu_run_test(test3);
mu_run_test(test4);
mu_run_test(test5);
mu_run_test(test6);
mu_run_test(test7);
mu_run_test(test8);
mu_run_test(test9);
mu_run_test(test10);
mu_run_test(test11);
return 0;
}
int main() {
if (!!(errno = system("gcc -Wall -Wextra -Werror -std=c99 " SOURCE ".c seq_min.c input.c util.c -o " SOURCE " 1>" SOURCE ".txt 2>&1"))) {
fprintf(stderr, "%s\n", strerror(errno));
FILE* file = fopen(SOURCE ".txt", "r");
if (file) {
int c = 0;
while ((c = fgetc(file)) != EOF) {
putchar(c);
}
fclose(file);
}
exit(errno);
}
char *result = all_tests();
if (result != 0) {
fprintf(stderr, "%s\n", result);
fprintf(stderr, "Tests run: %d\n", tests_run);
} else {
fprintf(stdout, "ALL TESTS PASSED\n");
fprintf(stdout, "Tests run: %d\n", tests_run);
}
remove(ERR_FILE);
remove(OUT_FILE);
remove(IN_FILE);
remove(SOURCE ".exe");
remove(SOURCE ".txt");
if (errno) {
return errno;
} else {
return result != 0;
}
}
echo off
gcc -Wall -Wextra -Werror -std=c99 test.c -o test 1>test.txt 2>&1
if exist test.exe (
.\test
echo %ERRORLEVEL%
del test.exe
del test.txt
) else (
type test.txt
)
pause
次回、機会と余力がありましたら、配列の最小値に続けたいと思います。