test.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #define JIM_IMPLEMENTATION
  5. #include "./jim.h"
  6. #include "./test_expected.h"
  7. #define ARRAY_LEN(xs) (sizeof(xs) / sizeof((xs)[0]))
  8. typedef struct {
  9. size_t capacity;
  10. size_t size;
  11. char *data;
  12. } Buffer;
  13. void buffer_clean(Buffer *buffer)
  14. {
  15. buffer->size = 0;
  16. }
  17. size_t buffer_write(const void *ptr, size_t size, size_t nmemb,
  18. Buffer *sink)
  19. {
  20. size_t esize = size * nmemb; // effective size
  21. if (sink->size + esize <= sink->capacity) {
  22. memcpy(sink->data + sink->size,
  23. ptr,
  24. esize);
  25. sink->size += esize;
  26. return esize;
  27. } else {
  28. return 0;
  29. }
  30. }
  31. static char static_memory_for_buffer[1024];
  32. static Buffer buffer = {
  33. .capacity = sizeof(static_memory_for_buffer),
  34. .data = static_memory_for_buffer
  35. };
  36. void null_case(Jim *jim)
  37. {
  38. jim_array_begin(jim);
  39. jim_null(jim);
  40. jim_array_end(jim);
  41. }
  42. void bool_case(Jim *jim)
  43. {
  44. jim_array_begin(jim);
  45. jim_bool(jim, 0);
  46. jim_bool(jim, 1);
  47. jim_array_end(jim);
  48. }
  49. void integer_case(Jim *jim)
  50. {
  51. jim_array_begin(jim);
  52. for (int i = -10; i <= 10; ++i) {
  53. jim_integer(jim, i);
  54. }
  55. jim_array_end(jim);
  56. }
  57. void float_case(Jim *jim)
  58. {
  59. jim_array_begin(jim);
  60. jim_float(jim, 0.0, 4);
  61. jim_float(jim, -0.0, 4);
  62. jim_float(jim, 3.1415, 4);
  63. jim_float(jim, 2.71828, 5);
  64. jim_float(jim, 1.6180, 1);
  65. jim_float(jim, 0.0 / 0.0, 4);
  66. jim_float(jim, 1.0 / 0.0, 4);
  67. jim_float(jim, -1.0 / 0.0, 4);
  68. jim_array_end(jim);
  69. }
  70. void string_case(Jim *jim)
  71. {
  72. jim_array_begin(jim);
  73. jim_string(jim, "hello", NULL);
  74. jim_string(jim, "world", NULL);
  75. jim_string(jim, "\n\b\t", NULL);
  76. const unsigned int size = 4;
  77. jim_string(jim, "\0\0\0\0", &size);
  78. jim_array_end(jim);
  79. }
  80. void array_case(Jim *jim)
  81. {
  82. jim_array_begin(jim);
  83. for (int n = 1; n <= 5; ++n) {
  84. for (int i = 0; i < n; ++i) jim_array_begin(jim);
  85. for (int i = 0; i < n; ++i) jim_array_end(jim);
  86. }
  87. jim_array_end(jim);
  88. }
  89. void object_case_rec(Jim *jim, int level, int *counter)
  90. {
  91. if (level < 3) {
  92. jim_object_begin(jim);
  93. jim_member_key(jim, "l", NULL);
  94. object_case_rec(jim, level + 1, counter);
  95. jim_member_key(jim, "r", NULL);
  96. object_case_rec(jim, level + 1, counter);
  97. jim_object_end(jim);
  98. } else {
  99. jim_integer(jim, (*counter)++);
  100. }
  101. }
  102. void object_case(Jim *jim)
  103. {
  104. int counter = 0;
  105. object_case_rec(jim, 0, &counter);
  106. }
  107. typedef struct {
  108. const char *name;
  109. void (*run)(Jim *jim);
  110. } Test_Case;
  111. #define TEST_CASE(case_name) \
  112. { \
  113. .name = #case_name, \
  114. .run = case_name \
  115. }
  116. const Test_Case test_cases[] = {
  117. TEST_CASE(null_case),
  118. TEST_CASE(bool_case),
  119. TEST_CASE(integer_case),
  120. TEST_CASE(float_case),
  121. TEST_CASE(string_case),
  122. TEST_CASE(array_case),
  123. TEST_CASE(object_case),
  124. };
  125. void record(const char *header_path)
  126. {
  127. FILE *stream = fopen(header_path, "w");
  128. Jim jim_stream = {
  129. .sink = stream,
  130. .write = (Jim_Write) fwrite,
  131. };
  132. Jim jim_buffer = {
  133. .sink = &buffer,
  134. .write = (Jim_Write) buffer_write,
  135. };
  136. fprintf(stream, "const char *test_cases_expected[] = {\n");
  137. for (size_t i = 0; i < ARRAY_LEN(test_cases); ++i) {
  138. buffer_clean(&buffer);
  139. test_cases[i].run(&jim_buffer);
  140. fprintf(stream, " ");
  141. const unsigned int size = buffer.size;
  142. jim_string(&jim_stream, buffer.data, &size);
  143. fprintf(stream, ",\n");
  144. }
  145. fprintf(stream, "};\n");
  146. fclose(stream);
  147. printf("Updated %s\n", header_path);
  148. }
  149. void test(void)
  150. {
  151. Jim jim_buffer = {
  152. .sink = &buffer,
  153. .write = (Jim_Write) buffer_write,
  154. };
  155. for (size_t i = 0; i < ARRAY_LEN(test_cases); ++i) {
  156. printf("%s ... ", test_cases[i].name);
  157. buffer_clean(&buffer);
  158. test_cases[i].run(&jim_buffer);
  159. if (buffer.size != strlen(test_cases_expected[i])
  160. || memcmp(buffer.data, test_cases_expected[i], buffer.size) != 0) {
  161. printf("FAILED!\n");
  162. printf("Expected: %s\n", test_cases_expected[i]);
  163. printf("Actual: ");
  164. fwrite(buffer.data, 1, buffer.size, stdout);
  165. printf("\n");
  166. exit(1);
  167. }
  168. printf("OK\n");
  169. }
  170. }
  171. int main(int argc, char **argv)
  172. {
  173. if (argc >= 2) {
  174. if (strcmp(argv[1], "record") == 0) {
  175. record("test_expected.h");
  176. } else {
  177. fprintf(stderr, "Usage: ./test [record]\n");
  178. fprintf(stderr, "ERROR: unknown subcommand %s.\n", argv[1]);
  179. }
  180. } else {
  181. test();
  182. }
  183. }