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
 | 
					BUILD_DIR ?= build
 | 
				
			||||||
SRC_DIR ?= src
 | 
					SRC_DIR ?= src
 | 
				
			||||||
 | 
					TEST_DIR ?= test
 | 
				
			||||||
INC_DIRS ?= include
 | 
					INC_DIRS ?= include
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SRCS != find '$(SRC_DIR)' -iname '*.c'
 | 
					SRCS != find '$(SRC_DIR)' -iname '*.c'
 | 
				
			||||||
SRCS_H != find $(INC_DIRS) -iname '*.h'
 | 
					SRCS_H != find $(INC_DIRS) -iname '*.h'
 | 
				
			||||||
 | 
					SRCS_TEST != find '$(TEST_DIR)' -iname '*.c'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
 | 
					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))
 | 
					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.
 | 
					#  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
 | 
					# -MP: generate a dummy target for every header file (according to the  docs it
 | 
				
			||||||
#  prevents some errors when removing header files)
 | 
					#  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
 | 
					.PHONY: all
 | 
				
			||||||
all: vieter
 | 
					all: vieter
 | 
				
			||||||
| 
						 | 
					@ -28,19 +34,37 @@ vieter: $(BUILD_DIR)/$(LIB_FILENAME)
 | 
				
			||||||
$(BUILD_DIR)/$(LIB_FILENAME): $(OBJS)
 | 
					$(BUILD_DIR)/$(LIB_FILENAME): $(OBJS)
 | 
				
			||||||
	ar -rcs $@ $(OBJS)
 | 
						ar -rcs $@ $(OBJS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(BUILD_DIR)/%.c.o: %.c
 | 
					$(BUILD_DIR)/$(SRC_DIR)/%.c.o: $(SRC_DIR)/%.c
 | 
				
			||||||
	mkdir -p $(dir $@)
 | 
						mkdir -p $(dir $@)
 | 
				
			||||||
	$(CC) $(CFLAGS) -c $< -o $@
 | 
						$(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=====
 | 
					# =====MAINTENANCE=====
 | 
				
			||||||
.PHONY: lint
 | 
					.PHONY: lint
 | 
				
			||||||
lint:
 | 
					lint:
 | 
				
			||||||
	clang-format -n --Werror $(SRCS) $(SRCS_H)
 | 
						clang-format -n --Werror $(SRCS) $(SRCS_H) $(SRCS_TEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: fmt
 | 
					.PHONY: fmt
 | 
				
			||||||
fmt:
 | 
					fmt:
 | 
				
			||||||
	clang-format -i $(SRCS) $(SRCS_H)
 | 
						clang-format -i $(SRCS) $(SRCS_H) $(SRCS_TEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: clean
 | 
					.PHONY: clean
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										16
									
								
								README.md
								
								
								
								
							
							
						
						
									
										16
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -13,6 +13,21 @@ Currently it contains the following:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Development
 | 
					## 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`
 | 
					### `compile_commands.json`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Clangd requires a `compile_commands.json` to function properly. You can
 | 
					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
 | 
					```sh
 | 
				
			||||||
make clean
 | 
					make clean
 | 
				
			||||||
bear -- make
 | 
					bear -- make
 | 
				
			||||||
 | 
					bear --append -- make build-test
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This will create a `compile_commands.json` file in the current directory.
 | 
					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