Skip to content

Commit

Permalink
Merge pull request #2 from sinemetu1/test-separation
Browse files Browse the repository at this point in the history
maint - adding tests that mock curl calls, separating integration tests, updated README
  • Loading branch information
sinemetu1 committed Jan 2, 2015
2 parents c80ce74 + 6db31ff commit f95bcc7
Show file tree
Hide file tree
Showing 15 changed files with 524 additions and 192 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ stamp-h1
test-drive
src/test/test_reply
src/test/test_twitc
src/test/integration
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ before_install:
install: libtoolize && ./autogen.sh && ./configure
compiler:
- gcc
script: make check
script: make check && make check-valgrind
env:
global:
- TWITC_KEY=A TWITC_SECRET=B TWITC_ACCESS_TOKEN=C TWITC_ACCESS_SECRET=D
- CFLAGS="-I/home/travis/include -L/home/travis/lib"
after_failure:
- ls /home/travis/build/sinemetu1/twitc/src
- ls /home/travis/build/sinemetu1/twitc/src/test
- cat /home/travis/build/sinemetu1/twitc/src/test-suite.log
- cat /home/travis/build/sinemetu1/twitc/src/test/test_reply.log
- cat /home/travis/build/sinemetu1/twitc/src/test/test_twitc.log
Expand Down
6 changes: 6 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ dist_doc_DATA = README.md
ACLOCAL_AMFLAGS = -I m4

README: README.md

integration:
cd src; make integration;

check-valgrind:
cd src; make check-valgrind;
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ A mini C library for interacting with the Twitter OAuth api.

### Installation:


./autogen.sh
./configure
make
make install

