Attention is currently required from: Anastasia Klimchuk.

Evan Benn has uploaded this change for review.

View Change

tests: Detect gcov file io and unmock io functions

Code coverage writes data to disk atexit of the program. We need to
unmock the file io at this point so that the data is really written.

BUG=b:187647884
BRANCH=None
TEST=meson test
TEST=ninja coverage

Change-Id: If06053ecd78e886c8f7fc55813f4b5635be78c6b
Signed-off-by: Evan Benn <evanbenn@chromium.org>
---
M Documentation/building.md
M tests/io_mock.h
M tests/tests.c
M tests/wraps.h
4 files changed, 78 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/flashrom refs/changes/66/69266/1
diff --git a/Documentation/building.md b/Documentation/building.md
index aabb45b..0e66f29 100644
--- a/Documentation/building.md
+++ b/Documentation/building.md
@@ -48,6 +48,13 @@
ninja -C builddir test
```

+### Run unit tests with code coverage
+```
+meson setup buildcov -Db_coverage=true
+ninja -C buildcov test
+ninja -C buildcov coverage
+```
+
## System specific information
### Ubuntu / Debian (Linux)
* __linux-headers__ are version specific
diff --git a/tests/io_mock.h b/tests/io_mock.h
index 8e6ecb9..ef79a61 100644
--- a/tests/io_mock.h
+++ b/tests/io_mock.h
@@ -107,8 +107,10 @@
FILE* (*fopen)(void *state, const char *pathname, const char *mode);
char* (*fgets)(void *state, char *buf, int len, FILE *fp);
size_t (*fread)(void *state, void *buf, size_t size, size_t len, FILE *fp);
+ size_t (*fwrite)(void *state, const void *buf, size_t size, size_t len, FILE *fp);
int (*fprintf)(void *state, FILE *fp, const char *fmt, va_list args);
int (*fclose)(void *state, FILE *fp);
+ FILE *(*fdopen)(void*state, int fd, const char *mode);

/*
* An alternative to custom open mock. A test can either register its
diff --git a/tests/tests.c b/tests/tests.c
index 530d5a7..1b5b6d6 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -18,10 +18,40 @@
#include "tests.h"
#include "wraps.h"

+#include "fcntl.h"
+#include <ctype.h>
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

+
+static int unwrap_open(void *state, const char *pathname, int flags, mode_t mode) {
+ LOG_ME;
+ (void)state;
+ return __real_open(pathname, flags, mode);
+}
+
+static FILE *unwrap_fdopen(void *state, int fd, const char *mode) {
+ LOG_ME;
+ (void)state;
+ return __real_fdopen(fd, mode);
+}
+
+static size_t unwrap_fwrite(void *state, const void *ptr, size_t size, size_t nmemb, FILE *fp) {
+ LOG_ME;
+ (void)state;
+ return __real_fwrite(ptr, size, nmemb, fp);
+}
+
+// Mock ios that defer to the real io functions.
+// These exist so that code coverage can print to real files on disk.
+struct io_mock real_io_mock = {
+ .open = unwrap_open,
+ .fwrite = unwrap_fwrite,
+ .fdopen = unwrap_fdopen,
+};
+
void *not_null(void)
{
return (void *)MOCK_FD;
@@ -75,8 +105,22 @@
return (uint8_t)mock();
}

+static int check_suffix(const char* string, const char* suffix) {
+ int len_l = strlen(string);
+ int len_r = strlen(suffix);
+ if (len_l > len_r) {
+ return strcmp(string + len_l - len_r, suffix);
+ }
+ return 1;
+}
+
static int mock_open(const char *pathname, int flags, mode_t mode)
{
+ // We detect code coverage writing the log files and defer to real io functions.
+ if (!check_suffix(pathname, ".gcda")) {
+ io_mock_register(&real_io_mock);
+ }
+
if (get_io() && get_io()->open)
return get_io()->open(get_io()->state, pathname, flags, mode);

@@ -163,6 +207,8 @@
FILE *__wrap_fdopen(int fd, const char *mode)
{
LOG_ME;
+ if (get_io() && get_io()->fdopen)
+ return get_io()->fdopen(get_io()->state, fd, mode);
return not_null();
}

@@ -241,6 +287,8 @@
size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
{
LOG_ME;
+ if (get_io() && get_io()->fwrite)
+ return get_io()->fwrite(get_io()->state, ptr, size, nmemb, fp);
return nmemb;
}

diff --git a/tests/wraps.h b/tests/wraps.h
index 59cd6ff..44f78f7 100644
--- a/tests/wraps.h
+++ b/tests/wraps.h
@@ -29,6 +29,7 @@
void __wrap_sio_write(uint16_t port, uint8_t reg, uint8_t data);
uint8_t __wrap_sio_read(uint16_t port, uint8_t reg);
int __wrap_open(const char *pathname, int flags, mode_t mode);
+int __real_open(const char *pathname, int flags, mode_t mode);
int __wrap_open64(const char *pathname, int flags, mode_t mode);
int __wrap___open64_2(const char *pathname, int flags, mode_t mode);
int __wrap_ioctl(int fd, unsigned long int request, ...);
@@ -37,6 +38,7 @@
FILE *__wrap_fopen(const char *pathname, const char *mode);
FILE *__wrap_fopen64(const char *pathname, const char *mode);
FILE *__wrap_fdopen(int fd, const char *mode);
+FILE *__real_fdopen(int fd, const char *mode);
int __wrap_stat(const char *path, void *buf);
int __wrap_stat64(const char *path, void *buf);
int __wrap___xstat(const char *path, void *buf);
@@ -49,6 +51,7 @@
char *__wrap___fgets_chk(char *buf, int len, FILE *fp);
size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *fp);
size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
+size_t __real_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
int __wrap_fflush(FILE *fp);
int __wrap_fileno(FILE *fp);
int __wrap_fsync(int fd);

To view, visit change 69266. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: If06053ecd78e886c8f7fc55813f4b5635be78c6b
Gerrit-Change-Number: 69266
Gerrit-PatchSet: 1
Gerrit-Owner: Evan Benn <evanbenn@google.com>
Gerrit-Reviewer: Anastasia Klimchuk <aklm@chromium.org>
Gerrit-Attention: Anastasia Klimchuk <aklm@chromium.org>
Gerrit-MessageType: newchange