forked from vieter-v/libvieter
				
			test: add structure & framework for writing tests
							parent
							
								
									3da95a63fb
								
							
						
					
					
						commit
						c018d8d86c
					
				
							
								
								
									
										34
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										34
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -2,12 +2,18 @@ LIB_FILENAME ?= libvieter.a
 | 
			
		|||
 | 
			
		||||
BUILD_DIR ?= build
 | 
			
		||||
SRC_DIR ?= src
 | 
			
		||||
TEST_DIR ?= test
 | 
			
		||||
INC_DIRS ?= include
 | 
			
		||||
 | 
			
		||||
SRCS != find '$(SRC_DIR)' -iname '*.c'
 | 
			
		||||
SRCS_H != find $(INC_DIRS) -iname '*.h'
 | 
			
		||||
SRCS_TEST != find '$(TEST_DIR)' -iname '*.c'
 | 
			
		||||
 | 
			
		||||
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
 | 
			
		||||
DEPS := $(SRCS:%=$(BUILD_DIR)/%.d)
 | 
			
		||||
OBJS_TEST := $(SRCS_TEST:%=$(BUILD_DIR)/%.o)
 | 
			
		||||
DEPS := $(SRCS:%=$(BUILD_DIR)/%.d) $(SRCS_TEST:%=$(BUILD_DIR)/%.d)
 | 
			
		||||
 | 
			
		||||
BINS_TEST := $(OBJS_TEST:%.c.o=%)
 | 
			
		||||
 | 
			
		||||
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +22,7 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS))
 | 
			
		|||
#  object file is also recompiled if only a header is changed.
 | 
			
		||||
# -MP: generate a dummy target for every header file (according to the  docs it
 | 
			
		||||
#  prevents some errors when removing header files)
 | 
			
		||||
CFLAGS ?= $(INC_FLAGS) -O3 -MMD -MP -Wall -Werror -Wextra
 | 
			
		||||
CFLAGS ?= $(INC_FLAGS) -MMD -MP -Wall -Werror -Wextra
 | 
			
		||||
 | 
			
		||||
.PHONY: all
 | 
			
		||||
all: vieter
 | 
			
		||||
| 
						 | 
				
			
			@ -28,19 +34,37 @@ vieter: $(BUILD_DIR)/$(LIB_FILENAME)
 | 
			
		|||
$(BUILD_DIR)/$(LIB_FILENAME): $(OBJS)
 | 
			
		||||
	ar -rcs $@ $(OBJS)
 | 
			
		||||
 | 
			
		||||
$(BUILD_DIR)/%.c.o: %.c
 | 
			
		||||
$(BUILD_DIR)/$(SRC_DIR)/%.c.o: $(SRC_DIR)/%.c
 | 
			
		||||
	mkdir -p $(dir $@)
 | 
			
		||||
	$(CC) $(CFLAGS) -c $< -o $@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# =====TESTING=====
 | 
			
		||||
.PHONY: test
 | 
			
		||||
test: build-test
 | 
			
		||||
	@ $(foreach bin,$(BINS_TEST),./$(bin);)
 | 
			
		||||
 | 
			
		||||
.PHONY: build-test
 | 
			
		||||
build-test: $(BINS_TEST)
 | 
			
		||||
 | 
			
		||||
# For simplicity, we link every object file to each of the test files. This
 | 
			
		||||
# might be changed later if this starts to become too slow.
 | 
			
		||||
$(BINS_TEST): %: %.c.o $(OBJS)
 | 
			
		||||
	$(CC) $^ -o $@
 | 
			
		||||
 | 
			
		||||
# Each test includes the test directory, which contains the acutest header file
 | 
			
		||||
$(BUILD_DIR)/$(TEST_DIR)/%.c.o: $(TEST_DIR)/%.c
 | 
			
		||||
	mkdir -p $(dir $@)
 | 
			
		||||
	$(CC) $(CFLAGS) -I$(TEST_DIR) -c $< -o $@
 | 
			
		||||
 | 
			
		||||
# =====MAINTENANCE=====
 | 
			
		||||
.PHONY: lint
 | 
			
		||||
lint:
 | 
			
		||||
	clang-format -n --Werror $(SRCS) $(SRCS_H)
 | 
			
		||||
	clang-format -n --Werror $(SRCS) $(SRCS_H) $(SRCS_TEST)
 | 
			
		||||
 | 
			
		||||
.PHONY: fmt
 | 
			
		||||
fmt:
 | 
			
		||||
	clang-format -i $(SRCS) $(SRCS_H)
 | 
			
		||||
	clang-format -i $(SRCS) $(SRCS_H) $(SRCS_TEST)
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
clean:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								README.md
								
								
								
								
							
							
						
						
									
										16
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -13,6 +13,21 @@ Currently it contains the following:
 | 
			
		|||
 | 
			
		||||
