blitz_coverage.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #include "blitz.h"
  2. #ifdef BMX_COVERAGE
  3. BBString * bbCoverageOutputFileName = &bbEmptyString;
  4. Hashmap* BBCoverageLineExecInfoTable;
  5. static int hashmapStringHash(intptr_t key) {
  6. const char* str = (const char*)key;
  7. int64_t hash = 0;
  8. while (*str) {
  9. hash = (31 * hash + *str++) % 0x7FFFFFFF;
  10. }
  11. return (int)(hash % 0x7FFFFFFF);
  12. }
  13. static int hashmapStringEquals(intptr_t keyA, intptr_t keyB) {
  14. const char* strA = (const char*)keyA;
  15. const char* strB = (const char*)keyB;
  16. return strcmp(strA, strB) == 0;
  17. }
  18. void bbCoverageStartup() {
  19. BBCoverageLineExecInfoTable = hashmapCreate(64, hashmapStringHash, hashmapStringEquals);
  20. }
  21. void bbCoverageRegisterFile(BBCoverageFileInfo * coverage_files) {
  22. for (int i = 0; coverage_files[i].filename != NULL; i++) {
  23. BBCoverageFileInfo * coverage_file = &coverage_files[i];
  24. if (coverage_file->line_map == NULL) {
  25. coverage_file->line_map = hashmapCreate(64, hashmapIntHash, hashmapIntEquals);
  26. hashmapPut(BBCoverageLineExecInfoTable, (void*)coverage_file->filename, coverage_file);
  27. }
  28. if (coverage_file->func_map == NULL) {
  29. coverage_file->func_map = hashmapCreate(64, hashmapIntHash, hashmapIntEquals);
  30. }
  31. for (int j = 0; j < coverage_file->coverage_lines_count; j++) {
  32. BBCoverageLineExecInfo* info = (BBCoverageLineExecInfo*) malloc(sizeof(BBCoverageLineExecInfo));
  33. info->file = coverage_file->filename;
  34. info->line = coverage_file->coverage_lines[j];
  35. info->count = 0;
  36. hashmapPut(coverage_file->line_map, (void*)(intptr_t)info->line, info);
  37. }
  38. for (int j = 0; j < coverage_file->coverage_functions_count; j++) {
  39. BBCoverageFuncExecInfo* info = (BBCoverageFuncExecInfo*) malloc(sizeof(BBCoverageFuncExecInfo));
  40. info->func = coverage_file->coverage_functions[j].func;
  41. info->line = coverage_file->coverage_functions[j].line;
  42. info->count = 0;
  43. hashmapPut(coverage_file->func_map, (void*)(intptr_t)info->line, info);
  44. }
  45. }
  46. }
  47. void bbCoverageUpdateLineInfo(const char* file, int line) {
  48. BBCoverageFileInfo * coverage_file = (Hashmap*) hashmapGet(BBCoverageLineExecInfoTable, (void*)file);
  49. if (!coverage_file) {
  50. // error
  51. return;
  52. }
  53. BBCoverageLineExecInfo* info = (BBCoverageLineExecInfo*) hashmapGet(coverage_file->line_map, (void*)(intptr_t)line);
  54. if (!info) {
  55. info = (BBCoverageLineExecInfo*) malloc(sizeof(BBCoverageLineExecInfo));
  56. info->file = file;
  57. info->line = line;
  58. info->count = 0;
  59. hashmapPut(coverage_file->line_map, (void*)(intptr_t)line, info);
  60. }
  61. info->count++;
  62. }
  63. void bbCoverageUpdateFunctionLineInfo(const char* file, const char* func, int line) {
  64. BBCoverageFileInfo * coverage_file = (Hashmap*) hashmapGet(BBCoverageLineExecInfoTable, (void*)file);
  65. if (!coverage_file) {
  66. // error
  67. return;
  68. }
  69. BBCoverageFuncExecInfo* info = (BBCoverageFuncExecInfo*) hashmapGet(coverage_file->func_map, (void*)(intptr_t)line);
  70. if (!info) {
  71. info = (BBCoverageFuncExecInfo*) malloc(sizeof(BBCoverageFuncExecInfo));
  72. info->file = file;
  73. info->func = func;
  74. info->line = line;
  75. info->count = 0;
  76. hashmapPut(coverage_file->line_map, (void*)(intptr_t)line, info);
  77. }
  78. info->count++;
  79. }
  80. static int write_line_exec_info(intptr_t key, void* value, void* context) {
  81. BBCoverageLineExecInfo* info = (BBCoverageLineExecInfo*)value;
  82. FILE* lcov_file = (FILE*)context;
  83. fprintf(lcov_file, "DA:%d,%d\n", info->line, info->count);
  84. return 1;
  85. }
  86. static int write_file_exec_info(intptr_t key, void* value, void* context) {
  87. const char* file = (const char*)key;
  88. BBCoverageFileInfo* coverage_file = (BBCoverageFileInfo*)value;
  89. FILE* lcov_file = (FILE*)context;
  90. fprintf(lcov_file, "SF:%s\n", file);
  91. int lines_hit = 0;
  92. for (int i=0; i < coverage_file->coverage_lines_count; i++) {
  93. BBCoverageLineExecInfo* info = (BBCoverageLineExecInfo*) hashmapGet(coverage_file->line_map, (void*)(intptr_t)coverage_file->coverage_lines[i]);
  94. if (info) {
  95. if (info->count > 0) {
  96. lines_hit++;
  97. }
  98. fprintf(lcov_file, "DA:%d,%d\n", info->line, info->count);
  99. }
  100. }
  101. fprintf(lcov_file, "LF:%d\n", coverage_file->coverage_lines_count);
  102. fprintf(lcov_file, "LH:%d\n", lines_hit);
  103. int functions_hit = 0;
  104. for (int i=0; i < coverage_file->coverage_functions_count; i++) {
  105. BBCoverageFuncExecInfo* info = (BBCoverageFuncExecInfo*) hashmapGet(coverage_file->func_map, (void*)(intptr_t)coverage_file->coverage_functions[i].line);
  106. if (info) {
  107. if (info->count > 0) {
  108. functions_hit++;
  109. }
  110. fprintf(lcov_file, "FN:%d,%s\n", info->line, info->func);
  111. fprintf(lcov_file, "FNDA:%d,%d\n", info->count, info->line);
  112. }
  113. }
  114. fprintf(lcov_file, "FNF:%d\n", coverage_file->coverage_functions_count);
  115. fprintf(lcov_file, "FNH:%d\n", functions_hit);
  116. // Write the end of record marker
  117. fprintf(lcov_file, "end_of_record\n");
  118. return 1;
  119. }
  120. void bbCoverageGenerateOutput() {
  121. const char* output_file_name;
  122. if ( bbCoverageOutputFileName == &bbEmptyString ) {
  123. output_file_name = "lcov.info";
  124. } else {
  125. output_file_name = bbStringToUTF8String(bbCoverageOutputFileName);
  126. }
  127. FILE* lcov_file = fopen(output_file_name, "w");
  128. if (!lcov_file) {
  129. printf("Error: Unable to open output file: %s\n", output_file_name);
  130. return;
  131. }
  132. // Iterate through the global hash table (BBCoverageLineExecInfoTable) and write file coverage data
  133. hashmapForEach(BBCoverageLineExecInfoTable, write_file_exec_info, lcov_file);
  134. fclose(lcov_file);
  135. }
  136. #endif // BMX_COVERAGE