1
0
mirror of https://github.com/meekrosoft/fff synced 2026-01-23 08:25:59 +01:00

Better examples with better code

This commit is contained in:
Mike Long
2011-01-01 21:27:48 +01:00
parent f923a5ad62
commit 7b0a149cfc
12 changed files with 471 additions and 270 deletions

17
examples/DISPLAY.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* DISPLAY.h
*
* Created on: Dec 17, 2010
* Author: mlong
*/
#ifndef DISPLAY_H_
#define DISPLAY_H_
void DISPLAY_init();
void DISPLAY_clear();
unsigned int DISPLAY_get_line_capacity();
unsigned int DISPLAY_get_line_insert_index();
void DISPLAY_output(char * message);
#endif /* DISPLAY_H_ */

25
examples/Kata.txt Normal file
View File

@@ -0,0 +1,25 @@
Problem Definition
------------------
The task is to write a user interface module for an embedded device.
Interrupts:
* The user interface is responsible for initializing the display.
* The user interface will register an interrupt handler for GPIO input 2 (a
push button).
* It will be possible to register a callback function for button presses.
* When there is no callback function set the irq handler will increment a
missed irq counter.
* When the interrupt occurs the handler will schedule or execute the button
press callback if there is one registered.
Output:
* Tasks can write messages to the user interface to be output on the display.
* The display is line oriented; when the last line of the display is written
the user interface is responsible for clearing the display.
* The display is 26 characters wide. Any string longer than that must be
truncated before being sent to the display. The string must be null
terminated and thus maximum 27 bytes long.
* BONUS: Have the display be scrolling, i.e. when the display is full, the
previous lines must be shifted up one and the new line written in the bottom
line.

View File

@@ -2,17 +2,17 @@ $(VERBOSE).SILENT:
BUILD_DIR = ../build
TEMPLATE_PROGNAME = $(BUILD_DIR)/template
C_PROGNAME = $(BUILD_DIR)/cmock
CPP_PROGNAME = $(BUILD_DIR)/cppmock
C_PROGNAME = $(BUILD_DIR)/ui_test_ansic
CPP_PROGNAME = $(BUILD_DIR)/ui_test_cpp
CC = gcc
CC += -c
CPP = g++
CPP += -c
LD = g++
C_OBJFILES = $(BUILD_DIR)/cmocktest.o $(BUILD_DIR)/embedded.o
C_OBJFILES = $(BUILD_DIR)/UI_test_ansic.o $(BUILD_DIR)/UI.o
TEMPLATE_OBJFILES = $(BUILD_DIR)/test_suite_template.o
CPP_OBJFILES = $(BUILD_DIR)/cppmocktest.o $(BUILD_DIR)/embedded.o
CPP_OBJFILES = $(BUILD_DIR)/UI_test_cpp.o $(BUILD_DIR)/UI.o
CPP_LIBS = -lgtest -lpthread -lgtest_main

21
examples/SYSTEM.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* DISPLAY.h
*
* Created on: Dec 17, 2010
* Author: mlong
*/
#ifndef SYSTEM_H_
#define SYSTEM_H_
typedef void (*irq_func_t)(void);
#define IRQ_GPIO_0 0x70
#define IRQ_GPIO_1 0x71
#define IRQ_GPIO_2 0x72
#define IRQ_GPIO_3 0x73
void SYSTEM_register_irq(irq_func_t, unsigned int irq);
#endif /* SYSTEM_H_ */

55
examples/UI.c Normal file
View File

