Cgreen Unit Test for C language
===============================
Marcus Baker <marcus@lastcraft.com>
João Henrique F. de Freitas <joaohf@gmail.com>
:Author Initials: MB JHF

Cgreen Quickstart Guide
-----------------------

[[X01]]
O que é Cgreen?
~~~~~~~~~~~~~~~
      
Cgreen é um testador de código unitário para desenvolvimento
software na linguagem C.                
Ou seja é uma ferramenta de automação de teste e garantia de 
qualidade de software para times de desenvolvimento.
A ferramenta é completamenta open source e publicada sob a 
http://www.gnu.org/licenses/lgpl.html[LGPL].


Testes unitários é uma prática de desenvolvimento popularizada
pela comunidade de desenvolvimento ágil.
É caracterizada pela escrita de muitos pequenos testes ao longo
do código fonte normal.
Frequentemente os testes são escritos antes do código que será
testado, em um rigoroso loop de teste e refatoração de código.
Feito deste modo, é uma prática conhecida como Desenvolvimento
Dirigido ao Teste (Test Driven Development TDD).
Cgreen suporta este estilo de trabalho.


Testes de unidade são escritos na mesma linguagem que o código,
no nosso caso C.
Isto evita confusão pela constante troca de linguagem, e também
permite utilizar qualquer parte do código nos seus testes.
      
      
A lista dos recuros são:

- Suite de Testes totalmente combináveis.
- 'setup()' e 'teardown()' para testes e suite de teste.
- Cada teste é executado por seu próprio processo.
- Um teste isolado pode ser executado em um único processo para debug.
- Abilidade para criar funções mock.
- O mecanismo de relatório pode ser facilmente extendido.


Esta ferramenta é para programação em C, não para C++.
      
[[X02]]
Instalando o Cgreen
~~~~~~~~~~~~~~~~~~~
      
Há dois modos de instalar o Cgreen em seu sistema.


O primeiro modo é utilizar os pacotes RPM ou DEB providos pelo Cgreen Time
e disponibilizados na página do projeto http://cgreen.sourceforge.net[Cgreen].
Uma vez feito o download, instale utilizando os procedimentos normais de
instalação para o seu sistema.


A segunda forma de instalação é indicada para desenvolvedores ou usuários avançados.
Basicamente consiste em pegar os fontes do projeto e compilar. Para isso é necessário
o sistema de build http://www.cmake.org[CMake] como pré-requisito.


Tendo o CMake instalado o processo é o seguinte:

-----------------------------------------
tar -zxpvf cgreen.tar.gz
mkdir cgreen-build
cd cgreen-build
cmake ../cgreen
make
make test    # opcional
make install # precisa de direitos root
-----------------------------------------

Esta técnica é conhecida como "build out of source". Ela compila e instala o Cgreen
fora do diretório que contendo os arquivos fontes. Isso ajuda na organização geral dos 
arquivos do projeto. 


Também é possivel utilizar o arquivo +Makefile+ disponibilizado 
na raiz do diretório descompactado. Este Makefile é usado para compilar e testar 
sem a necessidade do CMake. No entando ele não contém as regras de instalação no
sistema.


Ambos os métodos irão criar dentro do diretório 'cgreen' uma biblioteca
unix +libcgreen.so+ no qual pode ser utilizada em conjunto com o               
arquivo de cabeçalho +cgreen.h+ para compilar os códigos de
teste. A biblioteca criada é instalada no sistema, por default em +/usr/local/lib/+.                


Agora vamos escrever um teste para confirmar se tudo está 
funcionando.
Vamos começar com um simples script de teste não testado, chamado +first_test.c+

[source,c]
---------------------------------------
#include "cgreen/cgreen.h"

