Last active
January 2, 2016 10:39
-
-
Save edusantana/8291576 to your computer and use it in GitHub Desktop.
C Arquivo Learning Test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <assert.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <stdlib.h> | |
/* | |
* O último padrão adotado para a Linguagem C foi publicado | |
* pela ISO em 12/8/2011 no documento: ISO/IEC 9899:2011. | |
* Você pode consultar gratuitamente a última versão pública | |
* do documento em: | |
* http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf | |
* | |
* Fonte: http://www.open-std.org/jtc1/sc22/wg14/www/standards.html | |
*/ | |
void fechaArquivoSeNecessario(FILE* arquivo) { | |
if (arquivo != NULL) { | |
fclose(arquivo); | |
} | |
} | |
bool verificaAquivoExiste(char* nomeDoArquivo) { | |
/* 7.21.5.3 The fopen function | |
Opening a file with read mode ('r' as the first character in the mode argument) fails if the file does not exist or cannot be read. | |
*/ | |
FILE* arquivo = fopen(nomeDoArquivo, "r"); | |
fechaArquivoSeNecessario(arquivo); | |
return arquivo != NULL; | |
} | |
void testVerificaAquivoExiste() { | |
assert(verificaAquivoExiste("arquivos_test.c")); | |
assert(!verificaAquivoExiste("arquivo_inexistente.txt")); | |
} | |
void verificaStringIguais(char* stringA, char* stringB) { | |
assert(strcmp(stringA, stringB) == 0); | |
} | |
bool finalDoArquivoOuErro(FILE* arquivo) { | |
// chegou ao fim do arquivo ou erro ao acessar o arquivo | |
return feof(arquivo) || ferror(arquivo); | |
} | |
bool arquivoAbertoComSucesso(FILE* arquivo) { | |
return arquivo != NULL; | |
} | |
int lerTamanhoDoArquivo(FILE* arquivo) { | |
fseek(arquivo, 0, SEEK_END); // vai para o final do arquivo | |
int tamanho = ftell(arquivo); // pega posição atual (final) | |
fseek(arquivo, 0, SEEK_SET); // volta para o início | |
return tamanho; | |
} | |
char* lerConteudoDeArquivoArberto(FILE* arquivo) { | |
int tamanhoDoArquivo = lerTamanhoDoArquivo(arquivo); | |
char* conteudo = malloc(tamanhoDoArquivo + 1); // 7.22.3.4 The malloc function | |
fread(conteudo, tamanhoDoArquivo, 1, arquivo); // 7.21.8.1 The fread function | |
return conteudo; | |
} | |
char* lerConteudoDoArquivo(char* nomeDoArquivo) { | |
char* conteudo; | |
FILE* arquivo = fopen(nomeDoArquivo, "r"); | |
if (arquivoAbertoComSucesso(arquivo)) { | |
conteudo = lerConteudoDeArquivoArberto(arquivo); | |
fclose(arquivo); // fecha arquivo | |
} else { | |
conteudo = NULL; | |
} | |
return conteudo; | |
} | |
char* vogais = "aeiou\n"; | |
char* ARQUIVO_VOGAIS = "vogais.txt"; | |
void testLerConteudoDeArquivo() { | |
assert(verificaAquivoExiste(ARQUIVO_VOGAIS)); // pré-condição | |
char* conteudo = lerConteudoDoArquivo(ARQUIVO_VOGAIS); | |
verificaStringIguais(conteudo, vogais); | |
} | |
FILE *fluxoDeSaida; | |
FILE* saida() { | |
return fluxoDeSaida == NULL ? stdout : fluxoDeSaida; | |
} | |
void imprimeMensagem(char* mensagem) { | |
fprintf(saida(), "%s", mensagem); | |
} | |
FILE * criarArquivoTemporario(){ | |
return tmpfile(); | |
} | |
void substituiFluxoDeSaida() { | |
/* http://c-faq.com/stdio/undofreopen.html */ | |
// cria um arquivo temporario e salva | |
// ponteiro do arquivo em fluxoDeSaida | |
fluxoDeSaida = criarArquivoTemporario(); | |
} | |
void restauraFluxoDeSaida() { | |
fclose(fluxoDeSaida); | |
fluxoDeSaida = NULL; | |
} | |
char* lerMensagemEscritaNoFluxoDeSaida() { | |
return lerConteudoDeArquivoArberto(saida()); | |
} | |
void verificaQueMensagemFoiImpressa(char* mensagem) { | |
char* mensagemEscrita = lerMensagemEscritaNoFluxoDeSaida(); | |
verificaStringIguais(mensagemEscrita, mensagem); | |
} | |
void testVerificaImpressaoDeMensagem() { | |
substituiFluxoDeSaida(); | |
char* mensagem = "oi!"; | |
imprimeMensagem(mensagem); | |
verificaQueMensagemFoiImpressa(mensagem); | |
restauraFluxoDeSaida(); | |
} | |
#define TAMANHO_DO_NOME 255 | |
typedef struct jogador_registro{ | |
char nome_tamanho_fixo[TAMANHO_DO_NOME]; | |
int pontuacao; | |
} Jogador ; | |
typedef struct jogador_com_ponteiro{ | |
char* nome; | |
int pontuacao; | |
} JogadorNomeComPonteiro; | |
Jogador* criaUmRegistroJogador(){ | |
Jogador* jogador = calloc(1, sizeof(Jogador)); | |
jogador->pontuacao = rand(); // 7.22.2.1 The rand function | |
strcpy(jogador->nome_tamanho_fixo, "Nome qualquer aqui"); | |
return jogador; | |
} | |
char* nomeQualquer = "Nome qualquer"; | |
JogadorNomeComPonteiro* criaUmRegistroJogadorNomeComPonteiro(){ | |
JogadorNomeComPonteiro* jogador = calloc(1, sizeof(JogadorNomeComPonteiro)); | |
jogador->pontuacao = rand(); // 7.22.2.1 The rand function | |
jogador->nome = nomeQualquer; | |
return jogador; | |
} | |
const int QUANTIDADE_DE_REGISTROS = 1; | |
FILE* salvaRegistroJogadorEmArquivo(Jogador *jogador){ | |
FILE * arquivo = criarArquivoTemporario(); | |
fwrite(jogador, sizeof(Jogador), QUANTIDADE_DE_REGISTROS, arquivo); | |
fflush(arquivo); | |
return arquivo; | |
} | |
void escreveTamanhoDoNome(JogadorNomeComPonteiro *jogador, FILE* arquivo){ | |
int tamanho = strlen(jogador->nome); | |
fwrite(&tamanho, sizeof(int), 1, arquivo); | |
} | |
void escreveStringNome(JogadorNomeComPonteiro *jogador, FILE* arquivo){ | |
fwrite(jogador->nome, sizeof(char), strlen(jogador->nome), arquivo); | |
} | |
void escrevePontuacao(JogadorNomeComPonteiro *jogador, FILE* arquivo){ | |
fwrite(&jogador->pontuacao, sizeof(jogador->pontuacao), 1, arquivo); | |
} | |
FILE* salvaRegistroJogadorNomeComPonteiroEmArquivo(JogadorNomeComPonteiro *jogador){ | |
FILE * arquivo = criarArquivoTemporario(); | |
escreveTamanhoDoNome(jogador, arquivo); | |
escreveStringNome(jogador, arquivo); | |
escrevePontuacao(jogador, arquivo); | |
return arquivo; | |
} | |
Jogador* lerJogadorDeArquivo(FILE* arquivo){ | |
Jogador* jogador = calloc(1, sizeof(Jogador)); | |
fseek(arquivo, 0, SEEK_SET); // volta para o início | |
fread(jogador, sizeof(Jogador), QUANTIDADE_DE_REGISTROS, arquivo); | |
return jogador; | |
} | |
void atualizaNome(JogadorNomeComPonteiro *jogador, FILE* arquivo){ | |
int tamanhoDoNome; | |
fread(&tamanhoDoNome, sizeof(int), 1, arquivo); | |
jogador->nome = calloc(sizeof(char), tamanhoDoNome+1); // +1 para o \0 | |
fread(jogador->nome, sizeof(char), tamanhoDoNome, arquivo); | |
} | |
void atualizaPontuacao(JogadorNomeComPonteiro *jogador, FILE* arquivo){ | |
fread(&jogador->pontuacao, sizeof(int), 1, arquivo); | |
} | |
JogadorNomeComPonteiro* lerJogadorNomeComPonteiroDeArquivo(FILE* arquivo){ | |
fseek(arquivo, 0, SEEK_SET); // volta para o início | |
JogadorNomeComPonteiro* jogador = calloc(1, sizeof(Jogador)); | |
atualizaNome(jogador, arquivo); | |
atualizaPontuacao(jogador, arquivo); | |
return jogador; | |
} | |
void verificaQueRegistrosPossuemOMesmoConteudo(Jogador* jogador, Jogador* jogadorLidoDoArquivo){ | |
// verifica que apontam para posições diferentes | |
assert(jogador!=jogadorLidoDoArquivo); | |
assert(jogador->pontuacao == jogadorLidoDoArquivo->pontuacao); | |
verificaStringIguais(jogador->nome_tamanho_fixo, jogadorLidoDoArquivo->nome_tamanho_fixo); | |
} | |
void verificaQueRegistrosJogadorNomeComPonteiroPossuemOMesmoConteudo(JogadorNomeComPonteiro* jogador, JogadorNomeComPonteiro* jogadorLidoDoArquivo){ | |
assert(jogador!=jogadorLidoDoArquivo); | |
assert(jogador->pontuacao == jogadorLidoDoArquivo->pontuacao); | |
verificaStringIguais(jogador->nome, jogadorLidoDoArquivo->nome); | |
} | |
void testSalvaERecuperaRegistroDeTamanhoFixoEmArquivo(){ | |
Jogador* jogador = criaUmRegistroJogador(); | |
assert(sizeof(jogador->nome_tamanho_fixo) == TAMANHO_DO_NOME); | |
FILE* arquivo = salvaRegistroJogadorEmArquivo(jogador); | |
Jogador* jogadorLidoDoArquivo = lerJogadorDeArquivo(arquivo); | |
verificaQueRegistrosPossuemOMesmoConteudo(jogador, jogadorLidoDoArquivo); | |
fechaArquivoSeNecessario(arquivo); | |
free(jogador); | |
free(jogadorLidoDoArquivo); | |
} | |
void testSalvaERecuperaRegistroTamanhoVariavel(){ | |
JogadorNomeComPonteiro* jogador = criaUmRegistroJogadorNomeComPonteiro(); | |
FILE* arquivo = salvaRegistroJogadorNomeComPonteiroEmArquivo(jogador); | |
JogadorNomeComPonteiro* jogadorLidoDoArquivo = lerJogadorNomeComPonteiroDeArquivo(arquivo); | |
verificaQueRegistrosJogadorNomeComPonteiroPossuemOMesmoConteudo(jogador, jogadorLidoDoArquivo); | |
fechaArquivoSeNecessario(arquivo); | |
free(jogador); | |
free(jogadorLidoDoArquivo); | |
} | |
void apagaArquivoSeExistir(char* nomeDoArquivo){ | |
remove(nomeDoArquivo); | |
assert(!verificaAquivoExiste(nomeDoArquivo)); | |
} | |
char* CONTEUDO_ORIGINAL = "CONTEUDO-ORIGINAL com quebra de linha\n"; | |
void criaArquivoComConteudo(char* nomeDoArquivo){ | |
FILE* arquivo = fopen(nomeDoArquivo, "w"); | |
fputs(CONTEUDO_ORIGINAL, arquivo); | |
fclose(arquivo); | |
} | |
void abreArquivoModoAppendAdicionaMensagem(char* nomeDoArquivo, char* mensagem){ | |
FILE* arquivo = fopen(nomeDoArquivo, "a"); // modo append | |
fputs(mensagem, arquivo); | |
fclose(arquivo); | |
} | |
int TAMANHO_MAXIMO_DA_LINHA = 1024; | |
void verificaQueMensagemFoiAdicionadaAoFinalDoArquivo(char* nomeDoArquivo, char* mensagem){ | |
FILE* arquivo = fopen(nomeDoArquivo, "r"); | |
char* primeiraLinha = calloc(TAMANHO_MAXIMO_DA_LINHA, sizeof(char)); | |
char* segundaLinha = calloc(TAMANHO_MAXIMO_DA_LINHA, sizeof(char)); | |
fgets(primeiraLinha, TAMANHO_MAXIMO_DA_LINHA, arquivo); | |
fgets(segundaLinha, TAMANHO_MAXIMO_DA_LINHA, arquivo); | |
verificaStringIguais(primeiraLinha, CONTEUDO_ORIGINAL); | |
verificaStringIguais(segundaLinha, mensagem); | |
} | |
char* NOME_DO_ARQUIVO = "meu-arquivo.txt"; | |
char* MENSAGEM = "mensagem-qualquer com quebra de linha\n"; | |
void testAdicionarConteudoEmArquivo(){ | |
apagaArquivoSeExistir(NOME_DO_ARQUIVO); | |
criaArquivoComConteudo(NOME_DO_ARQUIVO); | |
abreArquivoModoAppendAdicionaMensagem(NOME_DO_ARQUIVO, MENSAGEM); | |
verificaQueMensagemFoiAdicionadaAoFinalDoArquivo(NOME_DO_ARQUIVO, MENSAGEM); | |
} | |
void criaArquivoEscreveDoisNumerosSeparadosPorEspaco ( | |
char* nomeDoArquivo, int primeiroNumero, int segundoNumero){ | |
FILE* arquivo = fopen(nomeDoArquivo, "w"); | |
fprintf(arquivo, "%d %d",primeiroNumero, segundoNumero); | |
fclose(arquivo); | |
} | |
void lerDeArquivoDoisNumerosSeparadosPorEspaco( | |
char* nomeDoArquivo, int *primeiroValor, int *segundoValor){ | |
FILE *arquivo = fopen(nomeDoArquivo, "r"); | |
fscanf(arquivo, "%d %d", primeiroValor, segundoValor); | |
fclose(arquivo); | |
} | |
void verificaQueNumerosEscritosSaoIguaisAosLidos( | |
int primeiroNumero,int segundoNumero,int primeiroValor,int segundoValor){ | |
assert(primeiroNumero==primeiroValor); | |
assert(segundoNumero==segundoValor); | |
} | |
void testEscrevendoConteudoFormatado(){ | |
char* nomeDoArquivo = "numeros.txt"; | |
int primeiroNumero = rand(); | |
int segundoNumero = rand(); | |
criaArquivoEscreveDoisNumerosSeparadosPorEspaco(nomeDoArquivo,primeiroNumero, segundoNumero); | |
int primeiroValor; | |
int segundoValor; | |
lerDeArquivoDoisNumerosSeparadosPorEspaco(nomeDoArquivo,&primeiroValor, &segundoValor); | |
verificaQueNumerosEscritosSaoIguaisAosLidos(primeiroNumero,segundoNumero,primeiroValor,segundoValor); | |
apagaArquivoSeExistir(nomeDoArquivo); | |
} | |
int main() { | |
testVerificaAquivoExiste(); | |
testLerConteudoDeArquivo(); | |
testVerificaImpressaoDeMensagem(); | |
// Arquivos com Registros | |
testSalvaERecuperaRegistroDeTamanhoFixoEmArquivo(); | |
testSalvaERecuperaRegistroTamanhoVariavel(); | |
testAdicionarConteudoEmArquivo(); | |
testEscrevendoConteudoFormatado(); | |
return 0; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CC=gcc | |
CFLAGS=-Wall -g -std=c1x | |
all: arquivos_test | |
arquivos_test: arquivos_test.c | |
$(CC) $(CFLAGS) arquivos_test.c -o arquivos_test | |
test_all: | |
./arquivos_test | |
clean: | |
rm -rf arquivos_test | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
aeiou |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Este gist é o meu Learning Test sobre Arquivos em C.
O Learning Test tem um propósito diferente dos testes unitários ou de integração. Seu propósito é registrar o conhecimento sobre conteúdos específicos que você está estudando.
O teste escrito desta forma deixa claro qual o resultado esperado para as funções, além de mostrar como elas interagem entre si.
A leitura deste arquivo de teste se inicia na função
main()
, então seguimos o fluxo das funções que são executadas.