PageRenderTime 71ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/esi/test/test.c

http://mongrel-esi.googlecode.com/
C | 645 lines | 485 code | 123 blank | 37 comment | 54 complexity | 78164c348ee5fa2297ce058108722328 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <regex.h>
  7. #include <fcntl.h>
  8. #include <unistd.h> /* for write */
  9. #define DEBUG
  10. #include "parser.h"
  11. #ifdef DEBUG
  12. #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__)
  13. #else
  14. #define TRACE()
  15. #endif
  16. /*
  17. * TagInfo is used for collecting tags and asserting we have generated the correct tag names
  18. */
  19. typedef struct _TagInfo {
  20. char *name;
  21. ESIAttribute *attributes;
  22. struct _TagInfo *next;
  23. }TagInfo;
  24. static
  25. TagInfo* tag_info_new( const char *name, size_t len, ESIAttribute *attributes )
  26. {
  27. TagInfo *ti = (TagInfo*)malloc(sizeof(TagInfo));
  28. ti->name = esi_strndup( name, len );
  29. ti->attributes = esi_attribute_copy( attributes );
  30. ti->next = NULL;
  31. return ti;
  32. }
  33. static
  34. void tag_info_show( TagInfo *ti )
  35. {
  36. char buffer1[1024], buffer2[1024];
  37. ESIAttribute *attrs = ti->attributes;
  38. if( attrs ) {
  39. printf("%s{", ti->name );
  40. while( attrs ) {
  41. memcpy( buffer1, attrs->name, attrs->name_length );
  42. buffer1[attrs->name_length] = '\0';
  43. memcpy( buffer2, attrs->value, attrs->value_length );
  44. buffer2[attrs->value_length] = '\0';
  45. printf( "(%s=>%s),", buffer1, buffer2 );
  46. attrs = attrs->next;
  47. }
  48. printf("}\n");
  49. }
  50. else {
  51. printf("%s\n", ti->name );
  52. }
  53. }
  54. static
  55. void tag_info_free( TagInfo *ti )
  56. {
  57. TagInfo *ptr = NULL;
  58. while( ti ){
  59. free( ti->name );
  60. if( ti->attributes ) esi_attribute_free( ti->attributes );
  61. ptr = ti->next; /* save the next pointer */
  62. free( ti );
  63. ti = ptr;
  64. }
  65. }
  66. static int verify_string( const char *str, const char *str_value, int line, const char *test_name )
  67. {
  68. int str_len = strlen( str );
  69. int str_value_length = strlen( str_value );
  70. if( str_len != str_value_length || strcmp( str, str_value ) ){
  71. printf( "Strings are not equal\n\t\"%s\":%d\n!=\t\n\"%s\":%d\nat\n%s:%d\n", str, str_len, str_value, str_value_length, test_name, line );
  72. return 1;
  73. }
  74. return 0;
  75. }
  76. static int verify_match_string( const char *expr, const char *str_value, int line, const char *test_name )
  77. {
  78. int status;
  79. regex_t reg_expr;
  80. regcomp( &reg_expr, expr, REG_EXTENDED|REG_NOSUB );
  81. status = regexec( &reg_expr, str_value, (size_t) 0, NULL, 0 );
  82. regfree( &reg_expr );
  83. if( status != 0 ){
  84. printf( "No matching %s expression found in '%s' at %s:%d \n", expr, str_value, test_name, line );
  85. return 1;
  86. }
  87. return 0;
  88. }
  89. static int verify_no_match_string( const char *expr, const char *str_value, int line, const char *test_name )
  90. {
  91. int status;
  92. regex_t reg_expr;
  93. regcomp( &reg_expr, expr, REG_EXTENDED|REG_NOSUB );
  94. status = regexec( &reg_expr, str_value, (size_t) 0, NULL, 0 );
  95. regfree( &reg_expr );
  96. if( status == 0 ){
  97. printf( "Found matching %s expression found in '%s' at %s:%d ", expr, str_value, test_name, line );
  98. return 1;
  99. }
  100. return 0;
  101. }
  102. static int verify_true( int expr, int line, const char *test_name )
  103. {
  104. if( !expr ){
  105. printf( "Expression is not true at %s:%d\n", test_name, line );
  106. return 1;
  107. }
  108. return 0;
  109. }
  110. static int start_tag_count = 0;
  111. static int end_tag_count = 0;
  112. static TagInfo *detected_start_tags = NULL; /* store parsed start tags from each test */
  113. static TagInfo *detected_end_tags = NULL; /* store parsed end tags from each test */
  114. static
  115. TagInfo *add_detected_tag( TagInfo *tags, TagInfo *ti )
  116. {
  117. if( tags ){
  118. TagInfo *next = tags;
  119. TagInfo *prev = NULL;
  120. while( next ){
  121. prev = next;
  122. next = next->next;
  123. }
  124. prev->next = ti;
  125. }
  126. else{
  127. tags = ti;
  128. }
  129. return tags;
  130. }
  131. static
  132. void free_detected_tags()
  133. {
  134. if( detected_start_tags ){
  135. tag_info_free( detected_start_tags );
  136. }
  137. if( detected_end_tags ){
  138. tag_info_free( detected_end_tags );
  139. }
  140. detected_end_tags = NULL;
  141. detected_start_tags = NULL;
  142. }
  143. static void start_tag_handler( const void *data,
  144. const char *name_start,
  145. size_t name_length,
  146. ESIAttribute *attributes,
  147. void *user_data )
  148. {
  149. ++start_tag_count;
  150. detected_start_tags = add_detected_tag( detected_start_tags, tag_info_new( name_start, name_length, attributes ) );
  151. }
  152. static void end_tag_handler( const void *data, const char *name_start, size_t name_length, void *user_data )
  153. {
  154. ++end_tag_count;
  155. detected_end_tags = add_detected_tag( detected_end_tags, tag_info_new( name_start, name_length, NULL ) );
  156. }
  157. static void output_handler( const void *data, size_t size, void *user_data )
  158. {
  159. write( (*(int*)user_data), data, size );
  160. }
  161. static void feed_data( ESIParser *parser, const char *data )
  162. {
  163. // printf( "feeding: %s\n", data );
  164. esi_parser_execute( parser, data, strlen(data) );
  165. }
  166. #define TEST_INIT \
  167. int fd; \
  168. struct stat st; \
  169. char *output = NULL; \
  170. size_t output_size; \
  171. int status = 0;\
  172. start_tag_count = 0; \
  173. end_tag_count = 0; \
  174. printf( "%s: ", __FUNCTION__ ); \
  175. esi_parser_init( parser ); \
  176. \
  177. esi_parser_start_tag_handler( parser, start_tag_handler ); \
  178. esi_parser_end_tag_handler( parser, end_tag_handler ); \
  179. \
  180. unlink( "output.html" ); \
  181. fd = open( "output.html", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); \
  182. parser->user_data = (void*)(&fd); \
  183. esi_parser_output_handler( parser, output_handler );
  184. #define TEST_WITH_FILE(file)\
  185. int size = 0;\
  186. FILE *input = NULL;\
  187. char buffer[4096]; \
  188. TEST_INIT\
  189. \
  190. input = fopen( file, "r" );\
  191. if( !input ){\
  192. printf( "Failed to open %s\n", file );\
  193. return;\
  194. }\
  195. \
  196. while( (size = fread( buffer, sizeof(char), 4095, input )) > 0 ){\
  197. esi_parser_execute( parser, buffer, size );\
  198. }\
  199. \
  200. fclose( input );
  201. #define TEST_PREPARE_ASSERTIONS \
  202. esi_parser_finish( parser ); \
  203. \
  204. close( fd ); \
  205. \
  206. fd = open( "output.html", O_RDONLY ); \
  207. fstat( fd, &st ); \
  208. output_size = st.st_size; \
  209. output = (char*)malloc(sizeof(char)*(output_size+1)); \
  210. read( fd, output, output_size ); \
  211. output[output_size] = '\0'; \
  212. close( fd ); \
  213. TagInfo *start_tags = detected_start_tags; \
  214. TagInfo *end_tags = detected_end_tags;
  215. #define TEST_FINISH\
  216. free( output ); \
  217. free_detected_tags(); \
  218. if( status ){ \
  219. printf( "FAILED\n" ); \
  220. }else{ \
  221. printf( "PASSED\n" ); \
  222. }
  223. #define ASSERT_EQUAL( s1, s2 )\
  224. status |= verify_string( s1, s2, __LINE__, __FUNCTION__ )
  225. #define ASSERT_MATCH( regex, str )\
  226. status |= verify_match_string( regex, str, __LINE__, __FUNCTION__ )
  227. #define ASSERT_NO_MATCH( regex, str )\
  228. status |= verify_no_match_string( regex, str, __LINE__, __FUNCTION__ )
  229. #define ASSERT_TRUE( expr )\
  230. status |= verify_true( expr, __LINE__, __FUNCTION__ )
  231. #define ASSERT_TAG_NAME( name )\
  232. ASSERT_NO_MATCH( "<", name ); \
  233. ASSERT_MATCH( "esi:", name );
  234. #define ASSERT_TAG_NAMES( tags )\
  235. while( tags ){ \
  236. ASSERT_TAG_NAME( tags->name );\
  237. tags = tags->next;\
  238. }
  239. static void test_simple_parser_input( ESIParser *parser )
  240. {
  241. TEST_INIT
  242. feed_data( parser, "<p>some input</p><esi:include />some more input\nsome input<esi:include timeout='10' src='hello'/>some more input" );
  243. TEST_PREPARE_ASSERTIONS
  244. ASSERT_EQUAL( "<p>some input</p>some more input\nsome inputsome more input", output );
  245. ASSERT_TRUE( start_tag_count == 2 );
  246. ASSERT_TRUE( end_tag_count == 2 );
  247. ASSERT_TAG_NAMES( start_tags )
  248. ASSERT_TAG_NAMES( end_tags )
  249. TEST_FINISH
  250. }
  251. static void test_small_buffer( ESIParser *parser )
  252. {
  253. const int input_size = 2;
  254. const char *input = "<p>some input</p><esi:include />some more input\nsome input<esi:include timeout='10' src='hello'/>some more input";
  255. int i, len = strlen(input);
  256. TEST_INIT
  257. // printf("\n");
  258. for( i = 0; i < len; i += input_size ) {
  259. if( i + input_size <= len ) {
  260. esi_parser_execute( parser, (input+i), input_size );
  261. }
  262. else {
  263. esi_parser_execute( parser, (input+i), len - i );
  264. }
  265. }
  266. TEST_PREPARE_ASSERTIONS
  267. ASSERT_EQUAL( "<p>some input</p>some more input\nsome inputsome more input", output );
  268. ASSERT_TRUE( start_tag_count == 2 );
  269. ASSERT_TRUE( end_tag_count == 2 );
  270. ASSERT_TAG_NAMES( start_tags )
  271. ASSERT_TAG_NAMES( end_tags )
  272. TEST_FINISH
  273. }
  274. static void test_chunked_input( ESIParser *parser )
  275. {
  276. TEST_INIT
  277. feed_data( parser, "some input<" );
  278. feed_data( parser, "e" );
  279. feed_data( parser, "s" );
  280. feed_data( parser, "i" );
  281. feed_data( parser, ":" );
  282. feed_data( parser, "i" );
  283. feed_data( parser, "n" );
  284. feed_data( parser, "lin" );
  285. feed_data( parser, "e" );
  286. feed_data( parser, " " );
  287. feed_data( parser, "s" );
  288. feed_data( parser, "rc" );
  289. feed_data( parser, "=" );
  290. feed_data( parser, "'hel" );
  291. feed_data( parser, "lo'" );
  292. feed_data( parser, "/" );
  293. feed_data( parser, ">some more input\nsome input" );
  294. feed_data( parser, "<esi:comment text=" );
  295. feed_data( parser, "'hello'/>some more input" );
  296. TEST_PREPARE_ASSERTIONS
  297. ASSERT_EQUAL( "some inputsome more input\nsome inputsome more input", output );
  298. ASSERT_TRUE( start_tag_count == 2 );
  299. ASSERT_TRUE( end_tag_count == 2 );
  300. ASSERT_TAG_NAMES( start_tags )
  301. ASSERT_TAG_NAMES( end_tags )
  302. TEST_FINISH
  303. }
  304. #define ESI_SAMPLE "../../../test/unit/esi-sample.html"
  305. static void test_sample_input( ESIParser *parser )
  306. {
  307. TEST_WITH_FILE( ESI_SAMPLE );
  308. TEST_PREPARE_ASSERTIONS
  309. ASSERT_MATCH(" <div class=\"body\">", output );
  310. ASSERT_MATCH(" <div>some content</div>", output);
  311. ASSERT_MATCH("<em>Support for em tags since they have an initial start sequence similar to and &lt;esi: start/end sequence</em>", output );
  312. ASSERT_NO_MATCH("<esi:", output);
  313. /*
  314. TagInfo *ptr = start_tags;
  315. while( ptr ){
  316. tag_info_show( ptr );
  317. ptr = ptr->next;
  318. }
  319. printf( "start_tag_count: %d\n", start_tag_count );
  320. printf( "end_tag_count: %d\n", end_tag_count );
  321. */
  322. ASSERT_TRUE( start_tag_count == 13 );
  323. ASSERT_TRUE( end_tag_count == 13 );
  324. ASSERT_TAG_NAMES( start_tags )
  325. ASSERT_TAG_NAMES( end_tags )
  326. TEST_FINISH
  327. }
  328. static void test_line_by_line( ESIParser *parser )
  329. {
  330. TEST_INIT
  331. feed_data( parser, "<html><head><body><esi:include timeout='1' max-age='600+600' src=\"hello\"/>some more input" );
  332. feed_data( parser, "some input<esi:include \nsrc='hello'/>some more input\nsome input<esi:include src=\"hello\"/>some more input" );
  333. feed_data( parser, "some input<esi:inline src='hello'/>some more input\nsome input<esi:comment text='hello'/>some more input" );
  334. feed_data( parser, "<p>some input</p><esi:include src='hello'/>some more input\nsome input<esi:include src='hello'/>some more input" );
  335. feed_data( parser, "</body></html>" );
  336. TEST_PREPARE_ASSERTIONS
  337. ASSERT_EQUAL("<html><head><body>some more inputsome inputsome more input\nsome inputsome more inputsome inputsome more input\nsome inputsome more input<p>some input</p>some more input\nsome inputsome more input</body></html>", output );
  338. ASSERT_TRUE( start_tag_count == 7 );
  339. ASSERT_TRUE( end_tag_count == 7 );
  340. ASSERT_TAG_NAMES( start_tags )
  341. ASSERT_TAG_NAMES( end_tags )
  342. TEST_FINISH
  343. }
  344. #define ESI_LARGE_FILE "../../../test/integration/docs/index.html"
  345. static void test_large_file( ESIParser *parser )
  346. {
  347. TEST_WITH_FILE( ESI_LARGE_FILE );
  348. TEST_PREPARE_ASSERTIONS
  349. ASSERT_NO_MATCH("<esi:", output);
  350. ASSERT_MATCH( "</html>", output );
  351. ASSERT_TAG_NAMES( start_tags )
  352. ASSERT_TAG_NAMES( end_tags )
  353. TEST_FINISH
  354. }
  355. static void test_sample1( ESIParser *parser )
  356. {
  357. TEST_WITH_FILE( "sample1.html" );
  358. TEST_PREPARE_ASSERTIONS
  359. // ASSERT_MATCH("YYY", output);
  360. //ASSERT_NO_MATCH("failed", output );
  361. ASSERT_NO_MATCH("<esi:", output);
  362. ASSERT_MATCH("<html", output);
  363. ASSERT_MATCH("</html>", output);
  364. ASSERT_MATCH("line 1: <pre>", output);
  365. ASSERT_MATCH("line 2: <pre>", output);
  366. ASSERT_MATCH("line 3: <pre>", output);
  367. ASSERT_MATCH("line 4: <pre>", output);
  368. ASSERT_MATCH("line 5: <pre>", output);
  369. ASSERT_MATCH("line 6: <pre>", output);
  370. ASSERT_MATCH("line 7: <pre>", output);
  371. ASSERT_MATCH("line 8: <pre>", output);
  372. ASSERT_MATCH("line 9: <pre>", output);
  373. /*
  374. TagInfo *ptr = start_tags;
  375. while( ptr ) {
  376. tag_info_show( ptr );
  377. ptr = ptr->next;
  378. }
  379. printf( "start_tag_count: %d\n", start_tag_count );
  380. printf( "end_tag_count: %d\n", end_tag_count );
  381. */
  382. ASSERT_TRUE( start_tag_count == 30 );
  383. ASSERT_TRUE( end_tag_count == 30 );
  384. ASSERT_TAG_NAMES( start_tags )
  385. ASSERT_TAG_NAMES( end_tags )
  386. TEST_FINISH
  387. }
  388. #if 0
  389. static void test_sample1_with_chunking( ESIParser *parser )
  390. {
  391. TEST_WITH_FILE( "sample1.html" );
  392. TEST_PREPARE_ASSERTIONS
  393. // ASSERT_MATCH("YYY", output);
  394. ASSERT_NO_MATCH("failed", output );
  395. ASSERT_NO_MATCH("<esi:", output);
  396. /*TagInfo *ptr = start_tags;
  397. while( ptr ) {
  398. tag_info_show( ptr );
  399. ptr = ptr->next;
  400. }
  401. printf( "start_tag_count: %d\n", start_tag_count );
  402. printf( "end_tag_count: %d\n", end_tag_count );
  403. */
  404. ASSERT_TRUE( start_tag_count == 23 );
  405. ASSERT_TRUE( end_tag_count == 16 );
  406. ASSERT_TAG_NAMES( start_tags )
  407. ASSERT_TAG_NAMES( end_tags )
  408. TEST_FINISH
  409. }
  410. #endif
  411. static void test_large_chunked_file( ESIParser *parser );
  412. static void test_large_with_two_chunks( ESIParser *parser );
  413. static void run_parser_through_all()
  414. {
  415. ESIParser *parser = esi_parser_new();
  416. printf( "%s\n", __FUNCTION__ );
  417. test_simple_parser_input( parser );
  418. test_small_buffer( parser );
  419. test_chunked_input( parser );
  420. test_sample_input( parser );
  421. test_line_by_line( parser );
  422. test_large_file( parser );
  423. test_large_chunked_file( parser );
  424. test_sample1( parser );
  425. test_large_with_two_chunks( parser );
  426. esi_parser_free( parser );
  427. }
  428. int main( int argc, char **argv )
  429. {
  430. run_parser_through_all();
  431. return 0;
  432. }
  433. static void test_large_with_two_chunks( ESIParser *parser )
  434. {
  435. int size1 = 0;
  436. int size2 = 0;
  437. FILE *input = NULL;
  438. char *chunk1 = NULL;
  439. char *chunk2 = NULL;
  440. TEST_INIT
  441. input = fopen( "chunk1.html", "rb" );
  442. if( !input ) {
  443. printf( "Failed to open %s\n", "chunk1.html" );
  444. return;
  445. }
  446. fstat( fileno(input), &st );
  447. chunk1 = (char*)malloc(sizeof(char)*st.st_size);
  448. size1 = fread( chunk1, sizeof(char), st.st_size, input );
  449. if( size1 != st.st_size ) {
  450. printf( "Read error\n" );
  451. return;
  452. }
  453. fclose(input);
  454. input = fopen( "chunk2.html", "rb" );
  455. if( !input ) {
  456. printf( "Failed to open %s\n", "chunk2.html" );
  457. return;
  458. }
  459. fstat( fileno(input), &st );
  460. chunk2 = (char*)malloc(sizeof(char)*st.st_size);
  461. size2 = fread( chunk2, sizeof(char), st.st_size, input );
  462. if( size2 != st.st_size ) {
  463. printf( "Read error\n" );
  464. return;
  465. }
  466. fclose(input);
  467. esi_parser_execute( parser, chunk1, size1 );
  468. esi_parser_execute( parser, chunk2, size2 );
  469. TEST_PREPARE_ASSERTIONS
  470. ASSERT_NO_MATCH("<esi:", output);
  471. ASSERT_MATCH( "</html>", output );
  472. ASSERT_TAG_NAMES( start_tags )
  473. ASSERT_TAG_NAMES( end_tags )
  474. TEST_FINISH
  475. }
  476. #define ESI_LARGE_FILE_CHUNKED "chunks.txt"
  477. static void test_large_chunked_file( ESIParser *parser )
  478. {
  479. int size = 0;
  480. FILE *input = NULL;
  481. char *buffer = NULL;
  482. char *chunk_start = NULL;
  483. char *chunk_end = NULL;
  484. char *buffer_end = NULL;
  485. TEST_INIT
  486. // printf( "\n" );
  487. input = fopen( ESI_LARGE_FILE_CHUNKED, "r" );
  488. if( !input ){
  489. printf( "Failed to open %s\n", ESI_LARGE_FILE_CHUNKED );
  490. return;
  491. }
  492. fstat( fileno(input), &st );
  493. buffer = (char*)malloc(sizeof(char)*st.st_size);
  494. size = fread( buffer, sizeof(char), st.st_size, input );
  495. if( size != st.st_size ) {
  496. printf( "Read error\n" );
  497. return;
  498. }
  499. buffer_end = buffer + size;
  500. for( chunk_start = buffer; chunk_start != buffer_end; ) {
  501. while( chunk_start != buffer_end && *chunk_start != '{' ) { ++chunk_start; }
  502. if( chunk_start == buffer_end ){ break; }
  503. chunk_end = chunk_start;
  504. while( chunk_end != buffer_end && *chunk_end != '}' ) { ++chunk_end; }
  505. ++chunk_start;
  506. if( chunk_start > buffer_end ){ break; }
  507. if( (chunk_end - chunk_start) > 0 ) {
  508. esi_parser_execute( parser, chunk_start, chunk_end - chunk_start );
  509. chunk_start = chunk_end;
  510. }
  511. }
  512. fclose( input );
  513. free( buffer );
  514. TEST_PREPARE_ASSERTIONS
  515. ASSERT_NO_MATCH("<esi:", output);
  516. ASSERT_MATCH( "</html>", output );
  517. ASSERT_TAG_NAMES( start_tags )
  518. ASSERT_TAG_NAMES( end_tags )
  519. TEST_FINISH
  520. }