## Development
 | 
			
		||||
 | 
			
		||||
### Compilation
 | 
			
		||||
 | 
			
		||||
Everything is handled by the provided Makefile. To compile the static library,
 | 
			
		||||
simply run `make`.
 | 
			
		||||
 | 
			
		||||
### Testing
 | 
			
		||||
 | 
			
		||||
This library uses [Acutest](https://github.com/mity/acutest) for its tests.
 | 
			
		||||
Tests should be placed in the `test` subdirectory, further divided into
 | 
			
		||||
directories that correspond those in `src`. Test files should begin with
 | 
			
		||||
`test_`, and their format should follow the expected format for Acutest.
 | 
			
		||||
 | 
			
		||||
To run the tests, simply run `make test`. If you wish to only run a specific
 | 
			
		||||
test binary, you can find them in `build/test`.
 | 
			
		||||
 | 
			
		||||
### `compile_commands.json`
 | 
			
		||||
 | 
			
		||||
Clangd requires a `compile_commands.json` to function properly. You can
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +36,7 @@ generate it using [bear](https://github.com/rizsotto/Bear):
 | 
			
		|||
```sh
 | 
			
		||||
make clean
 | 
			
		||||
bear -- make
 | 
			
		||||
bear --append -- make build-test
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This will create a `compile_commands.json` file in the current directory.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,69 @@
 | 
			
		|||
#include "acutest.h"
 | 
			
		||||
#include "vieter_cron.h"
 | 
			
		||||
 | 
			
		||||
void test_tutorial(void) {
 | 
			
		||||
  void *mem;
 | 
			
		||||
 | 
			
		||||
  mem = malloc(10);
 | 
			
		||||
  TEST_CHECK(mem != NULL);
 | 
			
		||||
 | 
			
		||||
  mem = realloc(mem, 20);
 | 
			
		||||
  TEST_CHECK(mem != NULL);
 | 
			
		||||
 | 
			
		||||
  free(mem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_fail(void) {
 | 
			
		||||
  int a, b;
 | 
			
		||||
 | 
			
		||||
  /* This condition is designed to fail so you can see what the failed test
 | 
			
		||||
   * output looks like. */
 | 
			
		||||
  a = 1;
 | 
			
		||||
  b = 2;
 | 
			
		||||
  TEST_CHECK(a + b == 5);
 | 
			
		||||
 | 
			
		||||
  /* Here is TEST_CHECK_ in action. */
 | 
			
		||||
  TEST_CHECK_(a + b == 5, "%d + %d == 5", a, b);
 | 
			
		||||
 | 
			
		||||
  /* We may also show more information about the failure. */
 | 
			
		||||
  if (!TEST_CHECK(a + b == 5)) {
 | 
			
		||||
    TEST_MSG("a: %d", a);
 | 
			
		||||
    TEST_MSG("b: %d", b);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* The macro TEST_MSG() only outputs something when the preceding
 | 
			
		||||
   * condition fails, so we can avoid the 'if' statement. */
 | 
			
		||||
  TEST_CHECK(a + b == 3);
 | 
			
		||||
  TEST_MSG("a: %d", a);
 | 
			
		||||
  TEST_MSG("b: %d", b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void helper(void) {
 | 
			
		||||
  /* Kill the current test with a condition which is never true. */
 | 
			
		||||
  TEST_ASSERT(1 == 2);
 | 
			
		||||
 | 
			
		||||
  /* This never happens because the test is aborted above. */
 | 
			
		||||
  TEST_CHECK(1 + 2 == 2 + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_abort(void) {
 | 
			
		||||
  helper();
 | 
			
		||||
 | 
			
		||||
  /* This test never happens because the test is aborted inside the helper()
 | 
			
		||||
   * function. */
 | 
			
		||||
  TEST_CHECK(1 * 2 == 2 * 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_crash(void) {
 | 
			
		||||
  int *invalid = ((int *)NULL) + 0xdeadbeef;
 | 
			
		||||
 | 
			
		||||
  *invalid = 42;
 | 
			
		||||
  TEST_CHECK_(1 == 1, "This should never execute, due to a write into "
 | 
			
		||||
                      "an invalid address.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST_LIST = {{"tutorial", test_tutorial},
 | 
			
		||||
             {"fail", test_fail},
 | 
			
		||||
             {"abort", test_abort},
 | 
			
		||||
             {"crash", test_crash},
 | 
			
		||||
             {NULL, NULL}};
 | 
			
		||||
		Loading…
	
		Reference in New Issue