@@ -0,0 +1,55 @@
/*
* UI.c
*
* Created on: Dec 17, 2010
* Author: mlong
*/
#include "UI.h"
#include "DISPLAY.h"
#include "SYSTEM.h"
#include <string.h>
static unsigned int missed_irq_counter;
button_cbk_t button_cbk;
void UI_init()
{
DISPLAY_init();
SYSTEM_register_irq(UI_button_irq_handler, IRQ_GPIO_2);
button_cbk = 0;
missed_irq_counter = 0;
}
unsigned int UI_get_missed_irqs()
{
return missed_irq_counter;
}
void UI_button_irq_handler()
{
if(button_cbk)
{
button_cbk();
}
else
{
missed_irq_counter++;
}
}
void UI_register_button_cbk(button_cbk_t cbk)
{
button_cbk = cbk;
}
void UI_write_line(char *line)
{
static char out[27];
strncpy(out, line, 26);
out[26] = '\0';
if(DISPLAY_get_line_capacity() == DISPLAY_get_line_insert_index())
DISPLAY_clear();
DISPLAY_output(out);
}

19
examples/UI.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* UI.h
*
* Created on: Dec 17, 2010
* Author: mlong
*/
#ifndef UI_H_
#define UI_H_
typedef void (*button_cbk_t)(void);
void UI_init();
unsigned int UI_get_missed_irqs();
void UI_button_irq_handler();
void UI_register_button_cbk(button_cbk_t cbk);
void UI_write_line(char *line);
#endif /* UI_H_ */

181
examples/UI_test_ansic.c Normal file
View File

