So I am trying to learn how to use the library check with a simple example on MacOS 11.6.1. For this I copied the code of Merlijn Sebrechts of the following question: Using C unit testing framework Check without Autotools?
#include <check.h>
START_TEST (sanity_check)
{
fail_unless(5 == 5, "this should succeed");
fail_unless(6 == 5, "this should fail");
ck_assert_str_eq("asa", "asasdfasdf");
}
END_TEST
int main(void)
{
Suite *s1 = suite_create("Core");
TCase *tc1_1 = tcase_create("Core");
SRunner *sr = srunner_create(s1);
int nf;
suite_add_tcase(s1, tc1_1);
tcase_add_test(tc1_1, sanity_check);
srunner_run_all(sr, CK_ENV);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return nf == 0 ? 0 : 1;
}
When I execute the command in the terminal, I get the following error message:
$ gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
ld: library not found for -lcheck_pic
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I check that the library check is installed by compiling the file following file (test2.c
) with gcc test2.c
and did not get any error message. From this I assumed that the library is indeed installed
#include <check.h>
int main(){
int a;
return 0;
}
What am I doing wrong?
EDIT
Ok following the comment, I removed calling most of the libraries and run the following command:
gcc test.c -Wall -o test -lcheck
$ ./test
Running suite(s): Core
0%: Checks: 1, Failures: 1, Errors: 0
test.c:6:F:Core:sanity_check:0: this should fail
Is it correct? And I have to say frankly: I do not understand what the code is doing?
EDIT 2
After the new comment of Jason, I had to serially removed several libraries in order not get an error by build (namely lcheck_pic
, lsubunit
, lrt
:
$ gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
ld: library not found for -lcheck_pic
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lm -lsubunit
ld: library not found for -lsubunit
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lrt -lm -lsubunit
ld: library not found for -lrt
clang: error: linker command failed with exit code 1 (use -v to see invocation)
-v to see invocation)
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lm
... build successful ...
CodePudding user response:
The build solution was to remove -lcheck_pic
.
Just expanding on the comment section...
Expecting 1 success and 1 failure... Is this correct?
Yes, that is correct. This is just an example of how to set up testing. In reality, you would never actually check 5 == 6
. You would run portions of your program and check the state of whatever you are testing. Also, you should not need that #include <check.h>
in the actual program code.
So think of something simple like an is_even
function. You could do:
fail_unless(is_even(6), "failure");
This should not fail if your is_even
function is correct. That may seem silly, but if later down the road you change the is_even
function (or maybe a dependency of that function, this test may fail. That will let you know you need to review your last set of changes. You are essentially setting up automatic testing so you know right away if you broke something in your program.
It should also be noted that fail_unless
has been deprecated. You should be using the functions provided here.
For more examples, here is a link to the test directory of a project of mine that uses libcheck
.
Expansion on comment discussion
I linked to the tests directory in hopes that you would look at the C files in there... an example of how and why you would use check
. For example, one of the more simple functions of the library is called sgetline
which just means "safe getline". It will retrieve a single line from a file that can have either Linux (\n
) or Windows (\r\n
) line terminators and allocate a line buffer for you. Allow me to walk you through one of the tests for that function (from check_sgetline.c):
START_TEST(test_safegetline_long)
{
_file = fopen("test_long.txt", "r");
if (!_file) {
perror("test_long.txt");
exit(EXIT_FAILURE);
}
int ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_ptr_nonnull(buf);
ck_assert_str_eq(buf, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
ck_assert_uint_eq(linelen, strlen("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
ck_assert_int_eq(ret, 0);
ck_assert_uint_gt(buflen, BUFFER_FACTOR);
ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_int_eq(ret, EOF);
}
END_TEST
First, I open the file (test_long.txt is in that tests directory). Then, that FILE*
is sent to sgetline
along with a buffer, a buffer length and a line length (globals). sgetline
can (and in this case will) modify these variables. The whole point of testing (and check
) is to prove that my program does exactly what I "expect." In order to prove to myself that sgetline
works as expected, I use the ck_*
functions provided by check
. So, here is what the checks are doing in English:
I would not EXPECT the buffer to be NULL as sgetline
should be allocating it for me:
ck_assert_ptr_nonnull(buf);
I EXPECT this silly long string to be placed into buf
:
ck_assert_str_eq(buf, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
I EXPECT linelen
to be equal to the length of the string that was placed in buf
:
ck_assert_uint_eq(linelen, strlen("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
I EXPECT the return value of sgetline
to be 0 (meaning success in this case):
ck_assert_int_eq(ret, 0);
I EXPECT the buflen
to increase beyond a constant in the library BUFFER_FACTOR
because the line is quite long (NOTE the _gt
means greater than):
ck_assert_uint_gt(buflen, BUFFER_FACTOR);
Run sgetline
again which should read the next line out of the file. I know that the file only has one line to begin with, so I EXPECT sgetline
to return EOF
.
ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_int_eq(ret, EOF);
If any of these checks fail, I know I have a bug in sgetline
.