int main(int argc, char **argv) {
TestSuite *suite = create_test_suite();
return run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

Este é um teste muito sem graça.
Somente cria uma suite de teste vazia e executa.
Geralmente é mais fácil avançar em pequenos passos, porém,
isso é o mais pequeno eu poderia pensar.
A única complicação é o arquivo de cabeçalho +cgreen.h+.
Aqui estou assumindo que nós temos um link simbólico com o diretório
do Cgreen no mesmo lugar dos nossos scripts de testes, ou colocando
o diretório Cgreen no seu path.


Fazer um build desse teste, com certeza, é algo trivial...

-----------------------------------------
gcc -c first_test.c
gcc first_test.o -lcgreen -o first_test
./first_test
-----------------------------------------

Invocando o executável teremos...
				
-----------------------------------------
Running "main"...
Completed "main": 0 passes, 0 failures, 0 exceptions.
-----------------------------------------

Tudo anteriormente assume que você está trabalhando em um ambiente
tipo Unix, provavelmente com o compilador 'gcc'.
O código é bastante aderente ao C99, de modo que qualquer compilador C
deve funcionar.
Cgreen pode ser compilador em todos os sistemas que suportam a 
biblioteca de mensagens +sys/msg.h+.
Foi testado em Linux e Mac OSX, mas não no Windows, apesar que 
pode trabalhar também.
      
      
Até agora, temos ensaiado a compilação, em que a suite de teste é
executada.
Vamos acrescentar um ou dois ensaios sem sentido, para que você
possa ver como isto ocorre...

[source,c]
---------------------------------------
#include "cgreen/cgreen.h"

void this_test_should_pass() {
assert_true(1);
}

void this_test_should_fail() {
assert_true(0);
}

int main(int argc, char **argv) {
TestSuite *suite = create_test_suite();
add_test(suite, this_test_should_pass);
add_test(suite, this_test_should_fail);
return run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

Um teste pode ser qualquer função com a assinatura 'void (void)'
'add_test()' é uma macro, então
não há '&' com o ponteiro para a função.
      
      
Compilando e executando, teremos o resultado...

-----------------------------------------
Running "main"...
Failure!: this_test_should_fail -> Problem at [first_test.c] line [8]
Completed "main": 1 pass, 1 failure, 0 exceptions.
-----------------------------------------

O 'TextReporter', criado pela chamada
'create_text_reporter()', é o jeito simples para
imprimir o resultado dos testes.
Ele somente envia os testes com falha.
Atualmente ele é o único método suportado.
      
[[X03]]
Fazendo TDD em cinco minutos com Cgreen
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      
Para um exemplo mais real precisamos de algo para testar.
Nós pretendemos escrever uma função que separe as palavras
de uma sentença.
Ela faz isso substituindo quaisquer espaços com terminadores
de palavras e retornando o número de conversões mais um.
Aqui está um exemplo do que temos em mente...

[source,c]
---------------------------------------
char *sentence = strdup("Just the first test");
word_count = split_words(sentence);
-----------------------------------------

'sentence' pode agora apontar para
'"Just\0the\0first\0test"'.
Não é obviamente uma função muito útil, mas usaremos 
isso para algo mais prático em breve.
      
      
Desta vez nós adicionaremos um pouco mais de estrutura em nossos testes.
Em vez de termos os testes em um programa único, nós separaremos
o principal dos de casos de teste.
Desta forma, vários suites de teste dos casos de teste podem ser
incluídos no 'main()' do arquivo principal.
Isto nos dará menos trabalho para adicionar mais testes.
      
      
Aqui está o, até agora vazio, caso de teste em +words_test.c+...

[source,c]
---------------------------------------
#include "cgreen/cgreen.h"

TestSuite *words_tests() {
TestSuite *suite = create_test_suite();
return suite;
}
-----------------------------------------

Aqui está o +all_tests.c+ teste principal...
				
[source,c]
---------------------------------------
#include "cgreen/cgreen.h"

TestSuite *words_tests();

int main(int argc, char **argv) {
TestSuite *suite = create_test_suite();
add_suite(suite, words_tests());
if (argc > 1) {
  return run_single_test(suite, argv[1], create_text_reporter());
}
return run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

Cgreen possui dois jeitos de executar os testes.
O padrão é cada teste ser executado dentro do seu próprio processo.
Isto é oque acontece se você invoca 'run_test_suite()'.
Enquanto isto faz todos os testes independentes, a constante 'fork()'
pode complicar o debug.
Para deixar o debug simples, Cgreen não faz 'fork()' 
quando um único teste é executado pelo nome com 'run_single_test()'. 
      
      
Building este suporte...

-----------------------------------------
gcc -c words_test.c
gcc -c all_tests.c
gcc words_test.o all_tests.o -lcgreen -o all_tests
-----------------------------------------

...e executando temos o resultado...                

-----------------------------------------
Running "main"...
Completed "main": 0 passes, 0 failures, 0 exceptions.
-----------------------------------------

Todo este suporte (scaffolding) é puro adendo, mas a partir de agora adicionar 
novos testes irá ser muito fácil.
      
      
Aqui está um primeiro teste de 'split_words()'...

[source,c]
---------------------------------------
#include "cgreen/cgreen.h"
#include "words.h"
#include <string.h>

void word_count_returned_from_split() {
char *sentence = strdup("Birds of a feather");
int word_count = split_words(sentence);
assert_equal(word_count, 4);
free(sentence);
}

TestSuite *words_tests() {
TestSuite *suite = create_test_suite();
add_test(suite, word_count_returned_from_split);
return suite;
}
-----------------------------------------

A macro 'assert_equal()' recebe dois valores para comparar.
Como padrão as mensagens são enviadas para 'STDOUT' pelo 
'TextReporter'. 
      
      
Para compilar isso precisamos criar o arquivo de cabeçalho
+words.h+...

[source,c]
---------------------------------------
int split_words(char *sentence);
-----------------------------------------

...e para linkar o código nós precisamos de uma pequena função em 
+words.c+...

[source,c]
---------------------------------------
int split_words(char *sentence) {
return 0;
}
-----------------------------------------

Um build completo mais adiante...

-----------------------------------------
gcc -c all_tests.c
gcc -c words_test.c
gcc -c words.c
gcc all_tests.o words_test.o words.o -lcgreen -o all_tests
./all_tests
-----------------------------------------

...e nós temos uma resposta mais útil...

-----------------------------------------
Running "main"...
Failure!: words_tests -> word_count_returned_from_split ->
        [0] should match [4] at [words_test.c] line [8]
Completed "main": 0 passes, 1 failure, 0 exceptions.
-----------------------------------------

O "segredo" é o encapsulamento dos testes.
Isto vem da suite de teste, no qual podem ser encapsulados um 
no outro, através da função de teste, e finalmente a mensagem vinda
de uma afirmação (assertion).
Na linguagem do Cgreen, uma falha é uma afirmação inadequada,
uma excessão é acumulada quando um teste falha por alguma razão.


Nós podemos fazer isto passar apenas retornando o valor 4.
Fazendo TDD realmente em pequenos passos, você fazeria isso, 
mas francamente este exemplo é muito simples.
Em vez disso nós vamos ir direto para a refatoração... 

[source,c]
---------------------------------------
#include <string.h>

int split_words(char *sentence) {
int i, count = 1;
for (i = 0; i < strlen(sentence); i++) {
  if (sentence[i] == ' ') {
      count++;
  }
}
return count;
}
-----------------------------------------

Existe um problema escondido aqui, mas nossos testes passarão
então fingiremos que não fomos avisados..
      
      
Hora de adicionar um novo teste.
Queremos confirmar que a string está quebrada em palavras
separadas...

[source,c]
---------------------------------------
#include "cgreen/cgreen.h"
#include "words.h"
#include <string.h>

void word_count_returned_from_split() { ... }

void spaces_should_be_converted_to_zeroes() {
char *sentence = strdup("Birds of a feather");
split_words(sentence);
int comparison = memcmp("Birds\0of\0a\0feather", sentence, strlen(sentence));
assert_equal(comparison, 0);
free(sentence); 
}

TestSuite *words_tests() {
TestSuite *suite = create_test_suite();
add_test(suite, word_count_returned_from_split);
add_test(suite, spaces_should_be_converted_to_zeroes);
return suite;
}
-----------------------------------------

Com certeza, nós temos uma falha...

-----------------------------------------
Running "main"...
Failure!: words_tests -> spaces_should_be_converted_to_zeroes ->
        [-32] should match [0] at [words_test.c] line [16]
Completed "main": 1 pass, 1 failure, 0 exceptions.
-----------------------------------------

Nada demais contando que ainda não escrevemos o código.
      
      
A solução...

[source,c]
---------------------------------------
int split_words(char *sentence) {
int i, count = 1;
for (i = 0; i < strlen(sentence); i++) {
  if (sentence[i] == ' ') {
      sentence[i] = '\0';
      count++;
  }
}
return count;
}
-----------------------------------------

...revela nossa suspeita anterior...

-----------------------------------------
Running "main"...
Failure!: words_tests -> word_count_returned_from_split ->
        [2] should match [4] at [words_test.c] line [8]
Completed "main": 1 pass, 1 failure, 0 exceptions.
-----------------------------------------

Nosso teste anterior falhou agora, porque modificamos a chamada
'strlen()' no nosso loop.
Movendo o cálculo do tamanho para fora do loop...                

[source,c]
---------------------------------------
int split_words(char *sentence) {
int i, count = 1, length = strlen(sentence);
for (i = 0; i < length; i++) {
  ...
}
return count;
}
-----------------------------------------

...restaurando a ordem...
				
-----------------------------------------
Running "main"...
Completed "main": 2 passes, 0 failures, 0 exceptions.
-----------------------------------------

É bom manter o código sob controle enquanto estamos escrevendo
efetivamente, e debugar depois quando as coisas se tornarem mais
complicadas.


Isso vai ser melhorado mais em frente.
Vamos fazer algo mais interessante.               
      
Oque são funções mock?
      
O próximo exemplo é mais realista.
Ainda no nosso arquivo +words.h+, queremos escrever
uma função que invoque uma callback em cada palavra na sentença.
Algo como...

[source,c]
---------------------------------------
void act_on_word(const char *word, void *memo) { ... }
words("This is a sentence", &act_on_word, &memo);
-----------------------------------------

Aqui o ponteiro 'memo' é apenas algum dado acumulado
que a callback 'act_on_word()' está trabalhando.
Outras pessoas escreverão a função 'act_on_world()' 
e provavelmente muitas outras iguais a esta.
A callback é na verdade um ponto flexível, e não é de interesse
agora.


A função em teste é a 'words()' e nós queremos ter 
certeza que ela caminhe na sentença corretamente, enviando palavras
individuais como esta.
Como testar isso?


Vamos começar com uma palavra.
Neste caso nós esperaríamos a callback ser invocada uma única vez
com a única palavra, certo?
Aqui está o teste para isso...

[source,c]
---------------------------------------
...
#include <stdlib.h>
...
void mocked_callback(const char *word, void *memo) {
mock(word, memo);
}

void single_word_sentence_invokes_callback_once() {
expect(mocked_callback, want_string(word, "Word"), want(memo, NULL));
words("Word", &mocked_callback, NULL);
}

TestSuite *words_tests() {
TestSuite *suite = create_test_suite();
...
add_test(suite, single_word_sentence_invokes_callback_once);
return suite;
}
-----------------------------------------

Qual é a graça olhando para a função 'mock()'?
      
      
Uma mock é basicamente um objeto programável.
Em C objetos são limitados a funções, então isto é a função mock.
A macro 'mock()' compara os parâmetros que estão chegando
com os valores esperados e envia mensagens para o suite de teste
se há alguma falha.
Ela também retorna quaisquer valores que tenham sido pré-programados
no teste.


A função teste é 'single_word_sentence_invokes_callback_once()'.
Usando a macro 'expect()' ela programa a função mock 
para esperar uma simples chamada.
Esta chamada terá parâmetros 'Word' e
'NULL'.
Se eles não forem iguais depois, nós teremos um teste com falha.


Somente o método do teste, não a callback mock, é adicionado ao
suite de teste.


Para uma compilação e linkagem com sucesso, o arquivo +words.h+
deve agora parecer como...

[source,c]
---------------------------------------
int split_words(char *sentence);
void words(const char *sentence, void (*walker)(const char *, void *), void *memo);
-----------------------------------------

...e o arquivo +words.c+ pode ter o trecho...

[source,c]
---------------------------------------
void words(const char *sentence, void (*walker)(const char *, void *), void *memo) {
}
-----------------------------------------

Isso mostra-nos as falhas esperadas nos testes.. 

-----------------------------------------
Running "main"...
Failure!: words_tests -> single_word_sentence_invokes_callback_once ->
        Call was not made to function [mocked_callback] at [words_test.c] line [25]
Completed "main": 2 passes, 1 failure, 0 exceptions.
-----------------------------------------

CGreen avisa que a callback nunca foi utilizada.

Nos podemos facilmente passar o teste preenchendo a implementação
com...

[source,c]
---------------------------------------
void words(const char *sentence, void (*walker)(const char *, void *), void *memo) {
(*walker)(sentence, memo);
}
-----------------------------------------

Isto é, nós somente invocamos isso uma vez com toda a string.
Este é uma medição temporária que nos ajudará a continuar.
Agora qualquer coisa pode passar, ainda que isto não esteja muito 
testado ainda.


Isso foi tudo convencional, mas vamos abordar o caso de separação
da sentença.
Aqui a função de teste será adicionada em +words_test.c+...

[source,c]
---------------------------------------
void phrase_invokes_callback_for_each_word() {
expect(mocked_callback, want_string(word, "Birds"));
expect(mocked_callback, want_string(word, "of"));
expect(mocked_callback, want_string(word, "a"));
expect(mocked_callback, want_string(word, "feather"));
words("Birds of a feather", &mocked_callback, NULL);
}
-----------------------------------------

Cada chamada é esperada em sequẽncia.
Todas as falhas, ou sem chamadas, ou extra chamadas, e podemos
vê-las.
Podemos ver tudo isso quando rodamos os testes...

-----------------------------------------
Running "main"...
Failure!: words_tests -> phrase_invokes_callback_for_each_word ->
        Wanted [Birds], but got [Birds of a feather] in function [mocked_callback] parameter [word] at [words_test.c] line [30]
Failure!: words_tests -> phrase_invokes_callback_for_each_word ->
        Call was not made to function [mocked_callback] at [words_test.c] line [31]
Failure!: words_tests -> phrase_invokes_callback_for_each_word ->
        Call was not made to function [mocked_callback] at [words_test.c] line [32]
Failure!: words_tests -> phrase_invokes_callback_for_each_word ->
        Call was not made to function [mocked_callback] at [words_test.c] line [33]
Completed "main": 4 passes, 4 failures, 0 exceptions.
-----------------------------------------

A primeira falha conta a história.
Nossa pequena função 'words()' chamou a callback mock 
com toda a sequência.
Isto faz sentido, porque aquela era o jeito para pegar o 
próximo teste.
      
      
Embora não seja relevante neste guia, eu não posso resistir em pegar
esses tester para passar.
Além disso, nós fizemos uso da função que nós criamos anteriormente...

[source,c]
---------------------------------------
void words(const char *sentence, void (*walker)(const char *, void *), void *memo) {
char *words = strdup(sentence);
int word_count = split_words(words);
char *word = words;
while (word_count-- > 0) {
  (*walker)(word, memo);
  word = word + strlen(word) + 1;
}
free(words);
}
-----------------------------------------

E com esse trabalho somos recompensados com...

-----------------------------------------
Running "main"...
Completed "main": 8 passes, 0 failures, 0 exceptions.

-----------------------------------------

Mais trabalho do que eu gostaria de admitir, mas isso me pegou
três vezes para funcionar.
Primeiramente esqueci-me o '+ 1' adicionado no 'strlen()',
então esqueci de trocar 'sentence' para 'word'
na chamada '(*walker)()', e finalmente a terceira vez foi sorte.
É claro rodando os testes cada vez que eram feitos esses erros 
muito óbvios.
Gastei mais tempo para escrever esses parágrafos do que para 
escrever o código.
        
[[30]]
Construindo suite de tests
--------------------------
      
Cgreen é uma ferramenta para construir testes de unidade na linguagem C.
Eles são normalmente escritos ao longo do código de produção pelos programadores
para prevenir bugs.
Apesar dos testes serem escritos por desenvolvedores de software,
eles são descritos de forma a serem entendidos, como parte da documentação do software.
Usado desta maneira, a finalidade é garantir a qualidade constante.
      
      
Em outras palavras você terá menos bugs.
      
[[X06]]
Escrevendo testes básicos
~~~~~~~~~~~~~~~~~~~~~~~~~
          
Testes utilizando o Cgreen são funções simples em C sem parâmetros e
um retorno de valor 'void'.
Um exemplo poderia ser...

[source,c]
-----------------------------
static void strlen_of_hello_should_be_five() {
    assert_equal(strlen("Hello"), 5);
}
-----------------------------------------

O nome da função de teste pode ser qualquer coisa que você queira.
A chamada 'assert_equal()' é um exemplo de assertion.
Assertions enviam mensagens para o Cgreen, no qual podem ativar a
saída de resultados.                
          
          
Aqui estão os assertions padrões...

|=========================================================
|Assertion|Descrição
|'assert_true(boolean)'|Passa se o valor boleano é verdadeiro
|'assert_false(boolean)'|Falha se o valor boleano é verdadeiro
|'assert_equal(first, second)'|Passa se 'first == second'
|'assert_not_equal(first, second)'|Passa se  'first != second'
|'assert_string_equal(char *, char *)'|Utiliza 'strcmp()' e passa se as strings são iguais
|'assert_string_not_equal(char *, char *)'|Utiliza 'strcmp()' e falha se as strings são iguais
|=========================================================

A macro para assertion boleano aceita valor 'int'.
As assertions de igualdade aceitam qualquer tipo no qual pode ser
convertido para 'intptr_t' e feita uma simples
operação de '=='.
A comparação de strings é ligeiramente diferente da utilizada na 
'strcmp()' biblioteca de funções '<string.h>'.
Se 'assert_equal()' for utilizada em ponteiros 'char *'
então eles devem apontar para a mesma string.                
          
          
Cada assertion tem uma mensagem default de comparação entre os dois valores.
Se você deseja substituir pela sua própria mensagem então você deve usar
as funções '*_with_message()'.

|=========================================================
|Assertion
|'assert_true_with_message(boolean, message, ...)'
|'assert_false_with_message(boolean, message, ...)'
|'assert_equal_with_message(first, second, message, ...)'
|'assert_not_equal_with_message(first, second, message, ...)'
|'assert_string_equal_with_message(char *, char *, message, ...)'
|'assert_string_not_equal_with_message(char *, char *, message, ...)'
|=========================================================

Todas as assertions possuem um parâmetro adicional 'char *' no qual 
é a mensagem que você deseja mostrar em caso de falha.
Se o parâmetro for 'NULL', então a mensagem padrão é 
utilizada.
A afirmação mais útil deste grupo é 'assert_true_with_message()'
você pode usa-la para criar sua própria assertion de funções com
mensagens próprias.                
          
          
Atualmente as macros de assertion possuem uma lista de argumentos variáveis.
A mensagem de falha segue o template da função 'printf()'.
Nos podemos mudar o teste acima para...    

[source,c]
-----------------------------------------
static void strlen_of_hello_should_be_five() {
    const char *greeting = "Hello";
    int length = strlen(greeting);
    assert_equal_with_message(length, 5,
            "[%s] should be 5, but was %d", greeting, length);
}
-----------------------------------------

Uma mensagem mais amigável para o usuário quando as coisas derem errado.                


Para o teste acima funcionar é necessário executa-lo em uma test suite.
Podemos cria-la explicitamente para este teste com...

[source,c]
-----------------------------
TestSuite *our_tests() {
    TestSuite *suite = create_test_suite();
    add_test(suite, strlen_of_hello_should_be_five);
    return suite;
}
-----------------------------------------

No caso você viu que 'strlen_of_hello_should_be_five()'
deve ter & comercial na frente dele, 'add_test()'
é uma macro.
O '&' é adicionado automaticamente.                 
          
          
Para executar o test suite, nos chamamos 'run_test_suite()'.
Esta função limpa todo o teste depois de executa-lo, então podemos 
escrever...

[source,c]
-----------------------------
run_test_suite(our_tests(), create_text_reporter());
-----------------------------------------

Os resultados das assertions são passadas e as falhas são coletadas via um
callback definido pela estrutura 'TestReporter'.
A única definição prédefinida no Cgreen é o 'TextReporter' no qual
emite as mensagens em texto plano.


O script de teste agora se parece com isso...

[source,c]
-----------------------------
#include "cgreen/cgreen.h"
#include <string.h>

static void strlen_of_hello_should_be_five() {
    assert_equal(strlen("Hello"), 5);
}

TestSuite *our_tests() {
    TestSuite *suite = create_test_suite();
    add_test(suite, strlen_of_hello_should_be_five);
    return suite;
}

int main(int argc, char **argv) {
    return run_test_suite(our_tests(), create_text_reporter());
}
-----------------------------------------

O valor de retorno do 'run_test_suite()' é um código 
Unix para exit.
          
          
Compilando e executando temos...

-----------------------------------------
gcc -c strlen_test.c
gcc strlen_test.o -lcgreen -o strlen_test
./strlen_test
Running "main"...
Completed "main": 1 pass, 0 failures, 0 exceptions.
-----------------------------------------

As mensagens do teste somente são mostradas em caso de falhas.
Se você quebras seus testes...

[source,c]
-----------------------------
static void strlen_of_hello_should_be_five() {
    assert_equal(strlen("Hiya", 5);
}
-----------------------------------------

...nós teremos uma mensagem...

-----------------------------------------
Running "main"...
Failure!: strlen_of_hello_should_be_five ->
        [5] shold be [4] at [strlen_test.c] line [6]
Completed "main": 0 passes, 1 failure, 0 exceptions.
-----------------------------------------

Cgreen apenda a localização da falha do teste na nossa string de erro.


Uma vez que temos a estrutura básica para os testes, é fácil adicionar 
mais testes.
Adicionar um teste para 'strlen()' com uma string vazia
por exemplo...

[source,c]
-----------------------------
...
static void strlen_of_empty_string_should_be_zero() {
    assert_equal(strlen("\0"), 0);
}

TestSuite *our_tests() {
    TestSuite *suite = create_test_suite();
    add_test(suite, strlen_of_hello_should_be_five);
    add_test(suite, strlen_of_empty_string_should_be_zero);
    return suite;
}
...
-----------------------------------------

E assim por diante.
          
[[08]]		  
Set up e tear down
~~~~~~~~~~~~~~~~~~
          
É comum para a suite de teste ter muito código duplicado,
especialmente quando são configurador testes similares.
Olha o exemplo com um banco de dados...

[source,c]
-----------------------------
#include "cgreen/cgreen.h"
#include <stdlib.h>
#include <mysql/mysql.h>
#include "person.h"

static void create_schema() {
    MYSQL *connection = mysql_init(NULL);
    mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0);
    mysql_query(connection, "create table people (name, varchar(255) unique)");
    mysql_close(connection);
}

static void drop_schema() {
    MYSQL *connection = mysql_init(NULL);
    mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0);
    mysql_query(connection, "drop table people");
    mysql_close(connection);
}

static void can_add_person_to_database() {
    create_schema();
    Person *person = create_person();
    set_person_name(person, "Fred");
    save_person(person);
    Person *found = find_person_by_name("Fred");
    assert_string_equal(get_person_name(person), "Fred");
    drop_schema();
}

static void cannot_add_duplicate_person() {
    create_schema();
    Person *person = create_person();
    set_person_name(person, "Fred");
    assert_true(save_person(person));
    Person *duplicate = create_person();
    set_person_name(duplicate, "Fred");
    assert_false(save_person(duplicate));
    drop_schema();
}

TestSuite *person_tests() {
    TestSuite *suite = create_test_suite();
    add_test(suite, can_add_person_to_database);
    add_test(suite, cannot_add_duplicate_person);
    return suite;
}

int main(int argc, char **argv) {
    return run_test_suite(person_tests(), create_text_reporter());
}
-----------------------------------------

Nós já haviamos retirado o código duplicado e separado nas funções
'create_scheme()' and 'drop_schema()', então
as coisas não estão tão ruins.
Até o momento ainda não.
Oque acontece se temos uma dúzia de testes deste tipo?
Por exemplo um teste mais complicado como http://www.martinfowler.com/eaaCatalog/activeRecord.html[ActiveRecord],
tendo dúzias de testes muito parecidos.                
          
          
Nós podemos fazer com que o Cgreen faça o trabalho para nós
declarando estes métodos como funções 'setup()' e
'teardown()' na suite de testes.


Aqui está a nova versão...

[source,c]
-----------------------------
...
static void create_schema() { ... }

static void drop_schema() { ... }

static void can_add_person_to_database() {
    Person *person = create_person();
    set_person_name(person, "Fred");
    save_person(person);
    Person *found = find_person_by_name("Fred");
    assert_string_equal(get_person_name(person), "Fred");
}

static void cannot_add_duplicate_person() {
    Person *person = create_person();
    set_person_name(person, "Fred");
    assert_true(save_person(person));
    Person *duplicate = create_person();
    set_person_name(duplicate, "Fred");
    assert_false(save_person(duplicate));
}

TestSuite *person_tests() {
    TestSuite *suite = create_test_suite();
    setup(suite, create_schema);
    teardown(suite, drop_schema);
    add_test(suite, can_add_person_to_database);
    add_test(suite, cannot_add_duplicate_person);
    return suite;
}
...
-----------------------------------------

Com estas nova forma Cgreen executa a função 'create_schema()' 
antes de cada teste, e a função 'drop_schema()' 
depois de cada teste.
Isto salva a digitação repetitiva e reduz as chances de acidentes.
Isto também fazem os testes mais focados.


A razão para nós tentarmos retirar fora tudo das funções de teste é que
a suite de teste atua como documentação.
No exemplo +person.h+ nós podemos facilmente ver que 'Person'
tem algum tipo de propriedade, e o valor desta propriedate tem que ser único.
Para que os testes atuem como uma especificação legível nós temos que
remover toda gordura o máximo possível.                 


Alguns detalhes.
Atualmente apenas um 'setup()' e 'teardown()'
podem ser adicionados em cada 'TestSuite'.
Também a função 'teardown()' pode não executar se algum teste
der errado (crash), causando algumas interferências nos testes.
Isso nós prepara para a próxima seção...
          
[[X011]]
Cada teste dentro de seu próprio processo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          
Considere este teste...

[source,c]
-----------------------------
void will_seg_fault() {
    int *p = NULL;
    (*p)++;
}
-----------------------------------------

Crash não é algo que normalmente queremos quando um teste está em
execução.
Não menos importante, isto irá parar o recebimento da saída dos testes
que você precisa para resolver o problema.


Para prevenir segmentation faults e outros problemas que interrompam a 
suite de testes, Cgreen executa todos os testes dentro de seu próprio 
processo.


Antes da chamada 'setup()', Cgreen faz um 'fork()'.
O processo principal aguarda o teste ser completado normalmente ou não.
Incluindo o 'teardown()'.
Se o processo falha, uma exception é reportada e o processo de teste principal
coleta.


Por exemplo...

[source,c]
-----------------------------
#include "cgreen/cgreen.h"
#include <stdlib.h>

static void will_seg_fault() {
    int *p = NULL;
    (*p)++;
}

int main(int argc, char **argv) {
    TestSuite *suite = create_test_suite();
    add_test(suite, will_seg_fault);
    run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

Quando compilamos e executamos, temos...

-----------------------------------------
Running "main"...
Exception!: will_seg_fault -> Test "will_seg_fault" failed to complete
Completed "main": 0 passes, 0 failures, 1 exception.
-----------------------------------------

A coisa obvia a ser feita agora é disparar o debugger.
Infelizmente, o 'fork()' de processos pelo Cgreen pode ser
uma complicação extra durante o debugger.
          
          
Para contornar isto, e também para permir a executação de um teste
por vez, Cgreen possui a função 'run_single_test()'.
A assinatura dos métodos de execução são...                

- 'int run_test_suite(TestSuite *suite, TestReporter *reporter);'
- 'int run_single_test(TestSuite *suite, char *test, TestReporter *reporter);'

Os parametros extras de 'run_single_test()', a string
'test', é o nome do teste selecionado.
Isto pode ser qualquer teste, até mesmo dentro das suite de testes (veja a seguir). 
          
          
Aqui está como nos podemos usar o debug no teste com problemas.

[source,c]
-----------------------------
int main(int argc, char **argv) {
    TestSuite *suite = create_test_suite();
    add_test(suite, will_seg_fault);
    run_single_test(suite, "will_seg_fault", create_text_reporter());
}
-----------------------------------------

Quando executamos desta maneira, Cgreen não irã fazer 'fork()'.


Isto contorna o caso de segmentation fault, mas e sobre a falha no processo
causando a queda no loop?


Bem, Cgreen pode esperar para sempre.
Usando manipuladores de sinais em C, nos podemos colocar um limite no processo
enviando uma interrupeção.
Para evitar a necessidade de escrever o manipulador, Cgreen inclui a função
'die_in()' para nos ajudar.

          
Aqui está um exemplo limitando o tempo do teste...

[source,c]
-----------------------------
...
static void will_seg_fault() { ... }

static void this_would_stall() {
    die_in(1);
    while(0 == 0) { }
}

int main(int argc, char **argv) {
    TestSuite *suite = create_test_suite();
    add_test(suite, will_seg_fault);
    add_test(suite, this_would_stall);
    run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

Quando executado, o código irá esperar por um segundo, e 
finalizar com...

-----------------------------------------
Running "main"...
Exception!: will_seg_fault -> Test "will_seg_fault" failed to complete
Exception!: will_stall -> Test "this_would_stall" failed to complete
Completed "main": 0 passes, 0 failures, 2 exceptions.
-----------------------------------------

Note que você vê o resultado do teste como ele é.
Cgreen faz o stream do resultado tal como ele acontece, ficando fácil
saber onde a suite de teste tem problema.


Claro, que se você quiser configurar um limite de tempo geral em 
todos os seus testes, então você pode adicionar o código 'die_in()'
na função 'setup()'.
Cgreen irá então aplica o limite para todos.
          
[[X12]]
Construindo uma suite composta de testes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
          
A 'TestSuite' é uma estrutura composta.
Isto significa que as suites de testes podem ser adicionadas a suites 
de testes, construindo uma árvore de estruturas que pode ser executada
na ordem.   


Vamos combinar os testes 'strlen()' com os testes 'Person'
acima.
Primeiramente nos precisamos remover a chamada 'main()'.
Isto é...

[source,c]
-----------------------------
#include "cgreen/cgreen.h"
#include <string.h>

static void strlen_of_hello_should_be_five() { ... }
static void strlen_of_empty_string_should_be_zero() { ... }

TestSuite *our_tests() {
    TestSuite *suite = create_test_suite();
    add_test(suite, strlen_of_hello_should_be_five);
    add_test(suite, strlen_of_empty_string_should_be_zero);
    return suite;
}
-----------------------------------------

Então nos podemos escrever um pequeno chamado com a nova função
'main()'...

[source,c]
-----------------------------
#include "strlen_tests.c"
#include "person_tests.c"

TestSuite *our_tests();
TestSuite *person_tests();

int main(int argc, char **argv) {
    TestSuite *suite = create_test_suite();
    add_suite(suite, our_tests());
    add_suite(suite, person_tests());
    if (argc > 1) {
        return run_single_test(suite, argv[1], create_text_reporter());
    }
    return run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

Normalmente é facil colocar os protótipos 'TestSuite' dentro
do código, ao invez de ter muitos arquivos de cabeçalho declarados.
Este é o mesmo raciocínio que vamos usar para deixar os protótipos
para testar as funções da suite.
Nós podemos deixar como está, porque os testes são mais sobre
documentação do que encapsulamento.


Algumas vezes é útil ser capaz de executar um único teste a partir
da linha de comando, por isso adicionamos um simples bloco 'if'
para pegar o nome do teste como um argumento opcional.
Toda a suite de teste será analisada em busca do teste selecionado.
Este jeito também poupa a recompilação quando vamos fazer debug.


Nós colocamos cada suite de teste dentro de seu próprio arquivo, 
mas não é necessário.
Nós poderiamos ter muitas suites de teste dentro do mesmo arquivo, 
mesmo encadeadas.
Você pode até mesmo misturar funções de teste e teste suites em uma
mesma suite de teste pai.
Porém vai dar trabalho.


Se você colocar várias suites de teste no mesmo arquivo, então todas as
suites irão ser nomeadas da mesma forma dentro do breadcrumb na mensagem de
texto.
Elas serão todas nomeadas depois da função criadora.
Se você quiser eivtar isso, ou somente nomear seus testes, você pode 
'create_named_test_suite()' ao invez de 'create_test_suite()'.
Isto necessita de uma única string como parâmetro.
Na realidade 'create_test_suite()' é apenas uma macro que 
inseri a constante '__func__' dentro de 'create_named_test_suite()'.


Oque aconte com 'setup()' e 'teardown()' no
'TestSuite' que contém outro 'TestSuite's?


Bem primeiramente, Cgreen não faz 'fork()' quando executa a suite.
Ele deixa a suite filha fazer 'fork()' dos processos individuais.
Desta maneira 'setup()' e 'teardown()' irão executar no processo
principal.
Eles irão ser executados uma vez para cada suite filha.


Nos podemos usar isso para aumentar a velocidade do nosso teste
'Person' acima.
Relembrando que nós criamos uma nova conexão e fechamos novamente dentro
do fixtures.
Isto significa abrir e fechar muitas conexões.
Com pouco risco de algum interferência dos testes, nós podemos 
reusar a conexão atravez dos testes...

[source,c]
-----------------------------
...
static MYSQL *connection;

static void create_schema() {
    mysql_query(connection, "create table people (name, varchar(255) unique)");
}

static void drop_schema() {
    mysql_query(connection, "drop table people");
}

static void can_add_person_to_database() { ... }
static void cannot_add_duplicate_person() { ... }

void open_connection() {
    connection = mysql_init(NULL);
    mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0);
}

void close_connection() {
    mysql_close(connection);
}

TestSuite *person_tests() {
    TestSuite *suite = create_test_suite();
    setup(suite, create_schema);
    teardown(suite, drop_schema);
    add_test(suite, can_add_person_to_database);
    add_test(suite, cannot_add_duplicate_person);

    TestSuite *fixture = create_named_test_suite("Mysql fixture");
    add_suite(fixture, suite);
    setup(fixture, open_connection);
    teardown(fixture, close_connection);
    return fixture;
}
-----------------------------------------

O segredo aqui é criar um wrapper para a suite de teste no qual
tem o propósito de fazer um wrap na suite de teste principal para 
o fixture.
Este é o nosso ponteiro 'fixture'.
Este código é um pouco confuso, porque temos dois conjuntos de fixture 
no mesmo script de teste.


Nos temos o fixture para as conexões MySQL.
Isto executa 'open_connection()' e 'close_connection()'
somente uma vez no início e fim do teste person.
Isto é porque o ponteiro 'suite' é o único membro do
'fixture'.


Nos também temos a fixture para o schema, o 'create_schema()'
e 'drop_schema()', no qual é executado antes e depois de todo
teste.
Estas ainda estão vinculadas dentro do 'suite'.


No mundo real nós provavelmente colocariamos o fixture para a conexão 
dentro de seu próprio arquivo...

[source,c]
-----------------------------
static MYSQL *connection;

MYSQL *get_connection() {
    return connection;
}

static void open_connection() {
    connection = mysql_init(NULL);
    mysql_real_connect(connection, "localhost", "me", "secret", "test", 0, NULL, 0);
}

static void close_connection() {
    mysql_close(connection);
}

TestSuite *connection_fixture(TestSuite *suite) {
    TestSuite *fixture = create_named_test_suite("Mysql fixture");
    add_suite(fixture, suite);
    setup(fixture, open_connection);
    teardown(fixture, close_connection);
    return fixture;
}
-----------------------------------------

Isto permite reusar fixtures comuns entre projetos.
          
[[X13]]
Funções Mock com Cgreen
-----------------------
        
Quando testamos você espera que eles estejam corretos.
Eventos aleatórios podem destruir a confiabilidade na suite de
testes e forçar execuções extras para ter certeza que estão certos.
Um bom teste coloca o assunto a ser testado dentro de um ambiente isolado
e controlado.
Uma câmara de testes se você preferir.
Isto fazem os testes rápidos, repetitivos e confiáveis.


Para criar uma câmare de testes para o código de teste, nós temos que
controlar todas as chamadas para fora do nosso código sob teste.
Nos iremos acreditar na falha dos nossos testes se o nosso código faz
uma chamada para a internet por exemplo.
A Internet pode falhar por si só.
Não só não temos total controle, mas pode ser necessário ter componentes
funcionais antes de poder testar o código de alto nível.
Isto torna difícil testar códigos em outras camadas.


A solução para este dilema é escrever um código falso (stub) para o componente
enquanto o código de alto nível é escrito.
Isto polui a base do código com código temporário, e o isolamento do 
teste desaparece quando o sistema eventualmente é modificado.


O ideal é ter um mínimo de stubs escrito para cada teste individual.
Cgreen encoraja esta abordagem fazendo tais testes faceis de escrever.
        
[[X14]]
O problema com streams
~~~~~~~~~~~~~~~~~~~~~~
            
Como testar este código... ?

[source,c]
-----------------------------
char *read_paragraph(int (*read)(void *), void *stream) {
    int buffer_size = 0, length = 0;
    char *buffer = NULL;
    int ch;
    while ((ch = (*read)(stream)) != EOF) {
        if (++length > buffer_size) {
            buffer_size += 100;
            buffer = realloc(buffer, buffer_size + 1);
        }
        if ((buffer[length] = ch) == '\n') {
            break;
        }
    }
    return buffer;
}
-----------------------------------------

Isto é um filtro de stream genérico que troca o caractere recebido
em C strings dentro de parágrafos.
Cada chamada cria um parágrafo, retornando um ponteiro ou retornando
'NULL' se não há parágrafo.
O parágrafo tem uma memória alocada e o stream avança lendo a próxima
chamada.
Tem pouca funcionalidade, e poucas condições.
Eu realmente quero que este código seja testado antes de usa-lo.


O problema é a dependência do stream.
Nós podemos usar uma stream real, mas pode causar todos os tipos 
de dores de cabeça.
Ele faz o teste da formatação do parágrafo dependente de um stream 
funcional.
Ele significa que nós temos que escrever o stream primeiro, codificar 
de baixo para cima em vez de cima para baixo.
Ele também significa configurar recursos externos.
Isto é mais trabalho, execução lenta, e pode gerar resultados falsos dos
testes. 


Em contraste nós podemos escrever um simulador de stream para cada
teste, chamado &quot;server stub&quot;.


Por exemplo, quando o stream é vazio nada acontece.
Nós recebemos um 'NULL' de 'read_paragraph' quando
o stream é exausto.
Isso é, ele somente retorna um stream steady de 'EOF's. 

For example, when the stream is empty nothing should happen.
We hopefully get 'NULL' from 'read_paragraph'
when the stream is exhausted.
That is, it just returns a steady stream of 'EOF's.

[source,c]
-----------------------------
static int empty_stream(void *stream) {
    return EOF;
}

static void reading_lines_from_empty_stream_gives_null() {
    assert_equal(read_paragraph(&empty_stream, NULL), NULL);
}

TestSuite *stream_tests() {
    TestSuite *suite = create_test_suite();
    add_test(suite, reading_lines_from_empty_stream_gives_null);
    return suite;
}
-----------------------------------------

Nossa simulação está facil aqui, por que nosso stream falso retorna somente
um valor.
As coisas são difíceis quando o resultado da função muda de chamada a chamada
como um stream real pode ser.
Simulando isto pode significar confusão com variáveis estáticas e contadores que
são reiniciados para cada teste.
E, nós vamos escrever poucos stubs.
Com frequentes diferenças em cada teste.
Ficando muito confuso.


Cgreen manipula esta desorganização para nós deixando nós escrever
uma função única para todos os nossos testes.
            

Gravando e tocando
~~~~~~~~~~~~~~~~~~
            
Nós podemos refazer nosso exemplo criando a função 'stub_stream()'
(qualquer nome vai fazer)...

We can redo our example by creating a 'stub_stream()' function
(any name will do)...

[source,c]
-----------------------------
static int stub_stream(void *stream) {
    return (int)mock();
}
-----------------------------------------
                
Trivial nosso servidor de stub acima,
ele é somente um macro para gerar um retorno do valor,
mas nós podemos reusar isto depois de cada teste.


Para o nosso simples exemplo acima nos apenas dizemos para ele sempre 
retornar 'EOF'...

[source,c]
-----------------------------
static int stub_stream(void *stream) {
    return (int)mock();
}

static void reading_lines_from_empty_stream_gives_null() {
    always_return(stub_stream, EOF);
    assert_equal(read_paragraph(stub_stream, NULL), NULL);
}
-----------------------------------------

A macro 'always_return()' recebe como argumento o nome
da função e retorna o valor.
Nós tinhamos dito para 'stub_stream()' sempre retornar
'EOF' quando chamado.

The 'always_return()' macro takes as arguments the
function name and the return value.
We have told 'stub_stream()' to always return
'EOF' when called.


Vamos ver se o nosos código de produção atualmente funciona...

-----------------------------------------
Running "main"...
Completed "main": 1 pass, 0 failures, 0 exceptions.
-----------------------------------------

Muito bom.
No próximo teste.
            
            
Se você quer testar uma linha com um caracter, nos temos que enviar o
terminador 'EOF' ou '"\n"' bem como
um único caracter.
De outra maneira nosso código entrará em loop eterno, pegando uma linha
infinita de caracteres.
            
            
Aqui está como nós podemos fazer isto...

[source,c]
-----------------------------
static void one_character_stream_gives_one_character_line() {
    will_return(stub_stream, 'a');
    will_return(stub_stream, EOF);
    char *line = read_paragraph(&stub_stream, NULL);
    assert_string_equal(line, "a");
    free(line);
}
-----------------------------------------

Diferente da instrução 'always_return()', 'will_return()'
ajusta somente um valor de retorno único.
Ele atua como um modo de gravação e reprodução.
Sucessivas instruções mapeiam o retorno da sequencia no qual é retornado uma
vez quando o teste inicia.


Nós vamos adicionar este teste na suite e executa-lo...

-----------------------------------------
Running "main"...
Failure!: stream_tests -> one_character_stream_gives_one_character_line ->
        [] should match [a] at [stream_test.c] line [19]
Completed "main": 1 pass, 1 failure, 0 exceptions.
-----------------------------------------

Oops. Nosso código sob teste não funciona.
Antes precisamos de um conserto...

[source,c]
-----------------------------
char *read_paragraph(int (*read)(void *), void *stream) {
    int buffer_size = 0, length = 0;
    char *buffer = NULL;
    int ch;
    while ((ch = (*read)(stream)) != EOF) {
        if (++length > buffer_size) {
            buffer_size += 100;
            buffer = realloc(buffer, buffer_size + 1);
        }
        if ((buffer[length - 1] = ch) == '\n') {
            break;
        }
    }
    return buffer;
}
-----------------------------------------

Depois que está tudo bem... 

-----------------------------------------
Running "main"...
Completed "main": 2 passes, 0 failures, 0 exceptions.
-----------------------------------------
            
            
Como fazer o stubs Cgreen?
A chamada 'will_return()' constroi uma lista estática de 
valores retornados no qual são limpos entre os testes.
A macro 'mock()' captura a propriedade '__func__'.
Ele usa isto para procurar entradas na lista retornada, e também para 
gerar mensagem mais claras.


Nós podemos passar nossos testes um pouco mais rápido agora... 

[source,c]
-----------------------------
static void one_word_stream_gives_one_word_line() {
    will_return(stub_stream, 't');
    will_return(stub_stream, 'h');
    will_return(stub_stream, 'e');
    always_return(stub_stream, EOF);
    assert_string_equal(read_paragraph(&stub_stream, NULL), "the");
}
-----------------------------------------

Eu tenho sido um pouco malcraido.
Como cada teste executa dentro de seu próprio processo, Eu não tenho
me preocupado em liberar os ponteiros para parágrafos.
Eu tenho somente deixado o sistema operacional fazer isto.
Puristas podem querer adiconar uma limpeza adicional no código.


Eu tenho usado também 'always_return()' para a última instrução.
Sem isto, se o stub recebe uma instrução no qual ele não espera, ele pode
lançar uma falha no teste.
Isto é muito restritivo, como nossa função 'read_paragraph()'
pode legitimamente chamar o stream depois dele ter executado no final.
OK, esse pode ser um comportamento estranho, mas não é oque estamos testando aqui.
Se tivéssemos, isto seria colocado em um teste próprio.
A chamada 'always_return()' diz para o <emphasis>Cgreen manter
após a chamada das três letras, permitindo chamadas extras.
            
            
Como nós construimos mais testes, eles iniciam procurando uma especificação do
comportamento...

[source,c]
-----------------------------
static void drops_line_ending_from_word_and_stops() {
    will_return(stub_stream, 't');
    will_return(stub_stream, 'h');
    will_return(stub_stream, 'e');
    will_return(stub_stream, '\n');
    assert_string_equal(read_paragraph(&stub_stream, NULL), "the");
}
-----------------------------------------
...e com sorte...

[source,c]
-----------------------------
static void single_line_ending_gives_empty_line() {
    will_return(stub_stream, '\n');
    assert_string_equal(read_paragraph(&stub_stream, NULL), "");
}
-----------------------------------------

Por agora nos não temos que usar 'always_return()'.
Nós queremos deixar o stream aonde ela está, pronta para a próxima
chamada de 'read_paragraph()'.
Se chamarmos o stream fora do final da linha, nos vamos ter falha.


Acontecendo a falha mesmo assim... 

-----------------------------------------
Running "main"...
Failure!: stream_tests -> drops_line_ending_from_word_and_stops -> [the
] should match [the] at [stream_test.c] line [36]
Failure!: stream_tests -> single_line_ending_gives_empty_line -> [
] should match [] at [stream_test.c] line [41]
Completed "main": 3 passes, 2 failures, 0 exceptions.
-----------------------------------------

Claramente nós passamos atravez do final da linha.
Depois de outro conserto...

Clearly we are passing through the line ending.
Another fix later...

[source,c]
-----------------------------
char *read_paragraph(int (*read)(void *), void *stream) {
    int buffer_size = 0, length = 0;
    char *buffer = NULL;
    int ch;
    while ((ch = (*read)(stream)) != EOF) {
        if (++length > buffer_size) {
            buffer_size += 100;
            buffer = realloc(buffer, buffer_size + 1);
        }
        if ((buffer[length - 1] = ch) == '\n') {
            buffer[--length] = '\0';
            break;
        }
        buffer[length] = '\0';
    }
    return buffer;
}
-----------------------------------------

E nós passamos novamente...
				
-----------------------------------------
Running "main"...
Completed "main": 5 passes, 0 failures, 0 exceptions.
-----------------------------------------
            
            
Não há limites no número de métodos stubs nos testes, somente aqueles dois
stubs não podem ter o mesmo nome.
Então isto pode causar problemas...

[source,c]
-----------------------------
static int stub_stream(void *stream) {
    return (int)mock();
}

static void bad_test() {
    will_return(stub_stream, 'a');
    do_stuff(&stub_stream, &stub_stream);
}
-----------------------------------------
Será necessário ter dois stubs para fazer o teste correto...

[source,c]
-----------------------------
static int first_stream(void *stream) {
    return (int)mock();
}

static int second_stream(void *stream) {
    return (int)mock();
}

static void good_test() {
    will_return(first_stream, 'a');
    will_return(second_stream, 'a');
    do_stuff(&first_stream, &second_stream);
}
-----------------------------------------

Nos agora temos um jeito de escrever testes rápidos e limpos sem 
nenhuma dependência externa.
A informação ainda segue um caminho, do stub para o código sob teste.
Quando o seu código chama um procedimento complexo, nos não queremos
saber os efeitos que acontece.
Isto é muito parecido com o trabalho de um detetive.
E oque queremos?
Nós somente queremos saber se estamos enviando as informações corretas.             
            
            
As coisas se tornam mais interessantes quando pensamos no tráfego
vindo de outro jeito, do código para o stub. 
Isto nos coloca no mesmo território assim como os objetos mock.
            
[[X15]]
Configurando valores aguardados em funções mock
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            
Para trocar o sentido do tráfego, nós temos que olhar em um exemplo 
contrário.
Aqui está um código de produção préescrito.

[source,c]
-----------------------------
void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out) {
    while (1) {
        char *line = read_paragraph(read, in);
        if (line == NULL) {
            return;
        }
        (*write)(out, line);
        free(line);
    }
}
-----------------------------------------

Isto é o início do utilitário de formatação.
Filtros anterirores vão provavelmente quebrar o parágrafo em texto
justificado, mas agora isso é tudo abstraído atraz da interface
'void write(void *, char *)'.
Nossos interesses são: fazer ele passar atravez os parágrafo, e fazer 
ele cair?


Nos podemos testar a correta formatação do parágrafo escrevendo um 
stub que coleta o parágrafo dentro de uma 'struct'.
Nos podemos então ficar a parte daquela 'struct' e testar
cada ponto com assertions.
Este jeito é extremamente desajeitado em C.
A linguagem não é apropriada para construir e destruir, nunca pense
em navegar-las com assertions.
Nós desorganizariamos nossos testes.


Em vez disso nos testamos a saída assim que possível, como na
chamada da função...

[source,c]
-----------------------------
...
void expect_one_letter_paragraph(char *paragraph, void *stream) {
    assert_string_equal(paragraph, "a", NULL);
}

void one_character_is_made_into_a_one_letter_paragraph() {
    by_paragraph(
            &one_character_stream,
            NULL,
            &expect_one_letter_paragraph,
            NULL);
}
...
-----------------------------------------

Colocando assertions entre as funções mock, mantemos os testes
mínimos.
A idéia deste método é que voltamos a escrever funções individuais
para cada teste.
Nós temos o mesmo problema como tinhamos codificando stubs.
            
            
Novamente, Cgreen tem um jeito para automatizar isto.
Aqui está o teste reescrito...

[source,c]
-----------------------------
static int reader(void *stream) {
    return (int)mock(stream);
}

static void writer(void *stream, char *paragraph) {
    mock(stream, paragraph);
}

void one_character_is_made_into_a_one_letter_paragraph() {
    will_return(reader, 'a');
    always_return(reader, EOF);
    expect(writer, want_string(paragraph, "a"));
    by_paragraph(&reader, NULL, &writer, NULL);
}
-----------------------------------------

Onde estão as assertions?
            
            
Como nosso stub anterior, 'reader()' pode agora verificar
seus parâmetros.
Em orientação a objeto, um objeto que checa seus próprios pararâmetros
bem como simula comportamento é chamado de objeto mock.
Por analogia 'reader()' é uma função mock, ou um callback mock.
            
            
Usando a macro 'expect', temos afirmado que 'writer()' 
será chamado apenas uma vez.
Esta chamada deve ter a string '"a"' para o parâmetro 
parágrafo.
Se este parâmetro não casar, a função mock vai emitir uma falha para
a suite de teste.
Isto é oque nós evita escrever um monte de assertions.

Using the 'expect' macro, we have stated that
'writer()' will be called just once.
That call must have the string '"a"' for the
paragraph parameter.
If this parameter does not match, the mock function will
issue a failure straight to the test suite.
This is what saves us writing a lot of assertions.


Aqui está uma lista de instruções que podem ser enviadas para mocks...

|=========================================
|Macro| Parameters
|'will_return(function, result)'| Returns result once only, but successive calls 
will be replayed in order. Generates a failure when called too many times.
|'always_return(function, result)'| Returns result repeatedly.
|'expect(function, arguments...)'| Sets up an expectation on each argument. If there is a mismatch,
 or a call is made without an expectation, a failure is generated.
|'always_expect(function, arguments...)'| Must receive exactly these arguments from now on.
|'expect_never(function)'| This function must not be called or a failure is generated.
|'will_respond(function, result, arguments...)'| Combines 'will_return()' and 'expect()'.
|'always_respond(function, result, arguments...)'| Combines 'always_return()' and 'always_expect()'
|=========================================

The 'expect_never()' macro is slightly different.
It's only task is to confirm that a method was never run.


The 'will_respond()' macro combines the 'will_return()'
and the 'expect()' calls into one call, as does 'always_respond'.


Each parameter can be tested with a constraint.
Two constraints are available:
'want(parameter, expected)' for integers and pointers, and
'want_string(parameter, expected)' does a string comparison.
            
            
Isto é uma questão de tempo, nos podemos rodar nossos testes...

-----------------------------------------
Running "main"...
Completed "main": 6 passes, 0 failures, 0 exceptions.
-----------------------------------------

Para um caractere único funciona, nos podemos adicionalmente 
especificar este comportamento.
Primeiramente uma sequencia de entradas...                

[source,c]
-----------------------
static void no_line_endings_makes_one_paragraph() {
    will_return(reader, 'a');
    will_return(reader, ' ');
    will_return(reader, 'b');
    will_return(reader, ' ');
    will_return(reader, 'c');
    always_return(reader, EOF);
    expect(writer, want_string(paragraph, "a b c"));
    by_paragraph(&reader, NULL, &writer, NULL);
}
-----------------------------------------

Um programador mais inteligente do que eu iria colocar todos
estas chamadas dentro de um loop.
Próximo, checando a saída da sequencia... 

[source,c]
-----------------------
static void line_endings_generate_separate_paragraphs() {
    will_return(reader, 'a');
    will_return(reader, '\n');
    will_return(reader, 'b');
    will_return(reader, '\n');
    will_return(reader, 'c');
    always_return(reader, EOF);
    expect(writer, want_string(paragraph, "a"));
    expect(writer, want_string(paragraph, "b"));
    expect(writer, want_string(paragraph, "c"));
    by_paragraph(&reader, NULL, &writer, NULL);
}
-----------------------------------------

Como o stub 'will_return()' acima, a chamada 'expect()'
segue um modelo de gravação e reprodução.
Cada teste é uma chamada sucessiva.
Esta sequencia confirma que nos temos '"a"',
'"b"' e '"c"' na ordem.


Então iremos ter certeza que os ponteiros corretos são passados para a
função correta.
Isto é uma checagem mais realista dos parâmetros...

[source,c]
-----------------------
static void resources_are_paired_with_the_functions() {
    will_respond(reader, 'a', want(stream, 1));
    always_respond(reader, EOF, want(stream, 1));
    expect(writer, want(stream, 2));
    by_paragraph(&reader, (void *)1, &writer, (void *)2);
}
-----------------------------------------

E finalmente iremos especificar que a escrita não é chamada se não
há parágrafo.

[source,c]
-----------------------
static void empty_paragraphs_are_ignored() {
    will_return(reader, '\n');
    always_return(reader, EOF);
    expect_never(writer);
    by_paragraph(&reader, NULL, &writer, NULL);
}
-----------------------------------------

Este último teste não está sendo feito...

-----------------------------------------
Running "main"...
Failure!: stream_tests -> empty_paragraphs_are_ignored ->
        Unexpected call to function [writer] at [stream_test.c] line [96]
Completed "main": 14 passes, 1 failure, 0 exceptions.
-----------------------------------------

Obviamente linhas em branco ainda são enviadas para 'writer()'.
Uma vez que isto é apontado, o concerto é óbvio...

[source,c]
-----------------------
void by_paragraph(int (*read)(void *), void *in, void (*write)(void *, char *), void *out) {
    while (1) {
        char *line = read_paragraph(read, in);
        if ((line == NULL) || (strlen(line) == 0)) {
            return;
        }
        (*write)(out, line);
        free(line);
    }
}
-----------------------------------------

Testes com 'expect_never()' podem ser muito efetivos
na descoberta sutil de bugs.
				
-----------------------------------------
Running "main"...
Completed "main": 14 passes, 0 failures, 0 exceptions.
-----------------------------------------
Tudo feito.
            
[[X19]]
Mudando os relatórios do Cgreen
-------------------------------

[[X20]]
Trocando o relatório
~~~~~~~~~~~~~~~~~~~~
            
Em toda suite de teste, nos temos que executar os testes com
esta linha...

[source,c]
-----------------------
return run_test_suite(our_tests(), create_text_reporter());
-----------------------------------------

Nos podemos mudar o mecanismo de relatório somente trocando este
método.
Aqui está um código para 'create_text_reporter()'...

[source,c]
-----------------------
TestReporter *create_text_reporter() {
    TestReporter *reporter = create_reporter();
    reporter->start = &text_reporter_start;
    reporter->finish = &text_reporter_finish;
    reporter->show_fail = &show_fail;
    reporter->show_incomplete = &show_incomplete;
    return reporter;
}
-----------------------------------------

A estrutura 'TestReporter' contem ponteiros de função 
no qual controlam o relatório.
Quando chamadas pelo construtor 'create_reporter()', estes
ponteiros são configurados com funções que não mostram nada.
O código do relatório de texto troca estas com alguma coisa mais dramática
, e então retorna um ponteiro para o novo objeto.
Desta maneira a função 'create_text_reporter()' efetivamente
extende o objeto a partir de 'create_reporter()'.


O relatório de texto somente mostra o conteúdo partir do início do
primeiro teste, até o final dos testes, quando uma falha ocorre e quando um teste
falha para completar.

Uma pequena olhada no arquivo +text_reporter.c+ do Cgreen
revela que sobrepõem somente a saída da mensagem e encadeia para a versão 
de +reporter.h+.


Para mudarmos o mecanisco de relatório, basta conhecermos um 
pouco sobre os métodos da estrutura 'TestReporter'.
            
[[X21]]
A estrutura do TestReporter
~~~~~~~~~~~~~~~~~~~~~~~~~~~
            
O 'TestReporter' do Cgreen é uma pseudo classe que se parece
como...

[source,c]
-----------------------
typedef struct _TestReporter TestReporter;
struct _TestReporter {
    void (*destroy)(TestReporter *);
    void (*start)(TestReporter *, const char *);
    void (*finish)(TestReporter *, const char *);
    void (*show_pass)(TestReporter *, const char *, int, const char *, va_list);
    void (*show_fail)(TestReporter *, const char *, int, const char *, va_list);
    void (*show_incomplete)(TestReporter *, const char *);
    void (*assert_true)(TestReporter *, const char *, int, int, const char *, ...);
    int passes;
    int failures;
    int exceptions;
    void *breadcrumb;
    int ipc;
    void *memo;
};
-----------------------------------------

O primeiro bloco são métodos que podem ser sobrepostos.                

[horizontal]
'void (*destroy)(TestReporter *)':: Este é o destrutor para a estrutura default.
 Se for sobreposto, então a função sobreposta necessita chamar 
 'destroy_reporter(TestReporter *reporter)' para finalizar e limpar.

'void (*start)(TestReporter *, const char *)':: A primeira das callbacks. No começo de cada suite de
                        teste <emphasis>Cgreen vai chamar este método dentro do 
                        relatório com o nome da suite iniciada.
                        A versão default mantem o registro da pilha de testes dentro do 
                        ponteiro 'breadcrumb' para 'TestReporter'.
                        Se você faz uso das funções breadcrumb, como por default faz, então você
                        precisa chamar 'reporter_start()' para manter os registros
                        sincronizados.

'void (*finish)(TestReporter *, const char *)':: Do outro lado a chamada para '(*start)()' é feita
                        quando a suite de teste é deixada. 
                        Ela precisa ser encadeiada pelo 'reporter_finish()' para
                        manter o registro de breadcrumb.
                        O próximo relatório usa o estado do breadcrumb para decidir se 
                        ele está no fim do teste.
                        Se esta, ele imprime o sumário familiar de falhas e sucessos.

'void (*show_pass)(TestReporter *, const char *, int, const char *, va_list)':: Este método é inicializado vazio, então não é necessário encadear a 
                        chamada para nenhuma outra função.
                        Além disso o ponteiro para a estrutura de relatório, Cgreen
                        também passa o nome do arquivo do teste, o número da linha da assertion falhada,
                        a mensagem para mostrar e qualquer parâmetro adicional para ser 
                        substituido dentro da mensagem.
                        A mensagem vem no estilo 'printf()' de formatação de string,
                        e então a lista de argumento variável faz as substituições.

'void (*show_fail)(TestReporter *, const char *, int, const char *, va_list)':: O parceiro do 'show_pass()', e é uma das que gostariamos
                        de sobrepor primeiro.

'void (*show_incomplete)(TestReporter *, const char *)':: Quando um teste falha, este é o handle que é chamado.
                        Como ele é um resultado inexperado, nenhuma mensagem é recebida, mas
                        faz chegar o nome do teste.
                        O relatório do teste combina isto com o breadcrumb para produzir
                        a exceção no relatório.

'void (*assert_true)(TestReporter *, const char *, int, int, const char *, ...)':: Isto não é normalmente sobreposto e é interno.
                        Ele é ponto de entrada para as mensagesm de teste a partir da suite de teste.
                        Por default isto dispacha a chamada para 'show_pass()' ou 
                        'show_fail()'.

O segundo bloco é somente recursos e registro no qual o relatório pode usar
para exibir as mensagens...

[horizontal]
'passes':: O número de sucesso gerado até agora.
'failures':: O número de falhas geradas até agora.
'exceptions':: O números de funções testadas que falharam em completar até agora.
'breadcrumb':: Este é um ponteiro para a lista de nomes dentro da stack.

O ponteiro 'breadcrumb' é diferente e necessita de uma pequena
explanação.
Basicamente ele é uma pilha, análogo a breadcrumb trail que você vê em websites.
Todo vez que o handle 'start()' é invocado, o nome é colocado dentro da stack.
Quando o handle 'finish()' é invocado, o nome é retirado da stack. 
            
            
Há um monte de funções uteis em +cgreen/breadcrumb.h+
no qual podem ajudar a ler o estado do stack.
As mais uteis são 'get_current_from_breadcrumb()' no qual pega
um ponteiro breadcrumb e retorna o nome do teste corrente, e 
'get_breadcrumb_depth()' no qual retorna a atual profundidade
da stack.
Uma profundidade zero significa que a execução do teste acabou.            


Se você precisa atravessar todos os nomes dentro do breadcrumb, então 
você pode chamar 'walk_breadcrumb()'.
Aqui está a assinatura completa...

[source,c]
-----------------------
void walk_breadcrumb(Breadcrumb *breadcrumb, void (*walker)(const char *, void *), void *memo);
-----------------------------------------

O 'void (*walker)(const char *, void *)' é uma callback que vai 
ser passada o nome da suite de teste para cada nível aninhado.
Ele também passa o ponteiro 'memo' que foi passado para a chamada
'walk_breadcrumb()'.
Você pode usar este ponteiro para qualquer coisa que você queira, como o
Cgreen faz é passar de chamada para chamada.
Trata-se de um agregado de informações mantendo o registro e ainda reentrantes. 
            
            
As últimas partes da estrutura do 'TestReporter' são...            

[horizontal]
'ipc':: Isto é uma estrutura interna para manipular as mensagem entre o 
relatório e a suite de testes. Você não preciso mexer nisto.
'memo':: Isto é um ponteiro livre para sua própria expansão.</listitem>
            
			
[[X23]]
Um exemplo de relatório XML
~~~~~~~~~~~~~~~~~~~~~~~~~~~
            
Vamos fazer coisas reais com um exemplo.
Suponha que queiremos enviar a saída do <emphasis>Cgreen no formato
XML, para armazenar em um repositório ou para enviar atravez da rede.


Suponha também que ele venha com o seguinte formato...

[source, xml]
-----------------------------------------
<?xml?>
<test name="Top Level">
    <test name="A Group">
        <test name="a_test_that_passes">
        </test>
        <test name="a_test_that_fails">
            <fail>
                <message>A failure</message>
                <location file="test_as_xml.c" line="8"/>
            </fail>
        </test>
    </test>
</test>
]]>
-----------------------------------------

Em outras palavras um simples aninhamento de testes com somente as
falhas reportadas.
A ausência da falha é o sucesso do teste.


Aqui esta um script de teste +test_in_xml.c+ no qual nos podemos usar
para construir a saída acima...

[source,c]
-----------------------
#include "cgreen/cgreen.h"

void a_test_that_passes() {
    assert_true(1);
}

void a_test_that_fails() {
    assert_true_with_message(0, "A failure");
}

TestSuite *create_test_group() {
    TestSuite *suite = create_named_test_suite("A Group");
    add_test(suite, a_test_that_passes);
    add_test(suite, a_test_that_fails);
    return suite;
}

int main(int argc, char **argv) {
    TestSuite *suite = create_named_test_suite("Top Level");
    add_suite(suite, create_test_group());
    return run_test_suite(suite, create_text_reporter());
}
-----------------------------------------

O relatório texto é usado somente para confirmar se tudo está funcionando
Até agora ele esta.
				
-----------------------------------------
Running "Top Level"...
Failure!: A Group -> a_test_that_fails -> A failure at [test_as_xml.c] line [8]
Completed "Top Level": 1 pass, 1 failure, 0 exceptions.
-----------------------------------------
            
            
Nosso primeiro movimento é trocar o relatório de texto, para o nosso ainda
não escrito na versão em XML...

[source,c]
-----------------------
#include "cgreen/cgreen.h
#include "xml_reporter.h"

...

int main(int argc, char **argv) {
    TestSuite *suite = create_named_test_suite("Top Level");
    add_suite(suite, create_test_group());
    return run_test_suite(suite, create_xml_reporter());
}
-----------------------------------------

Nos iniciaremos com o arquivo de cabeçalho +xml_reporter.h+...

[source,c]
-----------------------
#ifndef _XML_REPORTER_HEADER_
#define _XML_REPORTER_HEADER_

#include "cgreen/reporter.h"

TestReporter *create_xml_reporter();

#endif
-----------------------------------------

...e o relatório mais simplista possível em +reporter.c+.
				
[source,c]
-----------------------
#include "xml_reporter.h"
#include "cgreen/reporter.h"

TestReporter *create_xml_reporter() {
    TestReporter *reporter = create_reporter();
    return reporter;
}
-----------------------------------------

A saída não é nada.                

-----------------------------------------
gcc -c test_as_xml.c
gcc -c xml_reporter.c
gcc xml_reporter.o test_as_xml.o -lcgreen -o xml
./xml
-----------------------------------------

Ainda, nada.
            
            
Vamos adicionar as tags primeiro, de modo que possamos ver o <emphasis>Cgreen
navegar na test suite...

[source,c]
-----------------------
#include "xml_reporter.h"
#include "cgreen/reporter.h"
#include <stdio.h>

static void xml_reporter_start(TestReporter *reporter, const char *name);
static void xml_reporter_finish(TestReporter *reporter, const char *name);

TestReporter *create_xml_reporter() {
    TestReporter *reporter = create_reporter();
    reporter->start = &xml_reporter_start;
    reporter->finish = &xml_reporter_finish;
    return reporter;
}

static void xml_reporter_start(TestReporter *reporter, const char *name) {
    printf("<test name=\"%s\">;\n", name);
    reporter_start(reporter, name);
}

static void xml_reporter_finish(TestReporter *reporter, const char *name) {
    reporter_finish(reporter, name);
    printf("</test>\n");
}
-----------------------------------------

Apesar do encadeamento subjacente as funções 'reporter_start()'
e 'reporter_finish()' são opcionais, eu quero fazer uso de
algumas facilidades depois.


Nossa saída por enquanto, é fazer a tentativa em passos...                

-----------------------------------------
<![CDATA[
<test name="Top Level">
<test name="A Group">
<test name="a_test_that_passes">
</test>
<test name="a_test_that_fails">
</test>
</test>
</test>
]]>
-----------------------------------------

Nos não queremos uma mensagem de sucesso, então a função 'show_fail()'
é tudo oque precisamos...

[source,c]
-----------------------
...
static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments);

