Skip to content

Commit

Permalink
Rework on UI unit test to change from function call list to a more be…
Browse files Browse the repository at this point in the history
…haviour based approach

- Updated communication tests
- Updated onboard tests
- Updated pin tests
- Updated unlock tests
  • Loading branch information
italo-sampaio committed Nov 22, 2022
1 parent ea3abd3 commit b747e95
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 172 deletions.
5 changes: 4 additions & 1 deletion ledger/src/ui/test/communication/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ MOCKDIR = ../mock
CFLAGS = -I $(SRCDIR) -I $(MOCKDIR) -I ./

PROG = test.out
OBJS = os.o communication.o test_communication.o
OBJS = os.o pin.o communication.o test_communication.o

all: $(PROG)

Expand All @@ -41,6 +41,9 @@ communication.o: $(SRCDIR)/communication.c
os.o: $(MOCKDIR)/os.c
$(CC) $(CFLAGS) -c -o $@ $^

pin.o: $(SRCDIR)/pin.c
$(CC) $(CFLAGS) -c -o $@ $^

.PHONY: clean test

clean:
Expand Down
43 changes: 40 additions & 3 deletions ledger/src/ui/test/communication/test_communication.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
*/

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "defs.h"
#include "communication.h"
#include "os.h"
#include "pin.h"

