unittest now contained directly
This commit is contained in:
parent
c677358343
commit
865ea3386c
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "unittest"]
|
|
||||||
path = unittest
|
|
||||||
url = https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests.git
|
|
1
unittest
1
unittest
@ -1 +0,0 @@
|
|||||||
Subproject commit 76cbb97ae410a7440d2b71eaecd4eea4a5cccaf3
|
|
415
unittest/Makefile-FSFW-Tests
Normal file
415
unittest/Makefile-FSFW-Tests
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Makefile for FSFW Test
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# User-modifiable options
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Fundamentals on the build process of C/C++ Software:
|
||||||
|
# https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
|
||||||
|
|
||||||
|
# Make documentation: https://www.gnu.org/software/make/manual/make.pdf
|
||||||
|
# Online: https://www.gnu.org/software/make/manual/make.html
|
||||||
|
# General rules: http://make.mad-scientist.net/papers/rules-of-makefiles/#rule3
|
||||||
|
SHELL = /bin/sh
|
||||||
|
|
||||||
|
# Chip & board used for compilation
|
||||||
|
# (can be overriden by adding CHIP=chip and BOARD=board to the command-line)
|
||||||
|
# Unit Test can only be run on host machine for now (Linux)
|
||||||
|
FRAMEWORK_PATH = fsfw
|
||||||
|
FILE_ROOT = $(FRAMEWORK_PATH)/unittest
|
||||||
|
BOARD = unittest
|
||||||
|
LINUX = 1
|
||||||
|
OS_FSFW = linux
|
||||||
|
CUSTOM_DEFINES += -D$(OS_FSFW)
|
||||||
|
|
||||||
|
# Copied from stackoverflow, can be used to differentiate between Windows
|
||||||
|
# and Linux
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
CUSTOM_DEFINES += -DWIN32
|
||||||
|
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
|
||||||
|
CUSTOM_DEFINES += -DAMD64
|
||||||
|
else
|
||||||
|
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
|
||||||
|
CUSTOM_DEFINES += -DAMD64
|
||||||
|
endif
|
||||||
|
ifeq ($(PROCESSOR_ARCHITECTURE),x86)
|
||||||
|
CUSTOM_DEFINES += -DIA32
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
ifeq ($(UNAME_S),Linux)
|
||||||
|
DETECTED_OS = LINUX
|
||||||
|
CUSTOM_DEFINES += -DLINUX
|
||||||
|
endif
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
CUSTOM_DEFINES += -DOSX
|
||||||
|
endif
|
||||||
|
UNAME_P := $(shell uname -p)
|
||||||
|
ifeq ($(UNAME_P),x86_64)
|
||||||
|
CUSTOM_DEFINES += -DAMD64
|
||||||
|
endif
|
||||||
|
ifneq ($(filter %86,$(UNAME_P)),)
|
||||||
|
CUSTOM_DEFINES += -DIA32
|
||||||
|
endif
|
||||||
|
ifneq ($(filter arm%,$(UNAME_P)),)
|
||||||
|
CUSTOM_DEFINES += -DARM
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
UNIT_TEST = 1
|
||||||
|
# General folder paths
|
||||||
|
CONFIG_PATH = $(FILE_ROOT)/config
|
||||||
|
UNIT_TEST_PATH = $(FILE_ROOT)/tests
|
||||||
|
CORE_PATH = $(FILE_ROOT)/core
|
||||||
|
|
||||||
|
# Output file basename
|
||||||
|
BASENAME = fsfw
|
||||||
|
BINARY_NAME := $(BASENAME)-$(BOARD)
|
||||||
|
# Output files will be put in this directory inside
|
||||||
|
OUTPUT_FOLDER = $(OS)
|
||||||
|
|
||||||
|
# Optimization level. Optimized for debugging.
|
||||||
|
OPTIMIZATION = -O0
|
||||||
|
|
||||||
|
# Default debug output. Optimized for debugging.
|
||||||
|
DEBUG_LEVEL = -g3
|
||||||
|
|
||||||
|
ifdef GCOV
|
||||||
|
CUSTOM_DEFINES += -DGCOV
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
# Output directories
|
||||||
|
BUILDPATH = _bin
|
||||||
|
DEPENDPATH = _dep
|
||||||
|
OBJECTPATH = _obj
|
||||||
|
|
||||||
|
ifeq ($(MAKECMDGOALS),mission)
|
||||||
|
BUILD_FOLDER = mission
|
||||||
|
else
|
||||||
|
BUILD_FOLDER = devel
|
||||||
|
endif
|
||||||
|
|
||||||
|
DEPENDDIR = $(DEPENDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER)
|
||||||
|
OBJDIR = $(OBJECTPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER)
|
||||||
|
BINDIR = $(BUILDPATH)
|
||||||
|
|
||||||
|
CLEANDEP = $(DEPENDPATH)/$(OUTPUT_FOLDER)
|
||||||
|
CLEANOBJ = $(OBJECTPATH)/$(OUTPUT_FOLDER)
|
||||||
|
CLEANBIN = $(BUILDPATH)
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Tools and Includes
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Tool suffix when cross-compiling
|
||||||
|
CROSS_COMPILE =
|
||||||
|
|
||||||
|
# C Compiler
|
||||||
|
CC = $(CROSS_COMPILE)gcc
|
||||||
|
|
||||||
|
# C++ compiler
|
||||||
|
CXX = $(CROSS_COMPILE)g++
|
||||||
|
|
||||||
|
# Additional Tools
|
||||||
|
SIZE = $(CROSS_COMPILE)size
|
||||||
|
STRIP = $(CROSS_COMPILE)strip
|
||||||
|
CP = $(CROSS_COMPILE)objcopy
|
||||||
|
|
||||||
|
HEXCOPY = $(CP) -O ihex
|
||||||
|
BINCOPY = $(CP) -O binary
|
||||||
|
# files to be compiled, will be filled in by include makefiles
|
||||||
|
# := assignment is neccessary so we get all paths right
|
||||||
|
# https://www.gnu.org/software/make/manual/html_node/Flavors.html
|
||||||
|
CSRC :=
|
||||||
|
CXXSRC :=
|
||||||
|
ASRC :=
|
||||||
|
INCLUDES :=
|
||||||
|
|
||||||
|
# Directories where $(directoryname).mk files should be included from
|
||||||
|
SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(UNIT_TEST_PATH) $(CONFIG_PATH) \
|
||||||
|
$(CORE_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
I_INCLUDES += $(addprefix -I, $(INCLUDES))
|
||||||
|
|
||||||
|
# This is a hack from http://make.mad-scientist.net/the-eval-function/
|
||||||
|
#
|
||||||
|
# The problem is, that included makefiles should be aware of their relative path
|
||||||
|
# but not need to guess or hardcode it. So we set $(CURRENTPATH) for them. If
|
||||||
|
# we do this globally and the included makefiles want to include other makefiles as
|
||||||
|
# well, they would overwrite $(CURRENTPATH), screwing the include after them.
|
||||||
|
#
|
||||||
|
# By using a for-loop with an eval'd macro, we can generate the code to include all
|
||||||
|
# sub-makefiles (with the correct $(CURRENTPATH) set) before actually evaluating
|
||||||
|
# (and by this possibly changing $(CURRENTPATH)) them.
|
||||||
|
#
|
||||||
|
# This works recursively, if an included makefile wants to include, it can safely set
|
||||||
|
# $(SUBDIRS) (which has already been evaluated here) and do
|
||||||
|
# "$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))"
|
||||||
|
# $(SUBDIRS) must be relative to the project root, so to include subdir foo, set
|
||||||
|
# $(SUBDIRS) = $(CURRENTPATH)/foo.
|
||||||
|
define INCLUDE_FILE
|
||||||
|
CURRENTPATH := $S
|
||||||
|
include $(S)/$(notdir $S).mk
|
||||||
|
endef
|
||||||
|
$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))
|
||||||
|
|
||||||
|
INCLUDES += $(FILE_ROOT)
|
||||||
|
INCLUDES += $(FILE_ROOT)/catch2/
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Source Files
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# All source files which are not includes by the .mk files are added here
|
||||||
|
# Please ensure that no files are included by both .mk file and here !
|
||||||
|
|
||||||
|
# if a target is not listed in the current directory,
|
||||||
|
# make searches in the directories specified with VPATH
|
||||||
|
|
||||||
|
# All C Sources included by .mk files are assigned here
|
||||||
|
# Add the objects to sources so dependency handling works
|
||||||
|
C_OBJECTS += $(CSRC:.c=.o)
|
||||||
|
|
||||||
|
# Objects built from Assembly source files
|
||||||
|
ASM_OBJECTS = $(ASRC:.S=.o)
|
||||||
|
|
||||||
|
# Objects built from C++ source files
|
||||||
|
CXX_OBJECTS += $(CXXSRC:.cpp=.o)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Build Configuration + Output
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
TARGET = Debug build.
|
||||||
|
DEBUG_MESSAGE = Off
|
||||||
|
OPTIMIZATION_MESSAGE = Off
|
||||||
|
|
||||||
|
# Define Messages
|
||||||
|
MSG_INFO = Software: Hosted unittest \(Catch2\) for the FSFW.
|
||||||
|
MSG_OPTIMIZATION = Optimization: $(OPTIMIZATION), $(OPTIMIZATION_MESSAGE)
|
||||||
|
MSG_TARGET = Target Build: $(TARGET)
|
||||||
|
MSG_DEBUG = Debug level: $(DEBUG_LEVEL), FSFW Debugging: $(DEBUG_MESSAGE)
|
||||||
|
|
||||||
|
MSG_LINKING = Linking:
|
||||||
|
MSG_COMPILING = Compiling:
|
||||||
|
MSG_ASSEMBLING = Assembling:
|
||||||
|
MSG_DEPENDENCY = Collecting dependencies for:
|
||||||
|
MSG_BINARY = Generate binary:
|
||||||
|
|
||||||
|
# See https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld
|
||||||
|
# Used to throw away unused code. Reduces code size significantly !
|
||||||
|
# -Wl,--gc-sections: needs to be passed to the linker to throw aways unused code
|
||||||
|
ifdef KEEP_UNUSED_CODE
|
||||||
|
PROTOTYPE_OPTIMIZATION =
|
||||||
|
UNUSED_CODE_REMOVAL =
|
||||||
|
else
|
||||||
|
PROTOTYPE_OPTIMIZATION = -ffunction-sections -fdata-sections
|
||||||
|
UNUSED_CODE_REMOVAL = -Wl,--gc-sections
|
||||||
|
# Link time optimization
|
||||||
|
# See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for reference
|
||||||
|
# Link time is larger and size of object files can not be retrieved
|
||||||
|
# but resulting binary is smaller. Could be used in mission/deployment build
|
||||||
|
# Requires -ffunction-section in linker call
|
||||||
|
LINK_TIME_OPTIMIZATION = -flto
|
||||||
|
OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Dependency Flags
|
||||||
|
# These flags tell the compiler to build dependencies
|
||||||
|
# See: https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html
|
||||||
|
# Using following guide: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine
|
||||||
|
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPENDDIR)/$*.d
|
||||||
|
|
||||||
|
# Flags for the compiler call
|
||||||
|
# - std: Which C++ version to use. Common versions: c++11, c++14 and c++17
|
||||||
|
# - Wall: enable all warnings
|
||||||
|
# - Wextra: enable extra warnings
|
||||||
|
# - g: defines debug level
|
||||||
|
# - fmessage-length: to control the formatting algorithm for diagnostic messages;
|
||||||
|
# =0 means no line-wrapping is done; each error message appears on a single line
|
||||||
|
# - fno-exceptions: stops generating extra code needed to propagate exceptions,
|
||||||
|
# which can produce significant data size overhead
|
||||||
|
CUSTOM_DEFINES += -DUNIT_TEST
|
||||||
|
WARNING_FLAGS = -Wall -Wshadow=local -Wextra -Wimplicit-fallthrough=1 \
|
||||||
|
-Wno-unused-parameter
|
||||||
|
|
||||||
|
CXXDEFINES := $(CUSTOM_DEFINES)
|
||||||
|
CFLAGS +=
|
||||||
|
CXXFLAGS += -I. $(DEBUG_LEVEL) $(WARNING_FLAGS) $(DEPFLAGS) -fmessage-length=0 $(OPTIMIZATION)\
|
||||||
|
$(I_INCLUDES) $(CXXDEFINES)
|
||||||
|
CPPFLAGS += -std=c++11
|
||||||
|
|
||||||
|
# Flags for the linker call
|
||||||
|
# LINK_INCLUDES specify the path to used libraries and the linker script
|
||||||
|
# LINK_LIBRARIES: Link real time support
|
||||||
|
LDFLAGS := $(DEBUG_LEVEL) $(UNUSED_CODE_REMOVAL) $(OPTIMIZATION) -pthread
|
||||||
|
LINK_INCLUDES :=
|
||||||
|
LINK_LIBRARIES :=
|
||||||
|
|
||||||
|
ifdef LINUX
|
||||||
|
LINK_LIBRARIES += -lrt
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
LINK_LIBRARIES += -lwsock32 -lws2_32
|
||||||
|
LDFLASGS += -fuse-ld=lld
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Gnu Coverage Tools Flags
|
||||||
|
ifdef GCOV
|
||||||
|
GCOV_CXXFLAGS = -fprofile-arcs -ftest-coverage --coverage -fno-inline \
|
||||||
|
-fno-inline-small-functions -fno-default-inline
|
||||||
|
CXXFLAGS += $(GCOV_CXXFLAGS)
|
||||||
|
GCOV_LINKER_LIBS = -lgcov -fprofile-arcs -ftest-coverage
|
||||||
|
LINK_LIBRARIES += $(GCOV_LINKER_LIBS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# $(info $${CXXFLAGS} is [${CXXFLAGS}])
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Rules
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# the call function assigns parameters to temporary variables
|
||||||
|
# https://www.gnu.org/software/make/manual/make.html#Call-Function
|
||||||
|
# $(1) = Memory names
|
||||||
|
# Rules are called for each memory type
|
||||||
|
# Two Expansion Symbols $$ are to escape the dollar sign for eval.
|
||||||
|
# See: http://make.mad-scientist.net/the-eval-function/
|
||||||
|
|
||||||
|
default: all
|
||||||
|
|
||||||
|
# Cleans all files
|
||||||
|
hardclean:
|
||||||
|
-rm -rf $(BUILDPATH)
|
||||||
|
-rm -rf $(OBJECTPATH)
|
||||||
|
-rm -rf $(DEPENDPATH)
|
||||||
|
|
||||||
|
# Only clean files for current build
|
||||||
|
clean:
|
||||||
|
-rm -rf $(CLEANOBJ)
|
||||||
|
-rm -rf $(CLEANBIN)
|
||||||
|
-rm -rf $(CLEANDEP)
|
||||||
|
|
||||||
|
# Only clean binaries. Useful for changing the binary type when object files
|
||||||
|
# are already compiled so complete rebuild is not necessary
|
||||||
|
cleanbin:
|
||||||
|
-rm -rf $(CLEANBIN)
|
||||||
|
|
||||||
|
# In this section, the binaries are built for all selected memories
|
||||||
|
# notestfw: all
|
||||||
|
all: executable
|
||||||
|
|
||||||
|
# Build target configuration
|
||||||
|
release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION)
|
||||||
|
release: LINK_TIME_OPTIMIZATION = -flto
|
||||||
|
release: TARGET = Mission build.
|
||||||
|
release: OPTIMIZATION_MESSAGE = On with Link Time Optimization
|
||||||
|
|
||||||
|
debug: CXXDEFINES += -DDEBUG
|
||||||
|
debug: TARGET = Debug
|
||||||
|
debug: DEBUG_MESSAGE = On
|
||||||
|
|
||||||
|
ifndef KEEP_UNUSED_CODE
|
||||||
|
debug release: OPTIMIZATION_MESSAGE += , no unused code removal
|
||||||
|
endif
|
||||||
|
|
||||||
|
debug release notestfw: executable
|
||||||
|
|
||||||
|
executable: $(BINDIR)/$(BINARY_NAME).elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_INFO)
|
||||||
|
@echo $(MSG_TARGET)
|
||||||
|
@echo $(MSG_OPTIMIZATION)
|
||||||
|
@echo $(MSG_DEBUG)
|
||||||
|
|
||||||
|
C_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(C_OBJECTS))
|
||||||
|
CXX_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(CXX_OBJECTS))
|
||||||
|
ASM_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(ASM_OBJECTS))
|
||||||
|
ALL_OBJECTS = $(ASM_OBJECTS_PREFIXED) $(C_OBJECTS_PREFIXED) \
|
||||||
|
$(CXX_OBJECTS_PREFIXED)
|
||||||
|
|
||||||
|
# Useful for debugging the Makefile
|
||||||
|
# Also see: https://www.oreilly.com/openbook/make3/book/ch12.pdf
|
||||||
|
# $(info $${ALL_OBJECTS} is [${ALL_OBJECTS}])
|
||||||
|
# $(info $${CXXSRC} is [${CXXSRC}])
|
||||||
|
|
||||||
|
# Automatic variables are used here extensively. Some of them
|
||||||
|
# are escaped($$) to suppress immediate evaluation. The most important ones are:
|
||||||
|
# $@: Name of Target (left side of rule)
|
||||||
|
# $<: Name of the first prerequisite (right side of rule)
|
||||||
|
# @^: List of all prerequisite, omitting duplicates
|
||||||
|
# @D: Directory and file-within-directory part of $@
|
||||||
|
|
||||||
|
# Generates binary and displays all build properties
|
||||||
|
# -p with mkdir ignores error and creates directory when needed.
|
||||||
|
|
||||||
|
# SHOW_DETAILS = 1
|
||||||
|
|
||||||
|
|
||||||
|
# Link with required libraries: HAL (Hardware Abstraction Layer) and
|
||||||
|
# HCC (File System Library)
|
||||||
|
$(BINDIR)/$(BINARY_NAME).elf: $(ALL_OBJECTS)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_LINKING) Target $@
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ifdef SHOW_DETAILS
|
||||||
|
$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES)
|
||||||
|
else
|
||||||
|
@$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES)
|
||||||
|
endif
|
||||||
|
ifeq ($(BUILD_FOLDER), mission)
|
||||||
|
# With Link Time Optimization, section size is not available
|
||||||
|
$(SIZE) $@
|
||||||
|
else
|
||||||
|
$(SIZE) $^ $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(BINDIR)/$(BINARY_NAME).hex: $(BINDIR)/$(BINARY_NAME).elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_BINARY)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(HEXCOPY) $< $@
|
||||||
|
|
||||||
|
# Build new objects for changed dependencies.
|
||||||
|
$(OBJDIR)/%.o: %.cpp
|
||||||
|
$(OBJDIR)/%.o: %.cpp $(DEPENDDIR)/%.d | $(DEPENDDIR)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COMPILING) $<
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ifdef SHOW_DETAILS
|
||||||
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||||
|
else
|
||||||
|
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(OBJDIR)/%.o: %.c
|
||||||
|
$(OBJDIR)/%.o: %.c $(DEPENDDIR)/%.d | $(DEPENDDIR)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COMPILING) $<
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ifdef SHOW_DETAILS
|
||||||
|
$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $<
|
||||||
|
else
|
||||||
|
@$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $<
|
||||||
|
endif
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Dependency Handling
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Dependency Handling according to following guide:
|
||||||
|
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
|
||||||
|
$(DEPENDDIR):
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
DEPENDENCY_RELATIVE = $(CSRC:.c=.d) $(CXXSRC:.cpp=.d)
|
||||||
|
# This is the list of all dependencies
|
||||||
|
DEPFILES = $(addprefix $(DEPENDDIR)/, $(DEPENDENCY_RELATIVE))
|
||||||
|
# Create subdirectories for dependencies
|
||||||
|
$(DEPFILES):
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
# Include all dependencies
|
||||||
|
include $(wildcard $(DEPFILES))
|
||||||
|
|
||||||
|
# .PHONY tells make that these targets aren't files
|
||||||
|
.PHONY: clean release debug all hardclean cleanbin
|
121
unittest/README.md
Normal file
121
unittest/README.md
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
## FSFW Testing
|
||||||
|
This repository contains testing and unit testing components.
|
||||||
|
|
||||||
|
[Catch2](https://github.com/catchorg/Catch2) has been used as a framework,
|
||||||
|
and these unit tests can only be run on a linux host machine.
|
||||||
|
The makefile with default settings creates the unit test binary which can be
|
||||||
|
run in the terminal or in eclipse.
|
||||||
|
|
||||||
|
### Instructions
|
||||||
|
Basic steps:
|
||||||
|
|
||||||
|
1. Clone this branch
|
||||||
|
```sh
|
||||||
|
git clone https://egit.irs.uni-stuttgart.de/fsfw/fsfw_tests.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Inititate the framework submodule (need to only be done once)
|
||||||
|
```sh
|
||||||
|
git submodule init
|
||||||
|
git submodule sync
|
||||||
|
git submodule update
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Run the makefile With
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make all -j<Number Of Processors>
|
||||||
|
```
|
||||||
|
This will build the debug version of the unit tests.
|
||||||
|
The release version can be built with the target `release`
|
||||||
|
|
||||||
|
4. Run the binary located in the \_bin folder in the terminal or in eclipse.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
_bin/<binaryName>.elf [--success]
|
||||||
|
```
|
||||||
|
The success parameter is optional. Leaving it out ommits the success messages.
|
||||||
|
|
||||||
|
5. To clear the binary, object and dependency folder, run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that on most UNIX environments (e.g. Ubuntu), the real time functionalities used by the UNIX pthread module are restricted, which will lead to permission errors when creating these tasks.
|
||||||
|
|
||||||
|
To solve this issues, try following steps:
|
||||||
|
|
||||||
|
1. Edit the /etc/security/limits.conf
|
||||||
|
file and add following lines at the end (worked on Ubuntu 19.10):
|
||||||
|
```sh
|
||||||
|
<username> hard rtprio 99
|
||||||
|
<username> soft rtprio 99
|
||||||
|
```
|
||||||
|
Then restart the computer. <br>
|
||||||
|
The soft limit can also be set in the console with `ulimit -Sr` if the hard
|
||||||
|
limit has been increased,
|
||||||
|
but it is recommended to add it to the file as well for convenience.
|
||||||
|
If adding the second line is not desired for security reasons,
|
||||||
|
the soft limit needs to be set for each session. If using an IDE like eclipse
|
||||||
|
in that case, the IDE needs to be started from the console after setting
|
||||||
|
the soft limit higher there.
|
||||||
|
2. Run the shell script inside the linux folder (worked on Ubuntu 18.04)
|
||||||
|
```sh
|
||||||
|
./unlockRealtime
|
||||||
|
```
|
||||||
|
This script executes the `setcap` command on bash and on the binaries.
|
||||||
|
It also increases the soft real time limit of the current shell instance
|
||||||
|
to the maximum. If running the script before executing the binary does
|
||||||
|
not help, try the following step.
|
||||||
|
|
||||||
|
### Eclipse CDT settings
|
||||||
|
|
||||||
|
The default eclipse terminal has issues displaying the colors used
|
||||||
|
when running the unit test binary by catch2. To fix this issue,
|
||||||
|
install the ANSI Escape In Console package from the eclipse marketplace.
|
||||||
|
|
||||||
|
### GCOV integration
|
||||||
|
|
||||||
|
GCOV has been integrated as a code coverage tool.
|
||||||
|
It can be enabled by adding `GCOV=1` to the build process as an additional argument.
|
||||||
|
Coverage data will be provided in form of .gcno and .gcda files.
|
||||||
|
These can be displayed in eclipse by looking
|
||||||
|
for a .gcno or .gcda file in the \_obj folder, double-clicking it
|
||||||
|
and picking the right source-binary. This will generate
|
||||||
|
information about which lines of a file have run, provided it is open in
|
||||||
|
eclipse.
|
||||||
|
|
||||||
|
### LCOV integration
|
||||||
|
|
||||||
|
The files generated by GCOV can also be processed by the tool LCOV.
|
||||||
|
On ubuntu, the tool can be installed with the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt-get install lcov
|
||||||
|
````
|
||||||
|
|
||||||
|
After that, the tool can be run by building the unit tests with `GCOV=1`,
|
||||||
|
running them at least one time and then executing the `lcov.sh` script.
|
||||||
|
|
||||||
|
### Adding unit tests
|
||||||
|
|
||||||
|
The catch unit tests are located in unittest/testfw. To add new unit tests,
|
||||||
|
add them to the UnitTestCatch.cpp file or add a new source file which
|
||||||
|
includes catch.hpp.
|
||||||
|
|
||||||
|
For writing basics tests, the [assertion documentation](https://github.com/catchorg/Catch2/blob/master/docs/assertions.md#top)
|
||||||
|
or the existing examples are a good guideliens.
|
||||||
|
For more advanced tests, refer to the [catch2 documentation](https://github.com/catchorg/Catch2/blob/master/docs/Readme.md#top).
|
||||||
|
|
||||||
|
### Compile without test framework
|
||||||
|
Alternatively, the unit tests can also be run internally without
|
||||||
|
a framework. This can be used to perform unit tests on the real hardware.
|
||||||
|
To do this, run
|
||||||
|
```sh
|
||||||
|
make -j<Number Of Processors> notestfw
|
||||||
|
```
|
||||||
|
This will instruct the makefile to exclude the test framework main.cpp
|
||||||
|
and include our own. This will also create a binary which can be used
|
||||||
|
outside the host machine (a Makefile adaptions might be neccessary
|
||||||
|
if another OS than linux is required)
|
23
unittest/catch2/LICENSE.txt
Normal file
23
unittest/catch2/LICENSE.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
17618
unittest/catch2/catch.hpp
Normal file
17618
unittest/catch2/catch.hpp
Normal file
File diff suppressed because it is too large
Load Diff
62
unittest/catch2/catch_reporter_automake.hpp
Normal file
62
unittest/catch2/catch_reporter_automake.hpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Created by Justin R. Wilson on 2/19/2017.
|
||||||
|
* Copyright 2017 Justin R. Wilson. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct AutomakeReporter : StreamingReporterBase<AutomakeReporter> {
|
||||||
|
AutomakeReporter( ReporterConfig const& _config )
|
||||||
|
: StreamingReporterBase( _config )
|
||||||
|
{}
|
||||||
|
|
||||||
|
~AutomakeReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results in the format of Automake .trs files";
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertionStarting( AssertionInfo const& ) override {}
|
||||||
|
|
||||||
|
bool assertionEnded( AssertionStats const& /*_assertionStats*/ ) override { return true; }
|
||||||
|
|
||||||
|
void testCaseEnded( TestCaseStats const& _testCaseStats ) override {
|
||||||
|
// Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
|
||||||
|
stream << ":test-result: ";
|
||||||
|
if (_testCaseStats.totals.assertions.allPassed()) {
|
||||||
|
stream << "PASS";
|
||||||
|
} else if (_testCaseStats.totals.assertions.allOk()) {
|
||||||
|
stream << "XFAIL";
|
||||||
|
} else {
|
||||||
|
stream << "FAIL";
|
||||||
|
}
|
||||||
|
stream << ' ' << _testCaseStats.testInfo.name << '\n';
|
||||||
|
StreamingReporterBase::testCaseEnded( _testCaseStats );
|
||||||
|
}
|
||||||
|
|
||||||
|
void skipTest( TestCaseInfo const& testInfo ) override {
|
||||||
|
stream << ":test-result: SKIP " << testInfo.name << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
AutomakeReporter::~AutomakeReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "automake", AutomakeReporter)
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
|
181
unittest/catch2/catch_reporter_sonarqube.hpp
Normal file
181
unittest/catch2/catch_reporter_sonarqube.hpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Created by Daniel Garcia on 2018-12-04.
|
||||||
|
* Copyright Social Point SL. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||||
|
#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct SonarQubeReporter : CumulativeReporterBase<SonarQubeReporter> {
|
||||||
|
|
||||||
|
SonarQubeReporter(ReporterConfig const& config)
|
||||||
|
: CumulativeReporterBase(config)
|
||||||
|
, xml(config.stream()) {
|
||||||
|
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||||
|
m_reporterPrefs.shouldReportAllAssertions = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SonarQubeReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results in the Generic Test Data SonarQube XML format";
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::set<Verbosity> getSupportedVerbosities() {
|
||||||
|
return { Verbosity::Normal };
|
||||||
|
}
|
||||||
|
|
||||||
|
void noMatchingTestCases(std::string const& /*spec*/) override {}
|
||||||
|
|
||||||
|
void testRunStarting(TestRunInfo const& testRunInfo) override {
|
||||||
|
CumulativeReporterBase::testRunStarting(testRunInfo);
|
||||||
|
xml.startElement("testExecutions");
|
||||||
|
xml.writeAttribute("version", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
void testGroupEnded(TestGroupStats const& testGroupStats) override {
|
||||||
|
CumulativeReporterBase::testGroupEnded(testGroupStats);
|
||||||
|
writeGroup(*m_testGroups.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRunEndedCumulative() override {
|
||||||
|
xml.endElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeGroup(TestGroupNode const& groupNode) {
|
||||||
|
std::map<std::string, TestGroupNode::ChildNodes> testsPerFile;
|
||||||
|
for(auto const& child : groupNode.children)
|
||||||
|
testsPerFile[child->value.testInfo.lineInfo.file].push_back(child);
|
||||||
|
|
||||||
|
for(auto const& kv : testsPerFile)
|
||||||
|
writeTestFile(kv.first.c_str(), kv.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeTestFile(const char* filename, TestGroupNode::ChildNodes const& testCaseNodes) {
|
||||||
|
XmlWriter::ScopedElement e = xml.scopedElement("file");
|
||||||
|
xml.writeAttribute("path", filename);
|
||||||
|
|
||||||
|
for(auto const& child : testCaseNodes)
|
||||||
|
writeTestCase(*child);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeTestCase(TestCaseNode const& testCaseNode) {
|
||||||
|
// All test cases have exactly one section - which represents the
|
||||||
|
// test case itself. That section may have 0-n nested sections
|
||||||
|
assert(testCaseNode.children.size() == 1);
|
||||||
|
SectionNode const& rootSection = *testCaseNode.children.front();
|
||||||
|
writeSection("", rootSection, testCaseNode.value.testInfo.okToFail());
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
|
||||||
|
std::string name = trim(sectionNode.stats.sectionInfo.name);
|
||||||
|
if(!rootName.empty())
|
||||||
|
name = rootName + '/' + name;
|
||||||
|
|
||||||
|
if(!sectionNode.assertions.empty() || !sectionNode.stdOut.empty() || !sectionNode.stdErr.empty()) {
|
||||||
|
XmlWriter::ScopedElement e = xml.scopedElement("testCase");
|
||||||
|
xml.writeAttribute("name", name);
|
||||||
|
xml.writeAttribute("duration", static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
|
||||||
|
|
||||||
|
writeAssertions(sectionNode, okToFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto const& childNode : sectionNode.childSections)
|
||||||
|
writeSection(name, *childNode, okToFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeAssertions(SectionNode const& sectionNode, bool okToFail) {
|
||||||
|
for(auto const& assertion : sectionNode.assertions)
|
||||||
|
writeAssertion( assertion, okToFail);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeAssertion(AssertionStats const& stats, bool okToFail) {
|
||||||
|
AssertionResult const& result = stats.assertionResult;
|
||||||
|
if(!result.isOk()) {
|
||||||
|
std::string elementName;
|
||||||
|
if(okToFail) {
|
||||||
|
elementName = "skipped";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch(result.getResultType()) {
|
||||||
|
case ResultWas::ThrewException:
|
||||||
|
case ResultWas::FatalErrorCondition:
|
||||||
|
elementName = "error";
|
||||||
|
break;
|
||||||
|
case ResultWas::ExplicitFailure:
|
||||||
|
elementName = "failure";
|
||||||
|
break;
|
||||||
|
case ResultWas::ExpressionFailed:
|
||||||
|
elementName = "failure";
|
||||||
|
break;
|
||||||
|
case ResultWas::DidntThrowException:
|
||||||
|
elementName = "failure";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// We should never see these here:
|
||||||
|
case ResultWas::Info:
|
||||||
|
case ResultWas::Warning:
|
||||||
|
case ResultWas::Ok:
|
||||||
|
case ResultWas::Unknown:
|
||||||
|
case ResultWas::FailureBit:
|
||||||
|
case ResultWas::Exception:
|
||||||
|
elementName = "internalError";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlWriter::ScopedElement e = xml.scopedElement(elementName);
|
||||||
|
|
||||||
|
ReusableStringStream messageRss;
|
||||||
|
messageRss << result.getTestMacroName() << "(" << result.getExpression() << ")";
|
||||||
|
xml.writeAttribute("message", messageRss.str());
|
||||||
|
|
||||||
|
ReusableStringStream textRss;
|
||||||
|
if (stats.totals.assertions.total() > 0) {
|
||||||
|
textRss << "FAILED:\n";
|
||||||
|
if (result.hasExpression()) {
|
||||||
|
textRss << "\t" << result.getExpressionInMacro() << "\n";
|
||||||
|
}
|
||||||
|
if (result.hasExpandedExpression()) {
|
||||||
|
textRss << "with expansion:\n\t" << result.getExpandedExpression() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!result.getMessage().empty())
|
||||||
|
textRss << result.getMessage() << "\n";
|
||||||
|
|
||||||
|
for(auto const& msg : stats.infoMessages)
|
||||||
|
if(msg.type == ResultWas::Info)
|
||||||
|
textRss << msg.message << "\n";
|
||||||
|
|
||||||
|
textRss << "at " << result.getSourceInfo();
|
||||||
|
xml.writeText(textRss.str(), XmlFormatting::Newline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
XmlWriter xml;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
SonarQubeReporter::~SonarQubeReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "sonarqube", SonarQubeReporter )
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
|
253
unittest/catch2/catch_reporter_tap.hpp
Normal file
253
unittest/catch2/catch_reporter_tap.hpp
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Created by Colton Wolkins on 2015-08-15.
|
||||||
|
* Copyright 2015 Martin Moene. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TAPReporter : StreamingReporterBase<TAPReporter> {
|
||||||
|
|
||||||
|
using StreamingReporterBase::StreamingReporterBase;
|
||||||
|
|
||||||
|
~TAPReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results in TAP format, suitable for test harnesses";
|
||||||
|
}
|
||||||
|
|
||||||
|
ReporterPreferences getPreferences() const override {
|
||||||
|
return m_reporterPrefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void noMatchingTestCases( std::string const& spec ) override {
|
||||||
|
stream << "# No test cases matched '" << spec << "'" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertionStarting( AssertionInfo const& ) override {}
|
||||||
|
|
||||||
|
bool assertionEnded( AssertionStats const& _assertionStats ) override {
|
||||||
|
++counter;
|
||||||
|
|
||||||
|
stream << "# " << currentTestCaseInfo->name << std::endl;
|
||||||
|
AssertionPrinter printer( stream, _assertionStats, counter );
|
||||||
|
printer.print();
|
||||||
|
|
||||||
|
stream << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testRunEnded( TestRunStats const& _testRunStats ) override {
|
||||||
|
printTotals( _testRunStats.totals );
|
||||||
|
stream << "\n" << std::endl;
|
||||||
|
StreamingReporterBase::testRunEnded( _testRunStats );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t counter = 0;
|
||||||
|
class AssertionPrinter {
|
||||||
|
public:
|
||||||
|
AssertionPrinter& operator= ( AssertionPrinter const& ) = delete;
|
||||||
|
AssertionPrinter( AssertionPrinter const& ) = delete;
|
||||||
|
AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter )
|
||||||
|
: stream( _stream )
|
||||||
|
, result( _stats.assertionResult )
|
||||||
|
, messages( _stats.infoMessages )
|
||||||
|
, itMessage( _stats.infoMessages.begin() )
|
||||||
|
, printInfoMessages( true )
|
||||||
|
, counter(_counter)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
itMessage = messages.begin();
|
||||||
|
|
||||||
|
switch( result.getResultType() ) {
|
||||||
|
case ResultWas::Ok:
|
||||||
|
printResultType( passedString() );
|
||||||
|
printOriginalExpression();
|
||||||
|
printReconstructedExpression();
|
||||||
|
if ( ! result.hasExpression() )
|
||||||
|
printRemainingMessages( Colour::None );
|
||||||
|
else
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::ExpressionFailed:
|
||||||
|
if (result.isOk()) {
|
||||||
|
printResultType(passedString());
|
||||||
|
} else {
|
||||||
|
printResultType(failedString());
|
||||||
|
}
|
||||||
|
printOriginalExpression();
|
||||||
|
printReconstructedExpression();
|
||||||
|
if (result.isOk()) {
|
||||||
|
printIssue(" # TODO");
|
||||||
|
}
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::ThrewException:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "unexpected exception with message:" );
|
||||||
|
printMessage();
|
||||||
|
printExpressionWas();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::FatalErrorCondition:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "fatal error condition with message:" );
|
||||||
|
printMessage();
|
||||||
|
printExpressionWas();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::DidntThrowException:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "expected exception, got none" );
|
||||||
|
printExpressionWas();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::Info:
|
||||||
|
printResultType( "info" );
|
||||||
|
printMessage();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::Warning:
|
||||||
|
printResultType( "warning" );
|
||||||
|
printMessage();
|
||||||
|
printRemainingMessages();
|
||||||
|
break;
|
||||||
|
case ResultWas::ExplicitFailure:
|
||||||
|
printResultType( failedString() );
|
||||||
|
printIssue( "explicitly" );
|
||||||
|
printRemainingMessages( Colour::None );
|
||||||
|
break;
|
||||||
|
// These cases are here to prevent compiler warnings
|
||||||
|
case ResultWas::Unknown:
|
||||||
|
case ResultWas::FailureBit:
|
||||||
|
case ResultWas::Exception:
|
||||||
|
printResultType( "** internal error **" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Colour::Code dimColour() { return Colour::FileName; }
|
||||||
|
|
||||||
|
static const char* failedString() { return "not ok"; }
|
||||||
|
static const char* passedString() { return "ok"; }
|
||||||
|
|
||||||
|
void printSourceInfo() const {
|
||||||
|
Colour colourGuard( dimColour() );
|
||||||
|
stream << result.getSourceInfo() << ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
void printResultType( std::string const& passOrFail ) const {
|
||||||
|
if( !passOrFail.empty() ) {
|
||||||
|
stream << passOrFail << ' ' << counter << " -";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printIssue( std::string const& issue ) const {
|
||||||
|
stream << " " << issue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printExpressionWas() {
|
||||||
|
if( result.hasExpression() ) {
|
||||||
|
stream << ";";
|
||||||
|
{
|
||||||
|
Colour colour( dimColour() );
|
||||||
|
stream << " expression was:";
|
||||||
|
}
|
||||||
|
printOriginalExpression();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printOriginalExpression() const {
|
||||||
|
if( result.hasExpression() ) {
|
||||||
|
stream << " " << result.getExpression();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printReconstructedExpression() const {
|
||||||
|
if( result.hasExpandedExpression() ) {
|
||||||
|
{
|
||||||
|
Colour colour( dimColour() );
|
||||||
|
stream << " for: ";
|
||||||
|
}
|
||||||
|
std::string expr = result.getExpandedExpression();
|
||||||
|
std::replace( expr.begin(), expr.end(), '\n', ' ');
|
||||||
|
stream << expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printMessage() {
|
||||||
|
if ( itMessage != messages.end() ) {
|
||||||
|
stream << " '" << itMessage->message << "'";
|
||||||
|
++itMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printRemainingMessages( Colour::Code colour = dimColour() ) {
|
||||||
|
if (itMessage == messages.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// using messages.end() directly (or auto) yields compilation error:
|
||||||
|
std::vector<MessageInfo>::const_iterator itEnd = messages.end();
|
||||||
|
const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
|
||||||
|
|
||||||
|
{
|
||||||
|
Colour colourGuard( colour );
|
||||||
|
stream << " with " << pluralise( N, "message" ) << ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
for(; itMessage != itEnd; ) {
|
||||||
|
// If this assertion is a warning ignore any INFO messages
|
||||||
|
if( printInfoMessages || itMessage->type != ResultWas::Info ) {
|
||||||
|
stream << " '" << itMessage->message << "'";
|
||||||
|
if ( ++itMessage != itEnd ) {
|
||||||
|
Colour colourGuard( dimColour() );
|
||||||
|
stream << " and";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ostream& stream;
|
||||||
|
AssertionResult const& result;
|
||||||
|
std::vector<MessageInfo> messages;
|
||||||
|
std::vector<MessageInfo>::const_iterator itMessage;
|
||||||
|
bool printInfoMessages;
|
||||||
|
std::size_t counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
void printTotals( const Totals& totals ) const {
|
||||||
|
if( totals.testCases.total() == 0 ) {
|
||||||
|
stream << "1..0 # Skipped: No tests ran.";
|
||||||
|
} else {
|
||||||
|
stream << "1.." << counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
TAPReporter::~TAPReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "tap", TAPReporter )
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_TAP_HPP_INCLUDED
|
219
unittest/catch2/catch_reporter_teamcity.hpp
Normal file
219
unittest/catch2/catch_reporter_teamcity.hpp
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Created by Phil Nash on 19th December 2014
|
||||||
|
* Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
|
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*/
|
||||||
|
#ifndef TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||||
|
#define TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
||||||
|
|
||||||
|
// Don't #include any Catch headers here - we can assume they are already
|
||||||
|
// included before this header.
|
||||||
|
// This is not good practice in general but is necessary in this case so this
|
||||||
|
// file can be distributed as a single header that works with the main
|
||||||
|
// Catch single header.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wpadded"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Catch {
|
||||||
|
|
||||||
|
struct TeamCityReporter : StreamingReporterBase<TeamCityReporter> {
|
||||||
|
TeamCityReporter( ReporterConfig const& _config )
|
||||||
|
: StreamingReporterBase( _config )
|
||||||
|
{
|
||||||
|
m_reporterPrefs.shouldRedirectStdOut = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string escape( std::string const& str ) {
|
||||||
|
std::string escaped = str;
|
||||||
|
replaceInPlace( escaped, "|", "||" );
|
||||||
|
replaceInPlace( escaped, "'", "|'" );
|
||||||
|
replaceInPlace( escaped, "\n", "|n" );
|
||||||
|
replaceInPlace( escaped, "\r", "|r" );
|
||||||
|
replaceInPlace( escaped, "[", "|[" );
|
||||||
|
replaceInPlace( escaped, "]", "|]" );
|
||||||
|
return escaped;
|
||||||
|
}
|
||||||
|
~TeamCityReporter() override;
|
||||||
|
|
||||||
|
static std::string getDescription() {
|
||||||
|
return "Reports test results as TeamCity service messages";
|
||||||
|
}
|
||||||
|
|
||||||
|
void skipTest( TestCaseInfo const& /* testInfo */ ) override {
|
||||||
|
}
|
||||||
|
|
||||||
|
void noMatchingTestCases( std::string const& /* spec */ ) override {}
|
||||||
|
|
||||||
|
void testGroupStarting( GroupInfo const& groupInfo ) override {
|
||||||
|
StreamingReporterBase::testGroupStarting( groupInfo );
|
||||||
|
stream << "##teamcity[testSuiteStarted name='"
|
||||||
|
<< escape( groupInfo.name ) << "']\n";
|
||||||
|
}
|
||||||
|
void testGroupEnded( TestGroupStats const& testGroupStats ) override {
|
||||||
|
StreamingReporterBase::testGroupEnded( testGroupStats );
|
||||||
|
stream << "##teamcity[testSuiteFinished name='"
|
||||||
|
<< escape( testGroupStats.groupInfo.name ) << "']\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void assertionStarting( AssertionInfo const& ) override {}
|
||||||
|
|
||||||
|
bool assertionEnded( AssertionStats const& assertionStats ) override {
|
||||||
|
AssertionResult const& result = assertionStats.assertionResult;
|
||||||
|
if( !result.isOk() ) {
|
||||||
|
|
||||||
|
ReusableStringStream msg;
|
||||||
|
if( !m_headerPrintedForThisSection )
|
||||||
|
printSectionHeader( msg.get() );
|
||||||
|
m_headerPrintedForThisSection = true;
|
||||||
|
|
||||||
|
msg << result.getSourceInfo() << "\n";
|
||||||
|
|
||||||
|
switch( result.getResultType() ) {
|
||||||
|
case ResultWas::ExpressionFailed:
|
||||||
|
msg << "expression failed";
|
||||||
|
break;
|
||||||
|
case ResultWas::ThrewException:
|
||||||
|
msg << "unexpected exception";
|
||||||
|
break;
|
||||||
|
case ResultWas::FatalErrorCondition:
|
||||||
|
msg << "fatal error condition";
|
||||||
|
break;
|
||||||
|
case ResultWas::DidntThrowException:
|
||||||
|
msg << "no exception was thrown where one was expected";
|
||||||
|
break;
|
||||||
|
case ResultWas::ExplicitFailure:
|
||||||
|
msg << "explicit failure";
|
||||||
|
break;
|
||||||
|
|
||||||
|
// We shouldn't get here because of the isOk() test
|
||||||
|
case ResultWas::Ok:
|
||||||
|
case ResultWas::Info:
|
||||||
|
case ResultWas::Warning:
|
||||||
|
CATCH_ERROR( "Internal error in TeamCity reporter" );
|
||||||
|
// These cases are here to prevent compiler warnings
|
||||||
|
case ResultWas::Unknown:
|
||||||
|
case ResultWas::FailureBit:
|
||||||
|
case ResultWas::Exception:
|
||||||
|
CATCH_ERROR( "Not implemented" );
|
||||||
|
}
|
||||||
|
if( assertionStats.infoMessages.size() == 1 )
|
||||||
|
msg << " with message:";
|
||||||
|
if( assertionStats.infoMessages.size() > 1 )
|
||||||
|
msg << " with messages:";
|
||||||
|
for( auto const& messageInfo : assertionStats.infoMessages )
|
||||||
|
msg << "\n \"" << messageInfo.message << "\"";
|
||||||
|
|
||||||
|
|
||||||
|
if( result.hasExpression() ) {
|
||||||
|
msg <<
|
||||||
|
"\n " << result.getExpressionInMacro() << "\n"
|
||||||
|
"with expansion:\n" <<
|
||||||
|
" " << result.getExpandedExpression() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if( currentTestCaseInfo->okToFail() ) {
|
||||||
|
msg << "- failure ignore as test marked as 'ok to fail'\n";
|
||||||
|
stream << "##teamcity[testIgnored"
|
||||||
|
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
|
||||||
|
<< " message='" << escape( msg.str() ) << "'"
|
||||||
|
<< "]\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stream << "##teamcity[testFailed"
|
||||||
|
<< " name='" << escape( currentTestCaseInfo->name )<< "'"
|
||||||
|
<< " message='" << escape( msg.str() ) << "'"
|
||||||
|
<< "]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sectionStarting( SectionInfo const& sectionInfo ) override {
|
||||||
|
m_headerPrintedForThisSection = false;
|
||||||
|
StreamingReporterBase::sectionStarting( sectionInfo );
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCaseStarting( TestCaseInfo const& testInfo ) override {
|
||||||
|
m_testTimer.start();
|
||||||
|
StreamingReporterBase::testCaseStarting( testInfo );
|
||||||
|
stream << "##teamcity[testStarted name='"
|
||||||
|
<< escape( testInfo.name ) << "']\n";
|
||||||
|
stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void testCaseEnded( TestCaseStats const& testCaseStats ) override {
|
||||||
|
StreamingReporterBase::testCaseEnded( testCaseStats );
|
||||||
|
if( !testCaseStats.stdOut.empty() )
|
||||||
|
stream << "##teamcity[testStdOut name='"
|
||||||
|
<< escape( testCaseStats.testInfo.name )
|
||||||
|
<< "' out='" << escape( testCaseStats.stdOut ) << "']\n";
|
||||||
|
if( !testCaseStats.stdErr.empty() )
|
||||||
|
stream << "##teamcity[testStdErr name='"
|
||||||
|
<< escape( testCaseStats.testInfo.name )
|
||||||
|
<< "' out='" << escape( testCaseStats.stdErr ) << "']\n";
|
||||||
|
stream << "##teamcity[testFinished name='"
|
||||||
|
<< escape( testCaseStats.testInfo.name ) << "' duration='"
|
||||||
|
<< m_testTimer.getElapsedMilliseconds() << "']\n";
|
||||||
|
stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printSectionHeader( std::ostream& os ) {
|
||||||
|
assert( !m_sectionStack.empty() );
|
||||||
|
|
||||||
|
if( m_sectionStack.size() > 1 ) {
|
||||||
|
os << getLineOfChars<'-'>() << "\n";
|
||||||
|
|
||||||
|
std::vector<SectionInfo>::const_iterator
|
||||||
|
it = m_sectionStack.begin()+1, // Skip first section (test case)
|
||||||
|
itEnd = m_sectionStack.end();
|
||||||
|
for( ; it != itEnd; ++it )
|
||||||
|
printHeaderString( os, it->name );
|
||||||
|
os << getLineOfChars<'-'>() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
|
||||||
|
|
||||||
|
os << lineInfo << "\n";
|
||||||
|
os << getLineOfChars<'.'>() << "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// if string has a : in first line will set indent to follow it on
|
||||||
|
// subsequent lines
|
||||||
|
static void printHeaderString( std::ostream& os, std::string const& _string, std::size_t indent = 0 ) {
|
||||||
|
std::size_t i = _string.find( ": " );
|
||||||
|
if( i != std::string::npos )
|
||||||
|
i+=2;
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
os << Column( _string )
|
||||||
|
.indent( indent+i)
|
||||||
|
.initialIndent( indent ) << "\n";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
bool m_headerPrintedForThisSection = false;
|
||||||
|
Timer m_testTimer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CATCH_IMPL
|
||||||
|
TeamCityReporter::~TeamCityReporter() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CATCH_REGISTER_REPORTER( "teamcity", TeamCityReporter )
|
||||||
|
|
||||||
|
} // end namespace Catch
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
# pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TWOBLUECUBES_CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
|
32
unittest/config/FSFWConfig.h
Normal file
32
unittest/config/FSFWConfig.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef CONFIG_FSFWCONFIG_H_
|
||||||
|
#define CONFIG_FSFWCONFIG_H_
|
||||||
|
|
||||||
|
#include <fsfw/unittest/config/version.h>
|
||||||
|
|
||||||
|
//! Used to determine whether C++ ostreams are used
|
||||||
|
//! Those can lead to code bloat.
|
||||||
|
#define FSFW_CPP_OSTREAM_ENABLED 1
|
||||||
|
|
||||||
|
//! Reduced printout to further decrese code size
|
||||||
|
//! Be careful, this also turns off most diagnostic prinouts!
|
||||||
|
#define FSFW_REDUCED_PRINTOUT 0
|
||||||
|
|
||||||
|
//! If -DDEBUG is supplied in the build defines, there will be
|
||||||
|
//! additional output which requires the translation files translateObjects
|
||||||
|
//! and translateEvents (and their compiles source files)
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define FSFW_DEBUG_OUTPUT 1
|
||||||
|
//! Specify whether info events are printed too.
|
||||||
|
#define FSFW_DEBUG_INFO 1
|
||||||
|
#include <translateObjects.h>
|
||||||
|
#include <translateEvents.h>
|
||||||
|
#else
|
||||||
|
#define FSFW_DEBUG_OUTPUT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! When using the newlib nano library, C99 support for stdio facilities
|
||||||
|
//! will not be provided. This define should be set to 1 if this is the case.
|
||||||
|
#define FSFW_NEWLIB_NANO_NO_C99_IO 1
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_FSFWCONFIG_H_ */
|
8
unittest/config/TestsConfig.h
Normal file
8
unittest/config/TestsConfig.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||||
|
#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ */
|
48
unittest/config/cdatapool/dataPoolInit.cpp
Normal file
48
unittest/config/cdatapool/dataPoolInit.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <fsfw/unittest/config/cdatapool/dataPoolInit.h>
|
||||||
|
|
||||||
|
void datapool::dataPoolInit(std::map<uint32_t, PoolEntryIF*> * poolMap) {
|
||||||
|
uint8_t UINT8T_INIT[1] = {0};
|
||||||
|
uint16_t UINT16T_INIT[1] = {0};
|
||||||
|
uint32_t UINT32T_INIT[1] = {0};
|
||||||
|
float FLOAT_INIT[2] = {0.0, 0.0};
|
||||||
|
/* FSFW */
|
||||||
|
poolMap->emplace(datapool::INTERNAL_ERROR_STORE_FULL,
|
||||||
|
new PoolEntry<uint32_t>(UINT32T_INIT,1));
|
||||||
|
poolMap->emplace(datapool::INTERNAL_ERROR_MISSED_LIVE_TM,
|
||||||
|
new PoolEntry<uint32_t>(UINT32T_INIT,1));
|
||||||
|
poolMap->emplace(datapool::INTERNAL_ERROR_FULL_MSG_QUEUES,
|
||||||
|
new PoolEntry<uint32_t>(UINT32T_INIT,1));
|
||||||
|
|
||||||
|
/* TEST */
|
||||||
|
poolMap->emplace(datapool::TEST_UINT8,
|
||||||
|
new PoolEntry<uint8_t>(UINT8T_INIT,1));
|
||||||
|
poolMap->emplace(datapool::TEST_UINT16,
|
||||||
|
new PoolEntry<uint16_t>(UINT16T_INIT,1));
|
||||||
|
poolMap->emplace(datapool::TEST_UINT32,
|
||||||
|
new PoolEntry<uint32_t>(UINT32T_INIT,1));
|
||||||
|
poolMap->emplace(datapool::TEST_FLOAT_VECTOR,
|
||||||
|
new PoolEntry<float>(FLOAT_INIT,2));
|
||||||
|
|
||||||
|
// With new initializer list feature and boolean entries.
|
||||||
|
|
||||||
|
// /* FSFW */
|
||||||
|
// poolMap->emplace(datapool::INTERNAL_ERROR_STORE_FULL,
|
||||||
|
// new PoolEntry<uint32_t>({0},1));
|
||||||
|
// poolMap->emplace(datapool::INTERNAL_ERROR_MISSED_LIVE_TM,
|
||||||
|
// new PoolEntry<uint32_t>({0},1));
|
||||||
|
// poolMap->emplace(datapool::INTERNAL_ERROR_FULL_MSG_QUEUES,
|
||||||
|
// new PoolEntry<uint32_t>({0},1));
|
||||||
|
//
|
||||||
|
// /* TEST */
|
||||||
|
// poolMap->emplace(datapool::TEST_BOOLEAN,
|
||||||
|
// new PoolEntry<bool>({0},1));
|
||||||
|
// poolMap->emplace(datapool::TEST_UINT8,
|
||||||
|
// new PoolEntry<uint8_t>({0},1));
|
||||||
|
// poolMap->emplace(datapool::TEST_UINT16,
|
||||||
|
// new PoolEntry<uint16_t>({0},1));
|
||||||
|
// poolMap->emplace(datapool::TEST_UINT32,
|
||||||
|
// new PoolEntry<uint32_t>({0},1));
|
||||||
|
// poolMap->emplace(datapool::TEST_FLOAT_VECTOR,
|
||||||
|
// new PoolEntry<float>({0, 0},2));
|
||||||
|
|
||||||
|
}
|
29
unittest/config/cdatapool/dataPoolInit.h
Normal file
29
unittest/config/cdatapool/dataPoolInit.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||||
|
#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||||
|
|
||||||
|
#include <fsfw/datapool/DataPool.h>
|
||||||
|
#include <fsfw/datapool/PoolEntryIF.h>
|
||||||
|
#include <map>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
|
namespace datapool {
|
||||||
|
void dataPoolInit(std::map<uint32_t, PoolEntryIF*> * poolMap);
|
||||||
|
|
||||||
|
enum datapoolvariables {
|
||||||
|
NO_PARAMETER = 0,
|
||||||
|
|
||||||
|
/** [EXPORT] : [GROUP] FSFW */
|
||||||
|
INTERNAL_ERROR_STORE_FULL = 0xEE000001, //!< [EXPORT] : [NAME] Internal Error Store Entry [UNIT] (-) [SIZE] 1 [TYPE] uint32_t
|
||||||
|
INTERNAL_ERROR_MISSED_LIVE_TM = 0xEE000001, //!< [EXPORT] : [NAME] Internal Error Missed Live Tm [UNIT] (-) [SIZE] 1 [TYPE] uint32_t
|
||||||
|
INTERNAL_ERROR_FULL_MSG_QUEUES = 0xEE000001, //!< [EXPORT] : [NAME] Internal Error Full Msg Queue [UNIT] (-) [SIZE] 1 [TYPE] uint32_t
|
||||||
|
|
||||||
|
/** [EXPORT] : [GROUP] TEST */
|
||||||
|
TEST_BOOLEAN = 0x01010102, //!< [EXPORT] : [NAME] Test Boolean [UNIT] (-) [SIZE] 1 [TYPE] bool
|
||||||
|
TEST_UINT8 = 0x02020204, //!< [EXPORT] : [NAME] Test Byte [UNIT] (-) [SIZE] 1 [TYPE] uint8_t
|
||||||
|
TEST_UINT16 = 0x03030306, //!< [EXPORT] : [NAME] Test UINT16 [UNIT] (-) [SIZE] 1 [TYPE] uint16_t
|
||||||
|
TEST_UINT32 = 0x04040408, //!< [EXPORT] : [NAME] Test UINT32 [UNIT] (-) [SIZE] 1 [TYPE] uint32_t
|
||||||
|
TEST_FLOAT_VECTOR = 0x05050510, //!< [EXPORT] : [NAME] Test Float [UNIT] (-) [SIZE] 2 [TYPE] float
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_CDATAPOOL_DATAPOOLINIT_H_ */
|
15
unittest/config/config.mk
Normal file
15
unittest/config/config.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/cdatapool/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
|
||||||
|
|
||||||
|
INCLUDES += $(CURRENTPATH)
|
||||||
|
INCLUDES += $(CURRENTPATH)/objects
|
||||||
|
INCLUDES += $(CURRENTPATH)/ipc
|
||||||
|
INCLUDES += $(CURRENTPATH)/pollingsequence
|
||||||
|
INCLUDES += $(CURRENTPATH)/returnvalues
|
||||||
|
INCLUDES += $(CURRENTPATH)/tmtc
|
||||||
|
INCLUDES += $(CURRENTPATH)/events
|
||||||
|
INCLUDES += $(CURRENTPATH)/devices
|
||||||
|
INCLUDES += $(CURRENTPATH)/cdatapool
|
11
unittest/config/devices/logicalAddresses.cpp
Normal file
11
unittest/config/devices/logicalAddresses.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/**
|
||||||
|
* \file logicalAddresses.cpp
|
||||||
|
*
|
||||||
|
* \date 06.11.2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fsfw/unittest/config/devices/logicalAddresses.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
15
unittest/config/devices/logicalAddresses.h
Normal file
15
unittest/config/devices/logicalAddresses.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||||
|
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||||
|
|
||||||
|
#include <fsfw/devicehandlers/CookieIF.h>
|
||||||
|
#include <fsfw/unittest/config/objects/systemObjectList.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace addresses {
|
||||||
|
/* Logical addresses have uint32_t datatype */
|
||||||
|
enum logicalAddresses: address_t {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */
|
10
unittest/config/devices/powerSwitcherList.cpp
Normal file
10
unittest/config/devices/powerSwitcherList.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @file switcherList.cpp
|
||||||
|
*
|
||||||
|
* @date 28.11.2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <fsfw/unittest/config/devices/powerSwitcherList.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
22
unittest/config/devices/powerSwitcherList.h
Normal file
22
unittest/config/devices/powerSwitcherList.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* @file switcherList.h
|
||||||
|
*
|
||||||
|
* @date 28.11.2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||||
|
#define CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||||
|
|
||||||
|
namespace switches {
|
||||||
|
/* Switches are uint8_t datatype and go from 0 to 255 */
|
||||||
|
enum switcherList {
|
||||||
|
PCDU,
|
||||||
|
GPS0,
|
||||||
|
GPS1,
|
||||||
|
DUMMY = 129
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */
|
20
unittest/config/events/translateEvents.cpp
Normal file
20
unittest/config/events/translateEvents.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @brief Auto-generated event translation file. Contains 80 translations.
|
||||||
|
* Generated on: 2020-05-02 20:13:41
|
||||||
|
*/
|
||||||
|
#include <fsfw/unittest/config/events/translateEvents.h>
|
||||||
|
|
||||||
|
const char *TEST_EVENT_SERVICE_1_STRING = "TEST_EVENT_SERVICE_1";
|
||||||
|
const char *TEST2_STRING = "TEST2";
|
||||||
|
|
||||||
|
const char * translateEvents(Event event){
|
||||||
|
switch((event&0xFFFF)){
|
||||||
|
case 8000:
|
||||||
|
return TEST_EVENT_SERVICE_1_STRING;
|
||||||
|
case 9100:
|
||||||
|
return TEST2_STRING;
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_EVENT";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
16
unittest/config/events/translateEvents.h
Normal file
16
unittest/config/events/translateEvents.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* translateEvent.h
|
||||||
|
*
|
||||||
|
* Created on: 28 May 2019
|
||||||
|
* Author: Robin
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_EVENTS_TRANSLATEEVENTS_H_
|
||||||
|
#define CONFIG_EVENTS_TRANSLATEEVENTS_H_
|
||||||
|
|
||||||
|
#include <fsfw/events/Event.h>
|
||||||
|
|
||||||
|
const char * translateEvents(Event event);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_EVENTS_TRANSLATEEVENTS_H_ */
|
11
unittest/config/ipc/MissionMessageTypes.cpp
Normal file
11
unittest/config/ipc/MissionMessageTypes.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <fsfw/ipc/CommandMessage.h>
|
||||||
|
#include <fsfw/unittest/config/ipc/MissionMessageTypes.h>
|
||||||
|
|
||||||
|
void messagetypes::clearMissionMessage(CommandMessage* message) {
|
||||||
|
switch((message->getCommand()>>8) & 0xff) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
22
unittest/config/ipc/MissionMessageTypes.h
Normal file
22
unittest/config/ipc/MissionMessageTypes.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||||
|
#define CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||||
|
|
||||||
|
#include <fsfw/ipc/FwMessageTypes.h>
|
||||||
|
|
||||||
|
class CommandMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom command messages are specified here.
|
||||||
|
* Most messages needed to use FSFW are already located in
|
||||||
|
* <fsfw/ipc/FwMessageTypes.h>
|
||||||
|
* @param message Generic Command Message
|
||||||
|
*/
|
||||||
|
namespace messagetypes{
|
||||||
|
enum MESSAGE_TYPE {
|
||||||
|
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
void clearMissionMessage(CommandMessage* message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */
|
37
unittest/config/objects/Factory.cpp
Normal file
37
unittest/config/objects/Factory.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <fsfw/events/EventManager.h>
|
||||||
|
#include <fsfw/health/HealthTable.h>
|
||||||
|
|
||||||
|
#include <fsfw/internalError/InternalErrorReporter.h>
|
||||||
|
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||||
|
#include <fsfw/unittest/config/cdatapool/dataPoolInit.h>
|
||||||
|
#include <fsfw/unittest/config/objects/Factory.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Produces system objects.
|
||||||
|
* @details
|
||||||
|
* Build tasks by using SystemObject Interface (Interface).
|
||||||
|
* Header files of all tasks must be included
|
||||||
|
* Please note that an object has to implement the system object interface
|
||||||
|
* if the interface validity is checked or retrieved later by using the
|
||||||
|
* get<TargetInterface>(object_id) function from the ObjectManagerIF.
|
||||||
|
*
|
||||||
|
* Framework objects are created first.
|
||||||
|
*
|
||||||
|
* @ingroup init
|
||||||
|
*/
|
||||||
|
void Factory::produce(void) {
|
||||||
|
setStaticFrameworkObjectIds();
|
||||||
|
new EventManager(objects::EVENT_MANAGER);
|
||||||
|
new HealthTable(objects::HEALTH_TABLE);
|
||||||
|
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER,
|
||||||
|
datapool::INTERNAL_ERROR_FULL_MSG_QUEUES,
|
||||||
|
datapool::INTERNAL_ERROR_MISSED_LIVE_TM,
|
||||||
|
datapool::INTERNAL_ERROR_STORE_FULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Factory::setStaticFrameworkObjectIds() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
16
unittest/config/objects/Factory.h
Normal file
16
unittest/config/objects/Factory.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef FACTORY_H_
|
||||||
|
#define FACTORY_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||||
|
|
||||||
|
namespace Factory {
|
||||||
|
/**
|
||||||
|
* @brief Creates all SystemObject elements which are persistent
|
||||||
|
* during execution.
|
||||||
|
*/
|
||||||
|
void produce();
|
||||||
|
void setStaticFrameworkObjectIds();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FACTORY_H_ */
|
30
unittest/config/objects/systemObjectList.h
Normal file
30
unittest/config/objects/systemObjectList.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||||
|
#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
// The objects will be instantiated in the ID order
|
||||||
|
namespace objects {
|
||||||
|
enum sourceObjects: uint32_t {
|
||||||
|
/* First Byte 0x50-0x52 reserved for PUS Services **/
|
||||||
|
CCSDS_PACKET_DISTRIBUTOR = 0x50000100,
|
||||||
|
PUS_PACKET_DISTRIBUTOR = 0x50000200,
|
||||||
|
UDP_BRIDGE = 0x50000300,
|
||||||
|
UDP_POLLING_TASK = 0x50000400,
|
||||||
|
|
||||||
|
PUS_SERVICE_3 = 0x51000300,
|
||||||
|
PUS_SERVICE_6_MEM_MGMT = 0x51000500,
|
||||||
|
PUS_SERVICE_23 = 0x51002300,
|
||||||
|
PUS_SERVICE_201_HEALTH = 0x51020100,
|
||||||
|
|
||||||
|
PUS_TIME = 0x52000001,
|
||||||
|
PUS_FUNNEL = 0x52000002,
|
||||||
|
|
||||||
|
/* Test Task */
|
||||||
|
TEST_TASK = 0x42694269,
|
||||||
|
DUMMY_INTERFACE = 0xCAFECAFE,
|
||||||
|
DUMMY_HANDLER = 0x4400AFFE,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */
|
242
unittest/config/objects/translateObjects.cpp
Normal file
242
unittest/config/objects/translateObjects.cpp
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/* Auto-generated event translation file. Contains 77 translations. */
|
||||||
|
#include <fsfw/unittest/config/objects/translateObjects.h>
|
||||||
|
|
||||||
|
const char *AT91_UART2_TEST_TASK_STRING = "AT91_UART2_TEST_TASK";
|
||||||
|
const char *ARDUINO_0_STRING = "ARDUINO_0";
|
||||||
|
const char *ARDUINO_1_STRING = "ARDUINO_1";
|
||||||
|
const char *ARDUINO_2_STRING = "ARDUINO_2";
|
||||||
|
const char *ARDUINO_3_STRING = "ARDUINO_3";
|
||||||
|
const char *ARDUINO_4_STRING = "ARDUINO_4";
|
||||||
|
const char *AT91_I2C_TEST_TASK_STRING = "AT91_I2C_TEST_TASK";
|
||||||
|
const char *TEST_TASK_STRING = "TEST_TASK";
|
||||||
|
const char *PCDU_HANDLER_STRING = "PCDU_HANDLER";
|
||||||
|
const char *DUMMY_HANDLER_STRING = "DUMMY_HANDLER";
|
||||||
|
const char *S_ADC1_DEC2_STRING = "S_ADC1_DEC2";
|
||||||
|
const char *GPS0_HANDLER_STRING = "GPS0_HANDLER";
|
||||||
|
const char *DLR_PVCH_STRING = "DLR_PVCH";
|
||||||
|
const char *GYRO1_STRING = "GYRO1";
|
||||||
|
const char *DLR_IRAS_STRING = "DLR_IRAS";
|
||||||
|
const char *_DEC1_O1_STRING = "_DEC1_O1";
|
||||||
|
const char *_DEC1_O2_STRING = "_DEC1_O2";
|
||||||
|
const char *S1_DEC1_O3_STRING = "S1_DEC1_O3";
|
||||||
|
const char *S2_DEC1_O4_STRING = "S2_DEC1_O4";
|
||||||
|
const char *S3_DEC1_O5_STRING = "S3_DEC1_O5";
|
||||||
|
const char *PT1000_PVHC_DEC1_O6_STRING = "PT1000_PVHC_DEC1_O6";
|
||||||
|
const char *PT1000_CCSDS1_DEC2_STRING = "PT1000_CCSDS1_DEC2";
|
||||||
|
const char *PT1000_MGT1_DEC2_STRING = "PT1000_MGT1_DEC2";
|
||||||
|
const char *S4_DEC2_STRING = "S4_DEC2";
|
||||||
|
const char *S5_DEC2_STRING = "S5_DEC2";
|
||||||
|
const char *S6_DEC2_STRING = "S6_DEC2";
|
||||||
|
const char *PT1000_PVCH_DEC2_STRING = "PT1000_PVCH_DEC2";
|
||||||
|
const char *_DEC3_STRING = "_DEC3";
|
||||||
|
const char *PT1000_CCSDS2_DEC3_STRING = "PT1000_CCSDS2_DEC3";
|
||||||
|
const char *S7_DEC3_STRING = "S7_DEC3";
|
||||||
|
const char *S8_DEC3_STRING = "S8_DEC3";
|
||||||
|
const char *PT1000_PVCH_DEC3_STRING = "PT1000_PVCH_DEC3";
|
||||||
|
const char *GYRO2_STRING = "GYRO2";
|
||||||
|
const char *PT1000_PLOC_DEC4_STRING = "PT1000_PLOC_DEC4";
|
||||||
|
const char *S9_DEC4_STRING = "S9_DEC4";
|
||||||
|
const char *S10_DEC4_STRING = "S10_DEC4";
|
||||||
|
const char *PT1000_PVHC_DEC4_STRING = "PT1000_PVHC_DEC4";
|
||||||
|
const char *S_ADC_DEC4_STRING = "S_ADC_DEC4";
|
||||||
|
const char *GPS1_HANDLER_STRING = "GPS1_HANDLER";
|
||||||
|
const char *DUMMY_GPS_COM_IF_STRING = "DUMMY_GPS_COM_IF";
|
||||||
|
const char *RS232_DEVICE_COM_IF_STRING = "RS232_DEVICE_COM_IF";
|
||||||
|
const char *I2C_DEVICE_COM_IF_STRING = "I2C_DEVICE_COM_IF";
|
||||||
|
const char *GPIO_DEVICE_COM_IF_STRING = "GPIO_DEVICE_COM_IF";
|
||||||
|
const char *SPI_POLLING_TASK_STRING = "SPI_POLLING_TASK";
|
||||||
|
const char *SPI_DEVICE_COM_IF_STRING = "SPI_DEVICE_COM_IF";
|
||||||
|
const char *DUMMY_ECHO_COM_IF_STRING = "DUMMY_ECHO_COM_IF";
|
||||||
|
const char *SD_CARD_HANDLER_STRING = "SD_CARD_HANDLER";
|
||||||
|
const char *CCSDS_PACKET_DISTRIBUTOR_STRING = "CCSDS_PACKET_DISTRIBUTOR";
|
||||||
|
const char *PUS_PACKET_DISTRIBUTOR_STRING = "PUS_PACKET_DISTRIBUTOR";
|
||||||
|
const char *UDP_TMTC_BRIDGE_STRING = "UDP_TMTC_BRIDGE";
|
||||||
|
const char *EMAC_POLLING_TASK_STRING = "EMAC_POLLING_TASK";
|
||||||
|
const char *SERIAL_POLLING_TASK_STRING = "SERIAL_POLLING_TASK";
|
||||||
|
const char *UART_TMTC_BRIDGE_STRING = "UART_TMTC_BRIDGE";
|
||||||
|
const char *PUS_SERVICE_1_STRING = "PUS_SERVICE_1";
|
||||||
|
const char *PUS_SERVICE_2_STRING = "PUS_SERVICE_2";
|
||||||
|
const char *PUS_SERVICE_3_STRING = "PUS_SERVICE_3";
|
||||||
|
const char *PUS_SERVICE_5_STRING = "PUS_SERVICE_5";
|
||||||
|
const char *PUS_SERVICE_6_STRING = "PUS_SERVICE_6";
|
||||||
|
const char *PUS_SERVICE_8_STRING = "PUS_SERVICE_8";
|
||||||
|
const char *PUS_SERVICE_9_STRING = "PUS_SERVICE_9";
|
||||||
|
const char *PUS_SERVICE_17_STRING = "PUS_SERVICE_17";
|
||||||
|
const char *PUS_SERVICE_23_STRING = "PUS_SERVICE_23";
|
||||||
|
const char *PUS_SERVICE_200_STRING = "PUS_SERVICE_200";
|
||||||
|
const char *PUS_SERVICE_201_STRING = "PUS_SERVICE_201";
|
||||||
|
const char *PUS_TIME_STRING = "PUS_TIME";
|
||||||
|
const char *PUS_FUNNEL_STRING = "PUS_FUNNEL";
|
||||||
|
const char *HEALTH_TABLE_STRING = "HEALTH_TABLE";
|
||||||
|
const char *MODE_STORE_STRING = "MODE_STORE";
|
||||||
|
const char *EVENT_MANAGER_STRING = "EVENT_MANAGER";
|
||||||
|
const char *INTERNAL_ERROR_REPORTER_STRING = "INTERNAL_ERROR_REPORTER";
|
||||||
|
const char *TC_STORE_STRING = "TC_STORE";
|
||||||
|
const char *TM_STORE_STRING = "TM_STORE";
|
||||||
|
const char *IPC_STORE_STRING = "IPC_STORE";
|
||||||
|
const char *AT91_SPI_TEST_TASK_STRING = "AT91_SPI_TEST_TASK";
|
||||||
|
const char *STM32_TEST_TASK_STRING = "STM32_TEST_TASK";
|
||||||
|
const char *AT91_UART0_TEST_TASK_STRING = "AT91_UART0_TEST_TASK";
|
||||||
|
const char *NO_OBJECT_STRING = "NO_OBJECT";
|
||||||
|
|
||||||
|
const char* translateObject(object_id_t object){
|
||||||
|
switch((object&0xFFFFFFFF)){
|
||||||
|
case 0x000123336:
|
||||||
|
return AT91_UART2_TEST_TASK_STRING;
|
||||||
|
case 0x01010100:
|
||||||
|
return ARDUINO_0_STRING;
|
||||||
|
case 0x01010101:
|
||||||
|
return ARDUINO_1_STRING;
|
||||||
|
case 0x01010102:
|
||||||
|
return ARDUINO_2_STRING;
|
||||||
|
case 0x01010103:
|
||||||
|
return ARDUINO_3_STRING;
|
||||||
|
case 0x01010104:
|
||||||
|
return ARDUINO_4_STRING;
|
||||||
|
case 0x12345678:
|
||||||
|
return AT91_I2C_TEST_TASK_STRING;
|
||||||
|
case 0x42694269:
|
||||||
|
return TEST_TASK_STRING;
|
||||||
|
case 0x44003200:
|
||||||
|
return PCDU_HANDLER_STRING;
|
||||||
|
case 0x4400AFFE:
|
||||||
|
return DUMMY_HANDLER_STRING;
|
||||||
|
case 0x44020108:
|
||||||
|
return S_ADC1_DEC2_STRING;
|
||||||
|
case 0x44101F00:
|
||||||
|
return GPS0_HANDLER_STRING;
|
||||||
|
case 0x44104000:
|
||||||
|
return DLR_PVCH_STRING;
|
||||||
|
case 0x44105000:
|
||||||
|
return GYRO1_STRING;
|
||||||
|
case 0x44106000:
|
||||||
|
return DLR_IRAS_STRING;
|
||||||
|
case 0x44115401:
|
||||||
|
return _DEC1_O1_STRING;
|
||||||
|
case 0x44115402:
|
||||||
|
return _DEC1_O2_STRING;
|
||||||
|
case 0x44115404:
|
||||||
|
return S1_DEC1_O3_STRING;
|
||||||
|
case 0x44115405:
|
||||||
|
return S2_DEC1_O4_STRING;
|
||||||
|
case 0x44115406:
|
||||||
|
return S3_DEC1_O5_STRING;
|
||||||
|
case 0x44115407:
|
||||||
|
return PT1000_PVHC_DEC1_O6_STRING;
|
||||||
|
case 0x44125401:
|
||||||
|
return PT1000_CCSDS1_DEC2_STRING;
|
||||||
|
case 0x44125403:
|
||||||
|
return PT1000_MGT1_DEC2_STRING;
|
||||||
|
case 0x44125404:
|
||||||
|
return S4_DEC2_STRING;
|
||||||
|
case 0x44125405:
|
||||||
|
return S5_DEC2_STRING;
|
||||||
|
case 0x44125406:
|
||||||
|
return S6_DEC2_STRING;
|
||||||
|
case 0x44125407:
|
||||||
|
return PT1000_PVCH_DEC2_STRING;
|
||||||
|
case 0x44130301:
|
||||||
|
return _DEC3_STRING;
|
||||||
|
case 0x44130302:
|
||||||
|
return PT1000_CCSDS2_DEC3_STRING;
|
||||||
|
case 0x44130305:
|
||||||
|
return S7_DEC3_STRING;
|
||||||
|
case 0x44130306:
|
||||||
|
return S8_DEC3_STRING;
|
||||||
|
case 0x44130307:
|
||||||
|
return PT1000_PVCH_DEC3_STRING;
|
||||||
|
case 0x44130308:
|
||||||
|
return GYRO2_STRING;
|
||||||
|
case 0x44145401:
|
||||||
|
return PT1000_PLOC_DEC4_STRING;
|
||||||
|
case 0x44145404:
|
||||||
|
return S9_DEC4_STRING;
|
||||||
|
case 0x44145405:
|
||||||
|
return S10_DEC4_STRING;
|
||||||
|
case 0x44145406:
|
||||||
|
return PT1000_PVHC_DEC4_STRING;
|
||||||
|
case 0x44145407:
|
||||||
|
return S_ADC_DEC4_STRING;
|
||||||
|
case 0x44202000:
|
||||||
|
return GPS1_HANDLER_STRING;
|
||||||
|
case 0x49001F00:
|
||||||
|
return DUMMY_GPS_COM_IF_STRING;
|
||||||
|
case 0x49005200:
|
||||||
|
return RS232_DEVICE_COM_IF_STRING;
|
||||||
|
case 0x49005300:
|
||||||
|
return I2C_DEVICE_COM_IF_STRING;
|
||||||
|
case 0x49005400:
|
||||||
|
return GPIO_DEVICE_COM_IF_STRING;
|
||||||
|
case 0x49005410:
|
||||||
|
return SPI_POLLING_TASK_STRING;
|
||||||
|
case 0x49005600:
|
||||||
|
return SPI_DEVICE_COM_IF_STRING;
|
||||||
|
case 0x4900AFFE:
|
||||||
|
return DUMMY_ECHO_COM_IF_STRING;
|
||||||
|
case 0x4D0073AD:
|
||||||
|
return SD_CARD_HANDLER_STRING;
|
||||||
|
case 0x50000100:
|
||||||
|
return CCSDS_PACKET_DISTRIBUTOR_STRING;
|
||||||
|
case 0x50000200:
|
||||||
|
return PUS_PACKET_DISTRIBUTOR_STRING;
|
||||||
|
case 0x50000300:
|
||||||
|
return UDP_TMTC_BRIDGE_STRING;
|
||||||
|
case 0x50000400:
|
||||||
|
return EMAC_POLLING_TASK_STRING;
|
||||||
|
case 0x50000600:
|
||||||
|
return SERIAL_POLLING_TASK_STRING;
|
||||||
|
case 0x5000500:
|
||||||
|
return UART_TMTC_BRIDGE_STRING;
|
||||||
|
case 0x51000100:
|
||||||
|
return PUS_SERVICE_1_STRING;
|
||||||
|
case 0x51000200:
|
||||||
|
return PUS_SERVICE_2_STRING;
|
||||||
|
case 0x51000300:
|
||||||
|
return PUS_SERVICE_3_STRING;
|
||||||
|
case 0x51000400:
|
||||||
|
return PUS_SERVICE_5_STRING;
|
||||||
|
case 0x51000500:
|
||||||
|
return PUS_SERVICE_6_STRING;
|
||||||
|
case 0x51000800:
|
||||||
|
return PUS_SERVICE_8_STRING;
|
||||||
|
case 0x51000900:
|
||||||
|
return PUS_SERVICE_9_STRING;
|
||||||
|
case 0x51001700:
|
||||||
|
return PUS_SERVICE_17_STRING;
|
||||||
|
case 0x51002300:
|
||||||
|
return PUS_SERVICE_23_STRING;
|
||||||
|
case 0x51020000:
|
||||||
|
return PUS_SERVICE_200_STRING;
|
||||||
|
case 0x51020100:
|
||||||
|
return PUS_SERVICE_201_STRING;
|
||||||
|
case 0x52000001:
|
||||||
|
return PUS_TIME_STRING;
|
||||||
|
case 0x52000002:
|
||||||
|
return PUS_FUNNEL_STRING;
|
||||||
|
case 0x53010000:
|
||||||
|
return HEALTH_TABLE_STRING;
|
||||||
|
case 0x53010100:
|
||||||
|
return MODE_STORE_STRING;
|
||||||
|
case 0x53030000:
|
||||||
|
return EVENT_MANAGER_STRING;
|
||||||
|
case 0x53040000:
|
||||||
|
return INTERNAL_ERROR_REPORTER_STRING;
|
||||||
|
case 0x534f0100:
|
||||||
|
return TC_STORE_STRING;
|
||||||
|
case 0x534f0200:
|
||||||
|
return TM_STORE_STRING;
|
||||||
|
case 0x534f0300:
|
||||||
|
return IPC_STORE_STRING;
|
||||||
|
case 0x66666666:
|
||||||
|
return AT91_SPI_TEST_TASK_STRING;
|
||||||
|
case 0x77777777:
|
||||||
|
return STM32_TEST_TASK_STRING;
|
||||||
|
case 0x87654321:
|
||||||
|
return AT91_UART0_TEST_TASK_STRING;
|
||||||
|
case 0xFFFFFFFF:
|
||||||
|
return NO_OBJECT_STRING;
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_OBJECT";
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
16
unittest/config/objects/translateObjects.h
Normal file
16
unittest/config/objects/translateObjects.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* translateObjects.h
|
||||||
|
*
|
||||||
|
* Created on: 28 May 2019
|
||||||
|
* Author: Robin
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_OBJECTS_TRANSLATEOBJECTS_H_
|
||||||
|
#define CONFIG_OBJECTS_TRANSLATEOBJECTS_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/ObjectManagerIF.h>
|
||||||
|
|
||||||
|
const char* translateObject(object_id_t object);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_OBJECTS_TRANSLATEOBJECTS_H_ */
|
31
unittest/config/pollingsequence/PollingSequenceFactory.cpp
Normal file
31
unittest/config/pollingsequence/PollingSequenceFactory.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <PollingSequenceFactory.h>
|
||||||
|
#include <systemObjectList.h>
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||||
|
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||||
|
|
||||||
|
ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence)
|
||||||
|
{
|
||||||
|
/* Length of a communication cycle */
|
||||||
|
uint32_t length = thisSequence->getPeriodMs();
|
||||||
|
|
||||||
|
thisSequence->addSlot(objects::DUMMY_HANDLER,
|
||||||
|
length * 0, DeviceHandlerIF::SEND_WRITE);
|
||||||
|
thisSequence->addSlot(objects::DUMMY_HANDLER,
|
||||||
|
length * 0.25, DeviceHandlerIF::GET_WRITE);
|
||||||
|
thisSequence->addSlot(objects::DUMMY_HANDLER,
|
||||||
|
length * 0.5, DeviceHandlerIF::SEND_READ);
|
||||||
|
thisSequence->addSlot(objects::DUMMY_HANDLER,
|
||||||
|
length * 0.75, DeviceHandlerIF::GET_READ);
|
||||||
|
|
||||||
|
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sif::error << "PollingSequence::initialize has errors!" << std::endl;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
31
unittest/config/pollingsequence/PollingSequenceFactory.h
Normal file
31
unittest/config/pollingsequence/PollingSequenceFactory.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef POLLINGSEQUENCEFACTORY_H_
|
||||||
|
#define POLLINGSEQUENCEFACTORY_H_
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
class FixedTimeslotTaskIF;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All device handlers are scheduled by adding them into
|
||||||
|
* Polling Sequence Tables (PST) to satisfy stricter timing requirements of
|
||||||
|
* device communication, a device handler has four different communication steps:
|
||||||
|
* 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface
|
||||||
|
* 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write
|
||||||
|
* 3. DeviceHandlerIF::SEND_READ -> Send read request
|
||||||
|
* 4. DeviceHandlerIF::GET_READ -> Read from interface
|
||||||
|
* The PST specifies precisely when the respective ComIF functions are called
|
||||||
|
* during the communication cycle time.
|
||||||
|
* The task is created using the FixedTimeslotTaskIF,
|
||||||
|
* which utilises the underlying Operating System Abstraction Layer (OSAL)
|
||||||
|
*
|
||||||
|
* @param thisSequence FixedTimeslotTaskIF * object is passed inside the
|
||||||
|
* Factory class when creating the PST
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
namespace pst {
|
||||||
|
|
||||||
|
/* 0.4 second period init*/
|
||||||
|
ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* POLLINGSEQUENCEINIT_H_ */
|
28
unittest/config/returnvalues/classIds.h
Normal file
28
unittest/config/returnvalues/classIds.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* classIds.h
|
||||||
|
*
|
||||||
|
* Created on: 16.07.2018
|
||||||
|
* Author: mohr
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||||
|
#define CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source IDs starts at 73 for now
|
||||||
|
* Framework IDs for ReturnValues run from 0 to 56
|
||||||
|
* and are located inside <fsfw/returnvalues/FwClassIds.h>
|
||||||
|
*/
|
||||||
|
namespace CLASS_ID {
|
||||||
|
enum {
|
||||||
|
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
|
||||||
|
RS232_CHANNEL, //!< RS232
|
||||||
|
I2C_CHANNEL, //!< I2C
|
||||||
|
SPI_CHANNEL, //!< SPI
|
||||||
|
GPS_HANDLER, //!< GPS
|
||||||
|
PUS_SERVICE_3 //!< HKS
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */
|
29
unittest/config/tmtc/PusIds.hpp
Normal file
29
unittest/config/tmtc/PusIds.hpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* PusIds.hpp
|
||||||
|
*
|
||||||
|
* Created on: 27.02.2019
|
||||||
|
* Author: jakob
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_TMTC_PUSIDS_HPP_
|
||||||
|
#define CONFIG_TMTC_PUSIDS_HPP_
|
||||||
|
|
||||||
|
namespace PUS{
|
||||||
|
enum Ids{
|
||||||
|
PUS_SERVICE_1 = 1,
|
||||||
|
PUS_SERVICE_2 = 2,
|
||||||
|
PUS_SERVICE_3 = 3,
|
||||||
|
PUS_SERVICE_5 = 5,
|
||||||
|
PUS_SERVICE_6 = 6,
|
||||||
|
PUS_SERVICE_8 = 8,
|
||||||
|
PUS_SERVICE_9 = 9,
|
||||||
|
PUS_SERVICE_17 = 17,
|
||||||
|
PUS_SERVICE_23 = 23,
|
||||||
|
PUS_SERVICE_200 = 200,
|
||||||
|
PUS_SERVICE_201 = 201,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */
|
19
unittest/config/tmtc/apid.h
Normal file
19
unittest/config/tmtc/apid.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef CONFIG_TMTC_APID_H_
|
||||||
|
#define CONFIG_TMTC_APID_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application Process Definition: entity, uniquely identified by an
|
||||||
|
* application process ID (APID), capable of generating telemetry source
|
||||||
|
* packets and receiving telecommand packets
|
||||||
|
*
|
||||||
|
* SOURCE APID: 0x73 / 115 / s
|
||||||
|
* APID is a 11 bit number
|
||||||
|
*/
|
||||||
|
namespace apid {
|
||||||
|
static const uint16_t SOURCE_OBSW = 0x73;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_APID_H_ */
|
23
unittest/config/tmtc/pusIds.h
Normal file
23
unittest/config/tmtc/pusIds.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef CONFIG_TMTC_PUSIDS_HPP_
|
||||||
|
#define CONFIG_TMTC_PUSIDS_HPP_
|
||||||
|
|
||||||
|
namespace pus {
|
||||||
|
enum Ids{
|
||||||
|
PUS_SERVICE_1 = 1,
|
||||||
|
PUS_SERVICE_2 = 2,
|
||||||
|
PUS_SERVICE_3 = 3,
|
||||||
|
PUS_SERVICE_3_PSB = 3,
|
||||||
|
PUS_SERVICE_5 = 5,
|
||||||
|
PUS_SERVICE_6 = 6,
|
||||||
|
PUS_SERVICE_8 = 8,
|
||||||
|
PUS_SERVICE_9 = 9,
|
||||||
|
PUS_SERVICE_17 = 17,
|
||||||
|
PUS_SERVICE_19 = 19,
|
||||||
|
PUS_SERVICE_20 = 20,
|
||||||
|
PUS_SERVICE_23 = 23,
|
||||||
|
PUS_SERVICE_200 = 200,
|
||||||
|
PUS_SERVICE_201 = 201,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */
|
34
unittest/config/tmtc/subsystemIdRanges.h
Normal file
34
unittest/config/tmtc/subsystemIdRanges.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef CONFIG_TMTC_SUBSYSTEMIDRANGES_H_
|
||||||
|
#define CONFIG_TMTC_SUBSYSTEMIDRANGES_H_
|
||||||
|
|
||||||
|
#include <fsfw/events/fwSubsystemIdRanges.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These IDs are part of the ID for an event thrown by a subsystem.
|
||||||
|
* Numbers 0-80 are reserved for FSFW Subsystem IDs (framework/events/)
|
||||||
|
*/
|
||||||
|
namespace SUBSYSTEM_ID {
|
||||||
|
enum: uint8_t {
|
||||||
|
SUBSYSTE_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||||
|
/**
|
||||||
|
* 80-105: PUS Services
|
||||||
|
*/
|
||||||
|
PUS_SERVICE_2 = 82,
|
||||||
|
PUS_SERVICE_3 = 83,
|
||||||
|
PUS_SERVICE_5 = 85,
|
||||||
|
PUS_SERVICE_6 = 86,
|
||||||
|
PUS_SERVICE_8 = 88,
|
||||||
|
PUS_SERVICE_23 = 91,
|
||||||
|
DUMMY_DEVICE = 100,
|
||||||
|
/**
|
||||||
|
* 105-115: AOCS
|
||||||
|
*/
|
||||||
|
GPS_DEVICE = 105,
|
||||||
|
|
||||||
|
SPI_COM_IF = 128,
|
||||||
|
I2C_COM_IF = 138
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_SUBSYSTEMIDRANGES_H_ */
|
10
unittest/config/tmtc/tmTcSize.h
Normal file
10
unittest/config/tmtc/tmTcSize.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef CONFIG_TMTC_TMTCSIZE_H_
|
||||||
|
#define CONFIG_TMTC_TMTCSIZE_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace tmtcsize {
|
||||||
|
static const uint32_t MAX_TM_PACKET = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_TMTC_TMTCSIZE_H_ */
|
7
unittest/config/version.h
Normal file
7
unittest/config/version.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef CONFIG_VERSION_H_
|
||||||
|
#define CONFIG_VERSION_H_
|
||||||
|
|
||||||
|
#define SW_VERSION 1
|
||||||
|
#define SW_SUBVERSION 6
|
||||||
|
|
||||||
|
#endif /* CONFIG_VERSION_H_ */
|
11
unittest/core/CatchDefinitions.cpp
Normal file
11
unittest/core/CatchDefinitions.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <fsfw/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
StorageManagerIF* tglob::getIpcStoreHandle() {
|
||||||
|
if(objectManager != nullptr) {
|
||||||
|
return objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||||
|
} else {
|
||||||
|
sif::error << "Global object manager uninitialized" << std::endl;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
19
unittest/core/CatchDefinitions.h
Normal file
19
unittest/core/CatchDefinitions.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fsfw/ipc/messageQueueDefinitions.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||||
|
|
||||||
|
namespace retval {
|
||||||
|
static constexpr int CATCH_OK = static_cast<int>(HasReturnvaluesIF::RETURN_OK);
|
||||||
|
static constexpr int CATCH_FAILED = static_cast<int>(HasReturnvaluesIF::RETURN_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace tconst {
|
||||||
|
static constexpr MessageQueueId_t testQueueId = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace tglob {
|
||||||
|
StorageManagerIF* getIpcStoreHandle();
|
||||||
|
}
|
||||||
|
|
27
unittest/core/CatchRunner.cpp
Normal file
27
unittest/core/CatchRunner.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* @file CatchSource.cpp
|
||||||
|
* @brief Source file to compile catch framework.
|
||||||
|
* @details All tests should be written in other files.
|
||||||
|
* For eclipse console output, install ANSI Escape in Console
|
||||||
|
* from the eclipse market place to get colored characters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NO_UNIT_TEST_FRAMEWORK
|
||||||
|
|
||||||
|
#define CATCH_CONFIG_RUNNER
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
|
||||||
|
extern int customSetup();
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] ) {
|
||||||
|
customSetup();
|
||||||
|
|
||||||
|
// Catch internal function call
|
||||||
|
int result = Catch::Session().run( argc, argv );
|
||||||
|
|
||||||
|
// global clean-up
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
41
unittest/core/CatchSetup.cpp
Normal file
41
unittest/core/CatchSetup.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "../config/cdatapool/dataPoolInit.h"
|
||||||
|
#include <fsfw/unittest/config/cdatapool/dataPoolInit.h>
|
||||||
|
#include <fsfw/unittest/config/objects/Factory.h>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
#ifdef GCOV
|
||||||
|
#include <gcov.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/ObjectManager.h>
|
||||||
|
#include <fsfw/objectmanager/ObjectManagerIF.h>
|
||||||
|
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||||
|
#include <fsfw/datapool/DataPool.h>
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Global instantiations normally done in main.cpp */
|
||||||
|
/* Initialize Data Pool */
|
||||||
|
//namespace glob {
|
||||||
|
DataPool dataPool(datapool::dataPoolInit);
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
namespace sif {
|
||||||
|
/* Set up output streams */
|
||||||
|
ServiceInterfaceStream debug("DEBUG");
|
||||||
|
ServiceInterfaceStream info("INFO");
|
||||||
|
ServiceInterfaceStream error("ERROR");
|
||||||
|
ServiceInterfaceStream warning("WARNING");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Global object manager */
|
||||||
|
ObjectManagerIF *objectManager;
|
||||||
|
|
||||||
|
int customSetup() {
|
||||||
|
// global setup
|
||||||
|
objectManager = new ObjectManager(Factory::produce);
|
||||||
|
objectManager -> initialize();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
3
unittest/core/core.mk
Normal file
3
unittest/core/core.mk
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
|
||||||
|
|
||||||
|
INCLUDES += $(CURRENTPATH)
|
10
unittest/core/printChar.cpp
Normal file
10
unittest/core/printChar.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <fsfw/unittest/core/printChar.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
void printChar(const char* character, bool errStream) {
|
||||||
|
if(errStream) {
|
||||||
|
std::putc(*character, stderr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::putc(*character, stdout);
|
||||||
|
}
|
8
unittest/core/printChar.h
Normal file
8
unittest/core/printChar.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef FSFW_UNITTEST_CORE_PRINTCHAR_H_
|
||||||
|
#define FSFW_UNITTEST_CORE_PRINTCHAR_H_
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void printChar(const char*, bool errStream);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FSFW_UNITTEST_CORE_PRINTCHAR_H_ */
|
26
unittest/internal/InternalUnitTester.cpp
Normal file
26
unittest/internal/InternalUnitTester.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <unittest/internal/InternalUnitTester.h>
|
||||||
|
#include <unittest/internal/IntTestMq.h>
|
||||||
|
#include <unittest/internal/IntTestSemaphore.h>
|
||||||
|
#include <unittest/internal/IntTestSerialization.h>
|
||||||
|
#include <unittest/internal/UnittDefinitions.h>
|
||||||
|
#include <unittest/internal/IntTestMutex.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
InternalUnitTester::InternalUnitTester() {}
|
||||||
|
|
||||||
|
InternalUnitTester::~InternalUnitTester() {}
|
||||||
|
|
||||||
|
ReturnValue_t InternalUnitTester::performTests() {
|
||||||
|
sif::info << "Running internal unit tests..\r\n" << std::flush;
|
||||||
|
testserialize::test_serialization();
|
||||||
|
testmq::testMq();
|
||||||
|
testsemaph::testBinSemaph();
|
||||||
|
testsemaph::testCountingSemaph();
|
||||||
|
testmutex::testMutex();
|
||||||
|
sif::info << "Internal unit tests finished.\r\n" << std::flush;
|
||||||
|
return RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
29
unittest/internal/InternalUnitTester.h
Normal file
29
unittest/internal/InternalUnitTester.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef FRAMEWORK_TEST_UNITTESTCLASS_H_
|
||||||
|
#define FRAMEWORK_TEST_UNITTESTCLASS_H_
|
||||||
|
|
||||||
|
#include <unittest/internal/UnittDefinitions.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Can be used for internal testing, for example for hardware specific
|
||||||
|
* tests which can not be run on a host-machine.
|
||||||
|
*
|
||||||
|
* TODO: A lot of ways to improve this class. A way for tests to subscribe
|
||||||
|
* in this central class would be nice. Right now, this is the class
|
||||||
|
* which simply calls all other tests from other files manually.
|
||||||
|
* Maybe there is a better way..
|
||||||
|
*/
|
||||||
|
class InternalUnitTester: public HasReturnvaluesIF {
|
||||||
|
public:
|
||||||
|
InternalUnitTester();
|
||||||
|
virtual~ InternalUnitTester();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some function which calls all other tests
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ReturnValue_t performTests();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* FRAMEWORK_TEST_UNITTESTCLASS_H_ */
|
7
unittest/internal/UnittDefinitions.cpp
Normal file
7
unittest/internal/UnittDefinitions.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <fsfw/unittest/internal/UnittDefinitions.h>
|
||||||
|
|
||||||
|
ReturnValue_t unitt::put_error(std::string errorId) {
|
||||||
|
sif::error << "Unit Tester error: Failed at test ID "
|
||||||
|
<< errorId << "\n" << std::flush;
|
||||||
|
return HasReturnvaluesIF::RETURN_FAILED;
|
||||||
|
}
|
33
unittest/internal/UnittDefinitions.h
Normal file
33
unittest/internal/UnittDefinitions.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef UNITTEST_INTERNAL_UNITTDEFINITIONS_H_
|
||||||
|
#define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_
|
||||||
|
|
||||||
|
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||||
|
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace tv {
|
||||||
|
// POD test values
|
||||||
|
static const bool tv_bool = true;
|
||||||
|
static const uint8_t tv_uint8 {5};
|
||||||
|
static const uint16_t tv_uint16 {283};
|
||||||
|
static const uint32_t tv_uint32 {929221};
|
||||||
|
static const uint64_t tv_uint64 {2929329429};
|
||||||
|
|
||||||
|
static const int8_t tv_int8 {-16};
|
||||||
|
static const int16_t tv_int16 {-829};
|
||||||
|
static const int32_t tv_int32 {-2312};
|
||||||
|
|
||||||
|
static const float tv_float {8.2149214};
|
||||||
|
static const float tv_sfloat = {-922.2321321};
|
||||||
|
static const double tv_double {9.2132142141e8};
|
||||||
|
static const double tv_sdouble {-2.2421e19};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace unitt {
|
||||||
|
ReturnValue_t put_error(std::string errorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ */
|
52
unittest/internal/osal/IntTestMq.cpp
Normal file
52
unittest/internal/osal/IntTestMq.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <fsfw/ipc/MessageQueueIF.h>
|
||||||
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
|
#include <unittest/internal/IntTestMq.h>
|
||||||
|
#include <unittest/internal/UnittDefinitions.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
using retval = HasReturnvaluesIF;
|
||||||
|
|
||||||
|
void testmq::testMq() {
|
||||||
|
std::string id = "[testMq]";
|
||||||
|
MessageQueueIF* testSenderMq =
|
||||||
|
QueueFactory::instance()->createMessageQueue(1);
|
||||||
|
MessageQueueId_t testSenderMqId = testSenderMq->getId();
|
||||||
|
|
||||||
|
MessageQueueIF* testReceiverMq =
|
||||||
|
QueueFactory::instance()->createMessageQueue(1);
|
||||||
|
MessageQueueId_t testReceiverMqId = testReceiverMq->getId();
|
||||||
|
std::array<uint8_t, 20> testData { 0 };
|
||||||
|
testData[0] = 42;
|
||||||
|
MessageQueueMessage testMessage(testData.data(), 1);
|
||||||
|
testSenderMq->setDefaultDestination(testReceiverMqId);
|
||||||
|
|
||||||
|
|
||||||
|
auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
if(result != retval::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
MessageQueueMessage recvMessage;
|
||||||
|
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||||
|
if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
if(result != retval::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
MessageQueueId_t senderId = 0;
|
||||||
|
result = testReceiverMq->receiveMessage(&recvMessage,&senderId);
|
||||||
|
if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
if(senderId != testSenderMqId) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
senderId = testReceiverMq->getLastPartner();
|
||||||
|
if(senderId != testSenderMqId) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
9
unittest/internal/osal/IntTestMq.h
Normal file
9
unittest/internal/osal/IntTestMq.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef UNITTEST_INTERNAL_INTESTMQ_H_
|
||||||
|
#define UNITTEST_INTERNAL_INTESTMQ_H_
|
||||||
|
|
||||||
|
namespace testmq {
|
||||||
|
void testMq();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UNITTEST_INTERNAL_INTESTMQ_H_ */
|
41
unittest/internal/osal/IntTestMutex.cpp
Normal file
41
unittest/internal/osal/IntTestMutex.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <unittest/internal/IntTestMutex.h>
|
||||||
|
#include <fsfw/ipc/MutexFactory.h>
|
||||||
|
#include <unittest/internal/UnittDefinitions.h>
|
||||||
|
|
||||||
|
#if defined(hosted)
|
||||||
|
#include <fsfw/osal/hosted/Mutex.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void testmutex::testMutex() {
|
||||||
|
std::string id = "[testMutex]";
|
||||||
|
MutexIF* mutex = MutexFactory::instance()->createMutex();
|
||||||
|
auto result = mutex->lockMutex(MutexIF::POLLING);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
// timed_mutex from the C++ library specifies undefined behaviour if
|
||||||
|
// the timed mutex is locked twice from the same thread.
|
||||||
|
#if defined(hosted)
|
||||||
|
// hold on, this actually worked ? :-D This calls the function from
|
||||||
|
// another thread and stores the returnvalue in a future.
|
||||||
|
auto future = std::async(&MutexIF::lockMutex, mutex, 1);
|
||||||
|
result = future.get();
|
||||||
|
#else
|
||||||
|
result = mutex->lockMutex(MutexIF::TimeoutType::WAITING, 1);
|
||||||
|
#endif
|
||||||
|
if(result != MutexIF::MUTEX_TIMEOUT) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = mutex->unlockMutex();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
result = mutex->unlockMutex();
|
||||||
|
if(result != MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
10
unittest/internal/osal/IntTestMutex.h
Normal file
10
unittest/internal/osal/IntTestMutex.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef UNITTEST_INTERNAL_INTTESTMUTEX_H_
|
||||||
|
#define UNITTEST_INTERNAL_INTTESTMUTEX_H_
|
||||||
|
|
||||||
|
namespace testmutex {
|
||||||
|
void testMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UNITTEST_INTERNAL_INTTESTMUTEX_H_ */
|
159
unittest/internal/osal/IntTestSemaphore.cpp
Normal file
159
unittest/internal/osal/IntTestSemaphore.cpp
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||||
|
#include <unittest/internal/UnittDefinitions.h>
|
||||||
|
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||||
|
#include <fsfw/timemanager/Stopwatch.h>
|
||||||
|
#include <unittest/internal/IntTestSemaphore.h>
|
||||||
|
|
||||||
|
void testsemaph::testBinSemaph() {
|
||||||
|
std::string id = "[BinSemaphore]";
|
||||||
|
SemaphoreIF* binSemaph =
|
||||||
|
SemaphoreFactory::instance()->createBinarySemaphore();
|
||||||
|
if(binSemaph == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
testBinSemaphoreImplementation(binSemaph, id);
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||||
|
#if defined(freeRTOS)
|
||||||
|
SemaphoreIF* binSemaphUsingTask =
|
||||||
|
SemaphoreFactory::instance()->createBinarySemaphore(1);
|
||||||
|
testBinSemaphoreImplementation(binSemaphUsingTask, id);
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(binSemaphUsingTask);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void testsemaph::testCountingSemaph() {
|
||||||
|
std::string id = "[CountingSemaph]";
|
||||||
|
{
|
||||||
|
// First test: create a binary semaphore by using a counting semaphore.
|
||||||
|
SemaphoreIF* countingSemaph = SemaphoreFactory::instance()->
|
||||||
|
createCountingSemaphore(1,1);
|
||||||
|
if(countingSemaph == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
testBinSemaphoreImplementation(countingSemaph, id);
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||||
|
#if defined(freeRTOS)
|
||||||
|
countingSemaph = SemaphoreFactory::instance()->
|
||||||
|
createCountingSemaphore(1, 1, 1);
|
||||||
|
testBinSemaphoreImplementation(countingSemaph, id);
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Second test: counting semaphore with count 3 and init count of 3.
|
||||||
|
SemaphoreIF* countingSemaph = SemaphoreFactory::instance()->
|
||||||
|
createCountingSemaphore(3,3);
|
||||||
|
testCountingSemaphImplementation(countingSemaph, id);
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||||
|
#if defined(freeRTOS)
|
||||||
|
countingSemaph = SemaphoreFactory::instance()->
|
||||||
|
createCountingSemaphore(3, 0, 1);
|
||||||
|
uint8_t semaphCount = countingSemaph->getSemaphoreCounter();
|
||||||
|
if(semaphCount != 0) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
// release 3 times in a row
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
auto result = countingSemaph->release();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testCountingSemaphImplementation(countingSemaph, id);
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void testsemaph::testBinSemaphoreImplementation(SemaphoreIF* binSemaph,
|
||||||
|
std::string id) {
|
||||||
|
uint8_t semaphCount = binSemaph->getSemaphoreCounter();
|
||||||
|
if(semaphCount != 1) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t result = binSemaph->release();
|
||||||
|
if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
result = binSemaph->acquire(SemaphoreIF::BLOCKING);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// There is not really a point in testing time related, the task
|
||||||
|
// might get interrupted..
|
||||||
|
{
|
||||||
|
//Stopwatch stopwatch(false);
|
||||||
|
result = binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10);
|
||||||
|
//dur_millis_t time = stopwatch.stop();
|
||||||
|
// if(abs(time - 10) > 2) {
|
||||||
|
// sif::error << "UnitTester: Semaphore timeout measured incorrect."
|
||||||
|
// << std::endl;
|
||||||
|
// unitt::put_error(id);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
semaphCount = binSemaph->getSemaphoreCounter();
|
||||||
|
if(semaphCount != 0) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = binSemaph->release();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testsemaph::testCountingSemaphImplementation(SemaphoreIF* countingSemaph,
|
||||||
|
std::string id) {
|
||||||
|
// check count getter function
|
||||||
|
uint8_t semaphCount = countingSemaph->getSemaphoreCounter();
|
||||||
|
if(semaphCount != 3) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
ReturnValue_t result = countingSemaph->release();
|
||||||
|
if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
// acquire 3 times in a row
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
result = countingSemaph->acquire(SemaphoreIF::BLOCKING);
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
Stopwatch stopwatch(false);
|
||||||
|
// attempt to take when count is 0, measure time
|
||||||
|
result = countingSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10);
|
||||||
|
dur_millis_t time = stopwatch.stop();
|
||||||
|
if(abs(time - 10) > 1) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// release 3 times in a row
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
result = countingSemaph->release();
|
||||||
|
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// assert correct full count
|
||||||
|
if(countingSemaph->getSemaphoreCounter() != 3) {
|
||||||
|
unitt::put_error(id);
|
||||||
|
}
|
||||||
|
}
|
15
unittest/internal/osal/IntTestSemaphore.h
Normal file
15
unittest/internal/osal/IntTestSemaphore.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_
|
||||||
|
#define UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_
|
||||||
|
class SemaphoreIF;
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace testsemaph {
|
||||||
|
void testBinSemaph();
|
||||||
|
void testBinSemaphoreImplementation(SemaphoreIF* binSemaph, std::string id);
|
||||||
|
void testCountingSemaph();
|
||||||
|
void testCountingSemaphImplementation(SemaphoreIF* countingSemaph,
|
||||||
|
std::string id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_ */
|
230
unittest/internal/serialize/IntTestSerialization.cpp
Normal file
230
unittest/internal/serialize/IntTestSerialization.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#include <unittest/internal/IntTestSerialization.h>
|
||||||
|
#include <fsfw/serialize/SerializeElement.h>
|
||||||
|
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||||
|
#include <unittest/internal/UnittDefinitions.h>
|
||||||
|
#include <fsfw/serialize/SerializeIF.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
using retval = HasReturnvaluesIF;
|
||||||
|
std::array<uint8_t, 512> testserialize::test_array = { 0 };
|
||||||
|
|
||||||
|
ReturnValue_t testserialize::test_serialization() {
|
||||||
|
// Here, we test all serialization tools. First test basic cases.
|
||||||
|
ReturnValue_t result = test_endianness_tools();
|
||||||
|
if(result != retval::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = test_autoserialization();
|
||||||
|
if(result != retval::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = test_serial_buffer_adapter();
|
||||||
|
if(result != retval::RETURN_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return retval::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t testserialize::test_endianness_tools() {
|
||||||
|
std::string id = "[test_endianness_tools]";
|
||||||
|
test_array[0] = 0;
|
||||||
|
test_array[1] = 0;
|
||||||
|
uint16_t two_byte_value = 1;
|
||||||
|
size_t size = 0;
|
||||||
|
uint8_t* p_array = test_array.data();
|
||||||
|
SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2,
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
// Little endian: Value one on first byte
|
||||||
|
if(test_array[0] != 1 and test_array[1] != 0) {
|
||||||
|
return unitt::put_error(id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
p_array = test_array.data();
|
||||||
|
size = 0;
|
||||||
|
SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2,
|
||||||
|
SerializeIF::Endianness::BIG);
|
||||||
|
// Big endian: Value one on second byte
|
||||||
|
if(test_array[0] != 0 and test_array[1] != 1) {
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
return retval::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t testserialize::test_autoserialization() {
|
||||||
|
std::string id = "[test_autoserialization]";
|
||||||
|
// Unit Test getSerializedSize
|
||||||
|
if(SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_bool) != sizeof(tv::tv_bool) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_uint8) != sizeof(tv::tv_uint8) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_uint16) != sizeof(tv::tv_uint16) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_uint32) != sizeof(tv::tv_uint32) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_uint64) != sizeof(tv::tv_uint64) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_int8) != sizeof(tv::tv_int8) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_double) != sizeof(tv::tv_double) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_int16) != sizeof(tv::tv_int16) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_int32) != sizeof(tv::tv_int32) or
|
||||||
|
SerializeAdapter::
|
||||||
|
getSerializedSize(&tv::tv_float) != sizeof(tv::tv_float))
|
||||||
|
{
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t serialized_size = 0;
|
||||||
|
uint8_t * p_array = test_array.data();
|
||||||
|
|
||||||
|
SerializeAdapter::serialize(&tv::tv_bool, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_uint8, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_uint16, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_uint32, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_int8, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_int16, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_int32, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_uint64, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_float, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_double, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_sfloat, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv::tv_sdouble, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
// expected size is 1 + 1 + 2 + 4 + 1 + 2 + 4 + 8 + 4 + 8 + 4 + 8
|
||||||
|
if(serialized_size != 47) {
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
p_array = test_array.data();
|
||||||
|
size_t remaining_size = serialized_size;
|
||||||
|
bool tv_bool;
|
||||||
|
uint8_t tv_uint8;
|
||||||
|
uint16_t tv_uint16;
|
||||||
|
uint32_t tv_uint32;
|
||||||
|
int8_t tv_int8;
|
||||||
|
int16_t tv_int16;
|
||||||
|
int32_t tv_int32;
|
||||||
|
uint64_t tv_uint64;
|
||||||
|
float tv_float;
|
||||||
|
double tv_double;
|
||||||
|
float tv_sfloat;
|
||||||
|
double tv_sdouble;
|
||||||
|
|
||||||
|
SerializeAdapter::deSerialize(&tv_bool,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint8,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint16,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint32,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_int8,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_int16,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_int32,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint64,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_float,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_double,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_sfloat,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_sdouble,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
|
||||||
|
if(tv_bool != tv::tv_bool or tv_uint8 != tv::tv_uint8 or
|
||||||
|
tv_uint16 != tv::tv_uint16 or tv_uint32 != tv::tv_uint32 or
|
||||||
|
tv_uint64 != tv::tv_uint64 or tv_int8 != tv::tv_int8 or
|
||||||
|
tv_int16 != tv::tv_int16 or tv_int32 != tv::tv_int32)
|
||||||
|
{
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These epsilon values were just guessed.. It appears to work though.
|
||||||
|
if(abs(tv_float - tv::tv_float) > 0.0001 or
|
||||||
|
abs(tv_double - tv::tv_double) > 0.01 or
|
||||||
|
abs(tv_sfloat - tv::tv_sfloat) > 0.0001 or
|
||||||
|
abs(tv_sdouble - tv::tv_sdouble) > 0.01) {
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check overflow
|
||||||
|
return retval::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Also test for constant buffers.
|
||||||
|
ReturnValue_t testserialize::test_serial_buffer_adapter() {
|
||||||
|
std::string id = "[test_serial_buffer_adapter]";
|
||||||
|
|
||||||
|
// I will skip endian swapper testing, its going to be changed anyway..
|
||||||
|
// uint8_t tv::tv_uint8_swapped = EndianSwapper::swap(tv::tv_uint8);
|
||||||
|
|
||||||
|
size_t serialized_size = 0;
|
||||||
|
uint8_t * p_array = test_array.data();
|
||||||
|
std::array<uint8_t, 5> test_serial_buffer {5, 4, 3, 2, 1};
|
||||||
|
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter =
|
||||||
|
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||||
|
test_serial_buffer.size(), false);
|
||||||
|
uint16_t testUint16 = 16;
|
||||||
|
|
||||||
|
SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size,
|
||||||
|
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_serial_buffer_adapter, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size,
|
||||||
|
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
|
||||||
|
if(serialized_size != 8 or test_array[0] != true or test_array[1] != 5
|
||||||
|
or test_array[2] != 4 or test_array[3] != 3 or test_array[4] != 2
|
||||||
|
or test_array[5] != 1)
|
||||||
|
{
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
memcpy(&testUint16, test_array.data() + 6, sizeof(testUint16));
|
||||||
|
if(testUint16 != 16) {
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize with size field
|
||||||
|
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter2 =
|
||||||
|
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||||
|
test_serial_buffer.size(), true);
|
||||||
|
serialized_size = 0;
|
||||||
|
p_array = test_array.data();
|
||||||
|
SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size,
|
||||||
|
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_serial_buffer_adapter2, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size,
|
||||||
|
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
|
||||||
|
if(serialized_size != 9 or test_array[0] != true or test_array[1] != 5
|
||||||
|
or test_array[2] != 5 or test_array[3] != 4 or test_array[4] != 3
|
||||||
|
or test_array[5] != 2 or test_array[6] != 1)
|
||||||
|
{
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
memcpy(&testUint16, test_array.data() + 7, sizeof(testUint16));
|
||||||
|
if(testUint16 != 16) {
|
||||||
|
return unitt::put_error(id);
|
||||||
|
}
|
||||||
|
return retval::RETURN_OK;
|
||||||
|
}
|
15
unittest/internal/serialize/IntTestSerialization.h
Normal file
15
unittest/internal/serialize/IntTestSerialization.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_
|
||||||
|
#define UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace testserialize {
|
||||||
|
ReturnValue_t test_serialization();
|
||||||
|
ReturnValue_t test_endianness_tools();
|
||||||
|
ReturnValue_t test_autoserialization();
|
||||||
|
ReturnValue_t test_serial_buffer_adapter();
|
||||||
|
|
||||||
|
extern std::array<uint8_t, 512> test_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ */
|
3
unittest/lcov.sh
Normal file
3
unittest/lcov.sh
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
lcov --capture --directory . --output-file coverage.info
|
||||||
|
genhtml coverage.info --output-directory _coverage
|
105
unittest/tests/action/TestActionHelper.cpp
Normal file
105
unittest/tests/action/TestActionHelper.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include <fsfw/action/ActionHelper.h>
|
||||||
|
#include <fsfw/ipc/CommandMessage.h>
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
#include <fsfw/unittest/tests/action/TestActionHelper.h>
|
||||||
|
|
||||||
|
TEST_CASE( "Action Helper" , "[ActionHelper]") {
|
||||||
|
ActionHelperOwnerMockBase testDhMock;
|
||||||
|
MessageQueueMockBase testMqMock;
|
||||||
|
ActionHelper actionHelper = ActionHelper(
|
||||||
|
&testDhMock, dynamic_cast<MessageQueueIF*>(&testMqMock));
|
||||||
|
CommandMessage actionMessage;
|
||||||
|
ActionId_t testActionId = 777;
|
||||||
|
std::array <uint8_t, 3> testParams {1, 2, 3};
|
||||||
|
store_address_t paramAddress;
|
||||||
|
StorageManagerIF *ipcStore = tglob::getIpcStoreHandle();
|
||||||
|
ipcStore->addData(¶mAddress, testParams.data(), 3);
|
||||||
|
REQUIRE(actionHelper.initialize() == retval::CATCH_OK);
|
||||||
|
|
||||||
|
SECTION ("Simple tests") {
|
||||||
|
ActionMessage::setCommand(&actionMessage, testActionId, paramAddress);
|
||||||
|
CHECK(not testDhMock.executeActionCalled);
|
||||||
|
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK);
|
||||||
|
CHECK(testDhMock.executeActionCalled);
|
||||||
|
// No message is sent if everything is alright.
|
||||||
|
CHECK(not testMqMock.wasMessageSent());
|
||||||
|
store_address_t invalidAddress;
|
||||||
|
ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress);
|
||||||
|
actionHelper.handleActionMessage(&actionMessage);
|
||||||
|
CHECK(testMqMock.wasMessageSent());
|
||||||
|
const uint8_t* ptr = nullptr;
|
||||||
|
size_t size = 0;
|
||||||
|
REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) == static_cast<uint32_t>(StorageManagerIF::DATA_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(ptr == nullptr);
|
||||||
|
REQUIRE(size == 0);
|
||||||
|
testDhMock.getBuffer(&ptr, &size);
|
||||||
|
REQUIRE(size == 3);
|
||||||
|
for(uint8_t i = 0; i<3;i++){
|
||||||
|
REQUIRE(ptr[i] == (i+1));
|
||||||
|
}
|
||||||
|
testDhMock.clearBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Handle failures"){
|
||||||
|
actionMessage.setCommand(1234);
|
||||||
|
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == static_cast<uint32_t>(CommandMessage::UNKNOWN_COMMAND));
|
||||||
|
CHECK(not testMqMock.wasMessageSent());
|
||||||
|
uint16_t step = 5;
|
||||||
|
ReturnValue_t status = 0x1234;
|
||||||
|
actionHelper.step(step, testMqMock.getId(), testActionId, status);
|
||||||
|
step += 1;
|
||||||
|
CHECK(testMqMock.wasMessageSent());
|
||||||
|
CommandMessage testMessage;
|
||||||
|
REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||||
|
REQUIRE(testMessage.getParameter() == static_cast<uint32_t>(testActionId));
|
||||||
|
uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status;
|
||||||
|
REQUIRE(testMessage.getParameter2() == parameter2);
|
||||||
|
REQUIRE(ActionMessage::getStep(&testMessage) == step);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Handle finish"){
|
||||||
|
CHECK(not testMqMock.wasMessageSent());
|
||||||
|
ReturnValue_t status = 0x9876;
|
||||||
|
actionHelper.finish(testMqMock.getId(), testActionId, status);
|
||||||
|
CHECK(testMqMock.wasMessageSent());
|
||||||
|
CommandMessage testMessage;
|
||||||
|
REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::COMPLETION_FAILED));
|
||||||
|
REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||||
|
REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast<uint32_t>(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Handle failed"){
|
||||||
|
store_address_t toLongParamAddress = StorageManagerIF::INVALID_ADDRESS;
|
||||||
|
std::array<uint8_t, 5> toLongData = {5, 4, 3, 2, 1};
|
||||||
|
REQUIRE(ipcStore->addData(&toLongParamAddress, toLongData.data(), 5) == retval::CATCH_OK);
|
||||||
|
ActionMessage::setCommand(&actionMessage, testActionId, toLongParamAddress);
|
||||||
|
CHECK(not testDhMock.executeActionCalled);
|
||||||
|
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ipcStore->getData(toLongParamAddress).first == static_cast<uint32_t>(StorageManagerIF::DATA_DOES_NOT_EXIST));
|
||||||
|
CommandMessage testMessage;
|
||||||
|
REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||||
|
REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE);
|
||||||
|
REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
||||||
|
REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Missing IPC Data"){
|
||||||
|
ActionMessage::setCommand(&actionMessage, testActionId, StorageManagerIF::INVALID_ADDRESS);
|
||||||
|
CHECK(not testDhMock.executeActionCalled);
|
||||||
|
REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK);
|
||||||
|
CommandMessage testMessage;
|
||||||
|
REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||||
|
REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast<uint32_t>(StorageManagerIF::ILLEGAL_STORAGE_ID));
|
||||||
|
REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTION("Data Reply"){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
131
unittest/tests/action/TestActionHelper.h
Normal file
131
unittest/tests/action/TestActionHelper.h
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#ifndef UNITTEST_HOSTED_TESTACTIONHELPER_H_
|
||||||
|
#define UNITTEST_HOSTED_TESTACTIONHELPER_H_
|
||||||
|
|
||||||
|
#include <fsfw/action/HasActionsIF.h>
|
||||||
|
#include <fsfw/ipc/MessageQueueIF.h>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
class ActionHelperOwnerMockBase: public HasActionsIF {
|
||||||
|
public:
|
||||||
|
bool getCommandQueueCalled = false;
|
||||||
|
bool executeActionCalled = false;
|
||||||
|
static const size_t MAX_SIZE = 3;
|
||||||
|
uint8_t buffer[MAX_SIZE] = {0, 0, 0};
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
MessageQueueId_t getCommandQueue() const override {
|
||||||
|
return tconst::testQueueId;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||||
|
const uint8_t* data, size_t size) override {
|
||||||
|
executeActionCalled = true;
|
||||||
|
if(size > MAX_SIZE){
|
||||||
|
return 0xAFFE;
|
||||||
|
}
|
||||||
|
this->size = size;
|
||||||
|
memcpy(buffer, data, size);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearBuffer(){
|
||||||
|
this->size = 0;
|
||||||
|
for(size_t i = 0; i<MAX_SIZE; i++){
|
||||||
|
buffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getBuffer(const uint8_t** ptr, size_t* size){
|
||||||
|
if(size != nullptr){
|
||||||
|
*size = this->size;
|
||||||
|
}
|
||||||
|
if(ptr != nullptr){
|
||||||
|
*ptr = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MessageQueueMockBase: public MessageQueueIF {
|
||||||
|
public:
|
||||||
|
MessageQueueId_t myQueueId = 0;
|
||||||
|
bool defaultDestSet = false;
|
||||||
|
bool messageSent = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool wasMessageSent() {
|
||||||
|
bool tempMessageSent = messageSent;
|
||||||
|
messageSent = false;
|
||||||
|
return tempMessageSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ReturnValue_t reply( MessageQueueMessage* message ) {
|
||||||
|
messageSent = true;
|
||||||
|
lastMessage = (*message);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
};
|
||||||
|
virtual ReturnValue_t receiveMessage(MessageQueueMessage* message,
|
||||||
|
MessageQueueId_t *receivedFrom) {
|
||||||
|
(*message) = lastMessage;
|
||||||
|
lastMessage.clear();
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) {
|
||||||
|
(*message) = lastMessage;
|
||||||
|
lastMessage.clear();
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual ReturnValue_t flush(uint32_t* count) {
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual MessageQueueId_t getLastPartner() const {
|
||||||
|
return tconst::testQueueId;
|
||||||
|
}
|
||||||
|
virtual MessageQueueId_t getId() const {
|
||||||
|
return tconst::testQueueId;
|
||||||
|
}
|
||||||
|
virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
|
||||||
|
MessageQueueMessage* message, MessageQueueId_t sentFrom,
|
||||||
|
bool ignoreFault = false ) {
|
||||||
|
messageSent = true;
|
||||||
|
lastMessage = (*message);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo,
|
||||||
|
MessageQueueMessage* message, bool ignoreFault = false ) override {
|
||||||
|
messageSent = true;
|
||||||
|
lastMessage = (*message);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message,
|
||||||
|
MessageQueueId_t sentFrom, bool ignoreFault = false ) {
|
||||||
|
messageSent = true;
|
||||||
|
lastMessage = (*message);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) {
|
||||||
|
messageSent = true;
|
||||||
|
lastMessage = (*message);
|
||||||
|
return HasReturnvaluesIF::RETURN_OK;
|
||||||
|
}
|
||||||
|
virtual void setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||||
|
myQueueId = defaultDestination;
|
||||||
|
defaultDestSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual MessageQueueId_t getDefaultDestination() const {
|
||||||
|
return myQueueId;
|
||||||
|
}
|
||||||
|
virtual bool isDefaultDestinationSet() const {
|
||||||
|
return defaultDestSet;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
MessageQueueMessage lastMessage;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* UNITTEST_TESTFW_NEWTESTS_TESTACTIONHELPER_H_ */
|
327
unittest/tests/container/RingBufferTest.cpp
Normal file
327
unittest/tests/container/RingBufferTest.cpp
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
#include <fsfw/container/SimpleRingBuffer.h>
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
TEST_CASE("Ring Buffer Test" , "[RingBufferTest]") {
|
||||||
|
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
|
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||||
|
SimpleRingBuffer ringBuffer(10, false, 5);
|
||||||
|
|
||||||
|
SECTION("Simple Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||||
|
ringBuffer.clear();
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 4; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 9; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Get Free Element Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
uint8_t *testPtr = nullptr;
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED);
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||||
|
// too many excess bytes.
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getExcessBytes() == 3);
|
||||||
|
std::memcpy(testPtr, testData, 5);
|
||||||
|
ringBuffer.confirmBytesWritten(5);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 5);
|
||||||
|
ringBuffer.readData(readBuffer, 5, true);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Read Remaining Test") {
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||||
|
size_t trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
for(uint8_t i = 0; i< 3; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(trueSize == 0);
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Ring Buffer Test2" , "[RingBufferTest2]") {
|
||||||
|
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
|
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||||
|
uint8_t* newBuffer = new uint8_t[10];
|
||||||
|
SimpleRingBuffer ringBuffer(newBuffer, 10, true, 5);
|
||||||
|
|
||||||
|
SECTION("Simple Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||||
|
ringBuffer.clear();
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 4; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 9; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Get Free Element Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
uint8_t *testPtr = nullptr;
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED);
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||||
|
// too many excess bytes.
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getExcessBytes() == 3);
|
||||||
|
std::memcpy(testPtr, testData, 5);
|
||||||
|
ringBuffer.confirmBytesWritten(5);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 5);
|
||||||
|
ringBuffer.readData(readBuffer, 5, true);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Read Remaining Test") {
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||||
|
size_t trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
for(uint8_t i = 0; i< 3; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(trueSize == 0);
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Overflow"){
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace()==9);
|
||||||
|
//Writing more than the buffer is large, technically thats allowed
|
||||||
|
//But it is senseless and has undesired impact on read call
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 13) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||||
|
ringBuffer.clear();
|
||||||
|
uint8_t * ptr = nullptr;
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&ptr, 13) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ptr != nullptr);
|
||||||
|
memcpy(ptr, testData, 13);
|
||||||
|
ringBuffer.confirmBytesWritten(13);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 3, true)== retval::CATCH_OK);
|
||||||
|
for(auto i =0;i<3;i++){
|
||||||
|
REQUIRE(readBuffer[i] == testData[i+10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Ring Buffer Test3" , "[RingBufferTest3]") {
|
||||||
|
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
|
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||||
|
uint8_t* newBuffer = new uint8_t[10];
|
||||||
|
SimpleRingBuffer ringBuffer(newBuffer, 10, true, 15);
|
||||||
|
|
||||||
|
SECTION("Simple Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||||
|
ringBuffer.clear();
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 4; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 9; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Get Free Element Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
uint8_t *testPtr = nullptr;
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getExcessBytes() == 8);
|
||||||
|
|
||||||
|
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||||
|
// too many excess bytes.
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED);
|
||||||
|
// Less Execss bytes overwrites before
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 3) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getExcessBytes() == 1);
|
||||||
|
std::memcpy(testPtr, testData, 3);
|
||||||
|
ringBuffer.confirmBytesWritten(3);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||||
|
ringBuffer.readData(readBuffer, 3, true);
|
||||||
|
for(uint8_t i = 0; i< 3; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Read Remaining Test") {
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||||
|
size_t trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
for(uint8_t i = 0; i< 3; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(trueSize == 0);
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Overflow"){
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace()==9);
|
||||||
|
//Writing more than the buffer is large, technically thats allowed
|
||||||
|
//But it is senseless and has undesired impact on read call
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 13) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||||
|
ringBuffer.clear();
|
||||||
|
uint8_t * ptr = nullptr;
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&ptr, 13) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ptr != nullptr);
|
||||||
|
memcpy(ptr, testData, 13);
|
||||||
|
ringBuffer.confirmBytesWritten(13);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 3, true)== retval::CATCH_OK);
|
||||||
|
for(auto i =0;i<3;i++){
|
||||||
|
REQUIRE(readBuffer[i] == testData[i+10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Ring Buffer Test4" , "[RingBufferTest4]") {
|
||||||
|
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||||
|
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||||
|
SimpleRingBuffer ringBuffer(10, false, 15);
|
||||||
|
|
||||||
|
SECTION("Simple Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||||
|
ringBuffer.clear();
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 4; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||||
|
for(uint8_t i = 0; i< 9; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Get Free Element Test") {
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||||
|
uint8_t *testPtr = nullptr;
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED);
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getExcessBytes() == 3);
|
||||||
|
std::memcpy(testPtr, testData, 5);
|
||||||
|
ringBuffer.confirmBytesWritten(5);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 5);
|
||||||
|
ringBuffer.readData(readBuffer, 5, true);
|
||||||
|
for(uint8_t i = 0; i< 5; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Read Remaining Test") {
|
||||||
|
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||||
|
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||||
|
size_t trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
for(uint8_t i = 0; i< 3; i++) {
|
||||||
|
CHECK(readBuffer[i] == i);
|
||||||
|
}
|
||||||
|
trueSize = 0;
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||||
|
REQUIRE(trueSize == 0);
|
||||||
|
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||||
|
REQUIRE(trueSize == 3);
|
||||||
|
}
|
||||||
|
}
|
90
unittest/tests/container/TestArrayList.cpp
Normal file
90
unittest/tests/container/TestArrayList.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include <fsfw/container/ArrayList.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Array List test
|
||||||
|
*/
|
||||||
|
TEST_CASE("Array List" , "[ArrayListTest]") {
|
||||||
|
//perform set-up here
|
||||||
|
ArrayList<uint16_t> list(20);
|
||||||
|
struct TestClass{
|
||||||
|
public:
|
||||||
|
TestClass(){};
|
||||||
|
TestClass(uint32_t number1, uint64_t number2):
|
||||||
|
number1(number1), number2(number2){};
|
||||||
|
uint32_t number1 = -1;
|
||||||
|
uint64_t number2 = -1;
|
||||||
|
bool operator==(const TestClass& other){
|
||||||
|
return ((this->number1 == other.number1) and (this->number2 == other.number2));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ArrayList<TestClass> complexList(20);
|
||||||
|
SECTION("SimpleTest") {
|
||||||
|
REQUIRE(list.maxSize()==20);
|
||||||
|
REQUIRE(list.size == 0);
|
||||||
|
REQUIRE(list.insert(10) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(list[0] == 10);
|
||||||
|
REQUIRE(list.front() != nullptr);
|
||||||
|
REQUIRE((*list.front()) == 10);
|
||||||
|
REQUIRE(list.back() != nullptr);
|
||||||
|
REQUIRE((*list.back()) == 10);
|
||||||
|
// Need to test the const version of back as well
|
||||||
|
const uint16_t* number = const_cast<const ArrayList<uint16_t>*>(&list)->back();
|
||||||
|
REQUIRE(*number == 10);
|
||||||
|
list.clear();
|
||||||
|
REQUIRE(list.size == 0);
|
||||||
|
}
|
||||||
|
SECTION("Fill and check"){
|
||||||
|
//This is an invalid element but its not a nullptr
|
||||||
|
REQUIRE(list.back() != nullptr);
|
||||||
|
for (auto i =0; i < 20; i++){
|
||||||
|
REQUIRE(list.insert(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
REQUIRE(list.insert(20) == static_cast<int>(ArrayList<uint16_t>::FULL));
|
||||||
|
ArrayList<uint16_t>::Iterator it = list.begin();
|
||||||
|
REQUIRE((*it) == 0);
|
||||||
|
it++;
|
||||||
|
REQUIRE((*it) == 1);
|
||||||
|
it--;
|
||||||
|
REQUIRE((*it) == 0);
|
||||||
|
it++;
|
||||||
|
for(auto it2 = list.begin(); it2!=list.end(); it2++){
|
||||||
|
if (it == it2){
|
||||||
|
REQUIRE((*it) == (*it2));
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
REQUIRE((*it2) == 0);
|
||||||
|
REQUIRE(it2 != it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("Const Iterator"){
|
||||||
|
ArrayList<uint16_t>::Iterator it = list.begin();
|
||||||
|
for (auto i =0; i < 10; i++){
|
||||||
|
REQUIRE(list.insert(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
const uint16_t* number = it.value;
|
||||||
|
REQUIRE(*number == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Const Iterator"){
|
||||||
|
ArrayList<TestClass>::Iterator it = complexList.begin();
|
||||||
|
for (auto i =0; i < 10; i++){
|
||||||
|
REQUIRE(complexList.insert(TestClass(i, i+1)) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
const TestClass* secondTest = it.value;
|
||||||
|
bool compare = TestClass(1, 2) == *secondTest;
|
||||||
|
REQUIRE(compare);
|
||||||
|
it++;
|
||||||
|
REQUIRE(it->number1 == 2);
|
||||||
|
REQUIRE(it->number2 == 3);
|
||||||
|
const ArrayList<TestClass>::Iterator it4(&(complexList[2]));
|
||||||
|
REQUIRE(it4->number1 == 2);
|
||||||
|
REQUIRE((*it4).number2 == 3);
|
||||||
|
REQUIRE(complexList.remaining()==10);
|
||||||
|
}
|
||||||
|
}
|
149
unittest/tests/container/TestDynamicFifo.cpp
Normal file
149
unittest/tests/container/TestDynamicFifo.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
#include <fsfw/container/DynamicFIFO.h>
|
||||||
|
#include <fsfw/container/FIFO.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#include <catch.hpp>
|
||||||
|
#include <CatchDefinitions.h>
|
||||||
|
|
||||||
|
TEST_CASE( "Dynamic Fifo Tests", "[TestDynamicFifo]") {
|
||||||
|
INFO("Dynamic Fifo Tests");
|
||||||
|
struct Test{
|
||||||
|
uint64_t number1;
|
||||||
|
uint32_t number2;
|
||||||
|
uint8_t number3;
|
||||||
|
bool operator==(struct Test& other){
|
||||||
|
if ((other.number1 == this->number1) and
|
||||||
|
(other.number1 == this->number1) and
|
||||||
|
(other.number1 == this->number1)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
DynamicFIFO<Test> fifo(3);
|
||||||
|
std::vector<Test> list;
|
||||||
|
|
||||||
|
struct Test structOne({UINT64_MAX, UINT32_MAX, UINT8_MAX});
|
||||||
|
struct Test structTwo({0, 1, 2});
|
||||||
|
struct Test structThree({42, 43, 44});
|
||||||
|
list.push_back(structThree);
|
||||||
|
list.push_back(structTwo);
|
||||||
|
list.push_back(structOne);
|
||||||
|
SECTION("Insert, retrieval test"){
|
||||||
|
REQUIRE(fifo.getMaxCapacity()==3);
|
||||||
|
REQUIRE(fifo.size()==0);
|
||||||
|
REQUIRE(fifo.empty());
|
||||||
|
REQUIRE(not fifo.full());
|
||||||
|
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(FIFOBase<Test>::FULL));
|
||||||
|
|
||||||
|
struct Test testptr;
|
||||||
|
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool equal = testptr == structOne;
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
for(size_t i=2;i<3;i--){
|
||||||
|
testptr.number1 = 0;
|
||||||
|
testptr.number2 = 0;
|
||||||
|
testptr.number3 = 0;
|
||||||
|
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
equal = testptr == list[i];
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo.size()==i);
|
||||||
|
}
|
||||||
|
testptr.number1 = 0;
|
||||||
|
testptr.number2 = 0;
|
||||||
|
testptr.number3 = 0;
|
||||||
|
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||||
|
REQUIRE(fifo.peek(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||||
|
REQUIRE(not fifo.full());
|
||||||
|
REQUIRE(fifo.empty());
|
||||||
|
REQUIRE(fifo.pop()==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||||
|
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==1);
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==2);
|
||||||
|
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==1);
|
||||||
|
testptr.number1 = 0;
|
||||||
|
testptr.number2 = 0;
|
||||||
|
testptr.number3 = 0;
|
||||||
|
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
equal = testptr == structTwo;
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==0);
|
||||||
|
REQUIRE(fifo.empty());
|
||||||
|
//struct Test* ptr = nullptr;
|
||||||
|
//REQUIRE(fifo.retrieve(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||||
|
//REQUIRE(fifo.peek(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||||
|
};
|
||||||
|
SECTION("Copy Test"){
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
DynamicFIFO<Test> fifo2(fifo);
|
||||||
|
REQUIRE(fifo2.size()==3);
|
||||||
|
REQUIRE(fifo2.full());
|
||||||
|
REQUIRE(not fifo2.empty());
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Assignment Test"){
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
DynamicFIFO<Test> fifo2(6);
|
||||||
|
fifo2 = fifo;
|
||||||
|
REQUIRE(fifo2.size()==3);
|
||||||
|
REQUIRE(fifo2.full());
|
||||||
|
REQUIRE(not fifo2.empty());
|
||||||
|
for(size_t i=2;i<3;i--){
|
||||||
|
struct Test testptr = {0, 0, 0};
|
||||||
|
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool equal = testptr == list[i];
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo2.size()==i);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Assignment Test Smaller"){
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
DynamicFIFO<Test> fifo2(2);
|
||||||
|
fifo2 = fifo;
|
||||||
|
REQUIRE(fifo2.size()==3);
|
||||||
|
REQUIRE(fifo2.full());
|
||||||
|
REQUIRE(not fifo2.empty());
|
||||||
|
for(size_t i=2;i<3;i--){
|
||||||
|
struct Test testptr = {0, 0, 0};
|
||||||
|
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool equal = testptr == list[i];
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo2.size()==i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
138
unittest/tests/container/TestFifo.cpp
Normal file
138
unittest/tests/container/TestFifo.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
|
||||||
|
#include <fsfw/container/DynamicFIFO.h>
|
||||||
|
#include <fsfw/container/FIFO.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
TEST_CASE( "Static Fifo Tests", "[TestFifo]") {
|
||||||
|
INFO("Fifo Tests");
|
||||||
|
struct Test{
|
||||||
|
uint64_t number1;
|
||||||
|
uint32_t number2;
|
||||||
|
uint8_t number3;
|
||||||
|
bool operator==(struct Test& other){
|
||||||
|
if ((other.number1 == this->number1) and
|
||||||
|
(other.number1 == this->number1) and
|
||||||
|
(other.number1 == this->number1)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FIFO<Test, 3> fifo;
|
||||||
|
std::vector<Test> list;
|
||||||
|
|
||||||
|
struct Test structOne({UINT64_MAX, UINT32_MAX, UINT8_MAX});
|
||||||
|
struct Test structTwo({0, 1, 2});
|
||||||
|
struct Test structThree({42, 43, 44});
|
||||||
|
list.push_back(structThree);
|
||||||
|
list.push_back(structTwo);
|
||||||
|
list.push_back(structOne);
|
||||||
|
SECTION("Insert, retrieval test"){
|
||||||
|
REQUIRE(fifo.getMaxCapacity()==3);
|
||||||
|
REQUIRE(fifo.size()==0);
|
||||||
|
REQUIRE(fifo.empty());
|
||||||
|
REQUIRE(not fifo.full());
|
||||||
|
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(FIFOBase<Test>::FULL));
|
||||||
|
|
||||||
|
struct Test testptr;
|
||||||
|
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool equal = testptr == structOne;
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
for(size_t i=2;i<3;i--){
|
||||||
|
testptr.number1 = 0;
|
||||||
|
testptr.number2 = 0;
|
||||||
|
testptr.number3 = 0;
|
||||||
|
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
equal = testptr == list[i];
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo.size()==i);
|
||||||
|
}
|
||||||
|
testptr.number1 = 0;
|
||||||
|
testptr.number2 = 0;
|
||||||
|
testptr.number3 = 0;
|
||||||
|
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||||
|
REQUIRE(fifo.peek(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||||
|
REQUIRE(not fifo.full());
|
||||||
|
REQUIRE(fifo.empty());
|
||||||
|
REQUIRE(fifo.pop()==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||||
|
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==1);
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==2);
|
||||||
|
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==1);
|
||||||
|
testptr.number1 = 0;
|
||||||
|
testptr.number2 = 0;
|
||||||
|
testptr.number3 = 0;
|
||||||
|
|
||||||
|
// Test that retrieve and peek will not cause a nullptr dereference
|
||||||
|
struct Test* ptr = nullptr;
|
||||||
|
REQUIRE(fifo.retrieve(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||||
|
REQUIRE(fifo.peek(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
equal = testptr == structTwo;
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==0);
|
||||||
|
REQUIRE(fifo.empty());
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
SECTION("Copy Test"){
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
FIFO<Test, 3> fifo2(fifo);
|
||||||
|
REQUIRE(fifo2.size()==3);
|
||||||
|
REQUIRE(fifo2.full());
|
||||||
|
REQUIRE(not fifo2.empty());
|
||||||
|
for(size_t i=2;i<3;i--){
|
||||||
|
struct Test testptr = {0, 0, 0};
|
||||||
|
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool equal = testptr == list[i];
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo2.size()==i);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Assignment Test"){
|
||||||
|
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(fifo.size()==3);
|
||||||
|
REQUIRE(fifo.full());
|
||||||
|
REQUIRE(not fifo.empty());
|
||||||
|
|
||||||
|
FIFO<Test, 3> fifo2;
|
||||||
|
fifo2 = fifo;
|
||||||
|
REQUIRE(fifo2.size()==3);
|
||||||
|
REQUIRE(fifo2.full());
|
||||||
|
REQUIRE(not fifo2.empty());
|
||||||
|
for(size_t i=2;i<3;i--){
|
||||||
|
struct Test testptr = {0, 0, 0};
|
||||||
|
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool equal = testptr == list[i];
|
||||||
|
REQUIRE(equal);
|
||||||
|
REQUIRE(fifo2.size()==i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
41
unittest/tests/container/TestFixedArrayList.cpp
Normal file
41
unittest/tests/container/TestFixedArrayList.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <fsfw/container/FixedArrayList.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE( "FixedArrayList Tests", "[TestFixedArrayList]") {
|
||||||
|
INFO("FixedArrayList Tests");
|
||||||
|
using testList = FixedArrayList<uint32_t, 260, uint16_t>;
|
||||||
|
testList list;
|
||||||
|
REQUIRE(list.size==0);
|
||||||
|
REQUIRE(list.insert(10) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(list.size==1);
|
||||||
|
REQUIRE(list.maxSize()==260);
|
||||||
|
SECTION("Copy Constructor"){
|
||||||
|
testList list2(list);
|
||||||
|
REQUIRE(list2.size==1);
|
||||||
|
REQUIRE(list2[0] == 10);
|
||||||
|
REQUIRE(list.maxSize()==260);
|
||||||
|
};
|
||||||
|
SECTION("Assignment copy"){
|
||||||
|
testList list2;
|
||||||
|
REQUIRE(list2.size==0);
|
||||||
|
list2 = list;
|
||||||
|
REQUIRE(list2.size==1);
|
||||||
|
REQUIRE(list2[0] == 10);
|
||||||
|
REQUIRE(list.maxSize()==260);
|
||||||
|
};
|
||||||
|
SECTION("Fill"){
|
||||||
|
for(auto i=1;i<260;i++){
|
||||||
|
REQUIRE(list.insert(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
REQUIRE(list.insert(260) == static_cast<int>(ArrayList<uint32_t, uint16_t>::FULL));
|
||||||
|
list.clear();
|
||||||
|
REQUIRE(list.size == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
172
unittest/tests/container/TestFixedMap.cpp
Normal file
172
unittest/tests/container/TestFixedMap.cpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#include <fsfw/container/FixedMap.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
template class FixedMap<unsigned int, unsigned short>;
|
||||||
|
|
||||||
|
TEST_CASE( "FixedMap Tests", "[TestFixedMap]") {
|
||||||
|
INFO("FixedMap Tests");
|
||||||
|
|
||||||
|
FixedMap<unsigned int, unsigned short> map(30);
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
REQUIRE(map.maxSize() == 30);
|
||||||
|
REQUIRE(map.getSerializedSize() == sizeof(uint32_t));
|
||||||
|
REQUIRE(map.empty());
|
||||||
|
REQUIRE(not map.full());
|
||||||
|
|
||||||
|
SECTION("Fill and erase"){
|
||||||
|
for (uint16_t i=0;i<30;i++){
|
||||||
|
REQUIRE(map.insert(std::make_pair(i, i+1))== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.exists(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.find(i)->second==i+1);
|
||||||
|
REQUIRE(not map.empty());
|
||||||
|
}
|
||||||
|
REQUIRE(map.insert(0, 0) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_ALREADY_EXISTS));
|
||||||
|
REQUIRE(map.insert(31, 0) == static_cast<int>(FixedMap<uint32_t, uint16_t>::MAP_FULL));
|
||||||
|
REQUIRE(map.exists(31) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.size() == 30);
|
||||||
|
REQUIRE(map.full());
|
||||||
|
{
|
||||||
|
uint16_t* ptr;
|
||||||
|
REQUIRE(map.find(5,&ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(*ptr == 6);
|
||||||
|
REQUIRE(*(map.findValue(6)) == 7);
|
||||||
|
REQUIRE(map.find(31,&ptr) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(map.getSerializedSize() == (sizeof(uint32_t)+ 30*(sizeof(uint32_t) + sizeof(uint16_t))));
|
||||||
|
REQUIRE(map.erase(2) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.erase(31) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.exists(2) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.size() == 29);
|
||||||
|
|
||||||
|
for (auto element: map){
|
||||||
|
if (element.first == 5){
|
||||||
|
REQUIRE(element.second == 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FixedMap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
REQUIRE(it->second == it->first + 1);
|
||||||
|
REQUIRE((*it).second == (*it).first + 1);
|
||||||
|
it->second = it->second + 1;
|
||||||
|
REQUIRE(it->second == it->first + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FixedMap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
REQUIRE(map.erase(&it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
|
||||||
|
for (FixedMap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
// This line should never executed if begin and end is correct
|
||||||
|
FAIL("Should never be reached, Iterators invalid");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Insert variants"){
|
||||||
|
FixedMap<uint32_t, uint16_t>::Iterator it = map.end();
|
||||||
|
REQUIRE(map.insert(36, 37, &it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(it->first == 36);
|
||||||
|
REQUIRE(it->second == 37);
|
||||||
|
REQUIRE(map.size() == 1);
|
||||||
|
REQUIRE(map.insert(37, 38, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.find(37)->second == 38);
|
||||||
|
REQUIRE(map.size() == 2);
|
||||||
|
REQUIRE(map.insert(37, 24, nullptr) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_ALREADY_EXISTS));
|
||||||
|
REQUIRE(map.find(37)->second != 24);
|
||||||
|
REQUIRE(map.size() == 2);
|
||||||
|
};
|
||||||
|
SECTION("Serialize and DeSerialize") {
|
||||||
|
REQUIRE(map.insert(36, 37, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.insert(37, 38, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
uint8_t buffer[sizeof(uint32_t)
|
||||||
|
+ 2 * (sizeof(uint32_t) + sizeof(uint16_t))];
|
||||||
|
REQUIRE(
|
||||||
|
map.getSerializedSize()
|
||||||
|
== (sizeof(uint32_t)
|
||||||
|
+ 2 * (sizeof(uint32_t) + sizeof(uint16_t))));
|
||||||
|
uint8_t *loc_ptr = buffer;
|
||||||
|
size_t size = 0;
|
||||||
|
REQUIRE(
|
||||||
|
map.serialize(&loc_ptr, &size, 10, SerializeIF::Endianness::BIG)
|
||||||
|
== static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
|
||||||
|
loc_ptr = buffer;
|
||||||
|
size = 0;
|
||||||
|
REQUIRE(
|
||||||
|
map.serialize(&loc_ptr, &size,
|
||||||
|
sizeof(uint32_t)
|
||||||
|
+ 2 * (sizeof(uint32_t) + sizeof(uint16_t)),
|
||||||
|
SerializeIF::Endianness::BIG)
|
||||||
|
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(size == 16);
|
||||||
|
|
||||||
|
uint32_t internal_size = 0;
|
||||||
|
const uint8_t *ptr2 = buffer;
|
||||||
|
REQUIRE(
|
||||||
|
SerializeAdapter::deSerialize(&internal_size, &ptr2, &size,
|
||||||
|
SerializeIF::Endianness::BIG)
|
||||||
|
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(internal_size == 2);
|
||||||
|
for (uint8_t i = 36; i < 38; i++) {
|
||||||
|
uint32_t first_element = 0;
|
||||||
|
REQUIRE(
|
||||||
|
SerializeAdapter::deSerialize(&first_element, &ptr2, &size,
|
||||||
|
SerializeIF::Endianness::BIG)
|
||||||
|
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(first_element == i);
|
||||||
|
uint16_t second_element = 0;
|
||||||
|
REQUIRE(
|
||||||
|
SerializeAdapter::deSerialize(&second_element, &ptr2, &size,
|
||||||
|
SerializeIF::Endianness::BIG)
|
||||||
|
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(second_element == i + 1);
|
||||||
|
}
|
||||||
|
REQUIRE(size == 0);
|
||||||
|
map.clear();
|
||||||
|
const uint8_t* constPtr = buffer;
|
||||||
|
size = 16;
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
REQUIRE(map.deSerialize(&constPtr, &size,
|
||||||
|
SerializeIF::Endianness::BIG) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.size() == 2);
|
||||||
|
REQUIRE(map.find(36)->second == 37);
|
||||||
|
for(auto& element: map){
|
||||||
|
REQUIRE((element.first+1) == element.second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
SECTION("Failed erase and deSerialize"){
|
||||||
|
FixedMap<uint32_t, uint16_t>::Iterator it;
|
||||||
|
std::pair<uint32_t, uint16_t> pair = std::make_pair(44, 43);
|
||||||
|
it = FixedMap<uint32_t, uint16_t>::Iterator(&pair);
|
||||||
|
REQUIRE(map.erase(&it) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.find(45) == map.end());
|
||||||
|
size_t toLargeMap = 100;
|
||||||
|
const uint8_t* ptr = reinterpret_cast<uint8_t*>(&toLargeMap);
|
||||||
|
size_t size = sizeof(size_t);
|
||||||
|
REQUIRE(map.deSerialize(&ptr, &size, SerializeIF::Endianness::BIG) ==
|
||||||
|
static_cast<int>(SerializeIF::TOO_MANY_ELEMENTS));
|
||||||
|
};
|
||||||
|
SECTION("Little Endianess"){
|
||||||
|
map.clear();
|
||||||
|
map.insert(10,20, nullptr);
|
||||||
|
uint8_t newBuffer[sizeof(uint32_t)+ 1*(sizeof(uint32_t) + sizeof(uint16_t))];
|
||||||
|
uint8_t* ptr = newBuffer;
|
||||||
|
size_t size = 0;
|
||||||
|
size_t max_size = sizeof(uint32_t)+ 1*(sizeof(uint32_t) + sizeof(uint16_t));
|
||||||
|
REQUIRE(map.serialize(&ptr, &size, max_size,
|
||||||
|
SerializeIF::Endianness::LITTLE) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
map.clear();
|
||||||
|
REQUIRE(map.size()==0);
|
||||||
|
const uint8_t* ptr2 = newBuffer;
|
||||||
|
REQUIRE(map.deSerialize(&ptr2, &size,
|
||||||
|
SerializeIF::Endianness::LITTLE) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.size()==1);
|
||||||
|
REQUIRE(map.find(10)->second == 20);
|
||||||
|
};
|
||||||
|
}
|
203
unittest/tests/container/TestFixedOrderedMultimap.cpp
Normal file
203
unittest/tests/container/TestFixedOrderedMultimap.cpp
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#include <fsfw/container/FixedOrderedMultimap.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
TEST_CASE( "FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") {
|
||||||
|
INFO("FixedOrderedMultimap Tests");
|
||||||
|
|
||||||
|
FixedOrderedMultimap<unsigned int, unsigned short> map(30);
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
REQUIRE(map.maxSize() == 30);
|
||||||
|
|
||||||
|
SECTION("Test insert, find, exists"){
|
||||||
|
for (uint16_t i=0;i<30;i++){
|
||||||
|
REQUIRE(map.insert(std::make_pair(i, i+1))== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.exists(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.find(i)->second==i+1);
|
||||||
|
}
|
||||||
|
REQUIRE(map.insert(0, 0) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::MAP_FULL));
|
||||||
|
REQUIRE(map.exists(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.size() == 30);
|
||||||
|
{
|
||||||
|
uint16_t* ptr;
|
||||||
|
REQUIRE(map.find(5,&ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(*ptr == 6);
|
||||||
|
REQUIRE(map.find(31,&ptr) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
}
|
||||||
|
REQUIRE(map.erase(2) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.erase(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.exists(2) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.size() == 29);
|
||||||
|
|
||||||
|
for (auto element: map){
|
||||||
|
if (element.first == 5){
|
||||||
|
REQUIRE(element.second == 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
REQUIRE(it->second == it->first + 1);
|
||||||
|
REQUIRE((*it).second == (*it).first + 1);
|
||||||
|
it->second = it->second + 1;
|
||||||
|
REQUIRE(it->second == it->first + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.begin();
|
||||||
|
while(it != map.end()){
|
||||||
|
REQUIRE(map.erase(&it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
// This line should never executed if begin and end is correct
|
||||||
|
FAIL("Should never be reached, Iterators invalid");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Test different insert variants")
|
||||||
|
{
|
||||||
|
FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.end();
|
||||||
|
REQUIRE(map.insert(36, 37, &it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(it->first == 36);
|
||||||
|
REQUIRE(it->second == 37);
|
||||||
|
REQUIRE(map.size() == 1);
|
||||||
|
REQUIRE(map.insert(37, 38, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.find(37)->second == 38);
|
||||||
|
REQUIRE(map.size() == 2);
|
||||||
|
REQUIRE(map.insert(37, 24, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.find(37)->second == 38);
|
||||||
|
REQUIRE(map.insert(0, 1, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.find(0)->second == 1);
|
||||||
|
REQUIRE(map.size() == 4);
|
||||||
|
map.clear();
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
}
|
||||||
|
SECTION("Test different erase and find with no entries"){
|
||||||
|
FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it;
|
||||||
|
it = map.end();
|
||||||
|
REQUIRE(map.erase(&it) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.find(1)== map.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE( "FixedOrderedMultimap Non Trivial Type", "[TestFixedOrderedMultimapNonTrivial]") {
|
||||||
|
INFO("FixedOrderedMultimap Non Trivial Type");
|
||||||
|
|
||||||
|
class TestClass{
|
||||||
|
public:
|
||||||
|
TestClass(){};
|
||||||
|
TestClass(uint32_t number1, uint64_t number2):
|
||||||
|
number1(number1),number2(number2){};
|
||||||
|
~TestClass(){};
|
||||||
|
|
||||||
|
bool operator==(const TestClass& lhs){
|
||||||
|
return ((this->number1 == lhs.number1) and (this->number2 == lhs.number2));
|
||||||
|
}
|
||||||
|
bool operator!=(const TestClass& lhs){
|
||||||
|
return not(this->operator ==(lhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
TestClass(const TestClass& other){
|
||||||
|
this->number1 = other.number1;
|
||||||
|
this->number2 = other.number2;
|
||||||
|
};
|
||||||
|
TestClass& operator=(const TestClass& other){
|
||||||
|
this->number1 = other.number1;
|
||||||
|
this->number2 = other.number2;
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t number1 = 0;
|
||||||
|
uint64_t number2 = 5;
|
||||||
|
};
|
||||||
|
FixedOrderedMultimap<unsigned int, TestClass> map(30);
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
REQUIRE(map.maxSize() == 30);
|
||||||
|
|
||||||
|
SECTION("Test insert, find, exists"){
|
||||||
|
for (uint16_t i=0;i<30;i++){
|
||||||
|
REQUIRE(map.insert(std::make_pair(i, TestClass(i+1,i)))== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.exists(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool compare = map.find(i)->second == TestClass(i+1,i);
|
||||||
|
REQUIRE(compare);
|
||||||
|
}
|
||||||
|
REQUIRE(map.insert(0, TestClass()) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::MAP_FULL));
|
||||||
|
REQUIRE(map.exists(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.size() == 30);
|
||||||
|
{
|
||||||
|
TestClass* ptr = nullptr;
|
||||||
|
REQUIRE(map.find(5,&ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
bool compare = *ptr == TestClass(6, 5);
|
||||||
|
REQUIRE(compare);
|
||||||
|
REQUIRE(map.find(31,&ptr) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
}
|
||||||
|
REQUIRE(map.erase(2) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(map.erase(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.exists(2) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.size() == 29);
|
||||||
|
|
||||||
|
for (auto element: map){
|
||||||
|
if (element.first == 5){
|
||||||
|
bool compare = element.second == TestClass(6, 5);
|
||||||
|
REQUIRE(compare);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
bool compare = it->second == TestClass(it->first + 1, it->first);
|
||||||
|
REQUIRE(compare);
|
||||||
|
compare = (*it).second == TestClass((*it).first + 1, (*it).first);
|
||||||
|
REQUIRE(compare);
|
||||||
|
it->second = TestClass(it->first + 2, it->first);
|
||||||
|
compare = it->second == TestClass(it->first + 2, it->first);
|
||||||
|
REQUIRE(compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.begin();
|
||||||
|
while(it != map.end()){
|
||||||
|
REQUIRE(map.erase(&it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
}
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.begin(); it != map.end(); it++){
|
||||||
|
// This line should never executed if begin and end is correct
|
||||||
|
FAIL("Should never be reached, Iterators invalid");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SECTION("Test different insert variants")
|
||||||
|
{
|
||||||
|
FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.end();
|
||||||
|
REQUIRE(map.insert(36, TestClass(37, 36), &it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(it->first == 36);
|
||||||
|
bool compare = it->second == TestClass(37, 36);
|
||||||
|
REQUIRE(compare);
|
||||||
|
REQUIRE(map.size() == 1);
|
||||||
|
REQUIRE(map.insert(37, TestClass(38, 37), nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
compare = map.find(37)->second == TestClass(38, 37);
|
||||||
|
REQUIRE(compare);
|
||||||
|
REQUIRE(map.size() == 2);
|
||||||
|
REQUIRE(map.insert(37, TestClass(24, 37), nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
compare = map.find(37)->second == TestClass(38, 37);
|
||||||
|
REQUIRE(compare);
|
||||||
|
REQUIRE(map.insert(0, TestClass(1, 0), nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
compare = map.find(0)->second == TestClass(1, 0);
|
||||||
|
REQUIRE(compare);
|
||||||
|
REQUIRE(map.size() == 4);
|
||||||
|
map.clear();
|
||||||
|
REQUIRE(map.size() == 0);
|
||||||
|
}
|
||||||
|
SECTION("Test different erase and find with no entries"){
|
||||||
|
FixedOrderedMultimap<uint32_t, TestClass>::Iterator it;
|
||||||
|
it = map.end();
|
||||||
|
REQUIRE(map.erase(&it) == static_cast<int>(FixedOrderedMultimap<uint32_t, TestClass>::KEY_DOES_NOT_EXIST));
|
||||||
|
REQUIRE(map.find(1)== map.end());
|
||||||
|
}
|
||||||
|
}
|
45
unittest/tests/container/TestPlacementFactory.cpp
Normal file
45
unittest/tests/container/TestPlacementFactory.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include <fsfw/container/PlacementFactory.h>
|
||||||
|
#include <fsfw/storagemanager/LocalPool.h>
|
||||||
|
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||||
|
#include <fsfw/container/ArrayList.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") {
|
||||||
|
INFO("PlacementFactory Tests");
|
||||||
|
|
||||||
|
const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)};
|
||||||
|
const uint16_t n_elements[3] = {1, 1, 1};
|
||||||
|
LocalPool<3> storagePool(0x1, element_sizes, n_elements, false, true);
|
||||||
|
PlacementFactory factory(&storagePool);
|
||||||
|
|
||||||
|
SECTION("Pool overload"){
|
||||||
|
store_address_t address;
|
||||||
|
uint8_t* ptr = nullptr;
|
||||||
|
REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList<uint32_t, uint16_t>), &ptr)
|
||||||
|
== static_cast<int>(StorageManagerIF::DATA_TOO_LARGE));
|
||||||
|
ArrayList<uint32_t, uint16_t>* list2 = factory.generate<ArrayList<uint32_t, uint16_t> >(80);
|
||||||
|
REQUIRE(list2 == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Test generate and destroy"){
|
||||||
|
uint64_t* number = factory.generate<uint64_t>(32000);
|
||||||
|
REQUIRE(number != nullptr);
|
||||||
|
REQUIRE(*number == 32000);
|
||||||
|
store_address_t address;
|
||||||
|
uint8_t* ptr = nullptr;
|
||||||
|
REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr)
|
||||||
|
== static_cast<int>(StorageManagerIF::DATA_TOO_LARGE));
|
||||||
|
uint64_t* number2 = factory.generate<uint64_t>(12345);
|
||||||
|
REQUIRE(number2 == nullptr);
|
||||||
|
REQUIRE(factory.destroy(number) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr)
|
||||||
|
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
REQUIRE(storagePool.deleteData(address) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||||
|
|
||||||
|
//Check that PlacementFactory checks for nullptr
|
||||||
|
ptr = nullptr;
|
||||||
|
REQUIRE(factory.destroy(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||||
|
}
|
||||||
|
}
|
40
unittest/tests/osal/TestMessageQueue.cpp
Normal file
40
unittest/tests/osal/TestMessageQueue.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <fsfw/ipc/MessageQueueIF.h>
|
||||||
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
|
#include "catch.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include "core/CatchDefinitions.h"
|
||||||
|
|
||||||
|
TEST_CASE("MessageQueue Basic Test","[TestMq]") {
|
||||||
|
MessageQueueIF* testSenderMq =
|
||||||
|
QueueFactory::instance()->createMessageQueue(1);
|
||||||
|
MessageQueueId_t testSenderMqId = testSenderMq->getId();
|
||||||
|
|
||||||
|
MessageQueueIF* testReceiverMq =
|
||||||
|
QueueFactory::instance()->createMessageQueue(1);
|
||||||
|
MessageQueueId_t testReceiverMqId = testReceiverMq->getId();
|
||||||
|
std::array<uint8_t, 20> testData { 0 };
|
||||||
|
testData[0] = 42;
|
||||||
|
MessageQueueMessage testMessage(testData.data(), 1);
|
||||||
|
testSenderMq->setDefaultDestination(testReceiverMqId);
|
||||||
|
|
||||||
|
SECTION("Simple Tests") {
|
||||||
|
auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
MessageQueueMessage recvMessage;
|
||||||
|
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(recvMessage.getData()[0] == 42);
|
||||||
|
|
||||||
|
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
MessageQueueId_t senderId = 0;
|
||||||
|
result = testReceiverMq->receiveMessage(&recvMessage,&senderId);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(recvMessage.getData()[0] == 42);
|
||||||
|
CHECK(senderId == testSenderMqId);
|
||||||
|
senderId = testReceiverMq->getLastPartner();
|
||||||
|
CHECK(senderId == testSenderMqId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
46
unittest/tests/osal/TestSemaphore.cpp
Normal file
46
unittest/tests/osal/TestSemaphore.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
#ifdef LINUX
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "core/CatchDefinitions.h"
|
||||||
|
#include "catch.hpp"
|
||||||
|
|
||||||
|
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||||
|
#include <fsfw/timemanager/Stopwatch.h>
|
||||||
|
|
||||||
|
TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") {
|
||||||
|
//perform set-up here
|
||||||
|
SemaphoreIF* binSemaph = SemaphoreFactory::instance()->
|
||||||
|
createBinarySemaphore();
|
||||||
|
REQUIRE(binSemaph != nullptr);
|
||||||
|
SECTION("Simple Test") {
|
||||||
|
// set-up is run for each section
|
||||||
|
REQUIRE(binSemaph->getSemaphoreCounter() == 1);
|
||||||
|
REQUIRE(binSemaph->release() ==
|
||||||
|
static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED));
|
||||||
|
REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) ==
|
||||||
|
retval::CATCH_OK);
|
||||||
|
{
|
||||||
|
// not precise enough on linux.. should use clock instead..
|
||||||
|
//Stopwatch stopwatch(false);
|
||||||
|
//REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) ==
|
||||||
|
// SemaphoreIF::SEMAPHORE_TIMEOUT);
|
||||||
|
//dur_millis_t time = stopwatch.stop();
|
||||||
|
//CHECK(time == 5);
|
||||||
|
}
|
||||||
|
REQUIRE(binSemaph->getSemaphoreCounter() == 0);
|
||||||
|
REQUIRE(binSemaph->release() == retval::CATCH_OK);
|
||||||
|
}
|
||||||
|
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||||
|
// perform tear-down here
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") {
|
||||||
|
SECTION("Simple Test") {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
143
unittest/tests/serialize/TestSerialBufferAdapter.cpp
Normal file
143
unittest/tests/serialize/TestSerialBufferAdapter.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
|
||||||
|
static bool test_value_bool = true;
|
||||||
|
static uint16_t tv_uint16 {283};
|
||||||
|
static std::array<uint8_t, 512> testArray;
|
||||||
|
|
||||||
|
TEST_CASE("Serial Buffer Adapter", "[single-file]") {
|
||||||
|
size_t serialized_size = 0;
|
||||||
|
test_value_bool = true;
|
||||||
|
uint8_t * arrayPtr = testArray.data();
|
||||||
|
std::array<uint8_t, 5> test_serial_buffer {5, 4, 3, 2, 1};
|
||||||
|
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter =
|
||||||
|
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||||
|
test_serial_buffer.size(), false);
|
||||||
|
tv_uint16 = 16;
|
||||||
|
|
||||||
|
SECTION("Serialize without size field") {
|
||||||
|
SerializeAdapter::serialize(&test_value_bool, &arrayPtr,
|
||||||
|
&serialized_size, testArray.size(),
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_serial_buffer_adapter, &arrayPtr,
|
||||||
|
&serialized_size, testArray.size(),
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size,
|
||||||
|
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
|
||||||
|
REQUIRE(serialized_size == 8);
|
||||||
|
REQUIRE(testArray[0] == true);
|
||||||
|
REQUIRE(testArray[1] == 5);
|
||||||
|
REQUIRE(testArray[2] == 4);
|
||||||
|
REQUIRE(testArray[3] == 3);
|
||||||
|
REQUIRE(testArray[4] == 2);
|
||||||
|
REQUIRE(testArray[5] == 1);
|
||||||
|
memcpy(&tv_uint16, testArray.data() + 6, sizeof(tv_uint16));
|
||||||
|
REQUIRE(tv_uint16 == 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Serialize with size field") {
|
||||||
|
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter_loc =
|
||||||
|
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||||
|
test_serial_buffer.size(), true);
|
||||||
|
serialized_size = 0;
|
||||||
|
arrayPtr = testArray.data();
|
||||||
|
SerializeAdapter::serialize(&test_value_bool, &arrayPtr,&serialized_size,
|
||||||
|
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_serial_buffer_adapter_loc, &arrayPtr,
|
||||||
|
&serialized_size, testArray.size(),
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size,
|
||||||
|
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
|
||||||
|
REQUIRE(serialized_size == 9);
|
||||||
|
REQUIRE(testArray[0] == true);
|
||||||
|
REQUIRE(testArray[1] == 5);
|
||||||
|
REQUIRE(testArray[2] == 5);
|
||||||
|
REQUIRE(testArray[3] == 4);
|
||||||
|
REQUIRE(testArray[4] == 3);
|
||||||
|
REQUIRE(testArray[5] == 2);
|
||||||
|
REQUIRE(testArray[6] == 1);
|
||||||
|
memcpy(&tv_uint16, testArray.data() + 7, sizeof(tv_uint16));
|
||||||
|
REQUIRE(tv_uint16 == 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Test set buffer function") {
|
||||||
|
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter_loc =
|
||||||
|
SerialBufferAdapter<uint8_t>((uint8_t*)nullptr,
|
||||||
|
0, true);
|
||||||
|
tv_serial_buffer_adapter_loc.setBuffer(test_serial_buffer.data(),
|
||||||
|
test_serial_buffer.size());
|
||||||
|
serialized_size = 0;
|
||||||
|
arrayPtr = testArray.data();
|
||||||
|
SerializeAdapter::serialize(&test_value_bool, &arrayPtr,&serialized_size,
|
||||||
|
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_serial_buffer_adapter_loc, &arrayPtr,
|
||||||
|
&serialized_size, testArray.size(),
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size,
|
||||||
|
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
REQUIRE(serialized_size == 9);
|
||||||
|
REQUIRE(testArray[0] == true);
|
||||||
|
REQUIRE(testArray[1] == 5);
|
||||||
|
REQUIRE(testArray[2] == 5);
|
||||||
|
REQUIRE(testArray[3] == 4);
|
||||||
|
REQUIRE(testArray[4] == 3);
|
||||||
|
REQUIRE(testArray[5] == 2);
|
||||||
|
REQUIRE(testArray[6] == 1);
|
||||||
|
memcpy(&tv_uint16, testArray.data() + 7, sizeof(tv_uint16));
|
||||||
|
REQUIRE(tv_uint16 == 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Deserialization with size field") {
|
||||||
|
size_t buffer_size = 4;
|
||||||
|
memcpy(testArray.data(), &buffer_size, sizeof(uint16_t));
|
||||||
|
testArray[2] = 1;
|
||||||
|
testArray[3] = 1;
|
||||||
|
testArray[4] = 1;
|
||||||
|
testArray[5] = 0;
|
||||||
|
std::array<uint8_t, 4> test_recv_array;
|
||||||
|
arrayPtr = testArray.data();
|
||||||
|
// copy testArray[1] to testArray[4] into receive buffer, skip
|
||||||
|
// size field (testArray[0]) for deSerialization.
|
||||||
|
SerialBufferAdapter<uint16_t> tv_serial_buffer_adapter3 =
|
||||||
|
SerialBufferAdapter<uint16_t>(test_recv_array.data(), 4, true);
|
||||||
|
// Deserialization
|
||||||
|
size_t size = 6;
|
||||||
|
auto result = tv_serial_buffer_adapter3.deSerialize(
|
||||||
|
const_cast<const uint8_t**>(&arrayPtr), &size,
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(test_recv_array[0] == 1);
|
||||||
|
CHECK(test_recv_array[1] == 1);
|
||||||
|
CHECK(test_recv_array[2] == 1);
|
||||||
|
CHECK(test_recv_array[3] == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Deserialization without size field") {
|
||||||
|
size_t buffer_size = 4;
|
||||||
|
memcpy(testArray.data(), &buffer_size, sizeof(uint16_t));
|
||||||
|
testArray[2] = 1;
|
||||||
|
testArray[3] = 1;
|
||||||
|
testArray[4] = 1;
|
||||||
|
testArray[5] = 0;
|
||||||
|
std::array<uint8_t, 4> test_recv_array;
|
||||||
|
arrayPtr = testArray.data() + 2;
|
||||||
|
// copy testArray[1] to testArray[4] into receive buffer, skip
|
||||||
|
// size field (testArray[0])
|
||||||
|
SerialBufferAdapter<uint16_t> tv_serial_buffer_adapter3 =
|
||||||
|
SerialBufferAdapter<uint16_t>(test_recv_array.data(), 4, false);
|
||||||
|
// Deserialization
|
||||||
|
size_t size = 4;
|
||||||
|
tv_serial_buffer_adapter3.deSerialize(
|
||||||
|
const_cast<const uint8_t**>(&arrayPtr), &size,
|
||||||
|
SerializeIF::Endianness::MACHINE);
|
||||||
|
CHECK(test_recv_array[0] == 1);
|
||||||
|
CHECK(test_recv_array[1] == 1);
|
||||||
|
CHECK(test_recv_array[2] == 1);
|
||||||
|
CHECK(test_recv_array[3] == 0);
|
||||||
|
}
|
||||||
|
}
|
73
unittest/tests/serialize/TestSerialLinkedPacket.cpp
Normal file
73
unittest/tests/serialize/TestSerialLinkedPacket.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include <fsfw/globalfunctions/arrayprinter.h>
|
||||||
|
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
#include <fsfw/unittest/tests/serialize/TestSerialLinkedPacket.h>
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Serial Linked Packet" , "[SerLinkPacket]") {
|
||||||
|
// perform set-up here
|
||||||
|
uint32_t header = 42;
|
||||||
|
std::array<uint8_t, 3> testArray {1,2,3};
|
||||||
|
uint32_t tail = 96;
|
||||||
|
size_t packetMaxSize = 256;
|
||||||
|
uint8_t packet [packetMaxSize] = {};
|
||||||
|
size_t packetLen = 0;
|
||||||
|
|
||||||
|
SECTION("Test Deserialization with Serial Buffer Adapter.") {
|
||||||
|
// This is a serialization of a packet, made "manually".
|
||||||
|
// We generate a packet which store data big-endian by swapping some
|
||||||
|
// values. (like coming from ground).
|
||||||
|
header = EndianConverter::convertBigEndian(header);
|
||||||
|
std::memcpy(packet, &header, sizeof(header));
|
||||||
|
packetLen += sizeof(header);
|
||||||
|
|
||||||
|
std::copy(testArray.data(), testArray.data() + testArray.size(),
|
||||||
|
packet + packetLen);
|
||||||
|
packetLen += testArray.size();
|
||||||
|
|
||||||
|
tail = EndianConverter::convertBigEndian(tail);
|
||||||
|
std::memcpy(packet + packetLen, &tail, sizeof(tail));
|
||||||
|
packetLen += sizeof(tail);
|
||||||
|
|
||||||
|
//arrayprinter::print(packet, packetLen, OutputType::DEC);
|
||||||
|
|
||||||
|
// This is the buffer which will be filled when testClass.deSerialize
|
||||||
|
// is called.
|
||||||
|
std::array<uint8_t, 3> bufferAdaptee = {};
|
||||||
|
TestPacket testClass(packet, packetLen, bufferAdaptee.data(),
|
||||||
|
bufferAdaptee.size());
|
||||||
|
const uint8_t* readOnlyPointer = packet;
|
||||||
|
// Deserialize big endian packet by setting bigEndian to true.
|
||||||
|
ReturnValue_t result = testClass.deSerialize(&readOnlyPointer,
|
||||||
|
&packetLen, SerializeIF::Endianness::BIG);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(testClass.getHeader() == 42);
|
||||||
|
// Equivalent check.
|
||||||
|
// CHECK(testClass.getBuffer()[0] == 1);
|
||||||
|
CHECK(bufferAdaptee[0] == 1);
|
||||||
|
CHECK(bufferAdaptee[1] == 2);
|
||||||
|
CHECK(bufferAdaptee[2] == 3);
|
||||||
|
CHECK(testClass.getTail() == 96);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Test Serialization") {
|
||||||
|
// Same process as performed in setup, this time using the class
|
||||||
|
// instead of doing it manually.
|
||||||
|
TestPacket testClass(header, tail, testArray.data(), testArray.size());
|
||||||
|
size_t serializedSize = 0;
|
||||||
|
uint8_t* packetPointer = packet;
|
||||||
|
// serialize for ground: bigEndian = true.
|
||||||
|
ReturnValue_t result = testClass.serialize(&packetPointer,
|
||||||
|
&serializedSize, packetMaxSize, SerializeIF::Endianness::BIG);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
// Result should be big endian now.
|
||||||
|
CHECK(packet[3] == 42);
|
||||||
|
CHECK(packet[4] == 1);
|
||||||
|
CHECK(packet[5] == 2);
|
||||||
|
CHECK(packet[6] == 3);
|
||||||
|
CHECK(packet[10] == 96);
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform tear-down here
|
||||||
|
}
|
61
unittest/tests/serialize/TestSerialLinkedPacket.h
Normal file
61
unittest/tests/serialize/TestSerialLinkedPacket.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#ifndef UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_
|
||||||
|
#define UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_
|
||||||
|
|
||||||
|
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||||
|
#include <fsfw/parameters/HasParametersIF.h>
|
||||||
|
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||||
|
#include <fsfw/serialize/SerialLinkedListAdapter.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
class TestPacket: public SerialLinkedListAdapter<SerializeIF> {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* For Deserialization
|
||||||
|
*/
|
||||||
|
TestPacket(const uint8_t *somePacket, size_t size, uint8_t * storePointer,
|
||||||
|
size_t storeSize):
|
||||||
|
buffer(storePointer, storeSize)
|
||||||
|
{
|
||||||
|
setLinks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For Serialization
|
||||||
|
*/
|
||||||
|
TestPacket(uint32_t header, uint32_t tail,
|
||||||
|
const uint8_t* parameters, size_t paramSize):
|
||||||
|
header(header), buffer(parameters, paramSize),
|
||||||
|
tail(tail) {
|
||||||
|
setLinks();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getHeader() const {
|
||||||
|
return header.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t * getBuffer() {
|
||||||
|
return buffer.entry.getConstBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t getBufferLength() {
|
||||||
|
return buffer.getSerializedSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint16_t getTail() const {
|
||||||
|
return tail.entry;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void setLinks() {
|
||||||
|
setStart(&header);
|
||||||
|
header.setNext(&buffer);
|
||||||
|
buffer.setNext(&tail);
|
||||||
|
tail.setEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
SerializeElement<uint32_t> header = 0;
|
||||||
|
SerializeElement<SerialBufferAdapter<uint8_t>> buffer;
|
||||||
|
SerializeElement<uint32_t> tail = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* UNITTEST_TESTFW_NEWTESTS_TESTTEMPLATE_H_ */
|
129
unittest/tests/serialize/TestSerialization.cpp
Normal file
129
unittest/tests/serialize/TestSerialization.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include <fsfw/serialize/SerializeAdapter.h>
|
||||||
|
|
||||||
|
#include "catch.hpp"
|
||||||
|
#include <array>
|
||||||
|
#include "core/CatchDefinitions.h"
|
||||||
|
|
||||||
|
static bool test_value_bool = true;
|
||||||
|
static uint8_t tv_uint8 {5};
|
||||||
|
static uint16_t tv_uint16 {283};
|
||||||
|
static uint32_t tv_uint32 {929221};
|
||||||
|
static uint64_t tv_uint64 {2929329429};
|
||||||
|
|
||||||
|
static int8_t tv_int8 {-16};
|
||||||
|
static int16_t tv_int16 {-829};
|
||||||
|
static int32_t tv_int32 {-2312};
|
||||||
|
|
||||||
|
static float tv_float {8.2149214};
|
||||||
|
static float tv_sfloat = {-922.2321321};
|
||||||
|
static double tv_double {9.2132142141e8};
|
||||||
|
static double tv_sdouble {-2.2421e19};
|
||||||
|
|
||||||
|
static std::array<uint8_t, 512> test_array;
|
||||||
|
|
||||||
|
TEST_CASE( "Serialization size tests", "[TestSerialization]") {
|
||||||
|
//REQUIRE(unitTestClass.test_autoserialization() == 0);
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&test_value_bool) ==
|
||||||
|
sizeof(test_value_bool));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint8) ==
|
||||||
|
sizeof(tv_uint8));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint16) ==
|
||||||
|
sizeof(tv_uint16));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint32 ) ==
|
||||||
|
sizeof(tv_uint32));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint64) ==
|
||||||
|
sizeof(tv_uint64));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_int8) ==
|
||||||
|
sizeof(tv_int8));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_int16) ==
|
||||||
|
sizeof(tv_int16));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_int32) ==
|
||||||
|
sizeof(tv_int32));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_float) ==
|
||||||
|
sizeof(tv_float));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_sfloat) ==
|
||||||
|
sizeof(tv_sfloat ));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_double) ==
|
||||||
|
sizeof(tv_double));
|
||||||
|
REQUIRE(SerializeAdapter::getSerializedSize(&tv_sdouble) ==
|
||||||
|
sizeof(tv_sdouble));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_CASE("Auto Serialize Adapter testing", "[single-file]") {
|
||||||
|
size_t serialized_size = 0;
|
||||||
|
uint8_t * p_array = test_array.data();
|
||||||
|
|
||||||
|
SECTION("Serializing...") {
|
||||||
|
SerializeAdapter::serialize(&test_value_bool, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint8, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint16, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint32, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_int8, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_int16, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_int32, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_uint64, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_float, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_double, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_sfloat, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::serialize(&tv_sdouble, &p_array,
|
||||||
|
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||||
|
REQUIRE (serialized_size == 47);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Deserializing") {
|
||||||
|
p_array = test_array.data();
|
||||||
|
size_t remaining_size = serialized_size;
|
||||||
|
SerializeAdapter::deSerialize(&test_value_bool,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint8,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint16,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint32,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_int8,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_int16,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_int32,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_uint64,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_float,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_double,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_sfloat,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
SerializeAdapter::deSerialize(&tv_sdouble,
|
||||||
|
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||||
|
|
||||||
|
REQUIRE(test_value_bool == true);
|
||||||
|
REQUIRE(tv_uint8 == 5);
|
||||||
|
REQUIRE(tv_uint16 == 283);
|
||||||
|
REQUIRE(tv_uint32 == 929221);
|
||||||
|
REQUIRE(tv_uint64 == 2929329429);
|
||||||
|
REQUIRE(tv_int8 == -16);
|
||||||
|
REQUIRE(tv_int16 == -829);
|
||||||
|
REQUIRE(tv_int32 == -2312);
|
||||||
|
|
||||||
|
REQUIRE(tv_float == Approx(8.214921));
|
||||||
|
REQUIRE(tv_double == Approx(9.2132142141e8));
|
||||||
|
REQUIRE(tv_sfloat == Approx(-922.2321321));
|
||||||
|
REQUIRE(tv_sdouble == Approx(-2.2421e19));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
161
unittest/tests/storagemanager/TestNewAccessor.cpp
Normal file
161
unittest/tests/storagemanager/TestNewAccessor.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#include <fsfw/storagemanager/LocalPool.h>
|
||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
TEST_CASE( "New Accessor" , "[NewAccessor]") {
|
||||||
|
uint16_t numberOfElements[1] = {1};
|
||||||
|
uint16_t sizeofElements[1] = {10};
|
||||||
|
LocalPool<1> SimplePool = LocalPool<1>(0, sizeofElements, numberOfElements);
|
||||||
|
std::array<uint8_t, 20> testDataArray;
|
||||||
|
std::array<uint8_t, 20> receptionArray;
|
||||||
|
store_address_t testStoreId;
|
||||||
|
ReturnValue_t result = retval::CATCH_FAILED;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < testDataArray.size(); i++) {
|
||||||
|
testDataArray[i] = i;
|
||||||
|
}
|
||||||
|
size_t size = 10;
|
||||||
|
|
||||||
|
SECTION ("Simple tests getter functions") {
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
auto resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||||
|
resultPair.second.getDataCopy(receptionArray.data(), 20);
|
||||||
|
CHECK(resultPair.second.getId() == testStoreId);
|
||||||
|
CHECK(resultPair.second.size() == 10);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::copy(resultPair.second.data(), resultPair.second.data() +
|
||||||
|
resultPair.second.size(), receptionArray.data());
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto resultPairLoc = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPairLoc.first == retval::CATCH_OK);
|
||||||
|
// data should be deleted when accessor goes out of scope.
|
||||||
|
}
|
||||||
|
resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST);
|
||||||
|
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
{
|
||||||
|
ConstStorageAccessor constAccessor(testStoreId);
|
||||||
|
result = SimplePool.getData(testStoreId, constAccessor);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
constAccessor.getDataCopy(receptionArray.data(), 20);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
// likewise, data should be deleted when accessor gets out of scope.
|
||||||
|
}
|
||||||
|
resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST);
|
||||||
|
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
{
|
||||||
|
resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||||
|
resultPair.second.release();
|
||||||
|
// now data should not be deleted anymore
|
||||||
|
}
|
||||||
|
resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||||
|
resultPair.second.getDataCopy(receptionArray.data(), 20);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTION("Simple tests modify functions") {
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
{
|
||||||
|
StorageAccessor accessor(testStoreId);
|
||||||
|
result = SimplePool.modifyData(testStoreId, accessor);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
CHECK(accessor.getId() == testStoreId);
|
||||||
|
CHECK(accessor.size() == 10);
|
||||||
|
accessor.getDataCopy(receptionArray.data(), 20);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
std::copy(accessor.data(), accessor.data() +
|
||||||
|
accessor.size(), receptionArray.data());
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
// data should be deleted when accessor goes out of scope
|
||||||
|
}
|
||||||
|
auto resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST);
|
||||||
|
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
{
|
||||||
|
auto resultPairLoc = SimplePool.modifyData(testStoreId);
|
||||||
|
REQUIRE(resultPairLoc.first == retval::CATCH_OK);
|
||||||
|
CHECK(resultPairLoc.second.getId() == testStoreId);
|
||||||
|
CHECK(resultPairLoc.second.size() == 10);
|
||||||
|
resultPairLoc.second.getDataCopy(receptionArray.data(), 20);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() +
|
||||||
|
resultPairLoc.second.size(), receptionArray.data());
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
resultPairLoc.second.release();
|
||||||
|
// data should not be deleted when accessor goes out of scope
|
||||||
|
}
|
||||||
|
resultPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SECTION("Write tests") {
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
{
|
||||||
|
auto resultPair = SimplePool.modifyData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||||
|
testDataArray[9] = 42;
|
||||||
|
resultPair.second.write(testDataArray.data(), 10, 0);
|
||||||
|
// now data should not be deleted
|
||||||
|
resultPair.second.release();
|
||||||
|
}
|
||||||
|
auto resultConstPair = SimplePool.getData(testStoreId);
|
||||||
|
REQUIRE(resultConstPair.first == retval::CATCH_OK);
|
||||||
|
|
||||||
|
resultConstPair.second.getDataCopy(receptionArray.data(), 10);
|
||||||
|
for(size_t i = 0; i < size-1; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
CHECK(receptionArray[9] == 42 );
|
||||||
|
|
||||||
|
auto resultPair = SimplePool.modifyData(testStoreId);
|
||||||
|
REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||||
|
result = resultPair.second.write(testDataArray.data(), 20, 0);
|
||||||
|
REQUIRE(result == retval::CATCH_FAILED);
|
||||||
|
result = resultPair.second.write(testDataArray.data(), 10, 5);
|
||||||
|
REQUIRE(result == retval::CATCH_FAILED);
|
||||||
|
|
||||||
|
memset(testDataArray.data(), 42, 5);
|
||||||
|
result = resultPair.second.write(testDataArray.data(), 5, 5);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
resultConstPair = SimplePool.getData(testStoreId);
|
||||||
|
resultPair.second.getDataCopy(receptionArray.data(), 20);
|
||||||
|
for(size_t i = 5; i < 10; i++) {
|
||||||
|
CHECK(receptionArray[i] == 42 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
105
unittest/tests/storagemanager/TestPool.cpp
Normal file
105
unittest/tests/storagemanager/TestPool.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include <config/objects/Factory.h>
|
||||||
|
#include <fsfw/objectmanager/ObjectManager.h>
|
||||||
|
#include <fsfw/storagemanager/LocalPool.h>
|
||||||
|
#include <catch2/catch.hpp>
|
||||||
|
#include "core/CatchDefinitions.h"
|
||||||
|
|
||||||
|
TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") {
|
||||||
|
uint16_t numberOfElements[1] = {1};
|
||||||
|
uint16_t sizeofElements[1] = {10};
|
||||||
|
LocalPool<1> SimplePool = LocalPool<1>(0, sizeofElements, numberOfElements);
|
||||||
|
std::array<uint8_t, 20> testDataArray;
|
||||||
|
std::array<uint8_t, 20> receptionArray;
|
||||||
|
store_address_t testStoreId;
|
||||||
|
ReturnValue_t result = retval::CATCH_FAILED;
|
||||||
|
uint8_t *pointer = nullptr;
|
||||||
|
const uint8_t * constPointer = nullptr;
|
||||||
|
uint8_t test = 0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < testDataArray.size(); i++) {
|
||||||
|
testDataArray[i] = i;
|
||||||
|
}
|
||||||
|
size_t size = 10;
|
||||||
|
|
||||||
|
SECTION ( "Basic tests") {
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = SimplePool.getData(testStoreId, &constPointer, &size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
memcpy(receptionArray.data(), constPointer, size);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
memset(receptionArray.data(), 0, size);
|
||||||
|
result = SimplePool.modifyData(testStoreId, &pointer, &size);
|
||||||
|
memcpy(receptionArray.data(), pointer, size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
result = SimplePool.deleteData(testStoreId);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), 15);
|
||||||
|
CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION ( "Reservation Tests ") {
|
||||||
|
pointer = nullptr;
|
||||||
|
result = SimplePool.getFreeElement(&testStoreId, size, &pointer);
|
||||||
|
REQUIRE (result == retval::CATCH_OK);
|
||||||
|
memcpy(pointer, testDataArray.data(), size);
|
||||||
|
constPointer = nullptr;
|
||||||
|
result = SimplePool.getData(testStoreId, &constPointer, &size);
|
||||||
|
|
||||||
|
REQUIRE (result == retval::CATCH_OK);
|
||||||
|
memcpy(receptionArray.data(), constPointer, size);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION ( "Add, delete, add, add when full") {
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = SimplePool.getData(testStoreId, &constPointer, &size);
|
||||||
|
REQUIRE( result == retval::CATCH_OK);
|
||||||
|
memcpy(receptionArray.data(), constPointer, size);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
|
||||||
|
result = SimplePool.deleteData(testStoreId);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = SimplePool.getData(testStoreId, &constPointer, &size);
|
||||||
|
REQUIRE( result == retval::CATCH_OK);
|
||||||
|
memcpy(receptionArray.data(), constPointer, size);
|
||||||
|
for(size_t i = 0; i < size; i++) {
|
||||||
|
CHECK(receptionArray[i] == i );
|
||||||
|
}
|
||||||
|
|
||||||
|
store_address_t newAddress;
|
||||||
|
result = SimplePool.addData(&newAddress, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION ( "Initialize and clear store, delete with pointer") {
|
||||||
|
result = SimplePool.initialize();
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
SimplePool.clearStore();
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
result = SimplePool.modifyData(testStoreId, &pointer, &size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
store_address_t newId;
|
||||||
|
result = SimplePool.deleteData(pointer, size, &testStoreId);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS);
|
||||||
|
result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||||
|
REQUIRE(result == retval::CATCH_OK);
|
||||||
|
}
|
||||||
|
}
|
8
unittest/tests/tests.mk
Normal file
8
unittest/tests/tests.mk
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/container/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/action/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp)
|
||||||
|
CXXSRC += $(wildcard $(CURRENTPATH)/storagemanager/*.cpp)
|
||||||
|
|
||||||
|
# OSAL not included for now.
|
||||||
|
|
||||||
|
INCLUDES += $(CURRENTPATH)
|
31
unittest/testtemplate/TestTemplate.cpp
Normal file
31
unittest/testtemplate/TestTemplate.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <fsfw/unittest/catch2/catch.hpp>
|
||||||
|
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Template test file
|
||||||
|
* @details
|
||||||
|
* In each test case, the code outside the sections is executed
|
||||||
|
* for EACH section.
|
||||||
|
* The most common macros to perform tests are:
|
||||||
|
* - CHECK(...): assert expression and continues even if it fails
|
||||||
|
* - REQUIRE(...): test case fails if assertion fails
|
||||||
|
*
|
||||||
|
* Tests are generally sturctured in test cases and sections, see example
|
||||||
|
* below.
|
||||||
|
*
|
||||||
|
* More Documentation:
|
||||||
|
* - https://github.com/catchorg/Catch2
|
||||||
|
* - https://github.com/catchorg/Catch2/blob/master/docs/assertions.md
|
||||||
|
* - https://github.com/catchorg/Catch2/blob/master/docs/test-cases-and-sections.md
|
||||||
|
*/
|
||||||
|
TEST_CASE("Dummy Test" , "[DummyTest]") {
|
||||||
|
uint8_t testVariable = 1;
|
||||||
|
//perform set-up here
|
||||||
|
CHECK(testVariable == 1);
|
||||||
|
SECTION("TestSection") {
|
||||||
|
// set-up is run for each section
|
||||||
|
REQUIRE(testVariable == 1);
|
||||||
|
}
|
||||||
|
// perform tear-down here
|
||||||
|
}
|
34
unittest/unlockRealtime.sh
Normal file
34
unittest/unlockRealtime.sh
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Run this script to unlock all permissions to run the linux binaries
|
||||||
|
# and create threads
|
||||||
|
|
||||||
|
binaries=$(find $directory -type f -name "*.elf")
|
||||||
|
|
||||||
|
echo Unlocking real time permissions for binaries and bash console...
|
||||||
|
|
||||||
|
# Set up the soft realtime limit to maximum (99)
|
||||||
|
# Please note that the hard limit needs to be set to 99 too
|
||||||
|
# for this to work (check with ulimit -Hr).
|
||||||
|
# If that has not been done yet, add
|
||||||
|
# <username> hard rtprio 99
|
||||||
|
# to /etc/security/limits.conf
|
||||||
|
# It is also necessary and recommended to add
|
||||||
|
# <username> soft rtprio 99
|
||||||
|
# as well. This can also be done in the command line
|
||||||
|
# but would need to be done for each session.
|
||||||
|
ulimit -Sr 99
|
||||||
|
|
||||||
|
for binary in ${binaries}; do
|
||||||
|
sudo setcap 'cap_sys_nice=eip' ${binary}
|
||||||
|
result=$?
|
||||||
|
if [ ${result} = 0 ];then
|
||||||
|
echo ${binary} was unlocked
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# sudo setcap 'cap_sys_nice=eip' /bin/bash
|
||||||
|
# result=$?
|
||||||
|
# if [ ${result} = 0 ];then
|
||||||
|
# echo /bin/bash was unlocked
|
||||||
|
# fi
|
||||||
|
|
Loading…
Reference in New Issue
Block a user