TestReporter *create_xml_reporter() {
    TestReporter *reporter = create_reporter();
    reporter->start = &xml_reporter_start;
    reporter->finish = &xml_reporter_finish;
    reporter->show_fail = &xml_show_fail;
    return reporter;
}

...
<![CDATA[

static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) {
    printf("<fail>\n");
    printf("\t<message>");
    vprintf(message, arguments);
    printf("]]></message>\n");
    printf("\t<location file=\"%s\" line=\"%d\"/>\n", file, line);
    printf("</fail>\n");
}
]]>
-----------------------------------------

Nos temos que usar 'vprintf()' para manipular a lista de argumento
variável passada para nós.
Isto irá provavelmente significar a inclusão do cabeçalho +stdarg.h+
bem como +stdio.h+.                


Isto nos aproxima do que queremos...

-----------------------------------------
<![CDATA[
<test name="Top Level">
<test name="A Group">
<test name="a_test_that_passes">
</test>
<test name="a_test_that_fails">
<fail>
    <message>A failure]]></message>
    <location file="test_as_xml.c" line="9"/></fail>
</test>
</test>
</test>
]]>
-----------------------------------------

Para completar devemos adicionar uma tag para um teste incompleto.
Nos vamos visualizar isto como uma falha, entretando nos não vamos saber
a localização por enquanto...