@@ -0,0 +1,181 @@
#include "UI.h"
#include "../fff.h"
#include "SYSTEM.h"
#include "DISPLAY.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
/* Test Framework :-) */
void setup();
#define TEST_F(SUITE, NAME) void NAME()
#define RUN_TEST(SUITE, TESTNAME) printf(" Running %s.%s: \n", #SUITE, #TESTNAME); setup(); TESTNAME(); printf(" SUCCESS\n");
/* SYSTEM.h */
FAKE_VOID_FUNC2(SYSTEM_register_irq, irq_func_t, unsigned int);
/* DISPLAY.h */
FAKE_VOID_FUNC0(DISPLAY_init);
FAKE_VOID_FUNC0(DISPLAY_clear);
FAKE_VOID_FUNC1(DISPLAY_output, char *);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_insert_index);
FAKE_VOID_FUNC0(button_press_cbk);
/* Initialializers called for every test */
void setup()
{
RESET_FAKE(SYSTEM_register_irq);
RESET_FAKE(DISPLAY_init)
RESET_FAKE(DISPLAY_clear)
RESET_FAKE(DISPLAY_output)
RESET_FAKE(DISPLAY_get_line_capacity)
RESET_FAKE(DISPLAY_get_line_insert_index);
RESET_FAKE(button_press_cbk);
RESET_HISTORY();
DISPLAY_get_line_capacity_return_val = 2;
}
/* Tests go here */
TEST_F(UITests, init_will_initialise_display)
{
UI_init();
assert(DISPLAY_init_call_count == 1);
}
TEST_F(UITests, init_will_register_interrupt_gpio2)
{
UI_init();
assert(SYSTEM_register_irq_call_count == 1);
assert(SYSTEM_register_irq_arg0_val == UI_button_irq_handler);
assert(SYSTEM_register_irq_arg1_val == IRQ_GPIO_2);
}
TEST_F(UITests, when_no_irq_then_missed_irq_counter_zero)
{
assert(UI_get_missed_irqs() == 0);
}
TEST_F(UITests, when_one_irq_and_no_handler_then_missed_irq_counter_one)
{
UI_button_irq_handler();
assert(UI_get_missed_irqs() == 1);
}
TEST_F(UITests, when_one_irq_and_valid_callback_then_missed_irq_counter_zero)
{
UI_init();
UI_register_button_cbk(button_press_cbk);
UI_button_irq_handler();
assert(UI_get_missed_irqs() == 0);
}
TEST_F(UITests, when_one_irq_and_valid_callback_then_callback_called)
{
UI_register_button_cbk(button_press_cbk);
UI_button_irq_handler();
assert(button_press_cbk_call_count == 1);
}
TEST_F(UITests, write_line_outputs_lines_to_display)
{
char msg[] = "helloworld";
UI_write_line(msg);
assert(DISPLAY_output_call_count == 1);
assert(strncmp(DISPLAY_output_arg0_val, msg, 26) == 0);
}
TEST_F(UITests, when_no_empty_lines_write_line_clears_screen_and_outputs_lines_to_display)
{
DISPLAY_get_line_insert_index_return_val = 2;
char msg[] = "helloworld";
UI_write_line(msg);
assert(DISPLAY_clear_call_count == 1);
assert(DISPLAY_output_call_count == 1);
// Check the order of the calls: Don't care about the first two:
// DISPLAY_get_line_capacity and DISPLAY_get_line_insert_index
assert(call_history_idx == 4);
assert(call_history[2] == (void *) DISPLAY_clear);
assert(call_history[3] == (void *) DISPLAY_output);
}
TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
// given
DISPLAY_get_line_insert_index_return_val = 1;
char msg[] = "helloworld";
// when
UI_write_line(msg);
// then
assert(DISPLAY_clear_call_count == 0);
}
TEST_F(UITests, when_string_longer_than_26_then_truncated_string_output)
{
// given
char input[] = "abcdefghijklmnopqrstuvwxyz0123456789";
char expected[] = "abcdefghijklmnopqrstuvwxyz";
// when
UI_write_line(input);
// then
assert(strncmp(expected, DISPLAY_output_arg0_val, 37) == 0);
}
//TEST_F(UITests, when_outputting_to_full_display_then_previous_inserted)
//{
// // given
// DISPLAY_get_line_insert_index_return_val = 1;
// char oldest[] = "oldest";
// char newest[] = "newest";
// // when
// UI_write_line(oldest);
// UI_write_line(newest);
// // then
//
// assert(DISPLAY_output_call_count == 2);
//
// // fills last line
// assert(strncmp(oldest, DISPLAY_output_arg0_val_history[0], 37) == 0);
// //clears
// assert(DISPLAY_clear_call_count == 1);
// // inserts old line at first
// assert(strncmp(oldest, DISPLAY_output_arg0_val_history[1], 37) == 0);
// // then inserts new line
// assert(strncmp(newest, DISPLAY_output_arg0_val_history[2], 37) == 0);
//}
int main()
{
setbuf(stdout, NULL);
fprintf(stdout, "-------------\n");
fprintf(stdout, "Running Tests\n");
fprintf(stdout, "-------------\n\n");
fflush(0);
/* Run tests */
RUN_TEST(UITests, init_will_initialise_display);
RUN_TEST(UITests, init_will_register_interrupt_gpio2);
RUN_TEST(UITests, when_no_irq_then_missed_irq_counter_zero);
RUN_TEST(UITests, when_one_irq_and_no_handler_then_missed_irq_counter_one);
RUN_TEST(UITests, when_one_irq_and_valid_callback_then_missed_irq_counter_zero);
RUN_TEST(UITests, when_one_irq_and_valid_callback_then_callback_called);
RUN_TEST(UITests, write_line_outputs_lines_to_display);
RUN_TEST(UITests, when_no_empty_lines_write_line_clears_screen_and_outputs_lines_to_display);
RUN_TEST(UITests, when_empty_lines_write_line_doesnt_clear_screen);
RUN_TEST(UITests, when_string_longer_than_26_then_truncated_string_output);
printf("\n-------------\n");
printf("Complete\n");
printf("-------------\n\n");
return 0;
}

149
examples/UI_test_cpp.cpp Normal file
View File

