Add Unit Tests
parent
6b9018483e
commit
eab32ad7af
@ -0,0 +1,62 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS 3.10)
|
||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||
endif()
|
||||
|
||||
# project information
|
||||
project(unit_tests
|
||||
VERSION 0.1
|
||||
DESCRIPTION "Unit tests for Ledger OpenPGP application"
|
||||
LANGUAGES C)
|
||||
|
||||
|
||||
# guard against bad build-type strings
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
# guard against in-source builds
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
|
||||
endif()
|
||||
|
||||
include(CTest)
|
||||
|
||||
# specify C standard
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||
|
||||
add_compile_options(-Wall -Wextra -g -pedantic --coverage)
|
||||
# Flag depending on the Build Type
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}-O3")
|
||||
|
||||
set(GCC_COVERAGE_LINK_FLAGS "--coverage -lgcov")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
|
||||
|
||||
set(APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../src")
|
||||
set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
set(MOCK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mocks")
|
||||
|
||||
add_compile_definitions(TEST)
|
||||
|
||||
include_directories(
|
||||
${MOCK_DIR}
|
||||
${APP_DIR}
|
||||
)
|
||||
# include_directories($ENV{BOLOS_SDK}/lib_standard_app)
|
||||
|
||||
add_executable(test_io
|
||||
${SRC_DIR}/test_io.c
|
||||
${MOCK_DIR}/mocks.c
|
||||
${APP_DIR}/gpg_io.c
|
||||
${APP_DIR}/gpg_vars.c
|
||||
)
|
||||
|
||||
target_link_libraries(test_io PUBLIC
|
||||
cmocka
|
||||
gcov)
|
||||
|
||||
add_test(test_io test_io)
|
@ -0,0 +1,48 @@
|
||||
# Unit tests
|
||||
|
||||
## Prerequisite
|
||||
|
||||
Be sure to have installed:
|
||||
|
||||
- CMake >= 3.10
|
||||
- CMocka >= 1.1.5
|
||||
|
||||
and for code coverage generation:
|
||||
|
||||
- lcov >= 1.14
|
||||
|
||||
## Overview
|
||||
|
||||
In `unit-tests` folder, compile with:
|
||||
|
||||
```shell
|
||||
cmake -Bbuild -H. && make -C build
|
||||
```
|
||||
|
||||
and run tests with:
|
||||
|
||||
```shell
|
||||
CTEST_OUTPUT_ON_FAILURE=1 make -C build test
|
||||
```
|
||||
|
||||
To get more verbose output, use:
|
||||
|
||||
```shell
|
||||
CTEST_OUTPUT_ON_FAILURE=1 make -C build test ARGS="-V"
|
||||
```
|
||||
|
||||
Or also directly with:
|
||||
|
||||
```shell
|
||||
CTEST_OUTPUT_ON_FAILURE=1 build/test_io
|
||||
```
|
||||
|
||||
## Generate code coverage
|
||||
|
||||
Just execute in `unit-tests` folder:
|
||||
|
||||
```shell
|
||||
./gen_coverage.sh
|
||||
```
|
||||
|
||||
it will output `coverage.total` and `coverage/` folder with HTML details (in `coverage/index.html`).
|
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
BUILD_DIRECTORY=$(realpath build/)
|
||||
|
||||
lcov --directory . -b "${BUILD_DIRECTORY}" --capture --initial -o coverage.base &&
|
||||
lcov --rc lcov_branch_coverage=1 --directory . -b "${BUILD_DIRECTORY}" --capture -o coverage.capture &&
|
||||
lcov --directory . -b "${BUILD_DIRECTORY}" --add-tracefile coverage.base --add-tracefile coverage.capture -o coverage.info &&
|
||||
lcov --directory . -b "${BUILD_DIRECTORY}" --remove coverage.info '*/unit-tests/*' -o coverage.info &&
|
||||
echo "Generated 'coverage.info'." &&
|
||||
genhtml coverage.info -o coverage
|
||||
|
||||
rm -f coverage.base coverage.capture
|
@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
#define cx_rsa_public_key_t char
|
||||
#define cx_rsa_1024_public_key_t char
|
||||
#define cx_rsa_2048_public_key_t char
|
||||
#define cx_rsa_3072_public_key_t char
|
||||
#define cx_rsa_4096_public_key_t char
|
||||
|
||||
#define cx_rsa_private_key_t char
|
||||
#define cx_rsa_1024_private_key_t char
|
||||
#define cx_rsa_2048_private_key_t char
|
||||
#define cx_rsa_3072_private_key_t char
|
||||
#define cx_rsa_4096_private_key_t char
|
||||
|
||||
#define cx_ecfp_public_key_t char
|
||||
#define cx_ecfp_256_public_key_t char
|
||||
#define cx_ecfp_384_public_key_t char
|
||||
#define cx_ecfp_512_public_key_t char
|
||||
#define cx_ecfp_640_public_key_t char
|
||||
|
||||
#define cx_ecfp_private_key_t char
|
||||
#define cx_ecfp_256_private_key_t char
|
||||
#define cx_ecfp_384_private_key_t char
|
||||
#define cx_ecfp_512_private_key_t char
|
||||
#define cx_ecfp_640_private_key_t char
|
||||
|
||||
#define cx_sha3_t char
|
||||
#define cx_sha256_t char
|
||||
|
||||
#define cx_aes_key_t char
|
@ -0,0 +1,6 @@
|
||||
#define LEDGER_ASSERT(test, message) \
|
||||
do { \
|
||||
if (!(test)) { \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
@ -0,0 +1,17 @@
|
||||
|
||||
#include "os.h"
|
||||
|
||||
unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE];
|
||||
|
||||
unsigned short io_exchange(unsigned char channel_and_flags, unsigned short tx_len) {
|
||||
(void) channel_and_flags;
|
||||
(void) tx_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) {
|
||||
(void) dst_adr;
|
||||
(void) src_adr;
|
||||
(void) src_len;
|
||||
return;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Offset of instruction class.
|
||||
*/
|
||||
#define OFFSET_CLA 0
|
||||
/**
|
||||
* Offset of instruction code.
|
||||
*/
|
||||
#define OFFSET_INS 1
|
||||
/**
|
||||
* Offset of instruction parameter 1.
|
||||
*/
|
||||
#define OFFSET_P1 2
|
||||
/**
|
||||
* Offset of instruction parameter 2.
|
||||
*/
|
||||
#define OFFSET_P2 3
|
||||
/**
|
||||
* Offset of command data length.
|
||||
*/
|
||||
#define OFFSET_LC 4
|
||||
/**
|
||||
* Offset of command data.
|
||||
*/
|
||||
#define OFFSET_CDATA 5
|
@ -0,0 +1,22 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#undef MAX
|
||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#define PRINTF(...)
|
||||
#define THROW(x)
|
||||
|
||||
// send tx_len bytes (atr or rapdu) and retrieve the length of the next command apdu (over the
|
||||
// requested channel)
|
||||
#define CHANNEL_APDU 0
|
||||
#define IO_RETURN_AFTER_TX 0x20
|
||||
#define IO_ASYNCH_REPLY 0x10 // avoid apdu state reset if tx_len == 0 when we're expected to reply
|
||||
|
||||
#define IO_APDU_BUFFER_SIZE (255 + 5 + 64)
|
||||
|
||||
extern unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE];
|
||||
|
||||
extern unsigned short io_exchange(unsigned char channel_and_flags, unsigned short tx_len);
|
||||
extern void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len);
|
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#define U2(hi, lo) ((((hi) &0xFFu) << 8) | ((lo) &0xFFu))
|
||||
#define U4(hi3, hi2, lo1, lo0) \
|
||||
((((hi3) &0xFFu) << 24) | (((hi2) &0xFFu) << 16) | (((lo1) &0xFFu) << 8) | ((lo0) &0xFFu))
|
||||
static inline uint16_t U2BE(const uint8_t *buf, size_t off) {
|
||||
return (buf[off] << 8) | buf[off + 1];
|
||||
}
|
||||
static inline uint32_t U4BE(const uint8_t *buf, size_t off) {
|
||||
return (((uint32_t) buf[off]) << 24) | (buf[off + 1] << 16) | (buf[off + 2] << 8) |
|
||||
buf[off + 3];
|
||||
}
|
||||
|
||||
static inline void U2BE_ENCODE(uint8_t *buf, size_t off, uint32_t value) {
|
||||
buf[off + 0] = (value >> 8) & 0xFF;
|
||||
buf[off + 1] = value & 0xFF;
|
||||
}
|
||||
static inline void U4BE_ENCODE(uint8_t *buf, size_t off, uint32_t value) {
|
||||
buf[off + 0] = (value >> 24) & 0xFF;
|
||||
buf[off + 1] = (value >> 16) & 0xFF;
|
||||
buf[off + 2] = (value >> 8) & 0xFF;
|
||||
buf[off + 3] = value & 0xFF;
|
||||
}
|
@ -0,0 +1 @@
|
||||
#define PIN_OPR_APDU_CLA 0xEF
|
@ -0,0 +1 @@
|
||||
#define ux_state_t char
|
@ -0,0 +1,53 @@
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cmocka.h>
|
||||
|
||||
#include "gpg_vars.h"
|
||||
|
||||
static int setup(void **state) {
|
||||
(void) state;
|
||||
|
||||
// Init tests
|
||||
gpg_io_discard(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_io(void **state) {
|
||||
(void) state;
|
||||
|
||||
unsigned int v32 = 0x789ABCDE;
|
||||
unsigned int v16 = 0x3456;
|
||||
unsigned int v8 = 0x12;
|
||||
|
||||
gpg_io_insert_u8(v8);
|
||||
|
||||
gpg_io_insert_u16(v16);
|
||||
|
||||
// Mark the current offset
|
||||
gpg_io_mark();
|
||||
|
||||
gpg_io_insert_u32(v32);
|
||||
|
||||
// rewind offset to the beginning to the buffer
|
||||
gpg_io_set_offset(0);
|
||||
|
||||
assert_int_equal(gpg_io_fetch_u8(), v8);
|
||||
assert_int_equal(gpg_io_fetch_u16(), v16);
|
||||
assert_int_equal(gpg_io_fetch_u32(), v32);
|
||||
|
||||
// rewind offset to the mark
|
||||
gpg_io_set_offset(IO_OFFSET_MARK);
|
||||
|
||||
assert_int_equal(gpg_io_fetch_u32(), v32);
|
||||
}
|
||||
|
||||
int main() {
|
||||
const struct CMUnitTest tests[] = {cmocka_unit_test_setup(test_io, setup)};
|
||||
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
Loading…
Reference in New Issue