[source,c]
-----------------------
static void xml_show_incomplete(TestReporter *reporter, const char *name) {
    printf("<fail>\n");
    printf("\t<message>Failed to complete]]></message>\n");
    printf("</fail>\n");
}
-----------------------------------------

Tudo oque vem depois é a declaração XML e a identação.
Entretanto a identação não é estritamente necessária, isto pode fazer a
saída muito mais clara.


A profundidade do teste é registrada para nos com o objeto 'breadcrumb'
dentro da estrutura 'TestReporter'.
Nos vamos adicionar a função 'indent()' que imprime o correto
número de tabs...

[source,c]
-----------------------
static indent(TestReporter *reporter) {
    int depth = get_breadcrumb_depth((Breadcrumb *)reporter->breadcrumb);
    while (depth-- > 0) {
        printf("\t");
    }
}
-----------------------------------------

A função 'get_breadcrumb_depth()' somente dá a profundidade
atual do teste.
Como é apenas o número de tabs para imprimir, a implementação é trivial.                


Nos podemos então usar esta função no restante do código.
Aqui está a listagem completa...

[source,c]
-----------------------
#include "xml_reporter.h"
#include "cgreen/reporter.h"
#include "cgreen/breadcrumb.h"
#include <stdio.h>
#include <stdarg.h>