@@ -0,0 +1,149 @@
extern "C"{
#include "UI.h"
#include "SYSTEM.h"
#include "DISPLAY.h"
}
#include "../fff.h"
#include <gtest/gtest.h>
/* SYSTEM.h */
FAKE_VOID_FUNC2(SYSTEM_register_irq, irq_func_t, unsigned int);
/* DISPLAY.h */
FAKE_VOID_FUNC0(DISPLAY_init);
FAKE_VOID_FUNC0(DISPLAY_clear);
FAKE_VOID_FUNC1(DISPLAY_output, char *);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC0(unsigned int, DISPLAY_get_line_insert_index);
FAKE_VOID_FUNC0(button_press_cbk);
class UITests : public testing::Test
{
public:
void SetUp()
{
// Register resets
RESET_FAKES();
RESET_HISTORY();
// non default init
DISPLAY_get_line_capacity_return_val = 2;
}
};
/* Tests go here */
TEST_F(UITests, init_will_initialise_display)
{
UI_init();
ASSERT_EQ(DISPLAY_init_call_count, 1);
}
TEST_F(UITests, init_will_register_interrupt_gpio2)
{
UI_init();
ASSERT_EQ(SYSTEM_register_irq_call_count, 1);
ASSERT_EQ((void *)SYSTEM_register_irq_arg0_val, (void *)UI_button_irq_handler);
ASSERT_EQ(SYSTEM_register_irq_arg1_val, IRQ_GPIO_2);
}
TEST_F(UITests, when_no_irq_then_missed_irq_counter_zero)
{
ASSERT_EQ(UI_get_missed_irqs(), 0);
}
TEST_F(UITests, when_one_irq_and_no_handler_then_missed_irq_counter_one)
{
UI_button_irq_handler();
ASSERT_EQ(UI_get_missed_irqs(), 1);
}
TEST_F(UITests, when_one_irq_and_valid_callback_then_missed_irq_counter_zero)
{
UI_init();
UI_register_button_cbk(button_press_cbk);
UI_button_irq_handler();
ASSERT_EQ(UI_get_missed_irqs(), 0);
}
TEST_F(UITests, when_one_irq_and_valid_callback_then_callback_called)
{
UI_register_button_cbk(button_press_cbk);
UI_button_irq_handler();
ASSERT_EQ(button_press_cbk_call_count, 1);
}
TEST_F(UITests, write_line_outputs_lines_to_display)
{
char msg[] = "helloworld";
UI_write_line(msg);
ASSERT_EQ(DISPLAY_output_call_count, 1);
ASSERT_EQ(strncmp(DISPLAY_output_arg0_val, msg, 26), 0);
}
TEST_F(UITests, when_no_empty_lines_write_line_clears_screen_and_outputs_lines_to_display)
{
DISPLAY_get_line_insert_index_return_val = 2;
char msg[] = "helloworld";
UI_write_line(msg);
ASSERT_EQ(DISPLAY_clear_call_count, 1);
ASSERT_EQ(DISPLAY_output_call_count, 1);
// Check the order of the calls: Don't care about the first two:
// DISPLAY_get_line_capacity and DISPLAY_get_line_insert_index
ASSERT_EQ(call_history_idx, 4);
ASSERT_EQ(call_history[2], (void *) DISPLAY_clear);
ASSERT_EQ(call_history[3], (void *) DISPLAY_output);
}
TEST_F(UITests, when_empty_lines_write_line_doesnt_clear_screen)
{
// given
DISPLAY_get_line_insert_index_return_val = 1;
char msg[] = "helloworld";
// when
UI_write_line(msg);
// then
ASSERT_EQ(DISPLAY_clear_call_count, 0);
}
TEST_F(UITests, when_string_longer_than_26_then_truncated_string_output)
{
// given
char input[] = "abcdefghijklmnopqrstuvwxyz0123456789";
char expected[] = "abcdefghijklmnopqrstuvwxyz";
// when
UI_write_line(input);
// then
ASSERT_EQ(strncmp(expected, DISPLAY_output_arg0_val, 37), 0);
}
//TEST_F(UITests, when_outputting_to_full_display_then_previous_inserted)
//{
// // given
// DISPLAY_get_line_insert_index_return_val = 1;
// char oldest[] = "oldest";
// char newest[] = "newest";
// // when
// UI_write_line(oldest);
// UI_write_line(newest);
// // then
//
// ASSERT_EQ(DISPLAY_output_call_count, 2);
//
// // fills last line
// ASSERT_EQ(strncmp(oldest, DISPLAY_output_arg0_val_history[0], 37), 0);
// //clears
// ASSERT_EQ(DISPLAY_clear_call_count, 1);
// // inserts old line at first
// ASSERT_EQ(strncmp(oldest, DISPLAY_output_arg0_val_history[1], 37), 0);
// // then inserts new line
// ASSERT_EQ(strncmp(newest, DISPLAY_output_arg0_val_history[2], 37), 0);
//}

