Add Unit Tests

pull/94/head
Charles-Edouard de la Vergne 8 months ago
parent 6b9018483e
commit eab32ad7af
No known key found for this signature in database
GPG Key ID: F12296941B7BB9C6

@ -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…
Cancel
Save