static indent(TestReporter *reporter);
static void xml_reporter_start(TestReporter *reporter, const char *name);
static void xml_reporter_finish(TestReporter *reporter, const char *name);
static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments);
static void xml_show_incomplete(TestReporter *reporter, const char *name);

TestReporter *create_xml_reporter() {
    TestReporter *reporter = create_reporter();
    reporter->start = &xml_reporter_start;
    reporter->finish = &xml_reporter_finish;
    reporter->show_fail = &xml_show_fail;
    reporter->show_incomplete = &xml_show_incomplete;
    return reporter;
}

static indent(TestReporter *reporter) {
    int depth = get_breadcrumb_depth((Breadcrumb *)reporter->breadcrumb);
    while (depth-- > 0) {
        printf("\t");
    }
}

static void xml_reporter_start(TestReporter *reporter, const char *name) {
    if (get_breadcrumb_depth((Breadcrumb *)reporter->breadcrumb) == 0) {
        printf("<?xml?>\n");
    }
    indent(reporter);
    printf("<test name=\"%s\">\n", name);
    reporter_start(reporter, name);
}

static void xml_reporter_finish(TestReporter *reporter, const char *name) {
    reporter_finish(reporter, name);
    indent(reporter);
    printf("</test>\n");
}

static void xml_show_fail(TestReporter *reporter, const char *file, int line, const char *message, va_list arguments) {
    indent(reporter);
    printf("<fail>\n");
    indent(reporter);
    printf("\t<message>");
    vprintf(message, arguments);
    printf("]]></message>\n");
    indent(reporter);
    printf("\t<location file=\"%s\" line=\"%d\"/>\n", file, line);
    indent(reporter);
    printf("</fail>\n");
}