View File

@@ -1,115 +0,0 @@
/*
* cmock.c
*
* Created on: Dec 9, 2010
* Author: mlong
*/
#include "embedded.h"
#include "../fff.h"
#include <assert.h>
#include <stdio.h>
FAKE_VOID_FUNC0(DISPLAY_init);
FAKE_VOID_FUNC0(DISPLAY_clear);
FAKE_VOID_FUNC1(DISPLAY_output_message, const char*);
FAKE_VALUE_FUNC0(int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC0(int, DISPLAY_get_line_insert_index);
FAKE_VALUE_FUNC2(unsigned char, DISPLAY_get_pixel, unsigned int, unsigned int);
void setup()
{
// Register resets
RESET_FAKE(DISPLAY_init);
RESET_FAKE(DISPLAY_clear);
RESET_FAKE(DISPLAY_output_message);
RESET_FAKE(DISPLAY_get_line_capacity);
RESET_FAKE(DISPLAY_get_line_insert_index);
// non default init
DISPLAY_get_line_capacity_return_val = 10;
}
#define TEST_F(IGNORE, NAME) void NAME()
TEST_F(GreeterTests, init_initialises_display)
{
UI_init();
assert(1 == DISPLAY_init_call_count);
}
TEST_F(GreeterTests, given_name_when_greet_called_outputs_name)
{
// given
char name[] = "mike";
// when
UI_greet(name);
// then
assert(1 == DISPLAY_output_message_call_count);
assert(name == DISPLAY_output_message_arg0_val);
}
TEST_F(GreeterTests, given_name_and_3_times_when_greetmultiple_called_outputs_name_3_times)
{
// given
char name[] = "mike";
// when
UI_greet_multiple_times(name, 3);
// then
assert(3 == DISPLAY_output_message_call_count);
assert(name == DISPLAY_output_message_arg0_val);
}
TEST_F(GreeterTests, given_non_full_screen_will_not_reset_display)
{
char name[] = "mike";
// given
DISPLAY_get_line_capacity_return_val = 10;
DISPLAY_get_line_insert_index_return_val = 0;
// when
UI_greet(name);
// then
assert(0 == DISPLAY_clear_call_count);
assert(1 == DISPLAY_output_message_call_count);
}
// Order assumption
TEST_F(GreeterTests, given_full_screen_single_will_reset_display_then_output)
{
char name[] = "mike";
// given
DISPLAY_get_line_capacity_return_val = 1;
DISPLAY_get_line_insert_index_return_val = 1;
// when
UI_greet(name);
// then
assert(1 == DISPLAY_clear_call_count);
assert(1 == DISPLAY_output_message_call_count);
}
// Order assumption
TEST_F(GreeterTests, given_full_screen_multiple_will_reset_display_then_output)
{
char name[] = "mike";
// given
DISPLAY_get_line_capacity_return_val = 4;
DISPLAY_get_line_insert_index_return_val = 4;
// when
UI_greet_multiple_times(name, 1);
// then
assert(1 == DISPLAY_clear_call_count);
assert(1 == DISPLAY_output_message_call_count);
}
#define RUN_TEST(TESTNAME) printf("Running %s\n", #TESTNAME); setup(); TESTNAME();
int main()
{
RUN_TEST(init_initialises_display);
RUN_TEST(given_name_when_greet_called_outputs_name);
RUN_TEST(given_name_when_greet_called_outputs_name);
RUN_TEST(given_name_and_3_times_when_greetmultiple_called_outputs_name_3_times);
RUN_TEST(given_full_screen_single_will_reset_display_then_output);
RUN_TEST(given_full_screen_multiple_will_reset_display_then_output);
return 0;
}

View File

@@ -1,106 +0,0 @@
//============================================================================
// Name : cmock.cpp
// Author : Mike Long
// Version :
// Copyright : Don't steal
// Description : Hello World in C++, Ansi-style
//============================================================================
#include "../fff.h"
extern "C"{
#include "embedded.h"
}
#include <gtest/gtest.h>
FAKE_VOID_FUNC0(DISPLAY_init);
FAKE_VOID_FUNC0(DISPLAY_clear);
FAKE_VOID_FUNC1(DISPLAY_output_message, const char*);
FAKE_VALUE_FUNC0(int, DISPLAY_get_line_capacity);
FAKE_VALUE_FUNC0(int, DISPLAY_get_line_insert_index);
class GreeterTests : public testing::Test
{
public:
void SetUp()
{
// Register resets
RESET_FAKES();
// non default init
DISPLAY_get_line_capacity_return_val = 10;
}
};
TEST_F(GreeterTests, init_initialises_display)
{
UI_init();
ASSERT_EQ(1, DISPLAY_init_call_count);
}
TEST_F(GreeterTests, given_name_when_greet_called_outputs_name)
{
// given
char name[] = "mike";
// when
UI_greet(name);
// then
ASSERT_EQ(1, DISPLAY_output_message_call_count);
ASSERT_EQ(name, DISPLAY_output_message_arg0_val);
}
TEST_F(GreeterTests, given_name_and_3_times_when_greetmultiple_called_outputs_name_3_times)
{
// given
char name[] = "mike";
// when
UI_greet_multiple_times(name, 3);
// then
ASSERT_EQ(3, DISPLAY_output_message_call_count);
ASSERT_EQ(name, DISPLAY_output_message_arg0_val);
}
TEST_F(GreeterTests, given_non_full_screen_will_not_reset_display)
{
char name[] = "mike";
// given
DISPLAY_get_line_capacity_return_val = 10;
DISPLAY_get_line_insert_index_return_val = 0;
// when
UI_greet(name);
// then
ASSERT_EQ(0, DISPLAY_clear_call_count);
ASSERT_EQ(1, DISPLAY_output_message_call_count);
}
// Order assumption
TEST_F(GreeterTests, given_full_screen_single_will_reset_display_then_output)
{
char name[] = "mike";
// given
DISPLAY_get_line_capacity_return_val = 1;
DISPLAY_get_line_insert_index_return_val = 1;
// when
UI_greet(name);
// then
ASSERT_EQ(1, DISPLAY_clear_call_count);
ASSERT_EQ(1, DISPLAY_output_message_call_count);
}
// Order assumption
TEST_F(GreeterTests, given_full_screen_multiple_will_reset_display_then_output)
{
char name[] = "mike";
// given
DISPLAY_get_line_capacity_return_val = 4;
DISPLAY_get_line_insert_index_return_val = 4;
// when
UI_greet_multiple_times(name, 1);
// then
ASSERT_EQ(1, DISPLAY_clear_call_count);
ASSERT_EQ(1, DISPLAY_output_message_call_count);
}

View File

@@ -1,35 +0,0 @@
void DISPLAY_init();
void DISPLAY_clear();
int DISPLAY_get_line_capacity();
int DISPLAY_get_line_insert_index();
void DISPLAY_output_message(char * message);
unsigned char DISPLAY_get_pixel(unsigned int x, unsigned int y);
void UI_init()
{
DISPLAY_init();
}
void UI_greet(char * name)
{
if(DISPLAY_get_line_capacity() == DISPLAY_get_line_insert_index())
{
DISPLAY_clear();
}
DISPLAY_output_message(name);
}
void UI_greet_multiple_times(char * name, int times)
{
int i;
for(i = 0; i < times; i++)
{
UI_greet(name);
}
}

View File

@@ -1,10 +0,0 @@
#ifndef EMBEDDED_CODE
#define EMBEDDED_CODE
void UI_init();
void UI_greet(char * name);
void UI_greet_multiple_times(char * name, int times);
#endif /* EMBEDDED_CODE */