forked from 131/lab3_test
initial commit
This commit is contained in:
16
Makefile
Normal file
16
Makefile
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
CFLAGS=-Wall -I munit -ggdb
|
||||||
|
unittest_obj=munit/munit.o
|
||||||
|
|
||||||
|
all: str_bin str_test
|
||||||
|
|
||||||
|
str_test: $(unittest_obj) str_lib.o str_test.o
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
str_bin: str_lib.o str_bin.o
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
test: ./str_test
|
||||||
|
./str_test
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *_bin *.o $(unittest_obj) str_test
|
||||||
61
README.md
Normal file
61
README.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
Модульное тестирование
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Задачи:
|
||||||
|
|
||||||
|
* форкнуть git-репозиторий к себе в аккаунт https://timp.pw/121/lab3_test
|
||||||
|
|
||||||
|
* Собрать и запустить тестовый пример (example.c) из библиотеки munit (директория munit).
|
||||||
|
|
||||||
|
* Почитать документацию munit и исходники ./munit/example.c
|
||||||
|
Чтобы разобраться подробнее, можн глянуть сюда:
|
||||||
|
* ./munit/README.md
|
||||||
|
* https://nemequ.github.io/munit/
|
||||||
|
|
||||||
|
* В текущей директории лежит проект, использующий munit для тестирования функций,
|
||||||
|
которые вам нужно будет дописать (или скопировать из https://timp.pw/121/lab0_letsbegin ;-)).
|
||||||
|
|
||||||
|
Нужно реализовать функции (находятся в файле ./str_lib.c)
|
||||||
|
* mystrlen -- функция, возвращающая длину строки
|
||||||
|
* mystr_idx -- функция, принимающая 2 строки, и возвращающая индекс,
|
||||||
|
начиная с которого вторая строка встречается в первой
|
||||||
|
|
||||||
|
Тесты на функции написаны в этом файле ./str_test.c.
|
||||||
|
Запустить тесты можно с помощью команды:
|
||||||
|
make test
|
||||||
|
|
||||||
|
---------
|
||||||
|
|
||||||
|
* закоммитить изменения в репозиторий, перейти на ветку репозитория с именем aux
|
||||||
|
Подсказочка про команды:
|
||||||
|
```
|
||||||
|
скачать инфу про репозиторий
|
||||||
|
git fetch
|
||||||
|
посмотреть все доступные ветки:
|
||||||
|
git branch -a
|
||||||
|
перейти на ветку
|
||||||
|
git checkout BRANCHNAME
|
||||||
|
```
|
||||||
|
|
||||||
|
* написать функции (находятся в файле ./aux_lib.c):
|
||||||
|
* fibonacci -- функция возвращает n-ный элемент последовательности фибоначи
|
||||||
|
|
||||||
|
* sum_is_odd -- функция суммирует массив и возвращает информацию о том, является ли сумма нечётной
|
||||||
|
|
||||||
|
* написать тесты к функциям в файл aux_test.c
|
||||||
|
Используя творческий копипаст из файлов ./munit/example.c и ./str_test.c
|
||||||
|
|
||||||
|
---------
|
||||||
|
* написать функцию bit_count, считающую количество битиков в числе
|
||||||
|
интерфейс функции
|
||||||
|
```
|
||||||
|
int bit_count(unsigned_int number)
|
||||||
|
```
|
||||||
|
|
||||||
|
* написать к этой функции тесты
|
||||||
|
|
||||||
|
* добавить в Makefile цель для сборки тестов
|
||||||
|
|
||||||
|
---------
|
||||||
|
|
||||||
21
munit/COPYING
Normal file
21
munit/COPYING
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
µnit Testing Framework
|
||||||
|
Copyright (c) 2013-2016 Evan Nemerson <evan@nemerson.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 OR COPYRIGHT HOLDERS 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.
|
||||||
55
munit/Makefile
Normal file
55
munit/Makefile
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Using µnit is very simple; just include the header and add the C
|
||||||
|
# file to your sources. That said, here is a simple Makefile to build
|
||||||
|
# the example.
|
||||||
|
|
||||||
|
CSTD:=99
|
||||||
|
OPENMP:=n
|
||||||
|
ASAN:=n
|
||||||
|
UBSAN:=n
|
||||||
|
EXTENSION:=
|
||||||
|
TEST_ENV:=
|
||||||
|
CFLAGS:=
|
||||||
|
AGGRESSIVE_WARNINGS=n
|
||||||
|
|
||||||
|
ifeq ($(CC),pgcc)
|
||||||
|
CFLAGS+=-c$(CSTD)
|
||||||
|
else
|
||||||
|
CFLAGS+=-std=c$(CSTD)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OPENMP),y)
|
||||||
|
ifeq ($(CC),pgcc)
|
||||||
|
CFLAGS+=-mp
|
||||||
|
else
|
||||||
|
CFLAGS+=-fopenmp
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(SANITIZER),)
|
||||||
|
CFLAGS+=-fsanitize=$(SANITIZER)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(CC),pgcc)
|
||||||
|
ifeq ($(EXTRA_WARNINGS),y)
|
||||||
|
CFLAGS+=-Wall -Wextra -Werror
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(ASAN),y)
|
||||||
|
CFLAGS+=-fsanitize=address
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UBSAN),y)
|
||||||
|
CFLAGS+=-fsanitize=undefined
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
example$(EXTENSION): munit.h munit.c example.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ munit.c example.c
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(TEST_ENV) ./example$(EXTENSION)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f example$(EXTENSION)
|
||||||
|
|
||||||
|
all: example$(EXTENSION)
|
||||||
54
munit/README.md
Normal file
54
munit/README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# µnit
|
||||||
|
|
||||||
|
µnit is a small but full-featured unit testing framework for C. It has
|
||||||
|
no dependencies (beyond libc), is permissively licensed (MIT), and is
|
||||||
|
easy to include into any project.
|
||||||
|
|
||||||
|
For more information, see
|
||||||
|
[the µnit web site](https://nemequ.github.io/munit).
|
||||||
|
|
||||||
|
[](https://travis-ci.org/nemequ/munit)
|
||||||
|
[](https://ci.appveyor.com/project/quixdb/munit/branch/master)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Features µnit currently includes include:
|
||||||
|
|
||||||
|
* Handy assertion macros which make for nice error messages.
|
||||||
|
* Reproducible cross-platform random number generation, including
|
||||||
|
support for supplying a seed via CLI.
|
||||||
|
* Timing of both wall-clock and CPU time.
|
||||||
|
* Parameterized tests.
|
||||||
|
* Nested test suites.
|
||||||
|
* Flexible CLI.
|
||||||
|
* Forking
|
||||||
|
([except on Windows](https://github.com/nemequ/munit/issues/2)).
|
||||||
|
* Hiding output of successful tests.
|
||||||
|
|
||||||
|
Features µnit does not currently include, but some day may include
|
||||||
|
(a.k.a., if you file a PR…), include:
|
||||||
|
|
||||||
|
* [TAP](http://testanything.org/) support; feel free to discuss in
|
||||||
|
[issue #1](https://github.com/nemequ/munit/issues/1)
|
||||||
|
|
||||||
|
### Include into your project with meson
|
||||||
|
|
||||||
|
In your `subprojects` folder put a `munit.wrap` file containing:
|
||||||
|
|
||||||
|
```
|
||||||
|
[wrap-git]
|
||||||
|
directory=munit
|
||||||
|
url=https://github.com/nemequ/munit/
|
||||||
|
revision=head
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can use a subproject fallback when you include munit as a
|
||||||
|
dependency to your project: `dependency('munit', fallback: ['munit', 'munit_dep'])`
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
See [the µnit web site](https://nemequ.github.io/munit).
|
||||||
|
|
||||||
|
Additionally, there is a heavily-commented
|
||||||
|
[example.c](https://github.com/nemequ/munit/blob/master/example.c) in
|
||||||
|
the repository.
|
||||||
351
munit/example.c
Normal file
351
munit/example.c
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
/* Example file for using µnit.
|
||||||
|
*
|
||||||
|
* µnit is MIT-licensed, but for this file and this file alone:
|
||||||
|
*
|
||||||
|
* To the extent possible under law, the author(s) of this file have
|
||||||
|
* waived all copyright and related or neighboring rights to this
|
||||||
|
* work. See <https://creativecommons.org/publicdomain/zero/1.0/> for
|
||||||
|
* details.
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
#include "munit.h"
|
||||||
|
|
||||||
|
/* This is just to disable an MSVC warning about conditional
|
||||||
|
* expressions being constant, which you shouldn't have to do for your
|
||||||
|
* code. It's only here because we want to be able to do silly things
|
||||||
|
* like assert that 0 != 1 for our demo. */
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma warning(disable: 4127)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tests are functions that return void, and take a single void*
|
||||||
|
* parameter. We'll get to what that parameter is later. */
|
||||||
|
static MunitResult
|
||||||
|
test_compare(const MunitParameter params[], void* data) {
|
||||||
|
/* We'll use these later */
|
||||||
|
const unsigned char val_uchar = 'b';
|
||||||
|
const short val_short = 1729;
|
||||||
|
double pi = 3.141592654;
|
||||||
|
char* stewardesses = "stewardesses";
|
||||||
|
char* most_fun_word_to_type;
|
||||||
|
|
||||||
|
/* These are just to silence compiler warnings about the parameters
|
||||||
|
* being unused. */
|
||||||
|
(void) params;
|
||||||
|
(void) data;
|
||||||
|
|
||||||
|
/* Let's start with the basics. */
|
||||||
|
munit_assert(0 != 1);
|
||||||
|
|
||||||
|
/* There is also the more verbose, though slightly more descriptive
|
||||||
|
munit_assert_true/false: */
|
||||||
|
munit_assert_false(0);
|
||||||
|
|
||||||
|
/* You can also call munit_error and munit_errorf yourself. We
|
||||||
|
* won't do it is used to indicate a failure, but here is what it
|
||||||
|
* would look like: */
|
||||||
|
/* munit_error("FAIL"); */
|
||||||
|
/* munit_errorf("Goodbye, cruel %s", "world"); */
|
||||||
|
|
||||||
|
/* There are macros for comparing lots of types. */
|
||||||
|
munit_assert_char('a', ==, 'a');
|
||||||
|
|
||||||
|
/* Sure, you could just assert('a' == 'a'), but if you did that, a
|
||||||
|
* failed assertion would just say something like "assertion failed:
|
||||||
|
* val_uchar == 'b'". µnit will tell you the actual values, so a
|
||||||
|
* failure here would result in something like "assertion failed:
|
||||||
|
* val_uchar == 'b' ('X' == 'b')." */
|
||||||
|
munit_assert_uchar(val_uchar, ==, 'b');
|
||||||
|
|
||||||
|
/* Obviously we can handle values larger than 'char' and 'uchar'.
|
||||||
|
* There are versions for char, short, int, long, long long,
|
||||||
|
* int8/16/32/64_t, as well as the unsigned versions of them all. */
|
||||||
|
munit_assert_short(42, <, val_short);
|
||||||
|
|
||||||
|
/* There is also support for size_t.
|
||||||
|
*
|
||||||
|
* The longest word in English without repeating any letters is
|
||||||
|
* "uncopyrightables", which has uncopyrightable (and
|
||||||
|
* dermatoglyphics, which is the study of fingerprints) beat by a
|
||||||
|
* character */
|
||||||
|
munit_assert_size(strlen("uncopyrightables"), >, strlen("dermatoglyphics"));
|
||||||
|
|
||||||
|
/* Of course there is also support for doubles and floats. */
|
||||||
|
munit_assert_double(pi, ==, 3.141592654);
|
||||||
|
|
||||||
|
/* If you want to compare two doubles for equality, you might want
|
||||||
|
* to consider using munit_assert_double_equal. It compares two
|
||||||
|
* doubles for equality within a precison of 1.0 x 10^-(precision).
|
||||||
|
* Note that precision (the third argument to the macro) needs to be
|
||||||
|
* fully evaluated to an integer by the preprocessor so µnit doesn't
|
||||||
|
* have to depend pow, which is often in libm not libc. */
|
||||||
|
munit_assert_double_equal(3.141592654, 3.141592653589793, 9);
|
||||||
|
|
||||||
|
/* And if you want to check strings for equality (or inequality),
|
||||||
|
* there is munit_assert_string_equal/not_equal.
|
||||||
|
*
|
||||||
|
* "stewardesses" is the longest word you can type on a QWERTY
|
||||||
|
* keyboard with only one hand, which makes it loads of fun to type.
|
||||||
|
* If I'm going to have to type a string repeatedly, let's make it a
|
||||||
|
* good one! */
|
||||||
|
munit_assert_string_equal(stewardesses, "stewardesses");
|
||||||
|
|
||||||
|
/* A personal favorite macro which is fantastic if you're working
|
||||||
|
* with binary data, is the one which naïvely checks two blobs of
|
||||||
|
* memory for equality. If this fails it will tell you the offset
|
||||||
|
* of the first differing byte. */
|
||||||
|
munit_assert_memory_equal(7, stewardesses, "steward");
|
||||||
|
|
||||||
|
/* You can also make sure that two blobs differ *somewhere*: */
|
||||||
|
munit_assert_memory_not_equal(8, stewardesses, "steward");
|
||||||
|
|
||||||
|
/* There are equal/not_equal macros for pointers, too: */
|
||||||
|
most_fun_word_to_type = stewardesses;
|
||||||
|
munit_assert_ptr_equal(most_fun_word_to_type, stewardesses);
|
||||||
|
|
||||||
|
/* And null/not_null */
|
||||||
|
munit_assert_null(NULL);
|
||||||
|
munit_assert_not_null(most_fun_word_to_type);
|
||||||
|
|
||||||
|
/* Lets verify that the data parameter is what we expected. We'll
|
||||||
|
* see where this comes from in a bit.
|
||||||
|
*
|
||||||
|
* Note that the casting isn't usually required; if you give this
|
||||||
|
* function a real pointer (instead of a number like 0xdeadbeef) it
|
||||||
|
* would work as expected. */
|
||||||
|
munit_assert_ptr_equal(data, (void*)(uintptr_t)0xdeadbeef);
|
||||||
|
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MunitResult
|
||||||
|
test_rand(const MunitParameter params[], void* user_data) {
|
||||||
|
int random_int;
|
||||||
|
double random_dbl;
|
||||||
|
munit_uint8_t data[5];
|
||||||
|
|
||||||
|
(void) params;
|
||||||
|
(void) user_data;
|
||||||
|
|
||||||
|
/* One thing missing from a lot of unit testing frameworks is a
|
||||||
|
* random number generator. You can't just use srand/rand because
|
||||||
|
* the implementation varies across different platforms, and it's
|
||||||
|
* important to be able to look at the seed used in a failing test
|
||||||
|
* to see if you can reproduce it. Some randomness is a fantastic
|
||||||
|
* thing to have in your tests, I don't know why more people don't
|
||||||
|
* do it...
|
||||||
|
*
|
||||||
|
* µnit's PRNG is re-seeded with the same value for each iteration
|
||||||
|
* of each test. The seed is retrieved from the MUNIT_SEED
|
||||||
|
* envirnment variable or, if none is provided, one will be
|
||||||
|
* (pseudo-)randomly generated. */
|
||||||
|
|
||||||
|
/* If you need an integer in a given range */
|
||||||
|
random_int = munit_rand_int_range(128, 4096);
|
||||||
|
munit_assert_int(random_int, >=, 128);
|
||||||
|
munit_assert_int(random_int, <=, 4096);
|
||||||
|
|
||||||
|
/* Or maybe you want a double, between 0 and 1: */
|
||||||
|
random_dbl = munit_rand_double();
|
||||||
|
munit_assert_double(random_dbl, >=, 0.0);
|
||||||
|
munit_assert_double(random_dbl, <=, 1.0);
|
||||||
|
|
||||||
|
/* Of course, you want to be able to reproduce bugs discovered
|
||||||
|
* during testing, so every time the tests are run they print the
|
||||||
|
* random seed used. When you want to reproduce a result, just put
|
||||||
|
* that random seed in the MUNIT_SEED environment variable; it even
|
||||||
|
* works on different platforms.
|
||||||
|
*
|
||||||
|
* If you want this to pass, use 0xdeadbeef as the random seed and
|
||||||
|
* uncomment the next line of code. Note that the PRNG is not
|
||||||
|
* re-seeded between iterations of the same test, so this will only
|
||||||
|
* work on the first iteration. */
|
||||||
|
/* munit_assert_uint32(munit_rand_uint32(), ==, 1306447409); */
|
||||||
|
|
||||||
|
/* You can also get blobs of random memory: */
|
||||||
|
munit_rand_memory(sizeof(data), data);
|
||||||
|
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test case shows how to accept parameters. We'll see how to
|
||||||
|
* specify them soon.
|
||||||
|
*
|
||||||
|
* By default, every possible variation of a parameterized test is
|
||||||
|
* run, but you can specify parameters manually if you want to only
|
||||||
|
* run specific test(s), or you can pass the --single argument to the
|
||||||
|
* CLI to have the harness simply choose one variation at random
|
||||||
|
* instead of running them all. */
|
||||||
|
static MunitResult
|
||||||
|
test_parameters(const MunitParameter params[], void* user_data) {
|
||||||
|
const char* foo;
|
||||||
|
const char* bar;
|
||||||
|
|
||||||
|
(void) user_data;
|
||||||
|
|
||||||
|
/* The "foo" parameter is specified as one of the following values:
|
||||||
|
* "one", "two", or "three". */
|
||||||
|
foo = munit_parameters_get(params, "foo");
|
||||||
|
/* Similarly, "bar" is one of "four", "five", or "six". */
|
||||||
|
bar = munit_parameters_get(params, "bar");
|
||||||
|
/* "baz" is a bit more complicated. We don't actually specify a
|
||||||
|
* list of valid values, so by default NULL is passed. However, the
|
||||||
|
* CLI will accept any value. This is a good way to have a value
|
||||||
|
* that is usually selected randomly by the test, but can be
|
||||||
|
* overridden on the command line if desired. */
|
||||||
|
/* const char* baz = munit_parameters_get(params, "baz"); */
|
||||||
|
|
||||||
|
/* Notice that we're returning MUNIT_FAIL instead of writing an
|
||||||
|
* error message. Error messages are generally preferable, since
|
||||||
|
* they make it easier to diagnose the issue, but this is an
|
||||||
|
* option.
|
||||||
|
*
|
||||||
|
* Possible values are:
|
||||||
|
* - MUNIT_OK: Sucess
|
||||||
|
* - MUNIT_FAIL: Failure
|
||||||
|
* - MUNIT_SKIP: The test was skipped; usually this happens when a
|
||||||
|
* particular feature isn't in use. For example, if you're
|
||||||
|
* writing a test which uses a Wayland-only feature, but your
|
||||||
|
* application is running on X11.
|
||||||
|
* - MUNIT_ERROR: The test failed, but not because of anything you
|
||||||
|
* wanted to test. For example, maybe your test downloads a
|
||||||
|
* remote resource and tries to parse it, but the network was
|
||||||
|
* down.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (strcmp(foo, "one") != 0 &&
|
||||||
|
strcmp(foo, "two") != 0 &&
|
||||||
|
strcmp(foo, "three") != 0)
|
||||||
|
return MUNIT_FAIL;
|
||||||
|
|
||||||
|
if (strcmp(bar, "red") != 0 &&
|
||||||
|
strcmp(bar, "green") != 0 &&
|
||||||
|
strcmp(bar, "blue") != 0)
|
||||||
|
return MUNIT_FAIL;
|
||||||
|
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The setup function, if you provide one, for a test will be run
|
||||||
|
* before the test, and the return value will be passed as the sole
|
||||||
|
* parameter to the test function. */
|
||||||
|
static void*
|
||||||
|
test_compare_setup(const MunitParameter params[], void* user_data) {
|
||||||
|
(void) params;
|
||||||
|
|
||||||
|
munit_assert_string_equal(user_data, "µnit");
|
||||||
|
return (void*) (uintptr_t) 0xdeadbeef;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To clean up after a test, you can use a tear down function. The
|
||||||
|
* fixture argument is the value returned by the setup function
|
||||||
|
* above. */
|
||||||
|
static void
|
||||||
|
test_compare_tear_down(void* fixture) {
|
||||||
|
munit_assert_ptr_equal(fixture, (void*)(uintptr_t)0xdeadbeef);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* foo_params[] = {
|
||||||
|
(char*) "one", (char*) "two", (char*) "three", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static char* bar_params[] = {
|
||||||
|
(char*) "red", (char*) "green", (char*) "blue", NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static MunitParameterEnum test_params[] = {
|
||||||
|
{ (char*) "foo", foo_params },
|
||||||
|
{ (char*) "bar", bar_params },
|
||||||
|
{ (char*) "baz", NULL },
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Creating a test suite is pretty simple. First, you'll need an
|
||||||
|
* array of tests: */
|
||||||
|
static MunitTest test_suite_tests[] = {
|
||||||
|
{
|
||||||
|
/* The name is just a unique human-readable way to identify the
|
||||||
|
* test. You can use it to run a specific test if you want, but
|
||||||
|
* usually it's mostly decorative. */
|
||||||
|
(char*) "/example/compare",
|
||||||
|
/* You probably won't be surprised to learn that the tests are
|
||||||
|
* functions. */
|
||||||
|
test_compare,
|
||||||
|
/* If you want, you can supply a function to set up a fixture. If
|
||||||
|
* you supply NULL, the user_data parameter from munit_suite_main
|
||||||
|
* will be used directly. If, however, you provide a callback
|
||||||
|
* here the user_data parameter will be passed to this callback,
|
||||||
|
* and the return value from this callback will be passed to the
|
||||||
|
* test function.
|
||||||
|
*
|
||||||
|
* For our example we don't really need a fixture, but lets
|
||||||
|
* provide one anyways. */
|
||||||
|
test_compare_setup,
|
||||||
|
/* If you passed a callback for the fixture setup function, you
|
||||||
|
* may want to pass a corresponding callback here to reverse the
|
||||||
|
* operation. */
|
||||||
|
test_compare_tear_down,
|
||||||
|
/* Finally, there is a bitmask for options you can pass here. You
|
||||||
|
* can provide either MUNIT_TEST_OPTION_NONE or 0 here to use the
|
||||||
|
* defaults. */
|
||||||
|
MUNIT_TEST_OPTION_NONE,
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
/* Usually this is written in a much more compact format; all these
|
||||||
|
* comments kind of ruin that, though. Here is how you'll usually
|
||||||
|
* see entries written: */
|
||||||
|
{ (char*) "/example/rand", test_rand, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL },
|
||||||
|
/* To tell the test runner when the array is over, just add a NULL
|
||||||
|
* entry at the end. */
|
||||||
|
{ (char*) "/example/parameters", test_parameters, NULL, NULL, MUNIT_TEST_OPTION_NONE, test_params },
|
||||||
|
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
/* If you wanted to have your test suite run other test suites you
|
||||||
|
* could declare an array of them. Of course each sub-suite can
|
||||||
|
* contain more suites, etc. */
|
||||||
|
/* static const MunitSuite other_suites[] = { */
|
||||||
|
/* { "/second", test_suite_tests, NULL, 1, MUNIT_SUITE_OPTION_NONE }, */
|
||||||
|
/* { NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE } */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* Now we'll actually declare the test suite. You could do this in
|
||||||
|
* the main function, or on the heap, or whatever you want. */
|
||||||
|
static const MunitSuite test_suite = {
|
||||||
|
/* This string will be prepended to all test names in this suite;
|
||||||
|
* for example, "/example/rand" will become "/µnit/example/rand".
|
||||||
|
* Note that, while it doesn't really matter for the top-level
|
||||||
|
* suite, NULL signal the end of an array of tests; you should use
|
||||||
|
* an empty string ("") instead. */
|
||||||
|
(char*) "",
|
||||||
|
/* The first parameter is the array of test suites. */
|
||||||
|
test_suite_tests,
|
||||||
|
/* In addition to containing test cases, suites can contain other
|
||||||
|
* test suites. This isn't necessary in this example, but it can be
|
||||||
|
* a great help to projects with lots of tests by making it easier
|
||||||
|
* to spread the tests across many files. This is where you would
|
||||||
|
* put "other_suites" (which is commented out above). */
|
||||||
|
NULL,
|
||||||
|
/* An interesting feature of µnit is that it supports automatically
|
||||||
|
* running multiple iterations of the tests. This is usually only
|
||||||
|
* interesting if you make use of the PRNG to randomize your tests
|
||||||
|
* cases a bit, or if you are doing performance testing and want to
|
||||||
|
* average multiple runs. 0 is an alias for 1. */
|
||||||
|
1,
|
||||||
|
/* Just like MUNIT_TEST_OPTION_NONE, you can provide
|
||||||
|
* MUNIT_SUITE_OPTION_NONE or 0 to use the default settings. */
|
||||||
|
MUNIT_SUITE_OPTION_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is only necessary for EXIT_SUCCESS and EXIT_FAILURE, which you
|
||||||
|
* *should* be using but probably aren't (no, zero and non-zero don't
|
||||||
|
* always mean success and failure). I guess my point is that nothing
|
||||||
|
* about µnit requires it. */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)]) {
|
||||||
|
/* Finally, we'll actually run our test suite! That second argument
|
||||||
|
* is the user_data parameter which will be passed either to the
|
||||||
|
* test or (if provided) the fixture setup function. */
|
||||||
|
return munit_suite_main(&test_suite, (void*) "µnit", argc, argv);
|
||||||
|
}
|
||||||
37
munit/meson.build
Normal file
37
munit/meson.build
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
project('munit', 'c')
|
||||||
|
|
||||||
|
conf_data = configuration_data()
|
||||||
|
conf_data.set('version', '0.2.0')
|
||||||
|
|
||||||
|
add_project_arguments('-std=c99', language : 'c')
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
|
root_include = include_directories('.')
|
||||||
|
|
||||||
|
munit = library('munit',
|
||||||
|
['munit.c'],
|
||||||
|
install: meson.is_subproject())
|
||||||
|
|
||||||
|
if meson.is_subproject()
|
||||||
|
munit_dep = declare_dependency(
|
||||||
|
include_directories : root_include,
|
||||||
|
link_with : munit)
|
||||||
|
else
|
||||||
|
# standalone install
|
||||||
|
install_headers('munit.h')
|
||||||
|
|
||||||
|
pkg = import('pkgconfig')
|
||||||
|
pkg.generate(name: 'munit',
|
||||||
|
description: 'µnit Testing Library for C',
|
||||||
|
version: conf_data.get('version'),
|
||||||
|
libraries: munit)
|
||||||
|
|
||||||
|
# compile the demo project
|
||||||
|
munit_example_src = files('example.c')
|
||||||
|
munit_example = executable('munit_example', munit_example_src,
|
||||||
|
include_directories: root_include,
|
||||||
|
link_with: munit)
|
||||||
|
|
||||||
|
test('munit example test', munit_example)
|
||||||
|
endif
|
||||||
2055
munit/munit.c
Normal file
2055
munit/munit.c
Normal file
File diff suppressed because it is too large
Load Diff
535
munit/munit.h
Normal file
535
munit/munit.h
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
/* µnit Testing Framework
|
||||||
|
* Copyright (c) 2013-2017 Evan Nemerson <evan@nemerson.com>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use, copy,
|
||||||
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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 OR COPYRIGHT HOLDERS
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MUNIT_H)
|
||||||
|
#define MUNIT_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define MUNIT_VERSION(major, minor, revision) \
|
||||||
|
(((major) << 16) | ((minor) << 8) | (revision))
|
||||||
|
|
||||||
|
#define MUNIT_CURRENT_VERSION MUNIT_VERSION(0, 4, 1)
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||||
|
# define munit_int8_t __int8
|
||||||
|
# define munit_uint8_t unsigned __int8
|
||||||
|
# define munit_int16_t __int16
|
||||||
|
# define munit_uint16_t unsigned __int16
|
||||||
|
# define munit_int32_t __int32
|
||||||
|
# define munit_uint32_t unsigned __int32
|
||||||
|
# define munit_int64_t __int64
|
||||||
|
# define munit_uint64_t unsigned __int64
|
||||||
|
#else
|
||||||
|
# include <stdint.h>
|
||||||
|
# define munit_int8_t int8_t
|
||||||
|
# define munit_uint8_t uint8_t
|
||||||
|
# define munit_int16_t int16_t
|
||||||
|
# define munit_uint16_t uint16_t
|
||||||
|
# define munit_int32_t int32_t
|
||||||
|
# define munit_uint32_t uint32_t
|
||||||
|
# define munit_int64_t int64_t
|
||||||
|
# define munit_uint64_t uint64_t
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1800)
|
||||||
|
# if !defined(PRIi8)
|
||||||
|
# define PRIi8 "i"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIi16)
|
||||||
|
# define PRIi16 "i"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIi32)
|
||||||
|
# define PRIi32 "i"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIi64)
|
||||||
|
# define PRIi64 "I64i"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRId8)
|
||||||
|
# define PRId8 "d"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRId16)
|
||||||
|
# define PRId16 "d"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRId32)
|
||||||
|
# define PRId32 "d"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRId64)
|
||||||
|
# define PRId64 "I64d"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIx8)
|
||||||
|
# define PRIx8 "x"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIx16)
|
||||||
|
# define PRIx16 "x"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIx32)
|
||||||
|
# define PRIx32 "x"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIx64)
|
||||||
|
# define PRIx64 "I64x"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIu8)
|
||||||
|
# define PRIu8 "u"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIu16)
|
||||||
|
# define PRIu16 "u"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIu32)
|
||||||
|
# define PRIu32 "u"
|
||||||
|
# endif
|
||||||
|
# if !defined(PRIu64)
|
||||||
|
# define PRIu64 "I64u"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(munit_bool)
|
||||||
|
# if defined(bool)
|
||||||
|
# define munit_bool bool
|
||||||
|
# elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||||
|
# define munit_bool _Bool
|
||||||
|
# else
|
||||||
|
# define munit_bool int
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# define MUNIT_LIKELY(expr) (__builtin_expect ((expr), 1))
|
||||||
|
# define MUNIT_UNLIKELY(expr) (__builtin_expect ((expr), 0))
|
||||||
|
# define MUNIT_UNUSED __attribute__((__unused__))
|
||||||
|
#else
|
||||||
|
# define MUNIT_LIKELY(expr) (expr)
|
||||||
|
# define MUNIT_UNLIKELY(expr) (expr)
|
||||||
|
# define MUNIT_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__PGI)
|
||||||
|
# define MUNIT_ARRAY_PARAM(name) name
|
||||||
|
#else
|
||||||
|
# define MUNIT_ARRAY_PARAM(name)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
# define MUNIT_SIZE_MODIFIER "z"
|
||||||
|
# define MUNIT_CHAR_MODIFIER "hh"
|
||||||
|
# define MUNIT_SHORT_MODIFIER "h"
|
||||||
|
#else
|
||||||
|
# if defined(_M_X64) || defined(__amd64__)
|
||||||
|
# define MUNIT_SIZE_MODIFIER "I64"
|
||||||
|
# else
|
||||||
|
# define MUNIT_SIZE_MODIFIER ""
|
||||||
|
# endif
|
||||||
|
# define MUNIT_CHAR_MODIFIER ""
|
||||||
|
# define MUNIT_SHORT_MODIFIER ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||||
|
# define MUNIT_NO_RETURN _Noreturn
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
# define MUNIT_NO_RETURN __attribute__((__noreturn__))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define MUNIT_NO_RETURN __declspec(noreturn)
|
||||||
|
#else
|
||||||
|
# define MUNIT_NO_RETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER >= 1500)
|
||||||
|
# define MUNIT_PUSH_DISABLE_MSVC_C4127_ __pragma(warning(push)) __pragma(warning(disable:4127))
|
||||||
|
# define MUNIT_POP_DISABLE_MSVC_C4127_ __pragma(warning(pop))
|
||||||
|
#else
|
||||||
|
# define MUNIT_PUSH_DISABLE_MSVC_C4127_
|
||||||
|
# define MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MUNIT_LOG_DEBUG,
|
||||||
|
MUNIT_LOG_INFO,
|
||||||
|
MUNIT_LOG_WARNING,
|
||||||
|
MUNIT_LOG_ERROR
|
||||||
|
} MunitLogLevel;
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__MINGW32__)
|
||||||
|
# define MUNIT_PRINTF(string_index, first_to_check) __attribute__((format (printf, string_index, first_to_check)))
|
||||||
|
#else
|
||||||
|
# define MUNIT_PRINTF(string_index, first_to_check)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MUNIT_PRINTF(4, 5)
|
||||||
|
void munit_logf_ex(MunitLogLevel level, const char* filename, int line, const char* format, ...);
|
||||||
|
|
||||||
|
#define munit_logf(level, format, ...) \
|
||||||
|
munit_logf_ex(level, __FILE__, __LINE__, format, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define munit_log(level, msg) \
|
||||||
|
munit_logf(level, "%s", msg)
|
||||||
|
|
||||||
|
MUNIT_NO_RETURN
|
||||||
|
MUNIT_PRINTF(3, 4)
|
||||||
|
void munit_errorf_ex(const char* filename, int line, const char* format, ...);
|
||||||
|
|
||||||
|
#define munit_errorf(format, ...) \
|
||||||
|
munit_errorf_ex(__FILE__, __LINE__, format, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define munit_error(msg) \
|
||||||
|
munit_errorf("%s", msg)
|
||||||
|
|
||||||
|
#define munit_assert(expr) \
|
||||||
|
do { \
|
||||||
|
if (!MUNIT_LIKELY(expr)) { \
|
||||||
|
munit_error("assertion failed: " #expr); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_true(expr) \
|
||||||
|
do { \
|
||||||
|
if (!MUNIT_LIKELY(expr)) { \
|
||||||
|
munit_error("assertion failed: " #expr " is not true"); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_false(expr) \
|
||||||
|
do { \
|
||||||
|
if (!MUNIT_LIKELY(!(expr))) { \
|
||||||
|
munit_error("assertion failed: " #expr " is not false"); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_type_full(prefix, suffix, T, fmt, a, op, b) \
|
||||||
|
do { \
|
||||||
|
T munit_tmp_a_ = (a); \
|
||||||
|
T munit_tmp_b_ = (b); \
|
||||||
|
if (!(munit_tmp_a_ op munit_tmp_b_)) { \
|
||||||
|
munit_errorf("assertion failed: %s %s %s (" prefix "%" fmt suffix " %s " prefix "%" fmt suffix ")", \
|
||||||
|
#a, #op, #b, munit_tmp_a_, #op, munit_tmp_b_); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_type(T, fmt, a, op, b) \
|
||||||
|
munit_assert_type_full("", "", T, fmt, a, op, b)
|
||||||
|
|
||||||
|
#define munit_assert_char(a, op, b) \
|
||||||
|
munit_assert_type_full("'\\x", "'", char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b)
|
||||||
|
#define munit_assert_uchar(a, op, b) \
|
||||||
|
munit_assert_type_full("'\\x", "'", unsigned char, "02" MUNIT_CHAR_MODIFIER "x", a, op, b)
|
||||||
|
#define munit_assert_short(a, op, b) \
|
||||||
|
munit_assert_type(short, MUNIT_SHORT_MODIFIER "d", a, op, b)
|
||||||
|
#define munit_assert_ushort(a, op, b) \
|
||||||
|
munit_assert_type(unsigned short, MUNIT_SHORT_MODIFIER "u", a, op, b)
|
||||||
|
#define munit_assert_int(a, op, b) \
|
||||||
|
munit_assert_type(int, "d", a, op, b)
|
||||||
|
#define munit_assert_uint(a, op, b) \
|
||||||
|
munit_assert_type(unsigned int, "u", a, op, b)
|
||||||
|
#define munit_assert_long(a, op, b) \
|
||||||
|
munit_assert_type(long int, "ld", a, op, b)
|
||||||
|
#define munit_assert_ulong(a, op, b) \
|
||||||
|
munit_assert_type(unsigned long int, "lu", a, op, b)
|
||||||
|
#define munit_assert_llong(a, op, b) \
|
||||||
|
munit_assert_type(long long int, "lld", a, op, b)
|
||||||
|
#define munit_assert_ullong(a, op, b) \
|
||||||
|
munit_assert_type(unsigned long long int, "llu", a, op, b)
|
||||||
|
|
||||||
|
#define munit_assert_size(a, op, b) \
|
||||||
|
munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", a, op, b)
|
||||||
|
|
||||||
|
#define munit_assert_float(a, op, b) \
|
||||||
|
munit_assert_type(float, "f", a, op, b)
|
||||||
|
#define munit_assert_double(a, op, b) \
|
||||||
|
munit_assert_type(double, "g", a, op, b)
|
||||||
|
#define munit_assert_ptr(a, op, b) \
|
||||||
|
munit_assert_type(const void*, "p", a, op, b)
|
||||||
|
|
||||||
|
#define munit_assert_int8(a, op, b) \
|
||||||
|
munit_assert_type(munit_int8_t, PRIi8, a, op, b)
|
||||||
|
#define munit_assert_uint8(a, op, b) \
|
||||||
|
munit_assert_type(munit_uint8_t, PRIu8, a, op, b)
|
||||||
|
#define munit_assert_int16(a, op, b) \
|
||||||
|
munit_assert_type(munit_int16_t, PRIi16, a, op, b)
|
||||||
|
#define munit_assert_uint16(a, op, b) \
|
||||||
|
munit_assert_type(munit_uint16_t, PRIu16, a, op, b)
|
||||||
|
#define munit_assert_int32(a, op, b) \
|
||||||
|
munit_assert_type(munit_int32_t, PRIi32, a, op, b)
|
||||||
|
#define munit_assert_uint32(a, op, b) \
|
||||||
|
munit_assert_type(munit_uint32_t, PRIu32, a, op, b)
|
||||||
|
#define munit_assert_int64(a, op, b) \
|
||||||
|
munit_assert_type(munit_int64_t, PRIi64, a, op, b)
|
||||||
|
#define munit_assert_uint64(a, op, b) \
|
||||||
|
munit_assert_type(munit_uint64_t, PRIu64, a, op, b)
|
||||||
|
|
||||||
|
#define munit_assert_double_equal(a, b, precision) \
|
||||||
|
do { \
|
||||||
|
const double munit_tmp_a_ = (a); \
|
||||||
|
const double munit_tmp_b_ = (b); \
|
||||||
|
const double munit_tmp_diff_ = ((munit_tmp_a_ - munit_tmp_b_) < 0) ? \
|
||||||
|
-(munit_tmp_a_ - munit_tmp_b_) : \
|
||||||
|
(munit_tmp_a_ - munit_tmp_b_); \
|
||||||
|
if (MUNIT_UNLIKELY(munit_tmp_diff_ > 1e-##precision)) { \
|
||||||
|
munit_errorf("assertion failed: %s == %s (%0." #precision "g == %0." #precision "g)", \
|
||||||
|
#a, #b, munit_tmp_a_, munit_tmp_b_); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#define munit_assert_string_equal(a, b) \
|
||||||
|
do { \
|
||||||
|
const char* munit_tmp_a_ = a; \
|
||||||
|
const char* munit_tmp_b_ = b; \
|
||||||
|
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \
|
||||||
|
munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", \
|
||||||
|
#a, #b, munit_tmp_a_, munit_tmp_b_); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_string_not_equal(a, b) \
|
||||||
|
do { \
|
||||||
|
const char* munit_tmp_a_ = a; \
|
||||||
|
const char* munit_tmp_b_ = b; \
|
||||||
|
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) == 0)) { \
|
||||||
|
munit_errorf("assertion failed: string %s != %s (\"%s\" == \"%s\")", \
|
||||||
|
#a, #b, munit_tmp_a_, munit_tmp_b_); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_memory_equal(size, a, b) \
|
||||||
|
do { \
|
||||||
|
const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \
|
||||||
|
const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \
|
||||||
|
const size_t munit_tmp_size_ = (size); \
|
||||||
|
if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) != 0) { \
|
||||||
|
size_t munit_tmp_pos_; \
|
||||||
|
for (munit_tmp_pos_ = 0 ; munit_tmp_pos_ < munit_tmp_size_ ; munit_tmp_pos_++) { \
|
||||||
|
if (munit_tmp_a_[munit_tmp_pos_] != munit_tmp_b_[munit_tmp_pos_]) { \
|
||||||
|
munit_errorf("assertion failed: memory %s == %s, at offset %" MUNIT_SIZE_MODIFIER "u", \
|
||||||
|
#a, #b, munit_tmp_pos_); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_memory_not_equal(size, a, b) \
|
||||||
|
do { \
|
||||||
|
const unsigned char* munit_tmp_a_ = (const unsigned char*) (a); \
|
||||||
|
const unsigned char* munit_tmp_b_ = (const unsigned char*) (b); \
|
||||||
|
const size_t munit_tmp_size_ = (size); \
|
||||||
|
if (MUNIT_UNLIKELY(memcmp(munit_tmp_a_, munit_tmp_b_, munit_tmp_size_)) == 0) { \
|
||||||
|
munit_errorf("assertion failed: memory %s != %s (%zu bytes)", \
|
||||||
|
#a, #b, munit_tmp_size_); \
|
||||||
|
} \
|
||||||
|
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
|
||||||
|
} while (0) \
|
||||||
|
MUNIT_POP_DISABLE_MSVC_C4127_
|
||||||
|
|
||||||
|
#define munit_assert_ptr_equal(a, b) \
|
||||||
|
munit_assert_ptr(a, ==, b)
|
||||||
|
#define munit_assert_ptr_not_equal(a, b) \
|
||||||
|
munit_assert_ptr(a, !=, b)
|
||||||
|
#define munit_assert_null(ptr) \
|
||||||
|
munit_assert_ptr(ptr, ==, NULL)
|
||||||
|
#define munit_assert_not_null(ptr) \
|
||||||
|
munit_assert_ptr(ptr, !=, NULL)
|
||||||
|
#define munit_assert_ptr_null(ptr) \
|
||||||
|
munit_assert_ptr(ptr, ==, NULL)
|
||||||
|
#define munit_assert_ptr_not_null(ptr) \
|
||||||
|
munit_assert_ptr(ptr, !=, NULL)
|
||||||
|
|
||||||
|
/*** Memory allocation ***/
|
||||||
|
|
||||||
|
void* munit_malloc_ex(const char* filename, int line, size_t size);
|
||||||
|
|
||||||
|
#define munit_malloc(size) \
|
||||||
|
munit_malloc_ex(__FILE__, __LINE__, (size))
|
||||||
|
|
||||||
|
#define munit_new(type) \
|
||||||
|
((type*) munit_malloc(sizeof(type)))
|
||||||
|
|
||||||
|
#define munit_calloc(nmemb, size) \
|
||||||
|
munit_malloc((nmemb) * (size))
|
||||||
|
|
||||||
|
#define munit_newa(type, nmemb) \
|
||||||
|
((type*) munit_calloc((nmemb), sizeof(type)))
|
||||||
|
|
||||||
|
/*** Random number generation ***/
|
||||||
|
|
||||||
|
void munit_rand_seed(munit_uint32_t seed);
|
||||||
|
munit_uint32_t munit_rand_uint32(void);
|
||||||
|
int munit_rand_int_range(int min, int max);
|
||||||
|
double munit_rand_double(void);
|
||||||
|
void munit_rand_memory(size_t size, munit_uint8_t buffer[MUNIT_ARRAY_PARAM(size)]);
|
||||||
|
|
||||||
|
/*** Tests and Suites ***/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* Test successful */
|
||||||
|
MUNIT_OK,
|
||||||
|
/* Test failed */
|
||||||
|
MUNIT_FAIL,
|
||||||
|
/* Test was skipped */
|
||||||
|
MUNIT_SKIP,
|
||||||
|
/* Test failed due to circumstances not intended to be tested
|
||||||
|
* (things like network errors, invalid parameter value, failure to
|
||||||
|
* allocate memory in the test harness, etc.). */
|
||||||
|
MUNIT_ERROR
|
||||||
|
} MunitResult;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* name;
|
||||||
|
char** values;
|
||||||
|
} MunitParameterEnum;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* name;
|
||||||
|
char* value;
|
||||||
|
} MunitParameter;
|
||||||
|
|
||||||
|
const char* munit_parameters_get(const MunitParameter params[], const char* key);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MUNIT_TEST_OPTION_NONE = 0,
|
||||||
|
MUNIT_TEST_OPTION_SINGLE_ITERATION = 1 << 0,
|
||||||
|
MUNIT_TEST_OPTION_TODO = 1 << 1
|
||||||
|
} MunitTestOptions;
|
||||||
|
|
||||||
|
typedef MunitResult (* MunitTestFunc)(const MunitParameter params[], void* user_data_or_fixture);
|
||||||
|
typedef void* (* MunitTestSetup)(const MunitParameter params[], void* user_data);
|
||||||
|
typedef void (* MunitTestTearDown)(void* fixture);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* name;
|
||||||
|
MunitTestFunc test;
|
||||||
|
MunitTestSetup setup;
|
||||||
|
MunitTestTearDown tear_down;
|
||||||
|
MunitTestOptions options;
|
||||||
|
MunitParameterEnum* parameters;
|
||||||
|
} MunitTest;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MUNIT_SUITE_OPTION_NONE = 0
|
||||||
|
} MunitSuiteOptions;
|
||||||
|
|
||||||
|
typedef struct MunitSuite_ MunitSuite;
|
||||||
|
|
||||||
|
struct MunitSuite_ {
|
||||||
|
char* prefix;
|
||||||
|
MunitTest* tests;
|
||||||
|
MunitSuite* suites;
|
||||||
|
unsigned int iterations;
|
||||||
|
MunitSuiteOptions options;
|
||||||
|
};
|
||||||
|
|
||||||
|
int munit_suite_main(const MunitSuite* suite, void* user_data, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
|
||||||
|
|
||||||
|
/* Note: I'm not very happy with this API; it's likely to change if I
|
||||||
|
* figure out something better. Suggestions welcome. */
|
||||||
|
|
||||||
|
typedef struct MunitArgument_ MunitArgument;
|
||||||
|
|
||||||
|
struct MunitArgument_ {
|
||||||
|
char* name;
|
||||||
|
munit_bool (* parse_argument)(const MunitSuite* suite, void* user_data, int* arg, int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)]);
|
||||||
|
void (* write_help)(const MunitArgument* argument, void* user_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
int munit_suite_main_custom(const MunitSuite* suite,
|
||||||
|
void* user_data,
|
||||||
|
int argc, char* const argv[MUNIT_ARRAY_PARAM(argc + 1)],
|
||||||
|
const MunitArgument arguments[]);
|
||||||
|
|
||||||
|
#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
|
||||||
|
|
||||||
|
#define assert_true(expr) munit_assert_true(expr)
|
||||||
|
#define assert_false(expr) munit_assert_false(expr)
|
||||||
|
#define assert_char(a, op, b) munit_assert_char(a, op, b)
|
||||||
|
#define assert_uchar(a, op, b) munit_assert_uchar(a, op, b)
|
||||||
|
#define assert_short(a, op, b) munit_assert_short(a, op, b)
|
||||||
|
#define assert_ushort(a, op, b) munit_assert_ushort(a, op, b)
|
||||||
|
#define assert_int(a, op, b) munit_assert_int(a, op, b)
|
||||||
|
#define assert_uint(a, op, b) munit_assert_uint(a, op, b)
|
||||||
|
#define assert_long(a, op, b) munit_assert_long(a, op, b)
|
||||||
|
#define assert_ulong(a, op, b) munit_assert_ulong(a, op, b)
|
||||||
|
#define assert_llong(a, op, b) munit_assert_llong(a, op, b)
|
||||||
|
#define assert_ullong(a, op, b) munit_assert_ullong(a, op, b)
|
||||||
|
#define assert_size(a, op, b) munit_assert_size(a, op, b)
|
||||||
|
#define assert_float(a, op, b) munit_assert_float(a, op, b)
|
||||||
|
#define assert_double(a, op, b) munit_assert_double(a, op, b)
|
||||||
|
#define assert_ptr(a, op, b) munit_assert_ptr(a, op, b)
|
||||||
|
|
||||||
|
#define assert_int8(a, op, b) munit_assert_int8(a, op, b)
|
||||||
|
#define assert_uint8(a, op, b) munit_assert_uint8(a, op, b)
|
||||||
|
#define assert_int16(a, op, b) munit_assert_int16(a, op, b)
|
||||||
|
#define assert_uint16(a, op, b) munit_assert_uint16(a, op, b)
|
||||||
|
#define assert_int32(a, op, b) munit_assert_int32(a, op, b)
|
||||||
|
#define assert_uint32(a, op, b) munit_assert_uint32(a, op, b)
|
||||||
|
#define assert_int64(a, op, b) munit_assert_int64(a, op, b)
|
||||||
|
#define assert_uint64(a, op, b) munit_assert_uint64(a, op, b)
|
||||||
|
|
||||||
|
#define assert_double_equal(a, b, precision) munit_assert_double_equal(a, b, precision)
|
||||||
|
#define assert_string_equal(a, b) munit_assert_string_equal(a, b)
|
||||||
|
#define assert_string_not_equal(a, b) munit_assert_string_not_equal(a, b)
|
||||||
|
#define assert_memory_equal(size, a, b) munit_assert_memory_equal(size, a, b)
|
||||||
|
#define assert_memory_not_equal(size, a, b) munit_assert_memory_not_equal(size, a, b)
|
||||||
|
#define assert_ptr_equal(a, b) munit_assert_ptr_equal(a, b)
|
||||||
|
#define assert_ptr_not_equal(a, b) munit_assert_ptr_not_equal(a, b)
|
||||||
|
#define assert_ptr_null(ptr) munit_assert_null_equal(ptr)
|
||||||
|
#define assert_ptr_not_null(ptr) munit_assert_not_null(ptr)
|
||||||
|
|
||||||
|
#define assert_null(ptr) munit_assert_null(ptr)
|
||||||
|
#define assert_not_null(ptr) munit_assert_not_null(ptr)
|
||||||
|
|
||||||
|
#endif /* defined(MUNIT_ENABLE_ASSERT_ALIASES) */
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !defined(MUNIT_H) */
|
||||||
|
|
||||||
|
#if defined(MUNIT_ENABLE_ASSERT_ALIASES)
|
||||||
|
# if defined(assert)
|
||||||
|
# undef assert
|
||||||
|
# endif
|
||||||
|
# define assert(expr) munit_assert(expr)
|
||||||
|
#endif
|
||||||
21
str_bin.c
Normal file
21
str_bin.c
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "str_lib.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
const char *s1 = "hello";
|
||||||
|
const char *s2 = "ello";
|
||||||
|
|
||||||
|
if (argc > 2) {
|
||||||
|
s1 = argv[1];
|
||||||
|
s2 = argv[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// binary for manual testing
|
||||||
|
printf("\033[1;30mUse str_test for actual testing\033[0m\n");
|
||||||
|
|
||||||
|
printf("mystrlen(\"%s\") == %d\n", s1, mystrlen(s1));
|
||||||
|
printf("str_idx(\"%s\", \"%s\") == %d\n", s1, s2, mystr_idx(s1, s2));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
23
str_lib.c
Normal file
23
str_lib.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Вернуть длину строки.
|
||||||
|
* Строки в C -- это массив символов, в конце которого находится нулевой символ ( '\0')
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
mystrlen(const char *s)
|
||||||
|
{
|
||||||
|
// <YOURCODE>
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Найти индекс, с которого строка s2 присутствует в строке s1
|
||||||
|
* или -1
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
mystr_idx(const char *s1, const char *s2)
|
||||||
|
{
|
||||||
|
// <YOURCODE>
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
6
str_lib.h
Normal file
6
str_lib.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int mystrlen(const char *s);
|
||||||
|
|
||||||
|
int mystr_idx(const char *s1, const char *s2);
|
||||||
|
|
||||||
67
str_test.c
Normal file
67
str_test.c
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "munit.h"
|
||||||
|
#include "str_lib.h"
|
||||||
|
|
||||||
|
static MunitResult
|
||||||
|
test_mystrlen(const MunitParameter params[], void * data)
|
||||||
|
{
|
||||||
|
munit_assert_true(mystrlen("") == 0);
|
||||||
|
munit_assert_true(mystrlen("333") == 3);
|
||||||
|
munit_assert_true(mystrlen("helloworld") == 10);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MunitResult
|
||||||
|
test_mystr_idx(const MunitParameter params[], void * data)
|
||||||
|
{
|
||||||
|
munit_assert_true(mystr_idx("", "") == 0);
|
||||||
|
munit_assert_true(mystr_idx("h", "h") == 0);
|
||||||
|
munit_assert_true(mystr_idx("ah", "h") == 1);
|
||||||
|
munit_assert_true(mystr_idx("ah", "hh") == -1);
|
||||||
|
munit_assert_true(mystr_idx("ahh", "hh") == 1);
|
||||||
|
char *cap = "London is the capital of Great Britan";
|
||||||
|
munit_assert_true(mystr_idx(cap, "python") == -1);
|
||||||
|
munit_assert_true(mystr_idx(cap, "London") == 0);
|
||||||
|
munit_assert_true(mystr_idx(cap, "o") == 1);
|
||||||
|
munit_assert_true(mystr_idx(cap, "is") == 7);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MunitResult
|
||||||
|
test_mystr_idx_largestr(const MunitParameter params[], void * data)
|
||||||
|
{
|
||||||
|
munit_assert_true(mystr_idx("", "LARGE STRING") == -1);
|
||||||
|
munit_assert_true(mystr_idx("ARGE_STRING", "LARGE STRING") == -1);
|
||||||
|
munit_assert_true(mystr_idx("ARGE STRING", "LARGE STRING") == -1);
|
||||||
|
munit_assert_true(mystr_idx("RGE STRING", "LARGE STRING") == -1);
|
||||||
|
return MUNIT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_ITEM(func) {#func, func, NULL, NULL, MUNIT_TEST_OPTION_NONE }
|
||||||
|
static MunitTest test_suite_tests[] = {
|
||||||
|
TEST_ITEM(test_mystrlen),
|
||||||
|
|
||||||
|
TEST_ITEM(test_mystr_idx),
|
||||||
|
TEST_ITEM(test_mystr_idx_largestr),
|
||||||
|
//TEST_ITEM(test_pvector_init),
|
||||||
|
|
||||||
|
{ NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const MunitSuite test_suite = {
|
||||||
|
(char *) "",
|
||||||
|
test_suite_tests,
|
||||||
|
NULL,
|
||||||
|
1,
|
||||||
|
MUNIT_SUITE_OPTION_NONE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, const char *argv[])
|
||||||
|
{
|
||||||
|
munit_suite_main(&test_suite, (void *) "string library test", argc, (char * const*) argv);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user