Merge pull request #690 from fredizzimo/unit_test
Add Unit Testing support
This commit is contained in:
commit
4fd5ac8326
|
@ -7,3 +7,6 @@
|
||||||
[submodule "lib/ugfx"]
|
[submodule "lib/ugfx"]
|
||||||
path = lib/ugfx
|
path = lib/ugfx
|
||||||
url = https://bitbucket.org/Tectu/ugfx
|
url = https://bitbucket.org/Tectu/ugfx
|
||||||
|
[submodule "lib/googletest"]
|
||||||
|
path = lib/googletest
|
||||||
|
url = https://github.com/google/googletest
|
||||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -10,7 +10,10 @@ env:
|
||||||
global:
|
global:
|
||||||
- secure: vBTSL34BDPxDilKUuTXqU4CJ26Pv5hogD2nghatkxSQkI1/jbdnLj/DQdPUrMJFDIY6TK3AltsBx72MaMsLQ1JO/Ou24IeHINHXzUC1FlS9yQa48cpxnhX5kzXNyGs3oa0qaFbvnr7RgYRWtmD52n4bIZuSuW+xpBv05x2OCizdT2ZonH33nATaHGFasxROm4qYZ241VfzcUv766V6RVHgL4x9V08warugs+RENVkfzxxwhk3NmkrISabze0gSVJLHBPHxroZC6EUcf/ocobcuDrCwFqtEt90i7pNIAFUE7gZsN2uE75LmpzAWin21G7lLPcPL2k4FJVd8an1HiP2WmscJU6U89fOfMb2viObnKcCzebozBCmKGtHEuXZo9FcReOx49AnQSpmESJGs+q2dL/FApkTjQiyT4J6O5dJpoww0/r57Wx0cmmqjETKBb5rSgXM51Etk3wO09mvcPHsEwrT7qH8r9XWdyCDoEn7FCLX3/LYnf/D4SmZ633YPl5gv3v9XEwxR5+04akjgnvWDSNIaDbWBdxHNb7l4pMc+WR1bwCyMyA7KXj0RrftEGOrm9ZRLe6BkbT4cycA+j77nbPOMcyZChliV9pPQos+4TOJoTzcK2L8yWVoY409aDNVuAjdP6Yum0R2maBGl/etLmIMpJC35C5/lZ+dUNjJAM=
|
- secure: vBTSL34BDPxDilKUuTXqU4CJ26Pv5hogD2nghatkxSQkI1/jbdnLj/DQdPUrMJFDIY6TK3AltsBx72MaMsLQ1JO/Ou24IeHINHXzUC1FlS9yQa48cpxnhX5kzXNyGs3oa0qaFbvnr7RgYRWtmD52n4bIZuSuW+xpBv05x2OCizdT2ZonH33nATaHGFasxROm4qYZ241VfzcUv766V6RVHgL4x9V08warugs+RENVkfzxxwhk3NmkrISabze0gSVJLHBPHxroZC6EUcf/ocobcuDrCwFqtEt90i7pNIAFUE7gZsN2uE75LmpzAWin21G7lLPcPL2k4FJVd8an1HiP2WmscJU6U89fOfMb2viObnKcCzebozBCmKGtHEuXZo9FcReOx49AnQSpmESJGs+q2dL/FApkTjQiyT4J6O5dJpoww0/r57Wx0cmmqjETKBb5rSgXM51Etk3wO09mvcPHsEwrT7qH8r9XWdyCDoEn7FCLX3/LYnf/D4SmZ633YPl5gv3v9XEwxR5+04akjgnvWDSNIaDbWBdxHNb7l4pMc+WR1bwCyMyA7KXj0RrftEGOrm9ZRLe6BkbT4cycA+j77nbPOMcyZChliV9pPQos+4TOJoTzcK2L8yWVoY409aDNVuAjdP6Yum0R2maBGl/etLmIMpJC35C5/lZ+dUNjJAM=
|
||||||
script:
|
script:
|
||||||
- make all-keyboards AUTOGEN=true
|
- make $TARGET AUTOGEN=$AUTOGEN
|
||||||
|
env:
|
||||||
|
- TARGET=all-keyboards AUTOGEN=true
|
||||||
|
- TARGET=test AUTOGEN=false
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
|
@ -22,4 +25,7 @@ addons:
|
||||||
- binutils-arm-none-eabi
|
- binutils-arm-none-eabi
|
||||||
- libnewlib-arm-none-eabi
|
- libnewlib-arm-none-eabi
|
||||||
- diffutils
|
- diffutils
|
||||||
after_success: bash util/travis_compiled_push.sh
|
after_success:
|
||||||
|
if [ "$AUTOGEN" == "true" ]; then
|
||||||
|
bash util/travis_compiled_push.sh;
|
||||||
|
fi
|
||||||
|
|
71
Makefile
71
Makefile
|
@ -2,6 +2,10 @@ ifndef VERBOSE
|
||||||
.SILENT:
|
.SILENT:
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# Never run this makefile in parallel, as it could screw things up
|
||||||
|
# It won't affect the submakes, so you still get the speedup from specifying -jx
|
||||||
|
.NOTPARALLEL:
|
||||||
|
|
||||||
# Allow the silent with lower caps to work the same way as upper caps
|
# Allow the silent with lower caps to work the same way as upper caps
|
||||||
ifdef silent
|
ifdef silent
|
||||||
SILENT = $(silent)
|
SILENT = $(silent)
|
||||||
|
@ -28,6 +32,7 @@ ABS_ROOT_MAKEFILE := $(abspath $(ROOT_MAKEFILE))
|
||||||
ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE))
|
ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE))
|
||||||
ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE))
|
ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE))
|
||||||
STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR))
|
STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR))
|
||||||
|
TEST_DIR := $(ROOT_DIR)/.build/test
|
||||||
|
|
||||||
MAKEFILE_INCLUDED=yes
|
MAKEFILE_INCLUDED=yes
|
||||||
|
|
||||||
|
@ -224,6 +229,8 @@ define PARSE_RULE
|
||||||
# PARSE_ALL_KEYBOARDS
|
# PARSE_ALL_KEYBOARDS
|
||||||
ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allkb),true)
|
ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,allkb),true)
|
||||||
$$(eval $$(call PARSE_ALL_KEYBOARDS))
|
$$(eval $$(call PARSE_ALL_KEYBOARDS))
|
||||||
|
else ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,test),true)
|
||||||
|
$$(eval $$(call PARSE_TEST))
|
||||||
# If the rule starts with the name of a known keyboard, then continue
|
# If the rule starts with the name of a known keyboard, then continue
|
||||||
# the parsing from PARSE_KEYBOARD
|
# the parsing from PARSE_KEYBOARD
|
||||||
else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(KEYBOARDS)),true)
|
else ifeq ($$(call TRY_TO_MATCH_RULE_FROM_LIST,$$(KEYBOARDS)),true)
|
||||||
|
@ -356,7 +363,6 @@ define PARSE_KEYMAP
|
||||||
MAKE_TARGET := $$(patsubst -%,%,$$(RULE))
|
MAKE_TARGET := $$(patsubst -%,%,$$(RULE))
|
||||||
# We need to generate an unique indentifer to append to the COMMANDS list
|
# We need to generate an unique indentifer to append to the COMMANDS list
|
||||||
COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB)_SUBPROJECT_$(CURRENT_SP)_KEYMAP_$$(CURRENT_KM)
|
COMMAND := COMMAND_KEYBOARD_$$(CURRENT_KB)_SUBPROJECT_$(CURRENT_SP)_KEYMAP_$$(CURRENT_KM)
|
||||||
COMMANDS += $$(COMMAND)
|
|
||||||
# If we are compiling a keyboard without a subproject, we want to display just the name
|
# If we are compiling a keyboard without a subproject, we want to display just the name
|
||||||
# of the keyboard, otherwise keyboard/subproject
|
# of the keyboard, otherwise keyboard/subproject
|
||||||
ifeq ($$(CURRENT_SP),)
|
ifeq ($$(CURRENT_SP),)
|
||||||
|
@ -368,13 +374,18 @@ define PARSE_KEYMAP
|
||||||
KB_SP := $(BOLD)$$(KB_SP)$(NO_COLOR)
|
KB_SP := $(BOLD)$$(KB_SP)$(NO_COLOR)
|
||||||
# Specify the variables that we are passing forward to submake
|
# Specify the variables that we are passing forward to submake
|
||||||
MAKE_VARS := KEYBOARD=$$(CURRENT_KB) SUBPROJECT=$$(CURRENT_SP) KEYMAP=$$(CURRENT_KM)
|
MAKE_VARS := KEYBOARD=$$(CURRENT_KB) SUBPROJECT=$$(CURRENT_SP) KEYMAP=$$(CURRENT_KM)
|
||||||
MAKE_VARS += VERBOSE=$(VERBOSE) COLOR=$(COLOR)
|
|
||||||
# And the first part of the make command
|
# And the first part of the make command
|
||||||
MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_keyboard.mk $$(MAKE_TARGET)
|
MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_keyboard.mk $$(MAKE_TARGET)
|
||||||
# The message to display
|
# The message to display
|
||||||
MAKE_MSG := $$(MSG_MAKE_KB)
|
MAKE_MSG := $$(MSG_MAKE_KB)
|
||||||
# We run the command differently, depending on if we want more output or not
|
# We run the command differently, depending on if we want more output or not
|
||||||
# The true version for silent output and the false version otherwise
|
# The true version for silent output and the false version otherwise
|
||||||
|
$$(eval $$(call BUILD))
|
||||||
|
endef
|
||||||
|
|
||||||
|
define BUILD
|
||||||
|
MAKE_VARS += VERBOSE=$(VERBOSE) COLOR=$(COLOR)
|
||||||
|
COMMANDS += $$(COMMAND)
|
||||||
COMMAND_true_$$(COMMAND) := \
|
COMMAND_true_$$(COMMAND) := \
|
||||||
printf "$$(MAKE_MSG)" | \
|
printf "$$(MAKE_MSG)" | \
|
||||||
$$(MAKE_MSG_FORMAT); \
|
$$(MAKE_MSG_FORMAT); \
|
||||||
|
@ -388,7 +399,10 @@ define PARSE_KEYMAP
|
||||||
fi;
|
fi;
|
||||||
COMMAND_false_$$(COMMAND) := \
|
COMMAND_false_$$(COMMAND) := \
|
||||||
printf "$$(MAKE_MSG)\n\n"; \
|
printf "$$(MAKE_MSG)\n\n"; \
|
||||||
$$(MAKE_CMD) $$(MAKE_VARS) SILENT=false;
|
$$(MAKE_CMD) $$(MAKE_VARS) SILENT=false; \
|
||||||
|
if [ $$$$? -gt 0 ]; \
|
||||||
|
then error_occured=1; \
|
||||||
|
fi;
|
||||||
endef
|
endef
|
||||||
|
|
||||||
# Just parse all the keymaps for a specifc keyboard
|
# Just parse all the keymaps for a specifc keyboard
|
||||||
|
@ -396,6 +410,41 @@ define PARSE_ALL_KEYMAPS
|
||||||
$$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYMAP,$$(KEYMAPS)))
|
$$(eval $$(call PARSE_ALL_IN_LIST,PARSE_KEYMAP,$$(KEYMAPS)))
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define BUILD_TEST
|
||||||
|
TEST_NAME := $1
|
||||||
|
MAKE_TARGET := $2
|
||||||
|
COMMAND := $1
|
||||||
|
MAKE_CMD := $$(MAKE) -r -R -C $(ROOT_DIR) -f build_test.mk $$(MAKE_TARGET)
|
||||||
|
MAKE_VARS := TEST=$$(TEST_NAME)
|
||||||
|
MAKE_MSG := $$(MSG_MAKE_TEST)
|
||||||
|
$$(eval $$(call BUILD))
|
||||||
|
ifneq ($$(MAKE_TARGET),clean)
|
||||||
|
TEST_EXECUTABLE := $$(TEST_DIR)/$$(TEST_NAME).elf
|
||||||
|
TESTS += $$(TEST_NAME)
|
||||||
|
TEST_MSG := $$(MSG_TEST)
|
||||||
|
$$(TEST_NAME)_COMMAND := \
|
||||||
|
printf "$$(TEST_MSG)\n"; \
|
||||||
|
$$(TEST_EXECUTABLE); \
|
||||||
|
if [ $$$$? -gt 0 ]; \
|
||||||
|
then error_occured=1; \
|
||||||
|
fi; \
|
||||||
|
printf "\n";
|
||||||
|
endif
|
||||||
|
endef
|
||||||
|
|
||||||
|
define PARSE_TEST
|
||||||
|
TESTS :=
|
||||||
|
TEST_NAME := $$(firstword $$(subst -, ,$$(RULE)))
|
||||||
|
TEST_TARGET := $$(subst $$(TEST_NAME),,$$(subst $$(TEST_NAME)-,,$$(RULE)))
|
||||||
|
ifeq ($$(TEST_NAME),all)
|
||||||
|
MATCHED_TESTS := $$(TEST_LIST)
|
||||||
|
else
|
||||||
|
MATCHED_TESTS := $$(foreach TEST,$$(TEST_LIST),$$(if $$(findstring $$(TEST_NAME),$$(TEST)),$$(TEST),))
|
||||||
|
endif
|
||||||
|
$$(foreach TEST,$$(MATCHED_TESTS),$$(eval $$(call BUILD_TEST,$$(TEST),$$(TEST_TARGET))))
|
||||||
|
endef
|
||||||
|
|
||||||
|
|
||||||
# Set the silent mode depending on if we are trying to compile multiple keyboards or not
|
# Set the silent mode depending on if we are trying to compile multiple keyboards or not
|
||||||
# By default it's on in that case, but it can be overriden by specifying silent=false
|
# By default it's on in that case, but it can be overriden by specifying silent=false
|
||||||
# from the command line
|
# from the command line
|
||||||
|
@ -440,12 +489,13 @@ $(SUBPROJECTS): %: %-allkm
|
||||||
# But we return the error code at the end, to trigger travis failures
|
# But we return the error code at the end, to trigger travis failures
|
||||||
+error_occured=0; \
|
+error_occured=0; \
|
||||||
$(foreach COMMAND,$(COMMANDS),$(RUN_COMMAND)) \
|
$(foreach COMMAND,$(COMMANDS),$(RUN_COMMAND)) \
|
||||||
if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi
|
if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi;\
|
||||||
|
$(foreach TEST,$(TESTS),$($(TEST)_COMMAND)) \
|
||||||
|
if [ $$error_occured -gt 0 ]; then printf "$(MSG_ERRORS)" & exit $$error_occured; fi;\
|
||||||
|
|
||||||
# All should compile everything
|
# All should compile everything
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: all-keyboards
|
all: all-keyboards test-all
|
||||||
|
|
||||||
# Define some shortcuts, mostly for compability with the old syntax
|
# Define some shortcuts, mostly for compability with the old syntax
|
||||||
.PHONY: all-keyboards
|
.PHONY: all-keyboards
|
||||||
|
@ -454,9 +504,16 @@ all-keyboards: allkb-allsp-allkm
|
||||||
.PHONY: all-keyboards-defaults
|
.PHONY: all-keyboards-defaults
|
||||||
all-keyboards-defaults: allkb-allsp-default
|
all-keyboards-defaults: allkb-allsp-default
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test: test-all
|
||||||
|
|
||||||
|
.PHONY: test-clean
|
||||||
|
test-clean: test-all-clean
|
||||||
|
|
||||||
# Generate the version.h file
|
# Generate the version.h file
|
||||||
GIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags 2>/dev/null || date +"%Y-%m-%d-%H:%M:%S")
|
GIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags 2>/dev/null || date +"%Y-%m-%d-%H:%M:%S")
|
||||||
BUILD_DATE := $(shell date +"%Y-%m-%d-%H:%M:%S")
|
BUILD_DATE := $(shell date +"%Y-%m-%d-%H:%M:%S")
|
||||||
$(shell echo '#define QMK_VERSION "$(GIT_VERSION)"' > $(ROOT_DIR)/quantum/version.h)
|
$(shell echo '#define QMK_VERSION "$(GIT_VERSION)"' > $(ROOT_DIR)/quantum/version.h)
|
||||||
$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
|
$(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h)
|
||||||
|
|
||||||
|
include $(ROOT_DIR)/testlist.mk
|
|
@ -4,19 +4,7 @@ endif
|
||||||
|
|
||||||
.DEFAULT_GOAL := all
|
.DEFAULT_GOAL := all
|
||||||
|
|
||||||
include message.mk
|
include common.mk
|
||||||
|
|
||||||
|
|
||||||
# Directory common source filess exist
|
|
||||||
TOP_DIR = .
|
|
||||||
TMK_DIR = tmk_core
|
|
||||||
TMK_PATH = $(TOP_DIR)/$(TMK_DIR)
|
|
||||||
LIB_PATH = $(TOP_DIR)/lib
|
|
||||||
|
|
||||||
QUANTUM_DIR = quantum
|
|
||||||
QUANTUM_PATH = $(TOP_DIR)/$(QUANTUM_DIR)
|
|
||||||
|
|
||||||
BUILD_DIR := $(TOP_DIR)/.build
|
|
||||||
|
|
||||||
ifneq ($(SUBPROJECT),)
|
ifneq ($(SUBPROJECT),)
|
||||||
TARGET ?= $(KEYBOARD)_$(SUBPROJECT)_$(KEYMAP)
|
TARGET ?= $(KEYBOARD)_$(SUBPROJECT)_$(KEYMAP)
|
||||||
|
@ -35,6 +23,16 @@ ifdef master
|
||||||
MASTER = $(master)
|
MASTER = $(master)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(MASTER),right)
|
||||||
|
OPT_DEFS += -DMASTER_IS_ON_RIGHT
|
||||||
|
else
|
||||||
|
ifneq ($(MASTER),left)
|
||||||
|
$(error MASTER does not have a valid value(left/right))
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
KEYBOARD_PATH := keyboards/$(KEYBOARD)
|
KEYBOARD_PATH := keyboards/$(KEYBOARD)
|
||||||
KEYBOARD_C := $(KEYBOARD_PATH)/$(KEYBOARD).c
|
KEYBOARD_C := $(KEYBOARD_PATH)/$(KEYBOARD).c
|
||||||
|
|
||||||
|
@ -167,12 +165,8 @@ ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
|
ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
|
||||||
SERIAL_DIR = $(QUANTUM_DIR)/serial_link
|
|
||||||
SERIAL_PATH = $(QUANTUM_PATH)/serial_link
|
|
||||||
SERIAL_SRC = $(wildcard $(SERIAL_PATH)/protocol/*.c)
|
|
||||||
SERIAL_SRC += $(wildcard $(SERIAL_PATH)/system/*.c)
|
|
||||||
SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
|
SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
|
||||||
OPT_DEFS += -DSERIAL_LINK_ENABLE
|
OPT_DEFS += $(SERIAL_DEFS)
|
||||||
VAPTH += $(SERIAL_PATH)
|
VAPTH += $(SERIAL_PATH)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -185,15 +179,14 @@ ifneq ($(SUBPROJECT),)
|
||||||
VPATH += $(SUBPROJECT_PATH)
|
VPATH += $(SUBPROJECT_PATH)
|
||||||
endif
|
endif
|
||||||
VPATH += $(KEYBOARD_PATH)
|
VPATH += $(KEYBOARD_PATH)
|
||||||
VPATH += $(TOP_DIR)
|
VPATH += $(COMMON_VPATH)
|
||||||
VPATH += $(TMK_PATH)
|
|
||||||
VPATH += $(QUANTUM_PATH)
|
|
||||||
VPATH += $(QUANTUM_PATH)/keymap_extras
|
|
||||||
VPATH += $(QUANTUM_PATH)/audio
|
|
||||||
VPATH += $(QUANTUM_PATH)/process_keycode
|
|
||||||
|
|
||||||
|
|
||||||
include $(TMK_PATH)/common.mk
|
include $(TMK_PATH)/common.mk
|
||||||
|
SRC += $(TMK_COMMON_SRC)
|
||||||
|
OPT_DEFS += $(TMK_COMMON_DEFS)
|
||||||
|
EXTRALDFLAGS += $(TMK_COMMON_LDFLAGS)
|
||||||
|
|
||||||
ifeq ($(PLATFORM),AVR)
|
ifeq ($(PLATFORM),AVR)
|
||||||
include $(TMK_PATH)/protocol/lufa.mk
|
include $(TMK_PATH)/protocol/lufa.mk
|
||||||
include $(TMK_PATH)/avr.mk
|
include $(TMK_PATH)/avr.mk
|
||||||
|
@ -205,17 +198,24 @@ ifeq ($(strip $(VISUALIZER_ENABLE)), yes)
|
||||||
include $(VISUALIZER_PATH)/visualizer.mk
|
include $(VISUALIZER_PATH)/visualizer.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
|
OUTPUTS := $(KEYMAP_OUTPUT) $(KEYBOARD_OUTPUT)
|
||||||
$(KEYMAP_OUTPUT)_SRC := $(SRC)
|
$(KEYMAP_OUTPUT)_SRC := $(SRC)
|
||||||
$(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) -DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYMAP=\"$(KEYMAP)\"
|
$(KEYMAP_OUTPUT)_DEFS := $(OPT_DEFS) -DQMK_KEYBOARD=\"$(KEYBOARD)\" -DQMK_KEYMAP=\"$(KEYMAP)\"
|
||||||
$(KEYMAP_OUTPUT)_INC := $(EXTRAINCDIRS) $(VPATH)
|
$(KEYMAP_OUTPUT)_INC := $(VPATH) $(EXTRAINCDIRS)
|
||||||
$(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H)
|
$(KEYMAP_OUTPUT)_CONFIG := $(CONFIG_H)
|
||||||
$(KEYBOARD_OUTPUT)_SRC := $(CHIBISRC)
|
$(KEYBOARD_OUTPUT)_SRC := $(CHIBISRC)
|
||||||
$(KEYBOARD_OUTPUT)_DEFS := $(PROJECT_DEFS)
|
$(KEYBOARD_OUTPUT)_DEFS := $(PROJECT_DEFS)
|
||||||
$(KEYBOARD_OUTPUT)_INC := $(PROJECT_INC)
|
$(KEYBOARD_OUTPUT)_INC := $(PROJECT_INC)
|
||||||
$(KEYBOARD_OUTPUT)_CONFIG := $(PROJECT_CONFIG)
|
$(KEYBOARD_OUTPUT)_CONFIG := $(PROJECT_CONFIG)
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
all: build sizeafter
|
||||||
|
|
||||||
|
# Change the build target to build a HEX file or a library.
|
||||||
|
build: elf hex
|
||||||
|
#build: elf hex eep lss sym
|
||||||
|
#build: lib
|
||||||
|
|
||||||
|
|
||||||
include $(TMK_PATH)/rules.mk
|
include $(TMK_PATH)/rules.mk
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
ifndef VERBOSE
|
||||||
|
.SILENT:
|
||||||
|
endif
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := all
|
||||||
|
|
||||||
|
include common.mk
|
||||||
|
|
||||||
|
TARGET=test/$(TEST)
|
||||||
|
|
||||||
|
GTEST_OUTPUT = $(BUILD_DIR)/gtest
|
||||||
|
|
||||||
|
TEST_OBJ = $(BUILD_DIR)/test_obj
|
||||||
|
|
||||||
|
OUTPUTS := $(TEST_OBJ)/$(TEST) $(GTEST_OUTPUT)
|
||||||
|
|
||||||
|
GTEST_INC := \
|
||||||
|
$(LIB_PATH)/googletest/googletest/include\
|
||||||
|
$(LIB_PATH)/googletest/googlemock/include\
|
||||||
|
|
||||||
|
GTEST_INTERNAL_INC :=\
|
||||||
|
$(LIB_PATH)/googletest/googletest\
|
||||||
|
$(LIB_PATH)/googletest/googlemock
|
||||||
|
|
||||||
|
$(GTEST_OUTPUT)_SRC :=\
|
||||||
|
googletest/src/gtest-all.cc\
|
||||||
|
googletest/src/gtest_main.cc\
|
||||||
|
googlemock/src/gmock-all.cc
|
||||||
|
|
||||||
|
$(GTEST_OUTPUT)_DEFS :=
|
||||||
|
$(GTEST_OUTPUT)_INC := $(GTEST_INC) $(GTEST_INTERNAL_INC)
|
||||||
|
|
||||||
|
LDFLAGS += -lstdc++ -lpthread -shared-libgcc
|
||||||
|
CREATE_MAP := no
|
||||||
|
|
||||||
|
VPATH +=\
|
||||||
|
$(LIB_PATH)/googletest\
|
||||||
|
$(LIB_PATH)/googlemock
|
||||||
|
|
||||||
|
all: elf
|
||||||
|
|
||||||
|
VPATH += $(COMMON_VPATH)
|
||||||
|
|
||||||
|
include $(TMK_PATH)/common.mk
|
||||||
|
include $(QUANTUM_PATH)/serial_link/tests/rules.mk
|
||||||
|
|
||||||
|
$(TEST_OBJ)/$(TEST)_SRC := $($(TEST)_SRC)
|
||||||
|
$(TEST_OBJ)/$(TEST)_INC := $($(TEST)_INC) $(VPATH) $(GTEST_INC)
|
||||||
|
$(TEST_OBJ)/$(TEST)_DEFS := $($(TEST)_DEFS)
|
||||||
|
|
||||||
|
include $(TMK_PATH)/native.mk
|
||||||
|
include $(TMK_PATH)/rules.mk
|
||||||
|
|
||||||
|
|
||||||
|
$(shell mkdir -p $(BUILD_DIR)/test 2>/dev/null)
|
||||||
|
$(shell mkdir -p $(TEST_OBJ) 2>/dev/null)
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
include message.mk
|
||||||
|
|
||||||
|
# Directory common source files exist
|
||||||
|
TOP_DIR = .
|
||||||
|
TMK_DIR = tmk_core
|
||||||
|
TMK_PATH = $(TOP_DIR)/$(TMK_DIR)
|
||||||
|
LIB_PATH = $(TOP_DIR)/lib
|
||||||
|
|
||||||
|
QUANTUM_DIR = quantum
|
||||||
|
QUANTUM_PATH = $(TOP_DIR)/$(QUANTUM_DIR)
|
||||||
|
|
||||||
|
BUILD_DIR := $(TOP_DIR)/.build
|
||||||
|
|
||||||
|
SERIAL_DIR := $(QUANTUM_DIR)/serial_link
|
||||||
|
SERIAL_PATH := $(QUANTUM_PATH)/serial_link
|
||||||
|
SERIAL_SRC := $(wildcard $(SERIAL_PATH)/protocol/*.c)
|
||||||
|
SERIAL_SRC += $(wildcard $(SERIAL_PATH)/system/*.c)
|
||||||
|
SERIAL_DEFS += -DSERIAL_LINK_ENABLE
|
||||||
|
|
||||||
|
COMMON_VPATH := $(TOP_DIR)
|
||||||
|
COMMON_VPATH += $(TMK_PATH)
|
||||||
|
COMMON_VPATH += $(QUANTUM_PATH)
|
||||||
|
COMMON_VPATH += $(QUANTUM_PATH)/keymap_extras
|
||||||
|
COMMON_VPATH += $(QUANTUM_PATH)/audio
|
||||||
|
COMMON_VPATH += $(QUANTUM_PATH)/process_keycode
|
||||||
|
COMMON_VPATH += $(SERIAL_PATH)
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ec44c6c1675c25b9827aacd08c02433cccde7780
|
|
@ -69,3 +69,11 @@ define GENERATE_MSG_MAKE_KB
|
||||||
endif
|
endif
|
||||||
endef
|
endef
|
||||||
MSG_MAKE_KB = $(eval $(call GENERATE_MSG_MAKE_KB))$(MSG_MAKE_KB_ACTUAL)
|
MSG_MAKE_KB = $(eval $(call GENERATE_MSG_MAKE_KB))$(MSG_MAKE_KB_ACTUAL)
|
||||||
|
define GENERATE_MSG_MAKE_TEST
|
||||||
|
MSG_MAKE_TEST_ACTUAL := Making test $(BOLD)$(TEST_NAME)$(NO_COLOR)
|
||||||
|
ifneq ($$(MAKE_TARGET),)
|
||||||
|
MSG_MAKE_TEST_ACTUAL += with target $(BOLD)$$(MAKE_TARGET)$(NO_COLOR)
|
||||||
|
endif
|
||||||
|
endef
|
||||||
|
MSG_MAKE_TEST = $(eval $(call GENERATE_MSG_MAKE_TEST))$(MSG_MAKE_TEST_ACTUAL)
|
||||||
|
MSG_TEST = Testing $(BOLD)$(TEST_NAME)$(NO_COLOR)
|
||||||
|
|
|
@ -31,9 +31,6 @@ SOFTWARE.
|
||||||
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
|
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
|
||||||
// http://www.stuartcheshire.org/papers/COBSforToN.pdf
|
// http://www.stuartcheshire.org/papers/COBSforToN.pdf
|
||||||
|
|
||||||
#define MAX_FRAME_SIZE 1024
|
|
||||||
#define NUM_LINKS 2
|
|
||||||
|
|
||||||
typedef struct byte_stuffer_state {
|
typedef struct byte_stuffer_state {
|
||||||
uint16_t next_zero;
|
uint16_t next_zero;
|
||||||
uint16_t data_pos;
|
uint16_t data_pos;
|
||||||
|
|
|
@ -27,6 +27,9 @@ SOFTWARE.
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MAX_FRAME_SIZE 1024
|
||||||
|
#define NUM_LINKS 2
|
||||||
|
|
||||||
void init_byte_stuffer(void);
|
void init_byte_stuffer(void);
|
||||||
void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
|
void byte_stuffer_recv_byte(uint8_t link, uint8_t data);
|
||||||
void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);
|
void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size);
|
||||||
|
|
|
@ -31,6 +31,10 @@ SOFTWARE.
|
||||||
static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS];
|
static remote_object_t* remote_objects[MAX_REMOTE_OBJECTS];
|
||||||
static uint32_t num_remote_objects = 0;
|
static uint32_t num_remote_objects = 0;
|
||||||
|
|
||||||
|
void reinitialize_serial_link_transport(void) {
|
||||||
|
num_remote_objects = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
|
void add_remote_objects(remote_object_t** _remote_objects, uint32_t _num_remote_objects) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for(i=0;i<_num_remote_objects;i++) {
|
for(i=0;i<_num_remote_objects;i++) {
|
||||||
|
|
|
@ -82,7 +82,7 @@ typedef struct { \
|
||||||
remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
|
remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
|
||||||
uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
|
uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
|
||||||
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
|
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
|
||||||
return triple_buffer_read_internal(obj->object_size, tb); \
|
return (type*)triple_buffer_read_internal(obj->object_size, tb); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \
|
#define MASTER_TO_SINGLE_SLAVE_OBJECT(name, type) \
|
||||||
|
@ -112,7 +112,7 @@ typedef struct { \
|
||||||
remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
|
remote_object_t* obj = (remote_object_t*)&remote_object_##name; \
|
||||||
uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\
|
uint8_t* start = obj->buffer + NUM_SLAVES * LOCAL_OBJECT_SIZE(obj->object_size);\
|
||||||
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
|
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
|
||||||
return triple_buffer_read_internal(obj->object_size, tb); \
|
return (type*)triple_buffer_read_internal(obj->object_size, tb); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SLAVE_TO_MASTER_OBJECT(name, type) \
|
#define SLAVE_TO_MASTER_OBJECT(name, type) \
|
||||||
|
@ -139,12 +139,13 @@ typedef struct { \
|
||||||
uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
|
uint8_t* start = obj->buffer + LOCAL_OBJECT_SIZE(obj->object_size);\
|
||||||
start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \
|
start+=slave * REMOTE_OBJECT_SIZE(obj->object_size); \
|
||||||
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
|
triple_buffer_object_t* tb = (triple_buffer_object_t*)start; \
|
||||||
return triple_buffer_read_internal(obj->object_size, tb); \
|
return (type*)triple_buffer_read_internal(obj->object_size, tb); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name
|
#define REMOTE_OBJECT(name) (remote_object_t*)&remote_object_##name
|
||||||
|
|
||||||
void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects);
|
void add_remote_objects(remote_object_t** remote_objects, uint32_t num_remote_objects);
|
||||||
|
void reinitialize_serial_link_transport(void);
|
||||||
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
|
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size);
|
||||||
void update_transport(void);
|
void update_transport(void);
|
||||||
|
|
||||||
|
|
|
@ -22,70 +22,90 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cgreen/cgreen.h>
|
#include "gtest/gtest.h"
|
||||||
#include <cgreen/mocks.h>
|
#include "gmock/gmock.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
extern "C" {
|
||||||
#include "serial_link/protocol/byte_stuffer.h"
|
#include "serial_link/protocol/byte_stuffer.h"
|
||||||
#include "serial_link/protocol/byte_stuffer.c"
|
|
||||||
#include "serial_link/protocol/frame_validator.h"
|
#include "serial_link/protocol/frame_validator.h"
|
||||||
#include "serial_link/protocol/physical.h"
|
#include "serial_link/protocol/physical.h"
|
||||||
|
|
||||||
static uint8_t sent_data[MAX_FRAME_SIZE*2];
|
|
||||||
static uint16_t sent_data_size;
|
|
||||||
|
|
||||||
Describe(ByteStuffer);
|
|
||||||
BeforeEach(ByteStuffer) {
|
|
||||||
init_byte_stuffer();
|
|
||||||
sent_data_size = 0;
|
|
||||||
}
|
|
||||||
AfterEach(ByteStuffer) {}
|
|
||||||
|
|
||||||
void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
|
|
||||||
mock(data, size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
|
using testing::_;
|
||||||
memcpy(sent_data + sent_data_size, data, size);
|
using testing::ElementsAreArray;
|
||||||
sent_data_size += size;
|
using testing::Args;
|
||||||
|
|
||||||
|
class ByteStuffer : public ::testing::Test{
|
||||||
|
public:
|
||||||
|
ByteStuffer() {
|
||||||
|
Instance = this;
|
||||||
|
init_byte_stuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ByteStuffer() {
|
||||||
|
Instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_METHOD3(validator_recv_frame, void (uint8_t link, uint8_t* data, uint16_t size));
|
||||||
|
|
||||||
|
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
|
||||||
|
std::copy(data, data + size, std::back_inserter(sent_data));
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> sent_data;
|
||||||
|
|
||||||
|
static ByteStuffer* Instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
ByteStuffer* ByteStuffer::Instance = nullptr;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void validator_recv_frame(uint8_t link, uint8_t* data, uint16_t size) {
|
||||||
|
ByteStuffer::Instance->validator_recv_frame(link, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
|
||||||
|
ByteStuffer::Instance->send_data(link, data, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
|
TEST_F(ByteStuffer, receives_no_frame_for_a_single_zero_byte) {
|
||||||
never_expect(validator_recv_frame);
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
|
TEST_F(ByteStuffer, receives_no_frame_for_a_single_FF_byte) {
|
||||||
never_expect(validator_recv_frame);
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
byte_stuffer_recv_byte(0, 0xFF);
|
byte_stuffer_recv_byte(0, 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
|
TEST_F(ByteStuffer, receives_no_frame_for_a_single_random_byte) {
|
||||||
never_expect(validator_recv_frame);
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
byte_stuffer_recv_byte(0, 0x4A);
|
byte_stuffer_recv_byte(0, 0x4A);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
|
TEST_F(ByteStuffer, receives_no_frame_for_a_zero_length_frame) {
|
||||||
never_expect(validator_recv_frame);
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
byte_stuffer_recv_byte(0, 1);
|
byte_stuffer_recv_byte(0, 1);
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_single_byte_valid_frame) {
|
TEST_F(ByteStuffer, receives_single_byte_valid_frame) {
|
||||||
uint8_t expected[] = {0x37};
|
uint8_t expected[] = {0x37};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(1)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 1))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 2);
|
byte_stuffer_recv_byte(0, 2);
|
||||||
byte_stuffer_recv_byte(0, 0x37);
|
byte_stuffer_recv_byte(0, 0x37);
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
TEST_F(ByteStuffer, receives_three_bytes_valid_frame) {
|
||||||
Ensure(ByteStuffer, receives_three_bytes_valid_frame) {
|
|
||||||
uint8_t expected[] = {0x37, 0x99, 0xFF};
|
uint8_t expected[] = {0x37, 0x99, 0xFF};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(3)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 3))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 4);
|
byte_stuffer_recv_byte(0, 4);
|
||||||
byte_stuffer_recv_byte(0, 0x37);
|
byte_stuffer_recv_byte(0, 0x37);
|
||||||
byte_stuffer_recv_byte(0, 0x99);
|
byte_stuffer_recv_byte(0, 0x99);
|
||||||
|
@ -93,23 +113,19 @@ Ensure(ByteStuffer, receives_three_bytes_valid_frame) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_single_zero_valid_frame) {
|
TEST_F(ByteStuffer, receives_single_zero_valid_frame) {
|
||||||
uint8_t expected[] = {0};
|
uint8_t expected[] = {0};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(1)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 1))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 1);
|
byte_stuffer_recv_byte(0, 1);
|
||||||
byte_stuffer_recv_byte(0, 1);
|
byte_stuffer_recv_byte(0, 1);
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_valid_frame_with_zeroes) {
|
TEST_F(ByteStuffer, receives_valid_frame_with_zeroes) {
|
||||||
uint8_t expected[] = {5, 0, 3, 0};
|
uint8_t expected[] = {5, 0, 3, 0};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(4)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 4))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 2);
|
byte_stuffer_recv_byte(0, 2);
|
||||||
byte_stuffer_recv_byte(0, 5);
|
byte_stuffer_recv_byte(0, 5);
|
||||||
byte_stuffer_recv_byte(0, 2);
|
byte_stuffer_recv_byte(0, 2);
|
||||||
|
@ -118,17 +134,14 @@ Ensure(ByteStuffer, receives_valid_frame_with_zeroes) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_two_valid_frames) {
|
|
||||||
|
TEST_F(ByteStuffer, receives_two_valid_frames) {
|
||||||
uint8_t expected1[] = {5, 0};
|
uint8_t expected1[] = {5, 0};
|
||||||
uint8_t expected2[] = {3};
|
uint8_t expected2[] = {3};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(2)),
|
.With(Args<1, 2>(ElementsAreArray(expected1)));
|
||||||
when(data, is_equal_to_contents_of(expected1, 2))
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
);
|
.With(Args<1, 2>(ElementsAreArray(expected2)));
|
||||||
expect(validator_recv_frame,
|
|
||||||
when(size, is_equal_to(1)),
|
|
||||||
when(data, is_equal_to_contents_of(expected2, 1))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(1, 2);
|
byte_stuffer_recv_byte(1, 2);
|
||||||
byte_stuffer_recv_byte(1, 5);
|
byte_stuffer_recv_byte(1, 5);
|
||||||
byte_stuffer_recv_byte(1, 1);
|
byte_stuffer_recv_byte(1, 1);
|
||||||
|
@ -138,12 +151,10 @@ Ensure(ByteStuffer, receives_two_valid_frames) {
|
||||||
byte_stuffer_recv_byte(1, 0);
|
byte_stuffer_recv_byte(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
|
TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
|
||||||
uint8_t expected[] = {5, 7};
|
uint8_t expected[] = {5, 7};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(2)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 2))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(1, 3);
|
byte_stuffer_recv_byte(1, 3);
|
||||||
byte_stuffer_recv_byte(1, 1);
|
byte_stuffer_recv_byte(1, 1);
|
||||||
byte_stuffer_recv_byte(1, 0);
|
byte_stuffer_recv_byte(1, 0);
|
||||||
|
@ -153,12 +164,10 @@ Ensure(ByteStuffer, receives_valid_frame_after_unexpected_zero) {
|
||||||
byte_stuffer_recv_byte(1, 0);
|
byte_stuffer_recv_byte(1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
|
TEST_F(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
|
||||||
uint8_t expected[] = {5, 7};
|
uint8_t expected[] = {5, 7};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(2)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 2))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 2);
|
byte_stuffer_recv_byte(0, 2);
|
||||||
byte_stuffer_recv_byte(0, 9);
|
byte_stuffer_recv_byte(0, 9);
|
||||||
byte_stuffer_recv_byte(0, 4); // This should have been zero
|
byte_stuffer_recv_byte(0, 4); // This should have been zero
|
||||||
|
@ -169,16 +178,14 @@ Ensure(ByteStuffer, receives_valid_frame_after_unexpected_non_zero) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
|
TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_of_frame) {
|
||||||
uint8_t expected[254];
|
uint8_t expected[254];
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
expected[i] = i + 1;
|
expected[i] = i + 1;
|
||||||
}
|
}
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(254)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 254))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 0xFF);
|
byte_stuffer_recv_byte(0, 0xFF);
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
byte_stuffer_recv_byte(0, i+1);
|
byte_stuffer_recv_byte(0, i+1);
|
||||||
|
@ -186,17 +193,15 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_and_then_end_
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
|
TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_non_zero) {
|
||||||
uint8_t expected[255];
|
uint8_t expected[255];
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
expected[i] = i + 1;
|
expected[i] = i + 1;
|
||||||
}
|
}
|
||||||
expected[254] = 7;
|
expected[254] = 7;
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(255)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 255))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 0xFF);
|
byte_stuffer_recv_byte(0, 0xFF);
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
byte_stuffer_recv_byte(0, i+1);
|
byte_stuffer_recv_byte(0, i+1);
|
||||||
|
@ -206,17 +211,15 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
|
TEST_F(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_zero) {
|
||||||
uint8_t expected[255];
|
uint8_t expected[255];
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
expected[i] = i + 1;
|
expected[i] = i + 1;
|
||||||
}
|
}
|
||||||
expected[254] = 0;
|
expected[254] = 0;
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(255)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 255))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 0xFF);
|
byte_stuffer_recv_byte(0, 0xFF);
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
byte_stuffer_recv_byte(0, i+1);
|
byte_stuffer_recv_byte(0, i+1);
|
||||||
|
@ -226,7 +229,7 @@ Ensure(ByteStuffer, receives_a_valid_frame_with_over254_non_zeroes_next_byte_is_
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
|
TEST_F(ByteStuffer, receives_two_long_frames_and_some_more) {
|
||||||
uint8_t expected[515];
|
uint8_t expected[515];
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
@ -238,10 +241,8 @@ Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
|
||||||
for (i=0;i<7;i++) {
|
for (i=0;i<7;i++) {
|
||||||
expected[254*2+i] = i + 1;
|
expected[254*2+i] = i + 1;
|
||||||
}
|
}
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(515)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 510))
|
|
||||||
);
|
|
||||||
byte_stuffer_recv_byte(0, 0xFF);
|
byte_stuffer_recv_byte(0, 0xFF);
|
||||||
for (i=0;i<254;i++) {
|
for (i=0;i<254;i++) {
|
||||||
byte_stuffer_recv_byte(0, i+1);
|
byte_stuffer_recv_byte(0, i+1);
|
||||||
|
@ -261,12 +262,10 @@ Ensure(ByteStuffer, receives_two_long_frames_and_some_more) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
|
TEST_F(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
|
||||||
uint8_t expected[MAX_FRAME_SIZE] = {};
|
uint8_t expected[MAX_FRAME_SIZE] = {};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(MAX_FRAME_SIZE)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, MAX_FRAME_SIZE))
|
|
||||||
);
|
|
||||||
int i;
|
int i;
|
||||||
byte_stuffer_recv_byte(0, 1);
|
byte_stuffer_recv_byte(0, 1);
|
||||||
for(i=0;i<MAX_FRAME_SIZE;i++) {
|
for(i=0;i<MAX_FRAME_SIZE;i++) {
|
||||||
|
@ -275,9 +274,10 @@ Ensure(ByteStuffer, receives_an_all_zeros_frame_that_is_maximum_size) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
|
TEST_F(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
|
||||||
uint8_t expected[1] = {0};
|
uint8_t expected[1] = {0};
|
||||||
never_expect(validator_recv_frame);
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
int i;
|
int i;
|
||||||
byte_stuffer_recv_byte(0, 1);
|
byte_stuffer_recv_byte(0, 1);
|
||||||
for(i=0;i<MAX_FRAME_SIZE;i++) {
|
for(i=0;i<MAX_FRAME_SIZE;i++) {
|
||||||
|
@ -287,12 +287,10 @@ Ensure(ByteStuffer, doesnt_recv_a_frame_thats_too_long_all_zeroes) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
|
TEST_F(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
|
||||||
uint8_t expected[1] = {1};
|
uint8_t expected[1] = {1};
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(1)),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, 1))
|
|
||||||
);
|
|
||||||
int i;
|
int i;
|
||||||
byte_stuffer_recv_byte(0, 1);
|
byte_stuffer_recv_byte(0, 1);
|
||||||
for(i=0;i<MAX_FRAME_SIZE;i++) {
|
for(i=0;i<MAX_FRAME_SIZE;i++) {
|
||||||
|
@ -303,76 +301,68 @@ Ensure(ByteStuffer, received_frame_is_aborted_when_its_too_long) {
|
||||||
byte_stuffer_recv_byte(0, 0);
|
byte_stuffer_recv_byte(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
|
TEST_F(ByteStuffer, does_nothing_when_sending_zero_size_frame) {
|
||||||
assert_that(sent_data_size, is_equal_to(0));
|
EXPECT_EQ(sent_data.size(), 0);
|
||||||
byte_stuffer_send_frame(0, NULL, 0);
|
byte_stuffer_send_frame(0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, send_one_byte_frame) {
|
TEST_F(ByteStuffer, send_one_byte_frame) {
|
||||||
uint8_t data[] = {5};
|
uint8_t data[] = {5};
|
||||||
byte_stuffer_send_frame(1, data, 1);
|
byte_stuffer_send_frame(1, data, 1);
|
||||||
uint8_t expected[] = {2, 5, 0};
|
uint8_t expected[] = {2, 5, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_two_byte_frame) {
|
TEST_F(ByteStuffer, sends_two_byte_frame) {
|
||||||
uint8_t data[] = {5, 0x77};
|
uint8_t data[] = {5, 0x77};
|
||||||
byte_stuffer_send_frame(0, data, 2);
|
byte_stuffer_send_frame(0, data, 2);
|
||||||
uint8_t expected[] = {3, 5, 0x77, 0};
|
uint8_t expected[] = {3, 5, 0x77, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_one_byte_frame_with_zero) {
|
TEST_F(ByteStuffer, sends_one_byte_frame_with_zero) {
|
||||||
uint8_t data[] = {0};
|
uint8_t data[] = {0};
|
||||||
byte_stuffer_send_frame(0, data, 1);
|
byte_stuffer_send_frame(0, data, 1);
|
||||||
uint8_t expected[] = {1, 1, 0};
|
uint8_t expected[] = {1, 1, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
|
TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_zero) {
|
||||||
uint8_t data[] = {0, 9};
|
uint8_t data[] = {0, 9};
|
||||||
byte_stuffer_send_frame(1, data, 2);
|
byte_stuffer_send_frame(1, data, 2);
|
||||||
uint8_t expected[] = {1, 2, 9, 0};
|
uint8_t expected[] = {1, 2, 9, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
|
TEST_F(ByteStuffer, sends_two_byte_frame_starting_with_non_zero) {
|
||||||
uint8_t data[] = {9, 0};
|
uint8_t data[] = {9, 0};
|
||||||
byte_stuffer_send_frame(1, data, 2);
|
byte_stuffer_send_frame(1, data, 2);
|
||||||
uint8_t expected[] = {2, 9, 1, 0};
|
uint8_t expected[] = {2, 9, 1, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
|
TEST_F(ByteStuffer, sends_three_byte_frame_zero_in_the_middle) {
|
||||||
uint8_t data[] = {9, 0, 0x68};
|
uint8_t data[] = {9, 0, 0x68};
|
||||||
byte_stuffer_send_frame(0, data, 3);
|
byte_stuffer_send_frame(0, data, 3);
|
||||||
uint8_t expected[] = {2, 9, 2, 0x68, 0};
|
uint8_t expected[] = {2, 9, 2, 0x68, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
|
TEST_F(ByteStuffer, sends_three_byte_frame_data_in_the_middle) {
|
||||||
uint8_t data[] = {0, 0x55, 0};
|
uint8_t data[] = {0, 0x55, 0};
|
||||||
byte_stuffer_send_frame(0, data, 3);
|
byte_stuffer_send_frame(0, data, 3);
|
||||||
uint8_t expected[] = {1, 2, 0x55, 1, 0};
|
uint8_t expected[] = {1, 2, 0x55, 1, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
|
TEST_F(ByteStuffer, sends_three_byte_frame_with_all_zeroes) {
|
||||||
uint8_t data[] = {0, 0, 0};
|
uint8_t data[] = {0, 0, 0};
|
||||||
byte_stuffer_send_frame(0, data, 3);
|
byte_stuffer_send_frame(0, data, 3);
|
||||||
uint8_t expected[] = {1, 1, 1, 1, 0};
|
uint8_t expected[] = {1, 1, 1, 1, 0};
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) {
|
TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes) {
|
||||||
uint8_t data[254];
|
uint8_t data[254];
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<254;i++) {
|
for(i=0;i<254;i++) {
|
||||||
|
@ -385,11 +375,10 @@ Ensure(ByteStuffer, sends_frame_with_254_non_zeroes) {
|
||||||
expected[i] = i;
|
expected[i] = i;
|
||||||
}
|
}
|
||||||
expected[255] = 0;
|
expected[255] = 0;
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) {
|
TEST_F(ByteStuffer, sends_frame_with_255_non_zeroes) {
|
||||||
uint8_t data[255];
|
uint8_t data[255];
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<255;i++) {
|
for(i=0;i<255;i++) {
|
||||||
|
@ -404,17 +393,16 @@ Ensure(ByteStuffer, sends_frame_with_255_non_zeroes) {
|
||||||
expected[255] = 2;
|
expected[255] = 2;
|
||||||
expected[256] = 255;
|
expected[256] = 255;
|
||||||
expected[257] = 0;
|
expected[257] = 0;
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
|
TEST_F(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
|
||||||
uint8_t data[255];
|
uint8_t data[255];
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<254;i++) {
|
for(i=0;i<254;i++) {
|
||||||
data[i] = i + 1;
|
data[i] = i + 1;
|
||||||
}
|
}
|
||||||
data[255] = 0;
|
data[254] = 0;
|
||||||
byte_stuffer_send_frame(0, data, 255);
|
byte_stuffer_send_frame(0, data, 255);
|
||||||
uint8_t expected[258];
|
uint8_t expected[258];
|
||||||
expected[0] = 0xFF;
|
expected[0] = 0xFF;
|
||||||
|
@ -424,53 +412,46 @@ Ensure(ByteStuffer, sends_frame_with_254_non_zeroes_followed_by_zero) {
|
||||||
expected[255] = 1;
|
expected[255] = 1;
|
||||||
expected[256] = 1;
|
expected[256] = 1;
|
||||||
expected[257] = 0;
|
expected[257] = 0;
|
||||||
assert_that(sent_data_size, is_equal_to(sizeof(expected)));
|
EXPECT_THAT(sent_data, ElementsAreArray(expected));
|
||||||
assert_that(sent_data, is_equal_to_contents_of(expected, sizeof(expected)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
|
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet) {
|
||||||
uint8_t original_data[] = { 1, 2, 3};
|
uint8_t original_data[] = { 1, 2, 3};
|
||||||
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(original_data))),
|
.With(Args<1, 2>(ElementsAreArray(original_data)));
|
||||||
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
|
|
||||||
);
|
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<sent_data_size;i++) {
|
for(auto& d : sent_data) {
|
||||||
byte_stuffer_recv_byte(1, sent_data[i]);
|
byte_stuffer_recv_byte(1, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
|
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_small_packet_with_zeros) {
|
||||||
uint8_t original_data[] = { 1, 0, 3, 0, 0, 9};
|
uint8_t original_data[] = { 1, 0, 3, 0, 0, 9};
|
||||||
byte_stuffer_send_frame(1, original_data, sizeof(original_data));
|
byte_stuffer_send_frame(1, original_data, sizeof(original_data));
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(original_data))),
|
.With(Args<1, 2>(ElementsAreArray(original_data)));
|
||||||
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
|
|
||||||
);
|
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<sent_data_size;i++) {
|
for(auto& d : sent_data) {
|
||||||
byte_stuffer_recv_byte(0, sent_data[i]);
|
byte_stuffer_recv_byte(1, d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
|
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes) {
|
||||||
uint8_t original_data[254];
|
uint8_t original_data[254];
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<254;i++) {
|
for(i=0;i<254;i++) {
|
||||||
original_data[i] = i + 1;
|
original_data[i] = i + 1;
|
||||||
}
|
}
|
||||||
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(original_data))),
|
.With(Args<1, 2>(ElementsAreArray(original_data)));
|
||||||
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
|
for(auto& d : sent_data) {
|
||||||
);
|
byte_stuffer_recv_byte(1, d);
|
||||||
for(i=0;i<sent_data_size;i++) {
|
|
||||||
byte_stuffer_recv_byte(1, sent_data[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
|
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
|
||||||
uint8_t original_data[256];
|
uint8_t original_data[256];
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<254;i++) {
|
for(i=0;i<254;i++) {
|
||||||
|
@ -479,16 +460,14 @@ Ensure(ByteStuffer, sends_and_receives_full_roundtrip_256_bytes) {
|
||||||
original_data[254] = 22;
|
original_data[254] = 22;
|
||||||
original_data[255] = 23;
|
original_data[255] = 23;
|
||||||
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(original_data))),
|
.With(Args<1, 2>(ElementsAreArray(original_data)));
|
||||||
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
|
for(auto& d : sent_data) {
|
||||||
);
|
byte_stuffer_recv_byte(1, d);
|
||||||
for(i=0;i<sent_data_size;i++) {
|
|
||||||
byte_stuffer_recv_byte(1, sent_data[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
|
TEST_F(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
|
||||||
uint8_t original_data[255];
|
uint8_t original_data[255];
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<254;i++) {
|
for(i=0;i<254;i++) {
|
||||||
|
@ -496,11 +475,9 @@ Ensure(ByteStuffer, sends_and_receives_full_roundtrip_254_bytes_and_then_zero) {
|
||||||
}
|
}
|
||||||
original_data[254] = 0;
|
original_data[254] = 0;
|
||||||
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
byte_stuffer_send_frame(0, original_data, sizeof(original_data));
|
||||||
expect(validator_recv_frame,
|
EXPECT_CALL(*this, validator_recv_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(original_data))),
|
.With(Args<1, 2>(ElementsAreArray(original_data)));
|
||||||
when(data, is_equal_to_contents_of(original_data, sizeof(original_data)))
|
for(auto& d : sent_data) {
|
||||||
);
|
byte_stuffer_recv_byte(1, d);
|
||||||
for(i=0;i<sent_data_size;i++) {
|
|
||||||
byte_stuffer_recv_byte(1, sent_data[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,231 +0,0 @@
|
||||||
/*
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Fred Sundvik
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cgreen/cgreen.h>
|
|
||||||
#include <cgreen/mocks.h>
|
|
||||||
#include "serial_link/protocol/byte_stuffer.c"
|
|
||||||
#include "serial_link/protocol/frame_validator.c"
|
|
||||||
#include "serial_link/protocol/frame_router.c"
|
|
||||||
#include "serial_link/protocol/transport.h"
|
|
||||||
|
|
||||||
static uint8_t received_data[256];
|
|
||||||
static uint16_t received_data_size;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t sent_data[256];
|
|
||||||
uint16_t sent_data_size;
|
|
||||||
} receive_buffer_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
receive_buffer_t send_buffers[2];
|
|
||||||
} router_buffer_t;
|
|
||||||
|
|
||||||
router_buffer_t router_buffers[8];
|
|
||||||
|
|
||||||
router_buffer_t* current_router_buffer;
|
|
||||||
|
|
||||||
|
|
||||||
Describe(FrameRouter);
|
|
||||||
BeforeEach(FrameRouter) {
|
|
||||||
init_byte_stuffer();
|
|
||||||
memset(router_buffers, 0, sizeof(router_buffers));
|
|
||||||
current_router_buffer = 0;
|
|
||||||
}
|
|
||||||
AfterEach(FrameRouter) {}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t data;
|
|
||||||
uint8_t extra[16];
|
|
||||||
} frame_buffer_t;
|
|
||||||
|
|
||||||
|
|
||||||
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
|
|
||||||
receive_buffer_t* buffer = ¤t_router_buffer->send_buffers[link];
|
|
||||||
memcpy(buffer->sent_data + buffer->sent_data_size, data, size);
|
|
||||||
buffer->sent_data_size += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
|
|
||||||
int i;
|
|
||||||
for(i=0;i<size;i++) {
|
|
||||||
byte_stuffer_recv_byte(link, data[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void activate_router(uint8_t num) {
|
|
||||||
current_router_buffer = router_buffers + num;
|
|
||||||
router_set_master(num==0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void simulate_transport(uint8_t from, uint8_t to) {
|
|
||||||
activate_router(to);
|
|
||||||
if (from > to) {
|
|
||||||
receive_data(DOWN_LINK,
|
|
||||||
router_buffers[from].send_buffers[UP_LINK].sent_data,
|
|
||||||
router_buffers[from].send_buffers[UP_LINK].sent_data_size);
|
|
||||||
}
|
|
||||||
else if(to > from) {
|
|
||||||
receive_data(UP_LINK,
|
|
||||||
router_buffers[from].send_buffers[DOWN_LINK].sent_data,
|
|
||||||
router_buffers[from].send_buffers[DOWN_LINK].sent_data_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
|
|
||||||
mock(from, data, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ensure(FrameRouter, master_broadcast_is_received_by_everyone) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(0);
|
|
||||||
router_send_frame(0xFF, (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
expect(transport_recv_frame,
|
|
||||||
when(from, is_equal_to(0)),
|
|
||||||
when(size, is_equal_to(4)),
|
|
||||||
when(data, is_equal_to_contents_of(&data.data, 4))
|
|
||||||
);
|
|
||||||
simulate_transport(0, 1);
|
|
||||||
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
expect(transport_recv_frame,
|
|
||||||
when(from, is_equal_to(0)),
|
|
||||||
when(size, is_equal_to(4)),
|
|
||||||
when(data, is_equal_to_contents_of(&data.data, 4))
|
|
||||||
);
|
|
||||||
simulate_transport(1, 2);
|
|
||||||
assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(FrameRouter, master_send_is_received_by_targets) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(0);
|
|
||||||
router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
simulate_transport(0, 1);
|
|
||||||
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
expect(transport_recv_frame,
|
|
||||||
when(from, is_equal_to(0)),
|
|
||||||
when(size, is_equal_to(4)),
|
|
||||||
when(data, is_equal_to_contents_of(&data.data, 4))
|
|
||||||
);
|
|
||||||
simulate_transport(1, 2);
|
|
||||||
assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
expect(transport_recv_frame,
|
|
||||||
when(from, is_equal_to(0)),
|
|
||||||
when(size, is_equal_to(4)),
|
|
||||||
when(data, is_equal_to_contents_of(&data.data, 4))
|
|
||||||
);
|
|
||||||
simulate_transport(2, 3);
|
|
||||||
assert_that(router_buffers[3].send_buffers[DOWN_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[3].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(FrameRouter, first_link_sends_to_master) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(1);
|
|
||||||
router_send_frame(0, (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
expect(transport_recv_frame,
|
|
||||||
when(from, is_equal_to(1)),
|
|
||||||
when(size, is_equal_to(4)),
|
|
||||||
when(data, is_equal_to_contents_of(&data.data, 4))
|
|
||||||
);
|
|
||||||
simulate_transport(1, 0);
|
|
||||||
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(FrameRouter, second_link_sends_to_master) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(2);
|
|
||||||
router_send_frame(0, (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[2].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[2].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
simulate_transport(2, 1);
|
|
||||||
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
expect(transport_recv_frame,
|
|
||||||
when(from, is_equal_to(2)),
|
|
||||||
when(size, is_equal_to(4)),
|
|
||||||
when(data, is_equal_to_contents_of(&data.data, 4))
|
|
||||||
);
|
|
||||||
simulate_transport(1, 0);
|
|
||||||
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(FrameRouter, master_sends_to_master_does_nothing) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(0);
|
|
||||||
router_send_frame(0, (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(FrameRouter, link_sends_to_other_link_does_nothing) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(1);
|
|
||||||
router_send_frame(2, (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(FrameRouter, master_receives_on_uplink_does_nothing) {
|
|
||||||
frame_buffer_t data;
|
|
||||||
data.data = 0xAB7055BB;
|
|
||||||
activate_router(1);
|
|
||||||
router_send_frame(0, (uint8_t*)&data, 4);
|
|
||||||
assert_that(router_buffers[1].send_buffers[UP_LINK].sent_data_size, is_greater_than(0));
|
|
||||||
assert_that(router_buffers[1].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
|
|
||||||
never_expect(transport_recv_frame);
|
|
||||||
activate_router(0);
|
|
||||||
receive_data(UP_LINK,
|
|
||||||
router_buffers[1].send_buffers[UP_LINK].sent_data,
|
|
||||||
router_buffers[1].send_buffers[UP_LINK].sent_data_size);
|
|
||||||
assert_that(router_buffers[0].send_buffers[UP_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
assert_that(router_buffers[0].send_buffers[DOWN_LINK].sent_data_size, is_equal_to(0));
|
|
||||||
}
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Fred Sundvik
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include <array>
|
||||||
|
extern "C" {
|
||||||
|
#include "serial_link/protocol/transport.h"
|
||||||
|
#include "serial_link/protocol/byte_stuffer.h"
|
||||||
|
#include "serial_link/protocol/frame_router.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using testing::_;
|
||||||
|
using testing::ElementsAreArray;
|
||||||
|
using testing::Args;
|
||||||
|
|
||||||
|
class FrameRouter : public testing::Test {
|
||||||
|
public:
|
||||||
|
FrameRouter() :
|
||||||
|
current_router_buffer(nullptr)
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
init_byte_stuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
~FrameRouter() {
|
||||||
|
Instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
|
||||||
|
auto& buffer = current_router_buffer->send_buffers[link];
|
||||||
|
std::copy(data, data + size, std::back_inserter(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void receive_data(uint8_t link, uint8_t* data, uint16_t size) {
|
||||||
|
int i;
|
||||||
|
for(i=0;i<size;i++) {
|
||||||
|
byte_stuffer_recv_byte(link, data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void activate_router(uint8_t num) {
|
||||||
|
current_router_buffer = router_buffers + num;
|
||||||
|
router_set_master(num==0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void simulate_transport(uint8_t from, uint8_t to) {
|
||||||
|
activate_router(to);
|
||||||
|
if (from > to) {
|
||||||
|
receive_data(DOWN_LINK,
|
||||||
|
router_buffers[from].send_buffers[UP_LINK].data(),
|
||||||
|
router_buffers[from].send_buffers[UP_LINK].size());
|
||||||
|
}
|
||||||
|
else if(to > from) {
|
||||||
|
receive_data(UP_LINK,
|
||||||
|
router_buffers[from].send_buffers[DOWN_LINK].data(),
|
||||||
|
router_buffers[from].send_buffers[DOWN_LINK].size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_METHOD3(transport_recv_frame, void (uint8_t from, uint8_t* data, uint16_t size));
|
||||||
|
|
||||||
|
std::vector<uint8_t> received_data;
|
||||||
|
|
||||||
|
struct router_buffer {
|
||||||
|
std::vector<uint8_t> send_buffers[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
router_buffer router_buffers[8];
|
||||||
|
router_buffer* current_router_buffer;
|
||||||
|
|
||||||
|
static FrameRouter* Instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
FrameRouter* FrameRouter::Instance = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
std::array<uint8_t, 4> data;
|
||||||
|
uint8_t extra[16];
|
||||||
|
} frame_buffer_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void send_data(uint8_t link, const uint8_t* data, uint16_t size) {
|
||||||
|
FrameRouter::Instance->send_data(link, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void transport_recv_frame(uint8_t from, uint8_t* data, uint16_t size) {
|
||||||
|
FrameRouter::Instance->transport_recv_frame(from, data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, master_broadcast_is_received_by_everyone) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(0);
|
||||||
|
router_send_frame(0xFF, (uint8_t*)&data, 4);
|
||||||
|
EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
|
||||||
|
.With(Args<1, 2>(ElementsAreArray(data.data)));
|
||||||
|
simulate_transport(0, 1);
|
||||||
|
EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
|
||||||
|
.With(Args<1, 2>(ElementsAreArray(data.data)));
|
||||||
|
simulate_transport(1, 2);
|
||||||
|
EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, master_send_is_received_by_targets) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(0);
|
||||||
|
router_send_frame((1 << 1) | (1 << 2), (uint8_t*)&data, 4);
|
||||||
|
EXPECT_GT(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
|
||||||
|
|
||||||
|
simulate_transport(0, 1);
|
||||||
|
EXPECT_GT(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
|
||||||
|
.With(Args<1, 2>(ElementsAreArray(data.data)));
|
||||||
|
simulate_transport(1, 2);
|
||||||
|
EXPECT_GT(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[2].send_buffers[UP_LINK].size(), 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(0, _, _))
|
||||||
|
.With(Args<1, 2>(ElementsAreArray(data.data)));
|
||||||
|
simulate_transport(2, 3);
|
||||||
|
EXPECT_GT(router_buffers[3].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[3].send_buffers[UP_LINK].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, first_link_sends_to_master) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(1);
|
||||||
|
router_send_frame(0, (uint8_t*)&data, 4);
|
||||||
|
EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(1, _, _))
|
||||||
|
.With(Args<1, 2>(ElementsAreArray(data.data)));
|
||||||
|
simulate_transport(1, 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, second_link_sends_to_master) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(2);
|
||||||
|
router_send_frame(0, (uint8_t*)&data, 4);
|
||||||
|
EXPECT_GT(router_buffers[2].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[2].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
|
||||||
|
simulate_transport(2, 1);
|
||||||
|
EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(2, _, _))
|
||||||
|
.With(Args<1, 2>(ElementsAreArray(data.data)));
|
||||||
|
simulate_transport(1, 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, master_sends_to_master_does_nothing) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(0);
|
||||||
|
router_send_frame(0, (uint8_t*)&data, 4);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, link_sends_to_other_link_does_nothing) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(1);
|
||||||
|
router_send_frame(2, (uint8_t*)&data, 4);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FrameRouter, master_receives_on_uplink_does_nothing) {
|
||||||
|
frame_buffer_t data;
|
||||||
|
data.data = {0xAB, 0x70, 0x55, 0xBB};
|
||||||
|
activate_router(1);
|
||||||
|
router_send_frame(0, (uint8_t*)&data, 4);
|
||||||
|
EXPECT_GT(router_buffers[1].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[1].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
|
||||||
|
EXPECT_CALL(*this, transport_recv_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
|
activate_router(0);
|
||||||
|
receive_data(UP_LINK,
|
||||||
|
router_buffers[1].send_buffers[UP_LINK].data(),
|
||||||
|
router_buffers[1].send_buffers[UP_LINK].size());
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[UP_LINK].size(), 0);
|
||||||
|
EXPECT_EQ(router_buffers[0].send_buffers[DOWN_LINK].size(), 0);
|
||||||
|
}
|
|
@ -22,24 +22,47 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cgreen/cgreen.h>
|
#include "gtest/gtest.h"
|
||||||
#include <cgreen/mocks.h>
|
#include "gmock/gmock.h"
|
||||||
#include "serial_link/protocol/frame_validator.c"
|
extern "C" {
|
||||||
|
#include "serial_link/protocol/frame_validator.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
using testing::_;
|
||||||
|
using testing::ElementsAreArray;
|
||||||
|
using testing::Args;
|
||||||
|
|
||||||
|
class FrameValidator : public testing::Test {
|
||||||
|
public:
|
||||||
|
FrameValidator() {
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~FrameValidator() {
|
||||||
|
Instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_METHOD3(route_incoming_frame, void (uint8_t link, uint8_t* data, uint16_t size));
|
||||||
|
MOCK_METHOD3(byte_stuffer_send_frame, void (uint8_t link, uint8_t* data, uint16_t size));
|
||||||
|
|
||||||
|
static FrameValidator* Instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
FrameValidator* FrameValidator::Instance = nullptr;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
|
void route_incoming_frame(uint8_t link, uint8_t* data, uint16_t size) {
|
||||||
mock(data, size);
|
FrameValidator::Instance->route_incoming_frame(link, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
|
void byte_stuffer_send_frame(uint8_t link, uint8_t* data, uint16_t size) {
|
||||||
mock(data, size);
|
FrameValidator::Instance->byte_stuffer_send_frame(link, data, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Describe(FrameValidator);
|
TEST_F(FrameValidator, doesnt_validate_frames_under_5_bytes) {
|
||||||
BeforeEach(FrameValidator) {}
|
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
|
||||||
AfterEach(FrameValidator) {}
|
.Times(0);
|
||||||
|
|
||||||
Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) {
|
|
||||||
never_expect(route_incoming_frame);
|
|
||||||
uint8_t data[] = {1, 2};
|
uint8_t data[] = {1, 2};
|
||||||
validator_recv_frame(0, 0, 1);
|
validator_recv_frame(0, 0, 1);
|
||||||
validator_recv_frame(0, data, 2);
|
validator_recv_frame(0, data, 2);
|
||||||
|
@ -47,55 +70,46 @@ Ensure(FrameValidator, doesnt_validate_frames_under_5_bytes) {
|
||||||
validator_recv_frame(0, data, 4);
|
validator_recv_frame(0, data, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(FrameValidator, validates_one_byte_frame_with_correct_crc) {
|
TEST_F(FrameValidator, validates_one_byte_frame_with_correct_crc) {
|
||||||
uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
|
uint8_t data[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
|
||||||
expect(route_incoming_frame,
|
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
|
||||||
when(size, is_equal_to(1)),
|
.With(Args<1, 2>(ElementsAreArray(data, 1)));
|
||||||
when(data, is_equal_to_contents_of(data, 1))
|
|
||||||
);
|
|
||||||
validator_recv_frame(0, data, 5);
|
validator_recv_frame(0, data, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
|
TEST_F(FrameValidator, does_not_validate_one_byte_frame_with_incorrect_crc) {
|
||||||
uint8_t data[] = {0x44, 0, 0, 0, 0};
|
uint8_t data[] = {0x44, 0, 0, 0, 0};
|
||||||
never_expect(route_incoming_frame);
|
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
|
||||||
|
.Times(0);
|
||||||
validator_recv_frame(1, data, 5);
|
validator_recv_frame(1, data, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(FrameValidator, validates_four_byte_frame_with_correct_crc) {
|
TEST_F(FrameValidator, validates_four_byte_frame_with_correct_crc) {
|
||||||
uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
|
uint8_t data[] = {0x44, 0x10, 0xFF, 0x00, 0x74, 0x4E, 0x30, 0xBA};
|
||||||
expect(route_incoming_frame,
|
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
|
||||||
when(size, is_equal_to(4)),
|
.With(Args<1, 2>(ElementsAreArray(data, 4)));
|
||||||
when(data, is_equal_to_contents_of(data, 4))
|
|
||||||
);
|
|
||||||
validator_recv_frame(1, data, 8);
|
validator_recv_frame(1, data, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(FrameValidator, validates_five_byte_frame_with_correct_crc) {
|
TEST_F(FrameValidator, validates_five_byte_frame_with_correct_crc) {
|
||||||
uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
|
uint8_t data[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
|
||||||
expect(route_incoming_frame,
|
EXPECT_CALL(*this, route_incoming_frame(_, _, _))
|
||||||
when(size, is_equal_to(5)),
|
.With(Args<1, 2>(ElementsAreArray(data, 5)));
|
||||||
when(data, is_equal_to_contents_of(data, 5))
|
|
||||||
);
|
|
||||||
validator_recv_frame(0, data, 9);
|
validator_recv_frame(0, data, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(FrameValidator, sends_one_byte_with_correct_crc) {
|
TEST_F(FrameValidator, sends_one_byte_with_correct_crc) {
|
||||||
uint8_t original[] = {0x44, 0, 0, 0, 0};
|
uint8_t original[] = {0x44, 0, 0, 0, 0};
|
||||||
uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
|
uint8_t expected[] = {0x44, 0x04, 0x6A, 0xB3, 0xA3};
|
||||||
expect(byte_stuffer_send_frame,
|
EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(expected))),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, sizeof(expected)))
|
|
||||||
);
|
|
||||||
validator_send_frame(0, original, 1);
|
validator_send_frame(0, original, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(FrameValidator, sends_five_bytes_with_correct_crc) {
|
TEST_F(FrameValidator, sends_five_bytes_with_correct_crc) {
|
||||||
uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
|
uint8_t original[] = {1, 2, 3, 4, 5, 0, 0, 0, 0};
|
||||||
uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
|
uint8_t expected[] = {1, 2, 3, 4, 5, 0xF4, 0x99, 0x0B, 0x47};
|
||||||
expect(byte_stuffer_send_frame,
|
EXPECT_CALL(*this, byte_stuffer_send_frame(_, _, _))
|
||||||
when(size, is_equal_to(sizeof(expected))),
|
.With(Args<1, 2>(ElementsAreArray(expected)));
|
||||||
when(data, is_equal_to_contents_of(expected, sizeof(expected)))
|
|
||||||
);
|
|
||||||
validator_send_frame(0, original, 5);
|
validator_send_frame(0, original, 5);
|
||||||
}
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
serial_link_byte_stuffer_SRC :=\
|
||||||
|
$(SERIAL_PATH)/tests/byte_stuffer_tests.cpp \
|
||||||
|
$(SERIAL_PATH)/protocol/byte_stuffer.c
|
||||||
|
|
||||||
|
serial_link_frame_validator_SRC := \
|
||||||
|
$(SERIAL_PATH)/tests/frame_validator_tests.cpp \
|
||||||
|
$(SERIAL_PATH)/protocol/frame_validator.c
|
||||||
|
|
||||||
|
serial_link_frame_router_SRC := \
|
||||||
|
$(SERIAL_PATH)/tests/frame_router_tests.cpp \
|
||||||
|
$(SERIAL_PATH)/protocol/byte_stuffer.c \
|
||||||
|
$(SERIAL_PATH)/protocol/frame_validator.c \
|
||||||
|
$(SERIAL_PATH)/protocol/frame_router.c
|
||||||
|
|
||||||
|
serial_link_triple_buffered_object_SRC := \
|
||||||
|
$(SERIAL_PATH)/tests/triple_buffered_object_tests.cpp \
|
||||||
|
$(SERIAL_PATH)/protocol/triple_buffered_object.c
|
||||||
|
|
||||||
|
serial_link_transport_SRC := \
|
||||||
|
$(SERIAL_PATH)/tests/transport_tests.cpp \
|
||||||
|
$(SERIAL_PATH)/protocol/transport.c \
|
||||||
|
$(SERIAL_PATH)/protocol/triple_buffered_object.c
|
|
@ -0,0 +1,6 @@
|
||||||
|
TEST_LIST +=\
|
||||||
|
serial_link_byte_stuffer\
|
||||||
|
serial_link_frame_validator\
|
||||||
|
serial_link_frame_router\
|
||||||
|
serial_link_triple_buffered_object\
|
||||||
|
serial_link_transport
|
|
@ -1,168 +0,0 @@
|
||||||
/*
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Fred Sundvik
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cgreen/cgreen.h>
|
|
||||||
#include <cgreen/mocks.h>
|
|
||||||
#include "serial_link/protocol/transport.c"
|
|
||||||
#include "serial_link/protocol/triple_buffered_object.c"
|
|
||||||
|
|
||||||
void signal_data_written(void) {
|
|
||||||
mock();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t sent_data[2048];
|
|
||||||
static uint16_t sent_data_size;
|
|
||||||
|
|
||||||
void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
|
|
||||||
mock(destination);
|
|
||||||
memcpy(sent_data + sent_data_size, data, size);
|
|
||||||
sent_data_size += size;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t test;
|
|
||||||
} test_object1_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t test1;
|
|
||||||
uint32_t test2;
|
|
||||||
} test_object2_t;
|
|
||||||
|
|
||||||
MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1_t);
|
|
||||||
MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1_t);
|
|
||||||
SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1_t);
|
|
||||||
|
|
||||||
static remote_object_t* test_remote_objects[] = {
|
|
||||||
REMOTE_OBJECT(master_to_slave),
|
|
||||||
REMOTE_OBJECT(master_to_single_slave),
|
|
||||||
REMOTE_OBJECT(slave_to_master),
|
|
||||||
};
|
|
||||||
|
|
||||||
Describe(Transport);
|
|
||||||
BeforeEach(Transport) {
|
|
||||||
add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
|
|
||||||
sent_data_size = 0;
|
|
||||||
}
|
|
||||||
AfterEach(Transport) {}
|
|
||||||
|
|
||||||
Ensure(Transport, write_to_local_signals_an_event) {
|
|
||||||
begin_write_master_to_slave();
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_slave();
|
|
||||||
begin_write_slave_to_master();
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_slave_to_master();
|
|
||||||
begin_write_master_to_single_slave(1);
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_single_slave(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(Transport, writes_from_master_to_all_slaves) {
|
|
||||||
update_transport();
|
|
||||||
test_object1_t* obj = begin_write_master_to_slave();
|
|
||||||
obj->test = 5;
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_slave();
|
|
||||||
expect(router_send_frame,
|
|
||||||
when(destination, is_equal_to(0xFF)));
|
|
||||||
update_transport();
|
|
||||||
transport_recv_frame(0, sent_data, sent_data_size);
|
|
||||||
test_object1_t* obj2 = read_master_to_slave();
|
|
||||||
assert_that(obj2, is_not_equal_to(NULL));
|
|
||||||
assert_that(obj2->test, is_equal_to(5));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(Transport, writes_from_slave_to_master) {
|
|
||||||
update_transport();
|
|
||||||
test_object1_t* obj = begin_write_slave_to_master();
|
|
||||||
obj->test = 7;
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_slave_to_master();
|
|
||||||
expect(router_send_frame,
|
|
||||||
when(destination, is_equal_to(0)));
|
|
||||||
update_transport();
|
|
||||||
transport_recv_frame(3, sent_data, sent_data_size);
|
|
||||||
test_object1_t* obj2 = read_slave_to_master(2);
|
|
||||||
assert_that(read_slave_to_master(0), is_equal_to(NULL));
|
|
||||||
assert_that(obj2, is_not_equal_to(NULL));
|
|
||||||
assert_that(obj2->test, is_equal_to(7));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(Transport, writes_from_master_to_single_slave) {
|
|
||||||
update_transport();
|
|
||||||
test_object1_t* obj = begin_write_master_to_single_slave(3);
|
|
||||||
obj->test = 7;
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_single_slave(3);
|
|
||||||
expect(router_send_frame,
|
|
||||||
when(destination, is_equal_to(4)));
|
|
||||||
update_transport();
|
|
||||||
transport_recv_frame(0, sent_data, sent_data_size);
|
|
||||||
test_object1_t* obj2 = read_master_to_single_slave();
|
|
||||||
assert_that(obj2, is_not_equal_to(NULL));
|
|
||||||
assert_that(obj2->test, is_equal_to(7));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(Transport, ignores_object_with_invalid_id) {
|
|
||||||
update_transport();
|
|
||||||
test_object1_t* obj = begin_write_master_to_single_slave(3);
|
|
||||||
obj->test = 7;
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_single_slave(3);
|
|
||||||
expect(router_send_frame,
|
|
||||||
when(destination, is_equal_to(4)));
|
|
||||||
update_transport();
|
|
||||||
sent_data[sent_data_size - 1] = 44;
|
|
||||||
transport_recv_frame(0, sent_data, sent_data_size);
|
|
||||||
test_object1_t* obj2 = read_master_to_single_slave();
|
|
||||||
assert_that(obj2, is_equal_to(NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(Transport, ignores_object_with_size_too_small) {
|
|
||||||
update_transport();
|
|
||||||
test_object1_t* obj = begin_write_master_to_slave();
|
|
||||||
obj->test = 7;
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_slave();
|
|
||||||
expect(router_send_frame);
|
|
||||||
update_transport();
|
|
||||||
sent_data[sent_data_size - 2] = 0;
|
|
||||||
transport_recv_frame(0, sent_data, sent_data_size - 1);
|
|
||||||
test_object1_t* obj2 = read_master_to_slave();
|
|
||||||
assert_that(obj2, is_equal_to(NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ensure(Transport, ignores_object_with_size_too_big) {
|
|
||||||
update_transport();
|
|
||||||
test_object1_t* obj = begin_write_master_to_slave();
|
|
||||||
obj->test = 7;
|
|
||||||
expect(signal_data_written);
|
|
||||||
end_write_master_to_slave();
|
|
||||||
expect(router_send_frame);
|
|
||||||
update_transport();
|
|
||||||
sent_data[sent_data_size + 21] = 0;
|
|
||||||
transport_recv_frame(0, sent_data, sent_data_size + 22);
|
|
||||||
test_object1_t* obj2 = read_master_to_slave();
|
|
||||||
assert_that(obj2, is_equal_to(NULL));
|
|
||||||
}
|
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Fred Sundvik
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
using testing::_;
|
||||||
|
using testing::ElementsAreArray;
|
||||||
|
using testing::Args;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "serial_link/protocol/transport.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
struct test_object1 {
|
||||||
|
uint32_t test;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct test_object2 {
|
||||||
|
uint32_t test1;
|
||||||
|
uint32_t test2;
|
||||||
|
};
|
||||||
|
|
||||||
|
MASTER_TO_ALL_SLAVES_OBJECT(master_to_slave, test_object1);
|
||||||
|
MASTER_TO_SINGLE_SLAVE_OBJECT(master_to_single_slave, test_object1);
|
||||||
|
SLAVE_TO_MASTER_OBJECT(slave_to_master, test_object1);
|
||||||
|
|
||||||
|
static remote_object_t* test_remote_objects[] = {
|
||||||
|
REMOTE_OBJECT(master_to_slave),
|
||||||
|
REMOTE_OBJECT(master_to_single_slave),
|
||||||
|
REMOTE_OBJECT(slave_to_master),
|
||||||
|
};
|
||||||
|
|
||||||
|
class Transport : public testing::Test {
|
||||||
|
public:
|
||||||
|
Transport() {
|
||||||
|
Instance = this;
|
||||||
|
add_remote_objects(test_remote_objects, sizeof(test_remote_objects) / sizeof(remote_object_t*));
|
||||||
|
}
|
||||||
|
|
||||||
|
~Transport() {
|
||||||
|
Instance = nullptr;
|
||||||
|
reinitialize_serial_link_transport();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOCK_METHOD0(signal_data_written, void ());
|
||||||
|
MOCK_METHOD1(router_send_frame, void (uint8_t destination));
|
||||||
|
|
||||||
|
void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
|
||||||
|
router_send_frame(destination);
|
||||||
|
std::copy(data, data + size, std::back_inserter(sent_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Transport* Instance;
|
||||||
|
|
||||||
|
std::vector<uint8_t> sent_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
Transport* Transport::Instance = nullptr;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void signal_data_written(void) {
|
||||||
|
Transport::Instance->signal_data_written();
|
||||||
|
}
|
||||||
|
|
||||||
|
void router_send_frame(uint8_t destination, uint8_t* data, uint16_t size) {
|
||||||
|
Transport::Instance->router_send_frame(destination, data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, write_to_local_signals_an_event) {
|
||||||
|
begin_write_master_to_slave();
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_slave();
|
||||||
|
begin_write_slave_to_master();
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_slave_to_master();
|
||||||
|
begin_write_master_to_single_slave(1);
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_single_slave(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, writes_from_master_to_all_slaves) {
|
||||||
|
update_transport();
|
||||||
|
test_object1* obj = begin_write_master_to_slave();
|
||||||
|
obj->test = 5;
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_slave();
|
||||||
|
EXPECT_CALL(*this, router_send_frame(0xFF));
|
||||||
|
update_transport();
|
||||||
|
transport_recv_frame(0, sent_data.data(), sent_data.size());
|
||||||
|
test_object1* obj2 = read_master_to_slave();
|
||||||
|
EXPECT_NE(obj2, nullptr);
|
||||||
|
EXPECT_EQ(obj2->test, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, writes_from_slave_to_master) {
|
||||||
|
update_transport();
|
||||||
|
test_object1* obj = begin_write_slave_to_master();
|
||||||
|
obj->test = 7;
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_slave_to_master();
|
||||||
|
EXPECT_CALL(*this, router_send_frame(0));
|
||||||
|
update_transport();
|
||||||
|
transport_recv_frame(3, sent_data.data(), sent_data.size());
|
||||||
|
test_object1* obj2 = read_slave_to_master(2);
|
||||||
|
EXPECT_EQ(read_slave_to_master(0), nullptr);
|
||||||
|
EXPECT_NE(obj2, nullptr);
|
||||||
|
EXPECT_EQ(obj2->test, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, writes_from_master_to_single_slave) {
|
||||||
|
update_transport();
|
||||||
|
test_object1* obj = begin_write_master_to_single_slave(3);
|
||||||
|
obj->test = 7;
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_single_slave(3);
|
||||||
|
EXPECT_CALL(*this, router_send_frame(4));
|
||||||
|
update_transport();
|
||||||
|
transport_recv_frame(0, sent_data.data(), sent_data.size());
|
||||||
|
test_object1* obj2 = read_master_to_single_slave();
|
||||||
|
EXPECT_NE(obj2, nullptr);
|
||||||
|
EXPECT_EQ(obj2->test, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, ignores_object_with_invalid_id) {
|
||||||
|
update_transport();
|
||||||
|
test_object1* obj = begin_write_master_to_single_slave(3);
|
||||||
|
obj->test = 7;
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_single_slave(3);
|
||||||
|
EXPECT_CALL(*this, router_send_frame(4));
|
||||||
|
update_transport();
|
||||||
|
sent_data[sent_data.size() - 1] = 44;
|
||||||
|
transport_recv_frame(0, sent_data.data(), sent_data.size());
|
||||||
|
test_object1* obj2 = read_master_to_single_slave();
|
||||||
|
EXPECT_EQ(obj2, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, ignores_object_with_size_too_small) {
|
||||||
|
update_transport();
|
||||||
|
test_object1* obj = begin_write_master_to_slave();
|
||||||
|
obj->test = 7;
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_slave();
|
||||||
|
EXPECT_CALL(*this, router_send_frame(_));
|
||||||
|
update_transport();
|
||||||
|
sent_data[sent_data.size() - 2] = 0;
|
||||||
|
transport_recv_frame(0, sent_data.data(), sent_data.size() - 1);
|
||||||
|
test_object1* obj2 = read_master_to_slave();
|
||||||
|
EXPECT_EQ(obj2, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(Transport, ignores_object_with_size_too_big) {
|
||||||
|
update_transport();
|
||||||
|
test_object1* obj = begin_write_master_to_slave();
|
||||||
|
obj->test = 7;
|
||||||
|
EXPECT_CALL(*this, signal_data_written());
|
||||||
|
end_write_master_to_slave();
|
||||||
|
EXPECT_CALL(*this, router_send_frame(_));
|
||||||
|
update_transport();
|
||||||
|
sent_data.resize(sent_data.size() + 22);
|
||||||
|
sent_data[sent_data.size() - 1] = 0;
|
||||||
|
transport_recv_frame(0, sent_data.data(), sent_data.size());
|
||||||
|
test_object1* obj2 = read_master_to_slave();
|
||||||
|
EXPECT_EQ(obj2, nullptr);
|
||||||
|
}
|
|
@ -22,53 +22,55 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cgreen/cgreen.h>
|
#include "gtest/gtest.h"
|
||||||
#include "serial_link/protocol/triple_buffered_object.c"
|
extern "C" {
|
||||||
|
#include "serial_link/protocol/triple_buffered_object.h"
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
struct test_object{
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
uint32_t buffer[3];
|
uint32_t buffer[3];
|
||||||
}test_object_t;
|
};
|
||||||
|
|
||||||
test_object_t test_object;
|
test_object test_object;
|
||||||
|
|
||||||
Describe(TripleBufferedObject);
|
class TripleBufferedObject : public testing::Test {
|
||||||
BeforeEach(TripleBufferedObject) {
|
public:
|
||||||
triple_buffer_init((triple_buffer_object_t*)&test_object);
|
TripleBufferedObject() {
|
||||||
}
|
triple_buffer_init((triple_buffer_object_t*)&test_object);
|
||||||
AfterEach(TripleBufferedObject) {}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(TripleBufferedObject, writes_and_reads_object) {
|
||||||
Ensure(TripleBufferedObject, writes_and_reads_object) {
|
|
||||||
*triple_buffer_begin_write(&test_object) = 0x3456ABCC;
|
*triple_buffer_begin_write(&test_object) = 0x3456ABCC;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
assert_that(*triple_buffer_read(&test_object), is_equal_to(0x3456ABCC));
|
EXPECT_EQ(*triple_buffer_read(&test_object), 0x3456ABCC);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(TripleBufferedObject, does_not_read_empty) {
|
TEST_F(TripleBufferedObject, does_not_read_empty) {
|
||||||
assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
|
EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(TripleBufferedObject, writes_twice_and_reads_object) {
|
TEST_F(TripleBufferedObject, writes_twice_and_reads_object) {
|
||||||
*triple_buffer_begin_write(&test_object) = 0x3456ABCC;
|
*triple_buffer_begin_write(&test_object) = 0x3456ABCC;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
*triple_buffer_begin_write(&test_object) = 0x44778899;
|
*triple_buffer_begin_write(&test_object) = 0x44778899;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
assert_that(*triple_buffer_read(&test_object), is_equal_to(0x44778899));
|
EXPECT_EQ(*triple_buffer_read(&test_object), 0x44778899);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
|
TEST_F(TripleBufferedObject, performs_another_write_in_the_middle_of_read) {
|
||||||
*triple_buffer_begin_write(&test_object) = 1;
|
*triple_buffer_begin_write(&test_object) = 1;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
uint32_t* read = triple_buffer_read(&test_object);
|
uint32_t* read = triple_buffer_read(&test_object);
|
||||||
*triple_buffer_begin_write(&test_object) = 2;
|
*triple_buffer_begin_write(&test_object) = 2;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
assert_that(*read, is_equal_to(1));
|
EXPECT_EQ(*read, 1);
|
||||||
assert_that(*triple_buffer_read(&test_object), is_equal_to(2));
|
EXPECT_EQ(*triple_buffer_read(&test_object), 2);
|
||||||
assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
|
EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
|
TEST_F(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
|
||||||
*triple_buffer_begin_write(&test_object) = 1;
|
*triple_buffer_begin_write(&test_object) = 1;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
uint32_t* read = triple_buffer_read(&test_object);
|
uint32_t* read = triple_buffer_read(&test_object);
|
||||||
|
@ -76,7 +78,7 @@ Ensure(TripleBufferedObject, performs_two_writes_in_the_middle_of_read) {
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
*triple_buffer_begin_write(&test_object) = 3;
|
*triple_buffer_begin_write(&test_object) = 3;
|
||||||
triple_buffer_end_write(&test_object);
|
triple_buffer_end_write(&test_object);
|
||||||
assert_that(*read, is_equal_to(1));
|
EXPECT_EQ(*read, 1);
|
||||||
assert_that(*triple_buffer_read(&test_object), is_equal_to(3));
|
EXPECT_EQ(*triple_buffer_read(&test_object), 3);
|
||||||
assert_that(triple_buffer_read(&test_object), is_equal_to(NULL));
|
EXPECT_EQ(triple_buffer_read(&test_object), nullptr);
|
||||||
}
|
}
|
51
readme.md
51
readme.md
|
@ -1137,3 +1137,54 @@ Here is where you can (optionally) define your `KEYMAP` function to remap your m
|
||||||
```
|
```
|
||||||
|
|
||||||
Each of the `kxx` variables needs to be unique, and usually follows the format `k<row><col>`. You can place `KC_NO` where your dead keys are in your matrix.
|
Each of the `kxx` variables needs to be unique, and usually follows the format `k<row><col>`. You can place `KC_NO` where your dead keys are in your matrix.
|
||||||
|
|
||||||
|
# Unit Testing
|
||||||
|
|
||||||
|
If you are new to unit testing, then you can find many good resources on internet. However most of it is scattered around in small pieces here and there, and there's also many different opinions, so I won't give any recommendations.
|
||||||
|
|
||||||
|
Instead I recommend these two books, explaining two different styles of Unit Testing in detail.
|
||||||
|
|
||||||
|
* "Test Driven Development: By Example: Kent Beck"
|
||||||
|
* "Growing Object-Oriented Software, Guided By Tests: Steve Freeman, Nat Pryce"
|
||||||
|
|
||||||
|
If you prefer videos there are Uncle Bob's [Clean Coders Videos](https://cleancoders.com/), which unfortunately cost quite a bit, especially if you want to watch many of them. But James Shore has a free [Let's Play](http://www.jamesshore.com/Blog/Lets-Play) video series.
|
||||||
|
|
||||||
|
## Google Test and Google Mock
|
||||||
|
It's possible to Unit Test your code using [Google Test](https://github.com/google/googletest). The Google Test framework also includes another component for writing testing mocks and stubs, called "Google Mock". For information how to write the actual tests, please refer to the documentation on that site.
|
||||||
|
|
||||||
|
## Use of C++
|
||||||
|
|
||||||
|
Note that Google Test and therefore any test has to be written in C++, even if the rest of the QMK codebases is written in C. This should hopefully not be a problem even if you don't know any C++, since there's quite clear documentation and examples of the required C++ features, and you can write the rest of the test code almost as you would write normal C. Note that some compiler errors which you might get can look quite scary, but just read carefully what it says, and you should be ok.
|
||||||
|
|
||||||
|
One thing to remember, is that you have to append `extern "C"` around all of your C file includes.
|
||||||
|
|
||||||
|
## Adding tests for new or existing features
|
||||||
|
|
||||||
|
If you want to unit test some feature, then take a look at the existing serial_link tests, in the `quantum/serial_link/tests folder`, and follow the steps below to create a similar structure.
|
||||||
|
|
||||||
|
1. If it doesn't already exist, add a test subfolder to the folder containing the feature.
|
||||||
|
2. Create a `testlist.mk` and a `rules.mk` file in that folder.
|
||||||
|
3. Include those files from the root folder `testlist.mk`and `build_test.mk` respectively.
|
||||||
|
4. Add a new name for your testgroup to the `testlist.mk` file. Each group defined there will be a separate executable. And that's how you can support mocking out different parts. Note that it's worth adding some common prefix, just like it's done for the serial_link tests. The reason for that is that the make command allows substring filtering, so this way you can easily run a subset of the tests.
|
||||||
|
5. Define the source files and required options in the `rules.mk` file.
|
||||||
|
* `_SRC` for source files
|
||||||
|
* `_DEFS` for additional defines
|
||||||
|
* `_INC` for additional include folders
|
||||||
|
6. Write the tests in a new cpp file inside the test folder you created. That file has to be one of the files included from the `rules.mk` file.
|
||||||
|
|
||||||
|
Note how there's several different tests, each mocking out a separate part. Also note that each of them only compiles the very minimum that's needed for the tests. It's recommend that you try to do the same. For a relevant video check out [Matt Hargett "Advanced Unit Testing in C & C++](https://www.youtube.com/watch?v=Wmy6g-aVgZI)
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
To run all the tests in the codebase, type `make test`. You can also run test matching a substring by typing `make test-matchingsubstring` Note that the tests are always compiled with the native compiler of your platform, so they are also run like any other program on your computer.
|
||||||
|
|
||||||
|
## Debugging the tests
|
||||||
|
|
||||||
|
If there are problems with the tests, you can find the executable in the `./build/test` folder. You should be able to run those with GDB or a similar debugger.
|
||||||
|
|
||||||
|
## Full Integration tests
|
||||||
|
|
||||||
|
It's not yet possible to do a full integration test, where you would compile the whole firmware and define a keymap that you are going to test. However there are plans for doing that, because writing tests that way would probably be easier, at least for people that are not used to unit testing.
|
||||||
|
|
||||||
|
In that model you would emulate the input, and expect a certain output from the emulated keyboard.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
include $(ROOT_DIR)/quantum/serial_link/tests/testlist.mk
|
||||||
|
|
||||||
|
define VALIDATE_TEST_LIST
|
||||||
|
ifneq ($1,)
|
||||||
|
ifeq ($$(findstring -,$1),-)
|
||||||
|
$$(error Test names can't contain '-', but '$1' does)
|
||||||
|
else
|
||||||
|
$$(eval $$(call VALIDATE_TEST_LIST,$$(firstword $2),$$(wordlist 2,9999,$2)))
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call VALIDATE_TEST_LIST,$(firstword $(TEST_LIST)),$(wordlist 2,9999,$(TEST_LIST))))
|
|
@ -5,7 +5,7 @@ else ifeq ($(PLATFORM),CHIBIOS)
|
||||||
PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios
|
PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SRC += $(COMMON_DIR)/host.c \
|
TMK_COMMON_SRC += $(COMMON_DIR)/host.c \
|
||||||
$(COMMON_DIR)/keyboard.c \
|
$(COMMON_DIR)/keyboard.c \
|
||||||
$(COMMON_DIR)/action.c \
|
$(COMMON_DIR)/action.c \
|
||||||
$(COMMON_DIR)/action_tapping.c \
|
$(COMMON_DIR)/action_tapping.c \
|
||||||
|
@ -21,98 +21,89 @@ SRC += $(COMMON_DIR)/host.c \
|
||||||
$(PLATFORM_COMMON_DIR)/bootloader.c \
|
$(PLATFORM_COMMON_DIR)/bootloader.c \
|
||||||
|
|
||||||
ifeq ($(PLATFORM),AVR)
|
ifeq ($(PLATFORM),AVR)
|
||||||
SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
|
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(PLATFORM),CHIBIOS)
|
ifeq ($(PLATFORM),CHIBIOS)
|
||||||
SRC += $(PLATFORM_COMMON_DIR)/printf.c
|
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
|
||||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Option modules
|
# Option modules
|
||||||
ifeq ($(strip $(BOOTMAGIC_ENABLE)), yes)
|
ifeq ($(strip $(BOOTMAGIC_ENABLE)), yes)
|
||||||
OPT_DEFS += -DBOOTMAGIC_ENABLE
|
TMK_COMMON_DEFS += -DBOOTMAGIC_ENABLE
|
||||||
SRC += $(COMMON_DIR)/bootmagic.c
|
TMK_COMMON_SRC += $(COMMON_DIR)/bootmagic.c
|
||||||
else
|
else
|
||||||
OPT_DEFS += -DMAGIC_ENABLE
|
TMK_COMMON_DEFS += -DMAGIC_ENABLE
|
||||||
SRC += $(COMMON_DIR)/magic.c
|
TMK_COMMON_SRC += $(COMMON_DIR)/magic.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
|
ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
|
||||||
SRC += $(COMMON_DIR)/mousekey.c
|
TMK_COMMON_SRC += $(COMMON_DIR)/mousekey.c
|
||||||
OPT_DEFS += -DMOUSEKEY_ENABLE
|
TMK_COMMON_DEFS += -DMOUSEKEY_ENABLE
|
||||||
OPT_DEFS += -DMOUSE_ENABLE
|
TMK_COMMON_DEFS += -DMOUSE_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(EXTRAKEY_ENABLE)), yes)
|
ifeq ($(strip $(EXTRAKEY_ENABLE)), yes)
|
||||||
OPT_DEFS += -DEXTRAKEY_ENABLE
|
TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(CONSOLE_ENABLE)), yes)
|
ifeq ($(strip $(CONSOLE_ENABLE)), yes)
|
||||||
OPT_DEFS += -DCONSOLE_ENABLE
|
TMK_COMMON_DEFS += -DCONSOLE_ENABLE
|
||||||
else
|
else
|
||||||
OPT_DEFS += -DNO_PRINT
|
TMK_COMMON_DEFS += -DNO_PRINT
|
||||||
OPT_DEFS += -DNO_DEBUG
|
TMK_COMMON_DEFS += -DNO_DEBUG
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(COMMAND_ENABLE)), yes)
|
ifeq ($(strip $(COMMAND_ENABLE)), yes)
|
||||||
SRC += $(COMMON_DIR)/command.c
|
TMK_COMMON_SRC += $(COMMON_DIR)/command.c
|
||||||
OPT_DEFS += -DCOMMAND_ENABLE
|
TMK_COMMON_DEFS += -DCOMMAND_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(NKRO_ENABLE)), yes)
|
ifeq ($(strip $(NKRO_ENABLE)), yes)
|
||||||
OPT_DEFS += -DNKRO_ENABLE
|
TMK_COMMON_DEFS += -DNKRO_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
|
ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
|
||||||
OPT_DEFS += -DUSB_6KRO_ENABLE
|
TMK_COMMON_DEFS += -DUSB_6KRO_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(SLEEP_LED_ENABLE)), yes)
|
ifeq ($(strip $(SLEEP_LED_ENABLE)), yes)
|
||||||
SRC += $(PLATFORM_COMMON_DIR)/sleep_led.c
|
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/sleep_led.c
|
||||||
OPT_DEFS += -DSLEEP_LED_ENABLE
|
TMK_COMMON_DEFS += -DSLEEP_LED_ENABLE
|
||||||
OPT_DEFS += -DNO_SUSPEND_POWER_DOWN
|
TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
|
ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
|
||||||
SRC += $(COMMON_DIR)/backlight.c
|
TMK_COMMON_SRC += $(COMMON_DIR)/backlight.c
|
||||||
OPT_DEFS += -DBACKLIGHT_ENABLE
|
TMK_COMMON_DEFS += -DBACKLIGHT_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
|
ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
|
||||||
OPT_DEFS += -DBLUETOOTH_ENABLE
|
TMK_COMMON_DEFS += -DBLUETOOTH_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(ONEHAND_ENABLE)), yes)
|
ifeq ($(strip $(ONEHAND_ENABLE)), yes)
|
||||||
OPT_DEFS += -DONEHAND_ENABLE
|
TMK_COMMON_DEFS += -DONEHAND_ENABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(KEYMAP_SECTION_ENABLE)), yes)
|
ifeq ($(strip $(KEYMAP_SECTION_ENABLE)), yes)
|
||||||
OPT_DEFS += -DKEYMAP_SECTION_ENABLE
|
TMK_COMMON_DEFS += -DKEYMAP_SECTION_ENABLE
|
||||||
|
|
||||||
ifeq ($(strip $(MCU)),atmega32u2)
|
ifeq ($(strip $(MCU)),atmega32u2)
|
||||||
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
|
TMK_COMMON_LDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr35.x
|
||||||
else ifeq ($(strip $(MCU)),atmega32u4)
|
else ifeq ($(strip $(MCU)),atmega32u4)
|
||||||
EXTRALDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
|
TMK_COMMON_LDFLAGS = -Wl,-L$(TMK_DIR),-Tldscript_keymap_avr5.x
|
||||||
else
|
else
|
||||||
EXTRALDFLAGS = $(error no ldscript for keymap section)
|
TMK_COMMON_LDFLAGS = $(error no ldscript for keymap section)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(MASTER),right)
|
|
||||||
OPT_DEFS += -DMASTER_IS_ON_RIGHT
|
|
||||||
else
|
|
||||||
ifneq ($(MASTER),left)
|
|
||||||
$(error MASTER does not have a valid value(left/right))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
# Bootloader address
|
# Bootloader address
|
||||||
ifdef STM32_BOOTLOADER_ADDRESS
|
ifdef STM32_BOOTLOADER_ADDRESS
|
||||||
OPT_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
|
TMK_COMMON_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Search Path
|
# Search Path
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
CC = gcc
|
||||||
|
OBJCOPY =
|
||||||
|
OBJDUMP =
|
||||||
|
SIZE =
|
||||||
|
AR =
|
||||||
|
NM =
|
||||||
|
HEX =
|
||||||
|
EEP =
|
||||||
|
BIN =
|
||||||
|
|
||||||
|
|
||||||
|
COMPILEFLAGS += -funsigned-char
|
||||||
|
COMPILEFLAGS += -funsigned-bitfields
|
||||||
|
COMPILEFLAGS += -ffunction-sections
|
||||||
|
COMPILEFLAGS += -fdata-sections
|
||||||
|
COMPILEFLAGS += -fshort-enums
|
||||||
|
|
||||||
|
CFLAGS += $(COMPILEFLAGS)
|
||||||
|
CFLAGS += -fno-inline-small-functions
|
||||||
|
CFLAGS += -fno-strict-aliasing
|
||||||
|
|
||||||
|
CPPFLAGS += $(COMPILEFLAGS)
|
||||||
|
CPPFLAGS += -fno-exceptions
|
||||||
|
CPPFLAGS += -std=gnu++11
|
|
@ -21,13 +21,14 @@ VPATH_SRC := $(VPATH)
|
||||||
vpath %.c $(VPATH_SRC)
|
vpath %.c $(VPATH_SRC)
|
||||||
vpath %.h $(VPATH_SRC)
|
vpath %.h $(VPATH_SRC)
|
||||||
vpath %.cpp $(VPATH_SRC)
|
vpath %.cpp $(VPATH_SRC)
|
||||||
|
vpath %.cc $(VPATH_SRC)
|
||||||
vpath %.hpp $(VPATH_SRC)
|
vpath %.hpp $(VPATH_SRC)
|
||||||
vpath %.S $(VPATH_SRC)
|
vpath %.S $(VPATH_SRC)
|
||||||
VPATH :=
|
VPATH :=
|
||||||
|
|
||||||
# Convert all SRC to OBJ
|
# Convert all SRC to OBJ
|
||||||
define OBJ_FROM_SRC
|
define OBJ_FROM_SRC
|
||||||
$(patsubst %.c,$1/%.o,$(patsubst %.cpp,$1/%.o,$(patsubst %.S,$1/%.o,$($1_SRC))))
|
$(patsubst %.c,$1/%.o,$(patsubst %.cpp,$1/%.o,$(patsubst %.cc,$1/%.o,$(patsubst %.S,$1/%.o,$($1_SRC)))))
|
||||||
endef
|
endef
|
||||||
$(foreach OUTPUT,$(OUTPUTS),$(eval $(OUTPUT)_OBJ +=$(call OBJ_FROM_SRC,$(OUTPUT))))
|
$(foreach OUTPUT,$(OUTPUTS),$(eval $(OUTPUT)_OBJ +=$(call OBJ_FROM_SRC,$(OUTPUT))))
|
||||||
|
|
||||||
|
@ -160,6 +161,7 @@ SCANF_LIB =
|
||||||
|
|
||||||
|
|
||||||
MATH_LIB = -lm
|
MATH_LIB = -lm
|
||||||
|
CREATE_MAP ?= yes
|
||||||
|
|
||||||
|
|
||||||
#---------------- Linker Options ----------------
|
#---------------- Linker Options ----------------
|
||||||
|
@ -170,7 +172,10 @@ MATH_LIB = -lm
|
||||||
# Comennt out "--relax" option to avoid a error such:
|
# Comennt out "--relax" option to avoid a error such:
|
||||||
# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
|
# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
|
||||||
#
|
#
|
||||||
LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
|
|
||||||
|
ifeq ($(CREATE_MAP),yes)
|
||||||
|
LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
|
||||||
|
endif
|
||||||
#LDFLAGS += -Wl,--relax
|
#LDFLAGS += -Wl,--relax
|
||||||
LDFLAGS += $(EXTMEMOPTS)
|
LDFLAGS += $(EXTMEMOPTS)
|
||||||
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
||||||
|
@ -202,14 +207,6 @@ ALL_ASFLAGS = $(MCUFLAGS) -x assembler-with-cpp $(ASFLAGS) $(EXTRAFLAGS)
|
||||||
|
|
||||||
MOVE_DEP = mv -f $(patsubst %.o,%.td,$@) $(patsubst %.o,%.d,$@)
|
MOVE_DEP = mv -f $(patsubst %.o,%.td,$@) $(patsubst %.o,%.d,$@)
|
||||||
|
|
||||||
# Default target.
|
|
||||||
all: build sizeafter
|
|
||||||
|
|
||||||
# Change the build target to build a HEX file or a library.
|
|
||||||
build: elf hex
|
|
||||||
#build: elf hex eep lss sym
|
|
||||||
#build: lib
|
|
||||||
|
|
||||||
|
|
||||||
elf: $(BUILD_DIR)/$(TARGET).elf
|
elf: $(BUILD_DIR)/$(TARGET).elf
|
||||||
hex: $(BUILD_DIR)/$(TARGET).hex
|
hex: $(BUILD_DIR)/$(TARGET).hex
|
||||||
|
@ -305,7 +302,13 @@ $1/%.o : %.cpp $1/%.d $1/cppflags.txt $1/compiler.txt | $(BEGIN)
|
||||||
@mkdir -p $$(@D)
|
@mkdir -p $$(@D)
|
||||||
@$$(SILENT) || printf "$$(MSG_COMPILING_CPP) $$<" | $$(AWK_CMD)
|
@$$(SILENT) || printf "$$(MSG_COMPILING_CPP) $$<" | $$(AWK_CMD)
|
||||||
$$(eval CMD=$$(CC) -c $$($1_CPPFLAGS) $$(GENDEPFLAGS) $$< -o $$@ && $$(MOVE_DEP))
|
$$(eval CMD=$$(CC) -c $$($1_CPPFLAGS) $$(GENDEPFLAGS) $$< -o $$@ && $$(MOVE_DEP))
|
||||||
@$(BUILD_CMD)
|
@$$(BUILD_CMD)
|
||||||
|
|
||||||
|
$1/%.o : %.cc $1/%.d $1/cppflags.txt $1/compiler.txt | $(BEGIN)
|
||||||
|
@mkdir -p $$(@D)
|
||||||
|
@$$(SILENT) || printf "$$(MSG_COMPILING_CPP) $$<" | $$(AWK_CMD)
|
||||||
|
$$(eval CMD=$$(CC) -c $$($1_CPPFLAGS) $$(GENDEPFLAGS) $$< -o $$@ && $$(MOVE_DEP))
|
||||||
|
@$$(BUILD_CMD)
|
||||||
|
|
||||||
# Assemble: create object files from assembler source files.
|
# Assemble: create object files from assembler source files.
|
||||||
$1/%.o : %.S $1/asflags.txt $1/compiler.txt | $(BEGIN)
|
$1/%.o : %.S $1/asflags.txt $1/compiler.txt | $(BEGIN)
|
||||||
|
@ -361,10 +364,10 @@ show_path:
|
||||||
@echo OBJ=$(OBJ)
|
@echo OBJ=$(OBJ)
|
||||||
|
|
||||||
# Create build directory
|
# Create build directory
|
||||||
$(shell mkdir $(BUILD_DIR) 2>/dev/null)
|
$(shell mkdir -p $(BUILD_DIR) 2>/dev/null)
|
||||||
|
|
||||||
# Create object files directory
|
# Create object files directory
|
||||||
$(eval $(foreach OUTPUT,$(OUTPUTS),$(shell mkdir $(OUTPUT) 2>/dev/null)))
|
$(eval $(foreach OUTPUT,$(OUTPUTS),$(shell mkdir -p $(OUTPUT) 2>/dev/null)))
|
||||||
|
|
||||||
# Include the dependency files.
|
# Include the dependency files.
|
||||||
-include $(patsubst %.o,%.d,$(OBJ))
|
-include $(patsubst %.o,%.d,$(OBJ))
|
||||||
|
|
Loading…
Reference in New Issue