static void xml_show_incomplete(TestReporter *reporter, const char *name) {
    indent(reporter);
    printf("<fail>\n");
    indent(reporter);
    printf("\t<message>Failed to complete]]></message>\n");
    indent(reporter);
    printf("</fail>\n");
}
-----------------------------------------

E finalmente a saída desejada...
		
[source, xml]				
-----------------------------------------
<![CDATA[
<?xml?>
<test name="Top Level">
    <test name="A Group">
        <test name="a_test_that_passes">
        </test>
        <test name="a_test_that_fails">
            <fail>
                <message>A failure]]></message>
                <location file="test_as_xml.c" line="9"/>
            </fail>
        </test>
    </test>
</test>
]]>
-----------------------------------------

Trabalho concluído.
            
            
Possivelmente outras extensões incluem relatórios que escrevem para syslog,
integração com IDE, imprimir documentos ou somente retornar um boleano para
propósitos de monitoramento.                
            
[[X25]]
Coleta automática de testes
--------------------------

[[X27]]
A ferramenta collector
~~~~~~~~~~~~~~~~~~~~~~
            
Quando queremos adicionar um novo teste, acrescentamos no script
de testes uma função do tipo void. E então adicionamos o nome do
teste dentro da TestSuite.

Em resumo cada novo teste deve ser adicionado na TestSuite para ele ser
encontrado durante a execução dos testes.


