Skip to content

Commit

Permalink
Add rlp unit test to cmocka
Browse files Browse the repository at this point in the history
Ported from old c++ tests to cmocka
  • Loading branch information
relatko committed Jan 3, 2024
1 parent a7c3396 commit 1b547e8
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 7 deletions.
13 changes: 10 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ VARIANT_VALUES = FLOW

# Enabling DEBUG flag will enable PRINTF and disable optimizations
#DEBUG = 1
ifeq ($(DEBUG),1)
DEFINES += ZEMU_LOGGING
endif

#######################################
# Application custom permissions #
Expand Down Expand Up @@ -128,6 +125,16 @@ ifeq ($(TARGET_NAME),TARGET_NANOS)
APP_STACK_SIZE:=2480
endif

########################################
# Unit tests and misc #
########################################

ifeq ($(DEBUG),1)
DEFINES += ZEMU_LOGGING=1
else
DEFINES += ZEMU_LOGGING=0
endif

#########################

# Import generic rules from the SDK
Expand Down
5 changes: 3 additions & 2 deletions deps/ledger-zxlib/include/zxmacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ extern "C" {
#include <stdio.h>
#include "string.h"

#ifndef __APPLE__
// relatko: removed to make c unittests work
/*#ifndef __APPLE__
extern void explicit_bzero(void *s, size_t n) __THROW __nonnull ((1));
#endif
#endif*/

#define __Z_INLINE inline __attribute__((always_inline)) static
#define __Z_UNUSED __attribute__((unused))
Expand Down
2 changes: 0 additions & 2 deletions src/json/json_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@
extern "C" {
#endif

#include "bolos_target.h"

/// Max number of accepted tokens in the JSON input
#define MAX_NUMBER_OF_TOKENS 256

Expand Down
61 changes: 61 additions & 0 deletions unit-tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
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 Nano application"
LANGUAGES C)


# guard against bad build-type strings
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug")
endif()

include(CTest)
ENABLE_TESTING()

# specify C standard
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED True)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall -pedantic -g -O0 --coverage")

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}")

# 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()

add_compile_definitions(TEST)

include_directories(../src)
include_directories(../deps/ledger-zxlib/include)
include_directories($ENV{BOLOS_SDK}/lib_standard_app)

add_executable(test_rlp test_rlp.c)

add_library(base58 SHARED $ENV{BOLOS_SDK}/lib_standard_app/base58.c)
add_library(bip32 SHARED $ENV{BOLOS_SDK}/lib_standard_app/bip32.c)
add_library(buffer SHARED $ENV{BOLOS_SDK}/lib_standard_app/buffer.c)
add_library(read SHARED $ENV{BOLOS_SDK}/lib_standard_app/read.c)
add_library(write SHARED $ENV{BOLOS_SDK}/lib_standard_app/write.c)
add_library(format SHARED $ENV{BOLOS_SDK}/lib_standard_app/format.c)
add_library(varint SHARED $ENV{BOLOS_SDK}/lib_standard_app/varint.c)
add_library(apdu_parser SHARED $ENV{BOLOS_SDK}/lib_standard_app/parser.c)
add_library(rlp ../src/rlp.c)
add_library(hexutils ../deps/ledger-zxlib/src/hexutils.c)

target_link_libraries(test_rlp PUBLIC
cmocka
gcov
hexutils
rlp)

add_test(test_rlp test_rlp)
36 changes: 36 additions & 0 deletions unit-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# 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

```
cmake -Bbuild -H. && make -C build
```

and run tests with

```
CTEST_OUTPUT_ON_FAILURE=1 make -C build test
```

## Generate code coverage

Just execute in `unit-tests` folder

```
./gen_coverage.sh
```

it will output `coverage.total` and `coverage/` folder with HTML details (in `coverage/index.html`).
15 changes: 15 additions & 0 deletions unit-tests/gen_coverage.sh
Original file line number Diff line number Diff line change
@@ -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
160 changes: 160 additions & 0 deletions unit-tests/test_rlp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#include <cmocka.h>

