// fuzzgen.cm — generates self-checking .cm programs for fuzz testing // Each generated program returns a record of test functions that // validate their own expected results. // Newline constant — backtick strings don't interpret \n as escape var NL = "\n" // Simple seeded PRNG (xorshift32) var _seed = 1 function seed(s) { _seed = s != 0 ? s : 1 } function rand() { _seed = _seed ^ (_seed << 13) _seed = _seed ^ (_seed >> 17) _seed = _seed ^ (_seed << 5) if (_seed < 0) _seed = -_seed return _seed } function rand_int(lo, hi) { return lo + (rand() % (hi - lo + 1)) } function rand_float() { return rand_int(-10000, 10000) / 100 } function rand_bool() { return rand() % 2 == 0 } function pick(arr) { return arr[rand() % length(arr)] } // Expression generators — each returns {src: "code", val: expected_value} // depth is decremented to prevent infinite recursion function gen_int_literal() { var v = rand_int(-10000, 10000) return {src: text(v), val: v} } function gen_float_literal() { var v = rand_float() return {src: text(v), val: v} } function gen_bool_literal() { var v = rand_bool() var s = "false" if (v) s = "true" return {src: s, val: v} } function gen_text_literal() { var words = ["alpha", "beta", "gamma", "delta", "epsilon"] var w = pick(words) return {src: `"${w}"`, val: w} } function gen_null_literal() { return {src: "null", val: null} } function gen_int_expr(depth) { var a = null var b = null var op = null var result = null if (depth <= 0) return gen_int_literal() a = gen_int_expr(depth - 1) b = gen_int_expr(depth - 1) // Avoid division by zero if (b.val == 0) b = {src: "1", val: 1} op = pick(["+", "-", "*"]) if (op == "+") { result = a.val + b.val } else if (op == "-") { result = a.val - b.val } else { result = a.val * b.val } // Guard against overflow beyond safe integer range if (result > 9007199254740991 || result < -9007199254740991) { return gen_int_literal() } return {src: `(${a.src} ${op} ${b.src})`, val: result} } function gen_float_expr(depth) { var a = null var b = null var op = null var result = null if (depth <= 0) return gen_float_literal() a = gen_float_expr(depth - 1) b = gen_float_expr(depth - 1) if (b.val == 0) b = {src: "1.0", val: 1.0} op = pick(["+", "-", "*"]) if (op == "+") { result = a.val + b.val } else if (op == "-") { result = a.val - b.val } else { result = a.val * b.val } return {src: `(${a.src} ${op} ${b.src})`, val: result} } function gen_text_expr(depth) { var a = null var b = null if (depth <= 0) return gen_text_literal() a = gen_text_literal() b = gen_text_literal() return {src: `(${a.src} + ${b.src})`, val: a.val + b.val} } function gen_comparison_expr(depth) { var a = null var b = null var op = null var result = null a = gen_int_expr(depth > 0 ? depth - 1 : 0) b = gen_int_expr(depth > 0 ? depth - 1 : 0) op = pick(["==", "!=", "<", ">", "<=", ">="]) if (op == "==") { result = a.val == b.val } else if (op == "!=") { result = a.val != b.val } else if (op == "<") { result = a.val < b.val } else if (op == ">") { result = a.val > b.val } else if (op == "<=") { result = a.val <= b.val } else { result = a.val >= b.val } return {src: `(${a.src} ${op} ${b.src})`, val: result} } // Generate an if-else expression test function gen_if_else_test() { var cond = gen_comparison_expr(1) var then_val = gen_int_literal() var else_val = gen_int_literal() var expected = cond.val ? then_val.val : else_val.val var body = "var result = null" + NL body = body + " if (" + cond.src + ") {" + NL body = body + " result = " + then_val.src + NL body = body + " } else {" + NL body = body + " result = " + else_val.src + NL body = body + " }" + NL body = body + " if (result != " + text(expected) + ") return \"if_else: expected " + text(expected) + " got \" + text(result)" return body } // Generate a loop accumulator test function gen_loop_test() { var count = rand_int(1, 50) var step = rand_int(1, 10) var expected = 0 var i = 0 while (i < count) { expected = expected + step i = i + 1 } var body = "var acc = 0" + NL body = body + " var i = 0" + NL body = body + " while (i < " + text(count) + ") {" + NL body = body + " acc = acc + " + text(step) + NL body = body + " i = i + 1" + NL body = body + " }" + NL body = body + " if (acc != " + text(expected) + ") return \"loop: expected " + text(expected) + " got \" + text(acc)" return body } // Generate a closure test function gen_closure_test() { var init_val = rand_int(1, 100) var inc = rand_int(1, 10) var calls = rand_int(1, 10) var expected = init_val + (inc * calls) var body = "var counter = " + text(init_val) + NL body = body + " var inc = function() { counter = counter + " + text(inc) + " }" + NL body = body + " var i = 0" + NL body = body + " while (i < " + text(calls) + ") {" + NL body = body + " inc()" + NL body = body + " i = i + 1" + NL body = body + " }" + NL body = body + " if (counter != " + text(expected) + ") return \"closure: expected " + text(expected) + " got \" + text(counter)" return body } // Generate a record property test function gen_record_test() { var a = gen_int_literal() var b = gen_int_literal() var sum = a.val + b.val var body = "var r = {a: " + a.src + ", b: " + b.src + "}" + NL body = body + " var result = r.a + r.b" + NL body = body + " if (result != " + text(sum) + ") return \"record: expected " + text(sum) + " got \" + text(result)" return body } // Generate an array test function gen_array_test() { var n = rand_int(2, 10) var vals = [] var i = 0 var sum = 0 var v = 0 while (i < n) { v = rand_int(-100, 100) vals[] = v sum = sum + v i = i + 1 } var val_strs = [] i = 0 while (i < n) { val_strs[] = text(vals[i]) i = i + 1 } var body = "var a = [" + text(val_strs, ", ") + "]" + NL body = body + " var _sum = 0" + NL body = body + " var i = 0" + NL body = body + " while (i < length(a)) {" + NL body = body + " _sum = _sum + a[i]" + NL body = body + " i = i + 1" + NL body = body + " }" + NL body = body + " if (_sum != " + text(sum) + ") return \"array_sum: expected " + text(sum) + " got \" + text(_sum)" return body } // Generate a nested function / higher-order test function gen_higher_order_test() { var mul = rand_int(2, 10) var input = rand_int(1, 100) var expected = input * mul var body = "var make_mul = function(m) {" + NL body = body + " return function(x) { return x * m }" + NL body = body + " }" + NL body = body + " var fn = make_mul(" + text(mul) + ")" + NL body = body + " var result = fn(" + text(input) + ")" + NL body = body + " if (result != " + text(expected) + ") return \"higher_order: expected " + text(expected) + " got \" + text(result)" return body } // Generate a disruption handling test function gen_disrupt_test() { var body = "var caught = false" + NL body = body + " var _fn = function() { disrupt } disruption { caught = true }" + NL body = body + " _fn()" + NL body = body + " if (!caught) return \"disrupt: expected to catch disruption\"" return body } // Generate a text operation test function gen_text_op_test() { var words = ["hello", "world", "foo", "bar", "baz"] var w1 = pick(words) var w2 = pick(words) var expected = w1 + w2 var body = "var a = \"" + w1 + "\"" + NL body = body + " var b = \"" + w2 + "\"" + NL body = body + " var c = a + b" + NL body = body + " if (c != \"" + expected + "\") return \"text_op: expected " + expected + " got \" + c" return body } // All generators var generators = [ gen_if_else_test, gen_loop_test, gen_closure_test, gen_record_test, gen_array_test, gen_higher_order_test, gen_disrupt_test, gen_text_op_test ] // Generate a complete self-checking .cm program function generate(s) { seed(s) var num_tests = rand_int(5, 15) var src = "// Auto-generated fuzz test (seed=" + text(s) + ")\nreturn {\n" var i = 0 var gen = null var body = null while (i < num_tests) { gen = pick(generators) body = gen() if (i > 0) src = src + ",\n" src = src + " fuzz_" + text(i) + ": function() {\n" src = src + " " + body + "\n" src = src + " }" i = i + 1 } src = src + "\n}\n" return src } return { generate: generate, seed: seed }