From a0d68131c955790f7876e849314edd4fa1f50b64 Mon Sep 17 00:00:00 2001 From: Aleksey Lobanov Date: Wed, 4 Nov 2020 16:49:27 +0300 Subject: [PATCH] hw8: Initial commit --- 08_TestingCoverage/Makefile | 24 ++++++ 08_TestingCoverage/buf.c | 31 ++++++++ 08_TestingCoverage/buf.h | 87 +++++++++++++++++++++ 08_TestingCoverage/main.c | 13 ++++ 08_TestingCoverage/minctest.h | 137 ++++++++++++++++++++++++++++++++++ 08_TestingCoverage/tests.c | 71 ++++++++++++++++++ 6 files changed, 363 insertions(+) create mode 100644 08_TestingCoverage/Makefile create mode 100644 08_TestingCoverage/buf.c create mode 100644 08_TestingCoverage/buf.h create mode 100644 08_TestingCoverage/main.c create mode 100644 08_TestingCoverage/minctest.h create mode 100644 08_TestingCoverage/tests.c diff --git a/08_TestingCoverage/Makefile b/08_TestingCoverage/Makefile new file mode 100644 index 0000000..8fe8766 --- /dev/null +++ b/08_TestingCoverage/Makefile @@ -0,0 +1,24 @@ +GENERATES = main libbuf.so tester *.gcov +TRASH = *.o *~ o.* *.gcdna *.gcno *.gcda + +all: lib main tester + + +lib: + gcc -shared -fPIC -c buf.c -o libbuf.so + +main: lib + gcc -L. main.c -lbuf -o main + +tester: + # Запускаем без библиотеки для показа результатов покрытия + gcc -fprofile-arcs -ftest-coverage -O0 -g -L. tests.c buf.c -o tester + ./tester + gcov -b -c buf.c + +clean: + rm -f $(TRASH) + +distclean: clean + rm -rf $(GENERATES) + diff --git a/08_TestingCoverage/buf.c b/08_TestingCoverage/buf.c new file mode 100644 index 0000000..6c125e2 --- /dev/null +++ b/08_TestingCoverage/buf.c @@ -0,0 +1,31 @@ +#include "buf.h" + +void * +buf_grow1(void *v, size_t esize, ptrdiff_t n) +{ + struct buf *p; + size_t max = (size_t)-1 - sizeof(struct buf); + if (v) { + p = buf_ptr(v); + if (n > 0 && p->capacity + n > max / esize) + goto fail; /* overflow */ + p = realloc(p, sizeof(struct buf) + esize * (p->capacity + n)); + if (!p) + goto fail; + p->capacity += n; + if (p->size > p->capacity) + p->size = p->capacity; + } else { + if ((size_t)n > max / esize) + goto fail; /* overflow */ + p = malloc(sizeof(struct buf) + esize * n); + if (!p) + goto fail; + p->capacity = n; + p->size = 0; + } + return p->buffer; +fail: + BUF_ABORT; + return 0; +} \ No newline at end of file diff --git a/08_TestingCoverage/buf.h b/08_TestingCoverage/buf.h new file mode 100644 index 0000000..c603b29 --- /dev/null +++ b/08_TestingCoverage/buf.h @@ -0,0 +1,87 @@ +/* buf.h --- growable memory buffers for C99 + * This is free and unencumbered software released into the public domain. + * + * buf_size(v) : return the number of elements in the buffer (size_t) + * buf_capacity(v) : return the total capacity of the buffer (size_t) + * buf_free(v) : destroy and free the buffer + * buf_push(v, e) : append an element E to the end + * buf_pop(v) : remove and return an element E from the end + * buf_grow(v, n) : increase buffer capactity by (ptrdiff_t) N elements + * buf_trunc(v, n) : set buffer capactity to exactly (ptrdiff_t) N elements + * buf_clear(v, n) : set buffer size to 0 (for push/pop) + * + * Note: buf_push(), buf_grow(), buf_trunc(), and buf_free() may change + * the buffer pointer, and any previously-taken pointers should be + * considered invalidated. + * + * Example usage: + * + * float *values = 0; + * for (size_t i = 0; i < 25; i++) + * buf_push(values, rand() / (float)RAND_MAX); + * for (size_t i = 0; i < buf_size(values); i++) + * printf("values[%zu] = %f\n", i, values[i]); + * buf_free(values); + */ +#ifndef _LIB_BUF_H +#define _LIB_BUF_H +#include +#include + +#ifndef BUF_INIT_CAPACITY +# define BUF_INIT_CAPACITY 8 +#endif + +#ifndef BUF_ABORT +# define BUF_ABORT abort() +#endif + +struct buf { + size_t capacity; + size_t size; + char buffer[]; +}; + +void * buf_grow1(void *v, size_t esize, ptrdiff_t n); + +#define buf_ptr(v) \ + ((struct buf *)((char *)(v) - offsetof(struct buf, buffer))) + +#define buf_free(v) \ + do { \ + if (v) { \ + free(buf_ptr((v))); \ + (v) = 0; \ + } \ + } while (0) + +#define buf_size(v) \ + ((v) ? buf_ptr((v))->size : 0) + +#define buf_capacity(v) \ + ((v) ? buf_ptr((v))->capacity : 0) + +#define buf_push(v, e) \ + do { \ + if (buf_capacity((v)) == buf_size((v))) { \ + (v) = buf_grow1(v, sizeof(*(v)), \ + !buf_capacity((v)) ? \ + BUF_INIT_CAPACITY : \ + buf_capacity((v))); \ + } \ + (v)[buf_ptr((v))->size++] = (e); \ + } while (0) + +#define buf_pop(v) \ + ((v)[--buf_ptr(v)->size]) + +#define buf_grow(v, n) \ + ((v) = buf_grow1((v), sizeof(*(v)), n)) + +#define buf_trunc(v, n) \ + ((v) = buf_grow1((v), sizeof(*(v)), n - buf_capacity(v))) + +#define buf_clear(v) \ + ((v) ? (buf_ptr((v))->size = 0) : 0) + +#endif // _LIB_BUF_H \ No newline at end of file diff --git a/08_TestingCoverage/main.c b/08_TestingCoverage/main.c new file mode 100644 index 0000000..dd5a5e2 --- /dev/null +++ b/08_TestingCoverage/main.c @@ -0,0 +1,13 @@ +#include + +#include "buf.h" + +int main () { + float *values = 0; + for (size_t i = 0; i < 25; i++) + buf_push(values, rand() / (float)RAND_MAX); + for (size_t i = 0; i < buf_size(values); i++) + printf("values[%zu] = %f\n", i, values[i]); + buf_free(values); + return 0; +} \ No newline at end of file diff --git a/08_TestingCoverage/minctest.h b/08_TestingCoverage/minctest.h new file mode 100644 index 0000000..e4dd687 --- /dev/null +++ b/08_TestingCoverage/minctest.h @@ -0,0 +1,137 @@ +/* + * + * MINCTEST - Minimal C Test Library - 0.2.0 + * + * Copyright (c) 2014-2017 Lewis Van Winkle + * + * http://CodePlea.com + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgement in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + */ + + + +/* + * MINCTEST - Minimal testing library for C + * + * + * Example: + * + * void test1() { + * lok('a' == 'a'); + * } + * + * void test2() { + * lequal(5, 6); + * lfequal(5.5, 5.6); + * } + * + * int main() { + * lrun("test1", test1); + * lrun("test2", test2); + * lresults(); + * return lfails != 0; + * } + * + * + * + * Hints: + * All functions/variables start with the letter 'l'. + * + */ + + +#ifndef __MINCTEST_H__ +#define __MINCTEST_H__ + +#include +#include +#include +#include + + +/* How far apart can floats be before we consider them unequal. */ +#ifndef LTEST_FLOAT_TOLERANCE +#define LTEST_FLOAT_TOLERANCE 0.001 +#endif + + +/* Track the number of passes, fails. */ +/* NB this is made for all tests to be in one file. */ +static int ltests = 0; +static int lfails = 0; + + +/* Display the test results. */ +#define lresults() do {\ + if (lfails == 0) {\ + printf("ALL TESTS PASSED (%d/%d)\n", ltests, ltests);\ + } else {\ + printf("SOME TESTS FAILED (%d/%d)\n", ltests-lfails, ltests);\ + }\ +} while (0) + + +/* Run a test. Name can be any string to print out, test is the function name to call. */ +#define lrun(name, test) do {\ + const int ts = ltests;\ + const int fs = lfails;\ + const clock_t start = clock();\ + printf("\t%-14s", name);\ + test();\ + printf("pass:%2d fail:%2d %4dms\n",\ + (ltests-ts)-(lfails-fs), lfails-fs,\ + (int)((clock() - start) * 1000 / CLOCKS_PER_SEC));\ +} while (0) + + +/* Assert a true statement. */ +#define lok(test) do {\ + ++ltests;\ + if (!(test)) {\ + ++lfails;\ + printf("%s:%d error \n", __FILE__, __LINE__);\ + }} while (0) + + +/* Prototype to assert equal. */ +#define lequal_base(equality, a, b, format) do {\ + ++ltests;\ + if (!(equality)) {\ + ++lfails;\ + printf("%s:%d ("format " != " format")\n", __FILE__, __LINE__, (a), (b));\ + }} while (0) + + +/* Assert two integers are equal. */ +#define lequal(a, b)\ + lequal_base((a) == (b), a, b, "%d") + + +/* Assert two floats are equal (Within LTEST_FLOAT_TOLERANCE). */ +#define lfequal(a, b)\ + lequal_base(fabs((double)(a)-(double)(b)) <= LTEST_FLOAT_TOLERANCE\ + && fabs((double)(a)-(double)(b)) == fabs((double)(a)-(double)(b)), (double)(a), (double)(b), "%f") + + +/* Assert two strings are equal. */ +#define lsequal(a, b)\ + lequal_base(strcmp(a, b) == 0, a, b, "%s") + + +#endif /*__MINCTEST_H__*/ diff --git a/08_TestingCoverage/tests.c b/08_TestingCoverage/tests.c new file mode 100644 index 0000000..aebc6af --- /dev/null +++ b/08_TestingCoverage/tests.c @@ -0,0 +1,71 @@ +#include +#include +#include + +#include "minctest.h" + +#include "buf.h" + + +void test_buf_squares_operator() { + long *ai = 0; + for (int i = 0; i < 10000; i++) + buf_push(ai, i); + lequal((int)buf_size(ai), 10000); + int match = 0; + for (int i = 0; i < (int)(buf_size(ai)); i++) + match += ai[i] == i; + lequal(match, 10000); + buf_free(ai); +} + +void test_buf_grow_trunc() { + long *ai = 0; + buf_grow(ai, 1000); + lequal((int)buf_capacity(ai), 1000); + lequal((int)buf_size(ai), 0); + buf_trunc(ai, 100); + lequal((int)buf_capacity(ai), 100); + buf_free(ai); +} + +void test_buf_base() { + float *a = 0; + lok(buf_capacity(a) == 0); + lok(buf_size(a) == 0); + buf_push(a, 1.3f); + lok(buf_size(a) == 1); + lok(a[0] == (float)1.3f); + buf_clear(a); + lok(buf_size(a) == 0); + lok(a != 0); + buf_free(a); + lok(a == 0); + + buf_clear(a); + lok(buf_size(a) == 0); + lok(a == 0); + + buf_push(a, 1.1); + buf_push(a, 1.2); + buf_push(a, 1.3); + buf_push(a, 1.4); + lok(buf_size(a) == 4); + lok(buf_pop(a) == (float)1.4f); + buf_trunc(a, 3); + lok(buf_size(a) == 3); + lok(buf_pop(a) == (float)1.3f); + lok(buf_pop(a) == (float)1.2f); + lok(buf_pop(a) == (float)1.1f); + lok(buf_size(a) == 0); + buf_free(a); +} + +int main(int argc, char *argv[]) +{ + lrun("buf_push(), []", test_buf_squares_operator); + lrun("buf_grow(), buf_trunc", test_buf_grow_trunc); + lrun("buf_base_test", test_buf_base); + lresults(); + return lfails != 0; +} \ No newline at end of file