#include "hexutils.h"
#include "rlp.h"

struct RLPValueTestCase {
const char *data;
parser_error_t expectedError;
uint8_t expectedKind;
uint64_t expectedLen;
uint64_t expectedDataOffset;
uint64_t expectedConsumed;
};

struct RLPValueTestCase testCases[] = {
{"00", PARSER_OK, RLP_KIND_STRING, 1, 0, 1}, // Byte string (00)
{"01", PARSER_OK, RLP_KIND_STRING, 1, 0, 1}, // Byte string (01)
{"7F", PARSER_OK, RLP_KIND_STRING, 1, 0, 1}, // Byte string (7F)

{"80", PARSER_OK, RLP_KIND_STRING, 0, 1, 1}, // Empty string ("")
{"83646F67", PARSER_OK, RLP_KIND_STRING, 3, 1, 4}, // Short string ("dog")

{"B7"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000",
PARSER_OK, RLP_KIND_STRING, 55, 1, 56},
{"B90400"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000",
PARSER_OK, RLP_KIND_STRING, 1024, 3, 1027},
{"C0", PARSER_OK, RLP_KIND_LIST, 0, 1, 1},
{"C80000000000000000", PARSER_OK, RLP_KIND_LIST, 8, 1, 9},
{"F7"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000",
PARSER_OK, RLP_KIND_LIST, 55, 1, 56},
{"F90400"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000",
PARSER_OK, RLP_KIND_LIST, 1024, 3, 1027},
// Varios invalid RLP data examples
{"", PARSER_UNEXPECTED_BUFFER_END, RLP_KIND_UNKNOWN, 0, 0, 0},

{"BB", PARSER_UNEXPECTED_BUFFER_END, RLP_KIND_STRING, 0, 0, 0},

{"B800", PARSER_OK, RLP_KIND_STRING, 0, 2, 2},

{"B900", PARSER_UNEXPECTED_BUFFER_END, RLP_KIND_STRING, 0, 0, 0},
{"B90000", PARSER_OK, RLP_KIND_STRING, 0, 3, 3},
{"B9000100", PARSER_OK, RLP_KIND_STRING, 1, 3, 4},

{"BA000000", PARSER_RLP_ERROR_INVALID_VALUE_LEN, RLP_KIND_STRING, 0, 0, 0},
{"BB01000000", PARSER_RLP_ERROR_INVALID_VALUE_LEN, RLP_KIND_STRING, 0, 0, 0}
};

static void test_rlp(void **state) {
(void) state;

const size_t numberOfTests = (sizeof(testCases) / sizeof(*testCases));
for(int i=0; i<numberOfTests; i++) {
struct RLPValueTestCase *testCase = &(testCases[i]);

uint8_t data[2000];
const size_t dataSize = parseHexString(data, sizeof(data), testCase->data);
parser_context_t ctx_in;
parser_context_t ctx_out;

ctx_in.buffer = data;
ctx_in.bufferLen = dataSize;
ctx_in.offset = 0;

rlp_kind_e kind;
uint32_t bytesConsumed;

parser_error_t err = rlp_decode(&ctx_in, &ctx_out, &kind, &bytesConsumed);

assert_int_equal(err, testCase->expectedError);
assert_int_equal(kind, testCase->expectedKind);
assert_int_equal(ctx_out.bufferLen, testCase->expectedLen);
assert_int_equal(ctx_out.buffer - ctx_in.buffer, testCase->expectedDataOffset);
assert_int_equal(bytesConsumed, testCase->expectedConsumed);
}
}

int main() {
const struct CMUnitTest tests[] = {cmocka_unit_test(test_rlp)};

return cmocka_run_group_tests(tests, NULL, NULL);
}

0 comments on commit 1b547e8

Please sign in to comment.