A ferramenta collector muda este 
comportamento tedioso. A ideia da ferramenta é poupar o trabalho de 
adicionar o teste criado na 'TestSuite'. Basicamente cada teste passa 
a ser declarado usando a macro Ensure no qual é inserida automaticamente
na 'TestSuite'. via a ferramenta collector.
                                                         
[[X26]]
Exemplo prático
~~~~~~~~~~~~~~~
            
Para utilizar a ferramenta collector necessitamos modificar as definições
de cada função de teste. Antes usávamos:

[source,c]
-----------------------
void one_should_assert_char_equal_to_one() {
	char x = 1;
	char y = 1;
    assert_equal(x, y);
}
-----------------------------------------

Agora a função deve ser reescrita assim:

[source,c]
-----------------------
Ensure one_should_assert_char_equal_to_one() {
	char x = 1;
	char y = 1;
    assert_equal(x, y);
}
-----------------------------------------
                
Para cada teste escrito, declaramos como sendo do tipo 'Ensure'
que é uma macro informando para a ferramenta que este teste deve ser colocado
dentro da TestSuite.                


Na TestSuite não precisamos mais descrever quais testes compõem a TestSuite. Podemos
apenas deixar assim:

[source,c]
-----------------------
TestSuite *assertion_tests() {
    TestSuite *suite = create_test_suite();
    add_tests();
    return suite;
}                
-----------------------------------------                                

Supondo que o nosso script de teste é +assertion_tests.c+, 
executando o 'collector' temos:

-----------------------------------------                
./collector assertion_tests.c
-----------------------------------------

O resultado final no script de teste é:

[source,c]
-----------------------
Ensure one_should_assert_char_equal_to_one() {
	char x = 1;
	char y = 1;
    assert_equal(x, y);
}

TestSuite *assertion_tests() {
    TestSuite *suite = create_test_suite(&one_should_assert_char_equal_to_one);
    add_tests();
    return suite;
}
-----------------------------------------
          
          
A ferramenta lê todo o script, faz a substituição necessária e escreve
novamente no arquivo.
Assim apenas adicionamos um novo teste e executamos a ferramenta collector
para ajustar o TestSuite automaticamente.                   

