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