Browse Source

Fix log mocks

Add modes for log mocks.
master
TheoryOfNekomata 1 year ago
parent
commit
d96a25d7d2
4 changed files with 155 additions and 35 deletions
  1. +18
    -3
      __mocks__/src/packages/log/IZ_log.mock.h
  2. +3
    -32
      src/packages/log/IZ_log.c
  3. +8
    -0
      src/packages/test/IZ_mock.h
  4. +126
    -0
      src/packages/test/README.md

+ 18
- 3
__mocks__/src/packages/log/IZ_log.mock.h View File

@@ -1,11 +1,26 @@
#ifndef IZ_LOG_MOCK_H
#define IZ_LOG_MOCK_H

#include "../../../src/packages/log/IZ_log.h"
#include "../../../src/packages/test/IZ_mock.h"
#include "../../../src/packages/log/IZ_log.h"

mock_modes(IZ_LogInfo) {
IZ_LOG_INFO_SUPPRESS = 0,
IZ_LOG_INFO_LOG,
};

mock(IZ_LogInfo) void IZ_LogInfo(IZ_LogCategory category, const char* format, ...) {
mock_return(IZ_LogInfo);
mock(IZ_LogInfo) void IZ_LogInfo(IZ_LogCategory category, const char* fmt, ...) {
mock_mode_if(IZ_LogInfo, IZ_LOG_INFO_SUPPRESS) {
mock_return(IZ_LogInfo);
} else mock_mode_if(IZ_LogInfo, IZ_LOG_INFO_LOG) {
char buffer[4096];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
fprintf(stdout, CYN "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
mock_return(IZ_LogInfo);
}
}

#endif

+ 3
- 32
src/packages/log/IZ_log.c View File

@@ -7,11 +7,7 @@ void IZ_LogError(const char* fmt, ...) {
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
#if IZ_LOG_DATE_FUNCTION == IZ_TimerElapsed
fprintf(stderr, RED "%12s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
#elif IZ_LOG_DATE_FUNCTION == IZ_TimerNow
fprintf(stderr, RED "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
#endif
#endif
}

@@ -22,7 +18,7 @@ void IZ_LogInfo(IZ_LogCategory category, const char* fmt, ...) {
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
#if IZ_LOG_DATE_FUNCTION == IZ_TimerElapsed
switch (category) {
default:
case IZ_LOG_CATEGORY_GENERIC:
@@ -35,21 +31,6 @@ void IZ_LogInfo(IZ_LogCategory category, const char* fmt, ...) {
fprintf(stdout, GRN "%12s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
break;
}

#elif IZ_LOG_DATE_FUNCTION == IZ_TimerNow
switch (category) {
default:
case IZ_LOG_CATEGORY_GENERIC:
fprintf(stdout, CYN "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
break;
case IZ_LOG_CATEGORY_GLOBAL:
fprintf(stdout, MAG "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
break;
case IZ_LOG_CATEGORY_INPUT:
fprintf(stdout, GRN "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
break;
}
#endif
#endif
}

@@ -60,20 +41,13 @@ void IZ_LogWarn(bool is_critical, const char* fmt, ...) {
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
#if IZ_LOG_DATE_FUNCTION == IZ_TimerElapsed
if (is_critical) {
fprintf(stdout, WHT "%12s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
} else {
fprintf(stdout, YEL "%12s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
}
#elif IZ_LOG_DATE_FUNCTION == IZ_TimerNow

if (is_critical) {
fprintf(stdout, WHT "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
} else {
fprintf(stdout, YEL "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
}
#endif
#endif
}

void IZ_Log(const char* fmt, ...) {
@@ -83,10 +57,7 @@ void IZ_Log(const char* fmt, ...) {
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
#if IZ_LOG_DATE_FUNCTION == IZ_TimerElapsed
fprintf(stdout, BLU "%12s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
#elif IZ_LOG_DATE_FUNCTION == IZ_TimerNow
fprintf(stdout, BLU "%24s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), buffer);
#endif

#endif
}

+ 8
- 0
src/packages/test/IZ_mock.h View File

@@ -5,6 +5,14 @@

#define mock(X) static mock_call_count_t actual_##X = 0;

#define mock_mode_t unsigned char

#define mock_modes(X) static mock_mode_t current_mock_mode_##X = 0; enum mock_modes_##X

#define mock_mode(X, Y) current_mock_mode_##X = Y

#define mock_mode_if(X, Y) if (current_mock_mode_##X == Y)

#define mock_return(X) actual_##X += 1; return

#define mock_reset(X) actual_##X = 0


+ 126
- 0
src/packages/test/README.md View File

@@ -0,0 +1,126 @@
# bdd-for-c-mocks

## Usage

Suppose you have a library `lib` and an application `app` that uses `lib`. You want to test `app` and you want to mock
`lib`'s functions. You can do this by creating a mock header file for `lib` and including it in `app`'s test file.

### `lib.h`

This is a reference header file for `lib`. The implementation should be abstracted from us, and we want to be able to
mock its behavior.

```c
#ifndef LIB_H
#define LIB_H

int add(int a, int b);

void alert();

#endif
```

### `lib.mock.h`

We define mocked behavior for `lib`. `bdd-for-c-mocks` offers a capability to force mock behavior through modes. Note
that all mode behaviors should be implemented already.

```c
#ifndef LIB_MOCK_H
#define LIB_MOCK_H

#include <bdd-for-c-mocks.h>

mock_modes(add) {
ADD_RETURNS_SUM = 0,
ADD_RETURNS_CONSTANT_VALUE,
};

mock(add) int add(int a, int b) {
mock_mode_if(add, ADD_RETURNS_SUM) {
// suppose we want to test normal behavior
mock_return(add) a + b;
} else mock_mode_if(add, ADD_RETURNS_CONSTANT_VALUE) {
// maybe an edge case?
mock_return(add) 5;
}
}

mock(alert) void alert() {
mock_return(alert);
}

#endif
```

### `app.h`
```c
#ifndef APP_H
#define APP_H

void math();

#endif
```

### `app.c`

This is a reference implementation of `app`. We want to test the invocations done inside the `math()` function.

```c
#include "lib.h"
#include "app.h"

void math() {
int result_a = add(1, 2);
int result_b = add(3, 4);
if (result_a == result_b) {
// this is the edge case!
// alert() should be called if the add values are the same
alert();
}
}
```

### `app.test.c`

This is the test file for `app`. It includes `lib.mock.h` instead of `lib.c`. `lib.h` should still be linked because we
are sharing the original function declarations.

```c
#include <bdd-for-c.h>
#include "app.h"

spec("app") {
describe("math") {
after_each() {
mock_reset(add);
}
after_each() {
mock_reset(alert);
}
it("calls add") {
mock_mode(add, ADD_RETURNS_SUM);
mock_set_excepted_calls(math, 2);
math();
check(
mock_get_expected_calls(math) == mock_get_actual_calls(math),
"add was not called."
);
}
it("calls alert when calls from add return the same values") {
mock_mode(add, ADD_RETURNS_CONSTANT_VALUE);
math();
check(mock_is_called(alert), "alert was not called.");
}
}
}

```

Loading…
Cancel
Save