[[X21]]
GNU Free Documentation License
------------------------------


    Version 1.1, March 2000

    
      Copyright (C) 2000  Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
    
    0. PREAMBLE

    The purpose of this License is to make a manual, textbook,
    or other written document "free" in the sense of freedom: to
    assure everyone the effective freedom to copy and redistribute it,
    with or without modifying it, either commercially or
    noncommercially.  Secondarily, this License preserves for the
    author and publisher a way to get credit for their work, while not
    being considered responsible for modifications made by
    others.

    This License is a kind of "copyleft", which means that
    derivative works of the document must themselves be free in the
    same sense.  It complements the GNU General Public License, which
    is a copyleft license designed for free software.

    We have designed this License in order to use it for manuals
    for free software, because free software needs free documentation:
    a free program should come with manuals providing the same
    freedoms that the software does.  But this License is not limited
    to software manuals; it can be used for any textual work,
    regardless of subject matter or whether it is published as a
    printed book.  We recommend this License principally for works
    whose purpose is instruction or reference.

    1. APPLICABILITY AND DEFINITIONS

    This License applies to any manual or other work that
    contains a notice placed by the copyright holder saying it can be
    distributed under the terms of this License.  The "Document",
    below, refers to any such manual or work.  Any member of the
    public is a licensee, and is addressed as "you".

    A "Modified Version" of the Document means any work
    containing the Document or a portion of it, either copied
    verbatim, or with modifications and/or translated into another
    language.

    A "Secondary Section" is a named appendix or a front-matter
    section of the Document that deals exclusively with the
    relationship of the publishers or authors of the Document to the
    Document's overall subject (or to related matters) and contains
    nothing that could fall directly within that overall subject.
    (For example, if the Document is in part a textbook of
    mathematics, a Secondary Section may not explain any mathematics.)
    The relationship could be a matter of historical connection with
    the subject or with related matters, or of legal, commercial,
    philosophical, ethical or political position regarding
    them.

    The "Invariant Sections" are certain Secondary Sections
    whose titles are designated, as being those of Invariant Sections,
    in the notice that says that the Document is released under this
    License.

    The "Cover Texts" are certain short passages of text that
    are listed, as Front-Cover Texts or Back-Cover Texts, in the
    notice that says that the Document is released under this
    License.

    A "Transparent" copy of the Document means a
    machine-readable copy, represented in a format whose specification
    is available to the general public, whose contents can be viewed
    and edited directly and straightforwardly with generic text
    editors or (for images composed of pixels) generic paint programs
    or (for drawings) some widely available drawing editor, and that
    is suitable for input to text formatters or for automatic
    translation to a variety of formats suitable for input to text
    formatters.  A copy made in an otherwise Transparent file format
    whose markup has been designed to thwart or discourage subsequent
    modification by readers is not Transparent.  A copy that is not
    "Transparent" is called "Opaque".

    Examples of suitable formats for Transparent copies include
    plain ASCII without markup, Texinfo input format, LaTeX input
    format, SGML or XML using a publicly available DTD, and
    standard-conforming simple HTML designed for human modification.
    Opaque formats include PostScript, PDF, proprietary formats that
    can be read and edited only by proprietary word processors, SGML
    or XML for which the DTD and/or processing tools are not generally
    available, and the machine-generated HTML produced by some word
    processors for output purposes only.

    The "Title Page" means, for a printed book, the title page
    itself, plus such following pages as are needed to hold, legibly,
    the material this License requires to appear in the title page.
    For works in formats which do not have any title page as such,
    "Title Page" means the text near the most prominent appearance of
    the work's title, preceding the beginning of the body of the
    text.

    2. VERBATIM COPYING

    You may copy and distribute the Document in any medium,
    either commercially or noncommercially, provided that this
    License, the copyright notices, and the license notice saying this
    License applies to the Document are reproduced in all copies, and
    that you add no other conditions whatsoever to those of this
    License.  You may not use technical measures to obstruct or
    control the reading or further copying of the copies you make or
    distribute.  However, you may accept compensation in exchange for
    copies.  If you distribute a large enough number of copies you
    must also follow the conditions in section 3.

    You may also lend copies, under the same conditions stated
    above, and you may publicly display copies.

    3. COPYING IN QUANTITY

    If you publish printed copies of the Document numbering more
    than 100, and the Document's license notice requires Cover Texts,
    you must enclose the copies in covers that carry, clearly and
    legibly, all these Cover Texts: Front-Cover Texts on the front
    cover, and Back-Cover Texts on the back cover.  Both covers must
    also clearly and legibly identify you as the publisher of these
    copies.  The front cover must present the full title with all
    words of the title equally prominent and visible.  You may add
    other material on the covers in addition.  Copying with changes
    limited to the covers, as long as they preserve the title of the
    Document and satisfy these conditions, can be treated as verbatim
    copying in other respects.

    If the required texts for either cover are too voluminous to
    fit legibly, you should put the first ones listed (as many as fit
    reasonably) on the actual cover, and continue the rest onto
    adjacent pages.

    If you publish or distribute Opaque copies of the Document
    numbering more than 100, you must either include a
    machine-readable Transparent copy along with each Opaque copy, or
    state in or with each Opaque copy a publicly-accessible
    computer-network location containing a complete Transparent copy
    of the Document, free of added material, which the general
    network-using public has access to download anonymously at no
    charge using public-standard network protocols.  If you use the
    latter option, you must take reasonably prudent steps, when you
    begin distribution of Opaque copies in quantity, to ensure that
    this Transparent copy will remain thus accessible at the stated
    location until at least one year after the last time you
    distribute an Opaque copy (directly or through your agents or
    retailers) of that edition to the public.

    It is requested, but not required, that you contact the
    authors of the Document well before redistributing any large
    number of copies, to give them a chance to provide you with an
    updated version of the Document.

    4. MODIFICATIONS

    You may copy and distribute a Modified Version of the
    Document under the conditions of sections 2 and 3 above, provided
    that you release the Modified Version under precisely this
    License, with the Modified Version filling the role of the
    Document, thus licensing distribution and modification of the
    Modified Version to whoever possesses a copy of it.  In addition,
    you must do these things in the Modified Version:

      Use in the Title Page
      (and on the covers, if any) a title distinct from that of the
      Document, and from those of previous versions (which should, if
      there were any, be listed in the History section of the
      Document).  You may use the same title as a previous version if
      the original publisher of that version gives permission.
      

      List on the Title Page,
      as authors, one or more persons or entities responsible for
      authorship of the modifications in the Modified Version,
      together with at least five of the principal authors of the
      Document (all of its principal authors, if it has less than
      five).
      

      State on the Title page
      the name of the publisher of the Modified Version, as the
      publisher.
      

      Preserve all the
      copyright notices of the Document.
      

      Add an appropriate
      copyright notice for your modifications adjacent to the other
      copyright notices.
      

      Include, immediately
      after the copyright notices, a license notice giving the public
      permission to use the Modified Version under the terms of this
      License, in the form shown in the Addendum below.
      

      Preserve in that license
      notice the full lists of Invariant Sections and required Cover
      Texts given in the Document's license notice.
      

      Include an unaltered
      copy of this License.
      

      Preserve the section
      entitled "History", and its title, and add to it an item stating
      at least the title, year, new authors, and publisher of the
      Modified Version as given on the Title Page.  If there is no
      section entitled "History" in the Document, create one stating
      the title, year, authors, and publisher of the Document as given
      on its Title Page, then add an item describing the Modified
      Version as stated in the previous sentence.
      

      Preserve the network
      location, if any, given in the Document for public access to a
      Transparent copy of the Document, and likewise the network
      locations given in the Document for previous versions it was
      based on.  These may be placed in the "History" section.  You
      may omit a network location for a work that was published at
      least four years before the Document itself, or if the original
      publisher of the version it refers to gives permission.
      

      In any section entitled
      "Acknowledgements" or "Dedications", preserve the section's
      title, and preserve in the section all the substance and tone of
      each of the contributor acknowledgements and/or dedications
      given therein.
      

      Preserve all the
      Invariant Sections of the Document, unaltered in their text and
      in their titles.  Section numbers or the equivalent are not
      considered part of the section titles.
      

      Delete any section
      entitled "Endorsements".  Such a section may not be included in
      the Modified Version.
      

      Do not retitle any
      existing section as "Endorsements" or to conflict in title with
      any Invariant Section.
      
    
    If the Modified Version includes new front-matter sections
    or appendices that qualify as Secondary Sections and contain no
    material copied from the Document, you may at your option
    designate some or all of these sections as invariant.  To do this,
    add their titles to the list of Invariant Sections in the Modified
    Version's license notice.  These titles must be distinct from any
    other section titles.

    You may add a section entitled "Endorsements", provided it
    contains nothing but endorsements of your Modified Version by
    various parties--for example, statements of peer review or that
    the text has been approved by an organization as the authoritative
    definition of a standard.

    You may add a passage of up to five words as a Front-Cover
    Text, and a passage of up to 25 words as a Back-Cover Text, to the
    end of the list of Cover Texts in the Modified Version.  Only one
    passage of Front-Cover Text and one of Back-Cover Text may be
    added by (or through arrangements made by) any one entity.  If the
    Document already includes a cover text for the same cover,
    previously added by you or by arrangement made by the same entity
    you are acting on behalf of, you may not add another; but you may
    replace the old one, on explicit permission from the previous
    publisher that added the old one.

    The author(s) and publisher(s) of the Document do not by
    this License give permission to use their names for publicity for
    or to assert or imply endorsement of any Modified Version.

    5. COMBINING DOCUMENTS

    You may combine the Document with other documents released
    under this License, under the terms defined in section 4 above for
    modified versions, provided that you include in the combination
    all of the Invariant Sections of all of the original documents,
    unmodified, and list them all as Invariant Sections of your
    combined work in its license notice.

    The combined work need only contain one copy of this
    License, and multiple identical Invariant Sections may be replaced
    with a single copy.  If there are multiple Invariant Sections with
    the same name but different contents, make the title of each such
    section unique by adding at the end of it, in parentheses, the
    name of the original author or publisher of that section if known,
    or else a unique number.  Make the same adjustment to the section
    titles in the list of Invariant Sections in the license notice of
    the combined work.

    In the combination, you must combine any sections entitled
    "History" in the various original documents, forming one section
    entitled "History"; likewise combine any sections entitled
    "Acknowledgements", and any sections entitled "Dedications".  You
    must delete all sections entitled "Endorsements."

    6. COLLECTIONS OF DOCUMENTS

    You may make a collection consisting of the Document and
    other documents released under this License, and replace the
    individual copies of this License in the various documents with a
    single copy that is included in the collection, provided that you
    follow the rules of this License for verbatim copying of each of
    the documents in all other respects.

    You may extract a single document from such a collection,
    and distribute it individually under this License, provided you
    insert a copy of this License into the extracted document, and
    follow this License in all other respects regarding verbatim
    copying of that document.

    7. AGGREGATION WITH INDEPENDENT WORKS
    
    A compilation of the Document or its derivatives with other
    separate and independent documents or works, in or on a volume of
    a storage or distribution medium, does not as a whole count as a
    Modified Version of the Document, provided no compilation
    copyright is claimed for the compilation.  Such a compilation is
    called an "aggregate", and this License does not apply to the
    other self-contained works thus compiled with the Document, on
    account of their being thus compiled, if they are not themselves
    derivative works of the Document.

    If the Cover Text requirement of section 3 is applicable to
    these copies of the Document, then if the Document is less than
    one quarter of the entire aggregate, the Document's Cover Texts
    may be placed on covers that surround only the Document within the
    aggregate.  Otherwise they must appear on covers around the whole
    aggregate.

    8. TRANSLATION

    Translation is considered a kind of modification, so you may
    distribute translations of the Document under the terms of section
    4.  Replacing Invariant Sections with translations requires
    special permission from their copyright holders, but you may
    include translations of some or all Invariant Sections in addition
    to the original versions of these Invariant Sections.  You may
    include a translation of this License provided that you also
    include the original English version of this License.  In case of
    a disagreement between the translation and the original English
    version of this License, the original English version will
    prevail.

    9. TERMINATION
    
    You may not copy, modify, sublicense, or distribute the
    Document except as expressly provided for under this License.  Any
    other attempt to copy, modify, sublicense or distribute the
    Document is void, and will automatically terminate your rights
    under this License.  However, parties who have received copies, or
    rights, from you under this License will not have their licenses
    terminated so long as such parties remain in full
    compliance.

    10. FUTURE REVISIONS OF THIS LICENSE

    The Free Software Foundation may publish new, revised
    versions of the GNU Free Documentation License from time to time.
    Such new versions will be similar in spirit to the present
    version, but may differ in detail to address new problems or
    concerns.  See http://www.gnu.org/copyleft/.

    Each version of the License is given a distinguishing
    version number.  If the Document specifies that a particular
    numbered version of this License "or any later version" applies to
    it, you have the option of following the terms and conditions
    either of that specified version or of any later version that has
    been published (not as a draft) by the Free Software Foundation.
    If the Document does not specify a version number of this License,
    you may choose any version ever published (not as a draft) by the
    Free Software Foundation.

    How to use this License for your documents

    To use this License in a document you have written, include
    a copy of the License in the document and put the following
    copyright and license notices just after the title page:


      Copyright (c)  YEAR  YOUR NAME.
      Permission is granted to copy, distribute and/or modify this document
      under the terms of the GNU Free Documentation License, Version 1.1
      or any later version published by the Free Software Foundation;
      with the Invariant Sections being LIST THEIR TITLES, with the
      Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
      A copy of the license is included in the section entitled "GNU
      Free Documentation License".


    If you have no Invariant Sections, write "with no Invariant
    Sections" instead of saying which ones are invariant.  If you have
    no Front-Cover Texts, write "no Front-Cover Texts" instead of
    "Front-Cover Texts being LIST"; likewise for Back-Cover
    Texts.

    If your document contains nontrivial examples of program
    code, we recommend releasing these examples in parallel under your
    choice of free software license, such as the GNU General Public
    License, to permit their use in free software.