NOTE: There are environment variables that can be set for consumer token,
consumer secret, app token, and app secret. See
[twitc.h](https://github.com/sinemetu1/twitc/blob/master/src/twitc.h).
[twitc.h](https://github.com/sinemetu1/twitc/blob/master/src/twitc.h)
and the [usage section](https://github.com/sinemetu1/twitc/tree/test-separation#usage) below.

#### Dependencies:

Expand All @@ -29,21 +29,26 @@ See [main.c](https://github.com/sinemetu1/twitc/blob/master/src/main.c) for an e

Environment variables include:

TWITC_KEY
TWITC_SECRET
TWITC_ACCESS_TOKEN
TWITC_ACCESS_SECRET
export TWITC_KEY="Consumer Key (API Key)"
export TWITC_SECRET="Consumer Secret (API Secret)"
export TWITC_ACCESS_TOKEN="Access Token"
export TWITC_ACCESS_SECRET="Access Token Secret"

To generate these values go to
[https://apps.twitter.com/](https://apps.twitter.com/).

### Tests:

Tests can be run with `make check` if you have the environment variables above
setup correctly and uncommenting test calls in `twitc_all_tests` in
[src/test/test_twitc.c](https://github.com/sinemetu1/twitc/blob/master/src/test/test_twitc.c)
will help you debug any issues.
Local tests can be run with `make check`.

If you have the environment variables above setup correctly then
you can run `make integration` to test actual integration with
Twitter's API.

### Bugs:

Please file bugs in Github issues.

### License:

[MIT](https://github.com/sinemetu1/twitc/blob/test-separation/LICENSE)
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ AC_SUBST([CFLAGS])

AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CC_C99
AM_PROG_AR
AC_LANG([C])
LT_INIT
Expand Down
36 changes: 24 additions & 12 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,39 @@ AUTOMAKE_OPTIONS = subdir-objects
TWITC_H = \
twitc_reply.h \
twitc.h

TWITC_C = \
twitc_reply.c \
twitc.c

bin_PROGRAMS = twitc
include_HEADERS = $(TWITC_H)
twitc_SOURCES = main.c $(TWITC_H) $(TWITC_C)
TEST_TWITC_H = \
test/test.h

lib_LIBRARIES = libtwitc.a
include_HEADERS = $(TWITC_H)
lib_LIBRARIES = libtwitc.a
libtwitc_a_SOURCES = $(TWITC_H) $(TWITC_C)

SUBDIRS = test

check_PROGRAMS = \
test/test_reply \
test/test_twitc
test/test_twitc \
test/test_reply

TESTS = $(check_PROGRAMS)

test_test_reply_CFLAGS = $(AM_CFLAGS)
test_test_reply_SOURCES = test/test_reply.c
test_test_reply_LDADD = $(lib_LIBRARIES)
test_test_reply_CFLAGS = -DTEST_TWITC $(CFLAGS) $(AM_CFLAGS)
test_test_reply_SOURCES = $(TEST_TWITC_H) $(TWITC_H) $(TWITC_C) test/test_reply.c

test_test_twitc_CFLAGS = -DTEST_TWITC $(CFLAGS) $(AM_CFLAGS)
test_test_twitc_SOURCES = $(TEST_TWITC_H) $(TWITC_H) $(TWITC_C) test/test_twitc.c

EXTRA_PROGRAMS = test/integration
test_integration_CFLAGS = $(CFLAGS) $(AM_CFLAGS)
test_integration_SOURCES = $(TWITC_H) $(TWITC_C) test/test_twitc_integration.c

check-valgrind:
valgrind --leak-check=full --track-origins=yes test/test_twitc
valgrind --leak-check=full --track-origins=yes test/test_reply

test_test_twitc_CFLAGS = $(AM_CFLAGS)
test_test_twitc_SOURCES = test/test_twitc.c
test_test_twitc_LDADD = $(lib_LIBRARIES)
integration: test/integration
test/integration
55 changes: 44 additions & 11 deletions src/test/minunit.h
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
/* file: minunit.h */
/* taken from http://www.jera.com/techinfo/jtns/jtn002.html#Source_Code */
/* file: minunit.h
* taken and modified from http://www.jera.com/techinfo/jtns/jtn002.html#Source_Code
*/

#include <stdlib.h>
#include <stdarg.h>

#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
#define mu_run_test(file, line, func, test) do { \
char *message = test(); \
int ret_length = 1024; \
char *toRet = malloc(ret_length); \
memset(toRet, 0, ret_length); \
tests_run++; \
if (message) { \

#define mu_run_test(file, line, func, test) do { \
char *message = test(); \
tests_run++; \
if (message) { \
int ret_length = 1024; \
char *toRet = malloc(ret_length); \
memset(toRet, 0, ret_length); \
sprintf(toRet, "Failed %s at line %d: %s", __FILE__, __LINE__, message); \
return toRet; \
} \
return toRet; \
} \
} while (0)

/**
* Tests actual for equality with processed string.
*/
#define mu_assert_str(message, actual, format, ...) do { \
char local[BUFSIZ] = ""; \
snprintf(local, sizeof(local), format, __VA_ARGS__);\
int cmp = strcmp(local, actual); \
if (cmp != 0) { \
printf("%s != %s\n", local, actual); \
return message; \
} \
} while (0)

/**
* Tests actual for containment of processed string.
*/
#define mu_assert_strcspn(message, actual, format, ...) do {\
char local[BUFSIZ] = ""; \
snprintf(local, BUFSIZ, format, __VA_ARGS__); \
char *cmp = strstr(actual, local); \
if (cmp == NULL) { \
printf("didn't find %s in actual\n", local); \
printf("actual: %s\n", actual); \
return message; \
} \
} while (0)

extern int tests_run;
66 changes: 66 additions & 0 deletions src/test/test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @file test.h
* @author Sam Garrett <samdgarrett@gmail.com>
*/
#ifndef TEST_TWITC_H
#define TEST_TWITC_H

#include <curl/curl.h>

void print_tracked_params(void);
void free_tracked_params(void);

/**
* NOTE: will not work if using in multi-threaded tests
* because of global vars below.
*/
#define test_curl_easy_setopt(handle, option, paremeter, track) do { \
curl_easy_setopt(handle, option, paremeter); \
int length = strlen(paremeter) + 1; \
if (track == NULL) { \
track = malloc(length); \
if (track == NULL) { \
fprintf(stderr, "not enough memory (malloc returned NULL)\n"); \
exit(1); \
} \
} else { \
track = realloc(track, length); \
if (track == NULL) { \
fprintf(stderr, "not enough memory (realloc returned NULL)\n");\
exit(1); \
} \
} \
snprintf(track, length, "%s", paremeter); \
} while (0)

/**
* Can't really have a drop-in replacement for curl_easy_perform
* since it's return value is used, thus this one with an extra param.
*/
#define test_curl_easy_perform(handle, curl_res) do { \
test_curl_perform_called++; \
curl_res = CURLE_OK; \
} while (0)

int test_curl_perform_called = 0;
char *test_curl_url;
char *test_curl_post_data;
char *test_curl_header;

void
print_tracked_params(void)
{
printf("perform_called: %d\ncalled_url: %s\nposted_data: %s\ntest_curl_header: %s\n",
test_curl_perform_called, test_curl_url, test_curl_post_data,
test_curl_header);
}

void
free_tracked_params(void)
{
if (test_curl_url) { free(test_curl_url); }
if (test_curl_post_data) { free(test_curl_post_data); }
if (test_curl_header) { free(test_curl_header); }
}

#endif
83 changes: 52 additions & 31 deletions src/test/test_reply.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* basic tests for reply */
/* basic tests for twitc_reply */

#include <stdio.h>
#include <stdlib.h>
Expand All @@ -8,9 +8,10 @@

int tests_run = 0;

char *test_twitc_parse_json(void);
char *test_twitc_reply_has_error(void);
char *reply_all_tests(void);
char * test_twitc_parse_json(void);
char * test_twitc_reply_has_error(void);
char * test_twitc_reply_has_error_true(void);
char * reply_all_tests(void);

int
main(void)
Expand All @@ -26,53 +27,73 @@ main(void)
return result != 0;
}

char
*test_twitc_parse_json(void)
char *
reply_all_tests(void)
{
mu_run_test(__FILE__, __LINE__, __func__, test_twitc_parse_json);
mu_run_test(__FILE__, __LINE__, __func__, test_twitc_reply_has_error);
mu_run_test(__FILE__, __LINE__, __func__, test_twitc_reply_has_error_true);
return 0;
}

char *
test_twitc_parse_json(void)
{
printf("\nChecking test_twitc_parse_json...\n\n");

const char* author = "John Cage";
char contents[BUFSIZ];
const char *author = "John Cage";
char *reply_format = "{ \"%s\": { \"%s\": \"%s\" } }";
char contents[BUFSIZ] = "";
char *json;
int doesnt_have_error = 1;

sprintf(contents, "{ \"%s\": { \"%s\": \"%s\" } }",
snprintf(contents, sizeof(contents), reply_format,
TWITC_REPLY_USER_KEY, TWITC_REPLY_SN_KEY, author);
json = twitc_parse_json_author((void *)contents);

mu_assert("should parse json", json);
json = twitc_parse_json_author(contents);
mu_assert_str("should parse json", json, "%s", author);

doesnt_have_error = twitc_reply_has_error(contents);
mu_assert("should NOT indicate error for json", doesnt_have_error == 0);

if (json) { free(json); }

return 0;
}

char
*test_twitc_reply_has_error(void)
char *
test_twitc_reply_has_error(void)
{
printf("\nChecking twitc_reply_has_error...\n\n");

char contents[BUFSIZ];
int has_error;
int doesnt_have_error;
const char *author = "John Cage";
char *reply_format = "{ \"%s\": { \"%s\": \"%s\" } }";
char contents[BUFSIZ] = "";
int doesnt_have_error = 1;

sprintf(contents, "{ \"%s\": { \"%s\": \"an error occurred\" } }",
TWITC_REPLY_ERRORS, TWITC_REPLY_ERRORS_MESSAGE);

has_error = twitc_reply_has_error((void *)contents);
mu_assert("should indicate error for error json", has_error == 1);

// negative check, no error
sprintf(contents, "{ \"%s\": { \"%s\": \"John Cage\" } }",
TWITC_REPLY_USER_KEY, TWITC_REPLY_SN_KEY);
snprintf(contents, sizeof(contents), reply_format,
TWITC_REPLY_USER_KEY, TWITC_REPLY_SN_KEY, author);

doesnt_have_error = twitc_reply_has_error((void *)contents);
mu_assert("should indicate error for error json", doesnt_have_error == 0);
doesnt_have_error = twitc_reply_has_error(contents);
mu_assert("should NOT indicate error for json", doesnt_have_error == 0);

return 0;
}

char
*reply_all_tests(void)
char *
test_twitc_reply_has_error_true(void)
{
mu_run_test(__FILE__, __LINE__, __func__, test_twitc_parse_json);
mu_run_test(__FILE__, __LINE__, __func__, test_twitc_reply_has_error);
printf("\nChecking test_twitc_reply_has_error_true...\n\n");

char *reply_format = "{ \"%s\": \"\" }";
char contents[BUFSIZ] = "";
int has_error = 0;

snprintf(contents, sizeof(contents), reply_format,
TWITC_REPLY_ERRORS);

has_error = twitc_reply_has_error(contents);
mu_assert("should indicate error for error json", has_error == 1);

return 0;
}
Loading

0 comments on commit f95bcc7

Please sign in to comment.