CjdnsTest.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. 'use strict';
  16. const Fs = require("fs");
  17. const nThen = require("nthen");
  18. const Fs_stat = function (file, callback) {
  19. Fs.stat(file, function (err, ret) {
  20. if (err === 'ENOENT') {
  21. console.log("Magical ENOENT on a file which definitely does exist, good job Linus");
  22. setTimeout(function () {
  23. Fs_stat(file, callback);
  24. }, 1000);
  25. } else {
  26. callback(err, ret);
  27. }
  28. });
  29. };
  30. const getTests = function (file, tests, isSubnode, callback) {
  31. if (/\/(.git|build_.*|node_build|contrib|target)\//.test(file)) { callback(); return; }
  32. if (isSubnode && /\/dht\//.test(file)) { callback(); return; }
  33. Fs_stat(file, function (err, stat) {
  34. if (err) { throw err; }
  35. if (stat.isDirectory()) {
  36. nThen(function (waitFor) {
  37. Fs.readdir(file, waitFor(function (err, list) {
  38. if (err) { throw err; }
  39. list.forEach(function (subFile) {
  40. getTests(file + '/' + subFile, tests, isSubnode, waitFor());
  41. });
  42. }));
  43. }).nThen(function (waitFor) {
  44. callback();
  45. });
  46. return;
  47. } else if (!/_test\.c$/.test(file)) {
  48. // not a test
  49. } else {
  50. // get rid of the annoying ./
  51. const f = file.replace(/^\.\//, '');
  52. if (tests.indexOf(f) === -1) { tests.push(f); }
  53. }
  54. callback();
  55. });
  56. };
  57. const rmFuzz = function (builder, cb) {
  58. const inputs = builder.config.buildDir + '/fuzz_inputs';
  59. Fs_stat(inputs, function (err, stat) {
  60. if (err && err.code === 'ENOENT') {
  61. Fs.mkdir(inputs, function (err, ret) {
  62. if (err) { throw err; }
  63. return void cb();
  64. });
  65. return;
  66. } else if (err) {
  67. throw err;
  68. }
  69. if (!stat.isDirectory()) {
  70. throw new Error(inputs + ' found, and it is a file, not a directory');
  71. }
  72. Fs.readdir(inputs, function (err, list) {
  73. if (err) { throw err; }
  74. let nt = nThen;
  75. list.forEach(function (f) {
  76. nt = nt(function (w) {
  77. Fs.unlink(inputs + '/' + f, w(function (err) {
  78. if (err) { throw err; }
  79. }));
  80. }).nThen;
  81. });
  82. nt(function (w) { cb(); });
  83. });
  84. });
  85. };
  86. const mkFuzzCase = function (inFile, outPath, testId, cb) {
  87. Fs.readFile(inFile, 'utf8', function (err, ret) {
  88. if (err) { throw err; }
  89. ret = ret.replace(/#[^\n]*\n/g, '');
  90. ret = ret.replace(/[\s]*/g, '');
  91. const out = Buffer.from(ret, 'hex');
  92. const id = Buffer.alloc(4);
  93. id.writeInt32BE(testId, 0);
  94. Fs.writeFile(outPath, Buffer.concat([id, out]), function (err) {
  95. if (err) { throw err; }
  96. cb();
  97. });
  98. });
  99. };
  100. const mkFuzz = function (builder, testPath, testId, fuzzCases, cb) {
  101. const inputs = builder.config.buildDir + '/fuzz_inputs';
  102. nThen(function (w) {
  103. const casesPath = testPath.replace(/\.c$/, '_cases');
  104. Fs.readdir(casesPath, w(function (err, list) {
  105. if (err && err.code === 'ENOENT') {
  106. return void console.log("Fuzz test [" + testPath + "] has no test cases");
  107. }
  108. if (err) { throw err; }
  109. let nt = nThen;
  110. list.forEach(function (f) {
  111. nt = nt(function (w) {
  112. const fNoExt = f.replace(/\..*$/, '');
  113. const outPath = inputs + '/' + (testPath + fNoExt).replace(/[^a-zA-Z0-9_-]/g, '_');
  114. fuzzCases.push('"' + outPath + '",');
  115. const inFile = casesPath + '/' + f;
  116. mkFuzzCase(inFile, outPath, testId, w());
  117. }).nThen;
  118. });
  119. nt(w());
  120. }));
  121. }).nThen(function (w) {
  122. cb();
  123. });
  124. };
  125. module.exports.generate = function (builder, isSubnode, callback) {
  126. const tests = [];
  127. const fuzzCases = [];
  128. const prototypes = [];
  129. const listContent = [];
  130. const fuzzTests = [];
  131. builder.config.cjdnsTest_files = builder.config.cjdnsTest_files || [];
  132. nThen(function (w) {
  133. getTests('.', tests, isSubnode, w());
  134. rmFuzz(builder, w());
  135. }).nThen(function (w) {
  136. tests.forEach(function (test) {
  137. //console.log(test);
  138. const testProto = /^.*\/([^\/]+)\.c$/.exec(test)[1];
  139. builder.config.cjdnsTest_files.push(test);
  140. const cflags = (builder.config.fileCflags[test] = builder.config.fileCflags[test] || []);
  141. if (test.indexOf('_fuzz_test') > -1) {
  142. cflags.push(
  143. '-D', 'CJDNS_FUZZ_INIT='+testProto+'_FUZZ_INIT',
  144. '-D', 'CJDNS_FUZZ_MAIN='+testProto+'_FUZZ_MAIN'
  145. );
  146. prototypes.push(
  147. 'void* '+testProto+'_FUZZ_INIT(struct Allocator* alloc, struct Random* rand);',
  148. 'void '+testProto+'_FUZZ_MAIN(void* ctx, struct Message* fuzz);'
  149. );
  150. mkFuzz(builder, test, fuzzTests.length, fuzzCases, w());
  151. fuzzTests.push('{' +
  152. '.init = '+testProto+'_FUZZ_INIT, ' +
  153. '.name = "'+test.replace(/^.*\/|.c$/g, '')+'", ' +
  154. '.fuzz = '+testProto+'_FUZZ_MAIN, ' +
  155. '},');
  156. } else {
  157. var main = testProto + '_main';
  158. cflags.push(
  159. '-D', 'main='+main,
  160. '-D', main+'(...)='+main+'(int argc, char** argv);int '+main+'(int argc, char** argv)'
  161. );
  162. prototypes.push('int '+main+'(int argc, char** argv);');
  163. listContent.push('{ .func = '+main+', .name = "'+test.replace(/^.*\/|.c$/g, '')+'" },');
  164. }
  165. });
  166. }).nThen(function (w) {
  167. builder.config.cjdnsTest_fuzzCases = fuzzCases.join(' ');
  168. builder.config.cjdnsTest_tests = listContent.join(' ');
  169. builder.config.cjdnsTest_fuzzTests = fuzzTests.join(' ');
  170. builder.config.cjdnsTest_prototypes = prototypes.join(' ');
  171. callback();
  172. });
  173. };