void test_echo() {
printf("Test echo...\n");
Expand All @@ -43,11 +45,46 @@ void test_get_mode() {

void test_get_retries() {
printf("Test get retries...\n");
reset_mock_func_call_list();

unsigned char pin_buffer[] = "X1234567a";
unsigned char wrong_pin[] = "Xa7654321";
unsigned int rx = 4;
init_mock_ctx();
for (int i = 0; i < strlen((const char *)pin_buffer); i++) {
SET_APDU_AT(2, i);
SET_APDU_AT(3, pin_buffer[i]);
assert(3 == update_pin_buffer(rx));
}

assert(3 == set_pin());
assert(3 == get_retries());
assert(0 == APDU_AT(2));

// Send wrong pin
for (int i = 0; i < strlen((const char *)wrong_pin); i++) {
SET_APDU_AT(2, i);
SET_APDU_AT(3, wrong_pin[i]);
assert(3 == update_pin_buffer(rx));
}
assert(!unlock_with_pin(true));
assert(3 == get_retries());
assert(1 == APDU_AT(2));
assert(!unlock_with_pin(true));
assert(3 == get_retries());
assert(2 == APDU_AT(2));
assert(!unlock_with_pin(true));
assert(3 == get_retries());
assert(3 == APDU_AT(2));

// Send right pin again
for (int i = 0; i < strlen((const char *)pin_buffer); i++) {
SET_APDU_AT(2, i);
SET_APDU_AT(3, pin_buffer[i]);
assert(3 == update_pin_buffer(rx));
}
assert(unlock_with_pin(true));
assert(3 == get_retries());
assert(0 == APDU_AT(2));
assert(get_mock_func_call(0) == MOCK_FUNC_OS_GLOBAL_PIN_RETRIES);
assert(get_mock_func_call_count() == 1);
}

int main() {
Expand Down
14 changes: 12 additions & 2 deletions ledger/src/ui/test/mock/cx.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@

#include "cx.h"

unsigned char mock_random_buffer[] = "random-buffer\0";
static unsigned char mock_seed[32];

void set_mock_seed(const unsigned char *data, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
mock_seed[i] = data[i];
}
}

unsigned char *cx_rng(unsigned char *buffer, unsigned int len) {
return mock_random_buffer;
// Mock 32 random bytes
for (int i = 0; i < len; i++) {
buffer[i] = mock_seed[i];
}
return 0;
}
4 changes: 3 additions & 1 deletion ledger/src/ui/test/mock/cx.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@
/**
* generate a random buffer
*/
unsigned char *cx_rng(unsigned char *buffer, unsigned int len);
unsigned char *cx_rng(unsigned char *buffer, unsigned int len);

void set_mock_seed(const unsigned char *data, unsigned int len);
95 changes: 41 additions & 54 deletions ledger/src/ui/test/mock/os.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,24 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include <stdbool.h>
#include <stdio.h>
#include "defs.h"
#include "os.h"
#include "string.h"

static mock_func_call_t mock_func_call_list[128];
static size_t mock_func_call_count = 0;

/**
* Mocks pin currently loaded to device
*/
unsigned char current_pin[10];
#include "onboard.h"

/**
* Helper functions to handle call list
* Mock context used to assert current state
*/
void reset_mock_func_call_list() {
explicit_bzero(mock_func_call_list, sizeof(mock_func_call_list));
mock_func_call_count = 0;
}

void add_mock_func_call(mock_func_call_t func) {
mock_func_call_list[mock_func_call_count++] = func;
}
static mock_ctx_t mock_ctx;

mock_func_call_t get_mock_func_call(int order) {
return mock_func_call_list[order];
void init_mock_ctx() {
memset(&mock_ctx, 0, sizeof(mock_ctx));
}

int get_mock_func_call_count() {
return mock_func_call_count;
void get_mock_ctx(mock_ctx_t *ctx) {
memcpy(ctx, &mock_ctx, sizeof(mock_ctx));
}

/**
Expand All @@ -66,32 +54,33 @@ void explicit_bzero(void *s, size_t len) {

unsigned int os_global_pin_check(unsigned char *pin_buffer,
unsigned char pin_length) {
add_mock_func_call(MOCK_FUNC_OS_GLOBAL_PIN_CHECK);
return !strncmp(
(const char *)pin_buffer, (const char *)current_pin, pin_length);
mock_ctx.device_unlocked = !strncmp((const char *)pin_buffer,
(const char *)mock_ctx.global_pin,
pin_length);
if (mock_ctx.device_unlocked) {
mock_ctx.retries = 0;
} else {
mock_ctx.retries++;
}

return mock_ctx.device_unlocked;
}

void os_perso_set_pin(unsigned int identity,
unsigned char *pin,
unsigned int length) {
add_mock_func_call(MOCK_FUNC_OS_PERSO_SET_PIN);
strncpy((char *)current_pin, (char *)pin, length);
strncpy((char *)mock_ctx.global_pin, (char *)pin, length);
}

void os_global_pin_invalidate(void) {
add_mock_func_call(MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE);
mock_ctx.device_unlocked = false;
}

void os_memset(void *dst, unsigned char c, unsigned int length) {
memset(dst, c, length);
}

void mock_set_pin(unsigned char *pin, size_t n) {
memcpy(current_pin, pin, n);
}

void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) {
add_mock_func_call(MOCK_FUNC_NVM_WRITE);
if (src_adr == NULL) {
// Treat as memory reset
memset(dst_adr, 0, src_len);
Expand All @@ -102,39 +91,37 @@ void nvm_write(void *dst_adr, void *src_adr, unsigned int src_len) {
}

void os_perso_wipe() {
add_mock_func_call(MOCK_FUNC_OS_PERSO_WIPE);
}

void os_perso_derive_and_set_seed(unsigned char identity,
const char *prefix,
unsigned int prefix_length,
const char *passphrase,
unsigned int passphrase_length,
const char *words,
unsigned int words_length) {
add_mock_func_call(MOCK_FUNC_OS_PERSO_DERIVE_AND_SET_SEED);
// wipe global pin, seed and state
init_mock_ctx();
}

void os_perso_finalize(void) {
add_mock_func_call(MOCK_FUNC_OS_PERSO_FINALIZE);
mock_ctx.device_onboarded = true;
}

unsigned int os_perso_isonboarded(void) {
add_mock_func_call(MOCK_FUNC_OS_PERSO_ISONBOARDED);
return 1;
return mock_ctx.device_onboarded;
}

unsigned int os_global_pin_retries(void) {
add_mock_func_call(MOCK_FUNC_OS_GLOBAL_PIN_RETRIES);
return 0;
return mock_ctx.retries;
}

// Generated mnemonics buffer will be "mnemonics-generated-from:<in>"
unsigned int bolos_ux_mnemonic_from_data(unsigned char *in,
unsigned int inLength,
unsigned char *out,
unsigned int outLength) {
add_mock_func_call(MOCK_FUNC_BOLOS_UX_MNEMONIC_FROM_DATA);
const char mnemonic[] = "the-mnemonics";
strcpy((char *)out, mnemonic);
return strlen(mnemonic);
}
sprintf((char *)out, "mnemonics-generated-from-%s", in);
return strlen((const char *)out);
}

void os_perso_derive_and_set_seed(unsigned char identity,
const char *prefix,
unsigned int prefix_length,
const char *passphrase,
unsigned int passphrase_length,
const char *words,
unsigned int words_length) {
sprintf((char *)mock_ctx.global_seed, "seed-generated-from-%s", words);
}
32 changes: 12 additions & 20 deletions ledger/src/ui/test/mock/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* IN THE SOFTWARE.
*/

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "cx.h"
Expand All @@ -33,33 +34,25 @@
#define THROW(e) return e
#define PIC(x) (x)

typedef enum {
MOCK_FUNC_OS_GLOBAL_PIN_CHECK,
MOCK_FUNC_OS_PERSO_SET_PIN,
MOCK_FUNC_OS_GLOBAL_PIN_INVALIDATE,
MOCK_FUNC_OS_MEMSET,
MOCK_FUNC_NVM_WRITE,
MOCK_FUNC_OS_PERSO_WIPE,
MOCK_FUNC_OS_PERSO_DERIVE_AND_SET_SEED,
MOCK_FUNC_OS_PERSO_FINALIZE,
MOCK_FUNC_OS_PERSO_ISONBOARDED,
MOCK_FUNC_BOLOS_UX_MNEMONIC_FROM_DATA,
MOCK_FUNC_OS_GLOBAL_PIN_RETRIES,
} mock_func_call_t;

/**
* Mock APDU buffer
*/
#define IO_APDU_BUFFER_SIZE 85
extern unsigned char G_io_apdu_buffer[IO_APDU_BUFFER_SIZE];

/**
* Helper functions to handle call list
* Mock context used to assert current state
*/
void reset_mock_func_call_list();
void add_mock_func_call(mock_func_call_t func);
mock_func_call_t get_mock_func_call(int order);
int get_mock_func_call_count();
typedef struct {
unsigned char global_pin[10];
unsigned char global_seed[257];
bool device_unlocked;
bool device_onboarded;
unsigned int retries;
} mock_ctx_t;

void init_mock_ctx();
void get_mock_ctx(mock_ctx_t *ctx);

/**
* Mock calls for os API
Expand Down Expand Up @@ -88,4 +81,3 @@ unsigned int os_global_pin_retries(void);
* Other mocks
*/
void explicit_bzero(void *s, size_t len);
void mock_set_pin(unsigned char *pin, size_t n);
Loading

0 comments on commit b747e95

Please sign in to comment.