CoolFace
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
codeEvaluation.service.js.backup1353 linesDownload Raw Back to services
1const axios = require('axios');2const { applyWrappers } = require('./execution');3const heClient = require('./execution/hackerEarthClient');4const { LanguageExecutorFactory } = require('./execution/languageExecutors');5const AnswerVerifier = require('../utils/answerVerifiers');6 7// NEW: Import modular test harness and validators8const { createTestHarness, supportsOptimizedExecution, parseOptimizedOutput } = require('./testHarness');9const { validateMultipleOutputs, compareOutputs } = require('./validators/outputValidator');10 11// DOCKER: Import Docker executor12const dockerExecutor = require('./execution/dockerExecutor');13const USE_DOCKER = process.env.USE_DOCKER_EXECUTOR === 'true';14 15// Debug log16console.log('\n' + '='.repeat(80));17console.log('๐Ÿ”ง CODE EVALUATION SERVICE INITIALIZED');18console.log('='.repeat(80));19console.log(`๐Ÿณ Docker Executor: ${USE_DOCKER ? 'ENABLED โœ…' : 'DISABLED โŒ'}`);20console.log(`๐ŸŒ HackerEarth API: ${USE_DOCKER ? 'FALLBACK' : 'PRIMARY'}`);21console.log(`๐Ÿ“ Environment: ${process.env.NODE_ENV || 'development'}`);22console.log('='.repeat(80) + '\n');23 24// HackerEarth V4 API Configuration25const CODE_EVAL_URL = process.env.CODE_EVAL_URL || 'https://api.hackerearth.com/v4/partner/code-evaluation/submissions/';26const CLIENT_SECRET = process.env.CLIENT_SECRET;27 28// Status codes mapping29const STATUS_CODES = {30  'AC': 'Accepted',31  'TLE': 'Time Limit Exceeded',32  'MLE': 'Memory Limit Exceeded',33  'RE': 'Runtime Error',34  'CE': 'Compilation Error',35  'REQUEST_FAILED': 'Request Failed'36};37 38/**39 * Parse test input from various formats40 */41const parseTestInput = (raw) => {42  try {43    return JSON.parse(raw);44  } catch (e) {45    const result = {};46    const lines = String(raw || '').split(/\r?\n/).map(l => l.trim()).filter(Boolean);47    for (const line of lines) {48      const m = line.match(/^(\w+)\s*=\s*(.+)$/);49      if (m) {50        const key = m[1];51        let val = m[2].trim();52        const normalized = val.replace(/'/g, '"');53        try {54          result[key] = JSON.parse(normalized);55        } catch (e) {56          const num = Number(val);57          if (!Number.isNaN(num)) {58            result[key] = num;59          } else {60            result[key] = val.replace(/^\"|\"$/g, '');61          }62        }63      } else if (!result.x && /^-?\d+(?:\.\d+)?$/.test(line)) {64        result.x = Number(line);65      }66    }67    return result;68  }69};70 71 72/**73 * Submit code - Docker with HackerEarth fallback74 */75const submitCode = async (sourceCode, language, testInput, memoryLimit = 262144, timeLimit = 5, options = {}) => {76  // Debug: Show executor status77  console.log('\n' + 'โ–ˆ'.repeat(80));78  console.log('โšก CODE EXECUTION REQUEST');79  console.log('โ–ˆ'.repeat(80));80  console.log(`๐Ÿ”ง Docker Enabled: ${USE_DOCKER ? 'โœ… YES' : 'โŒ NO'}`);81  console.log(`๐Ÿ“ฆ Language: ${language}`);82  console.log(`โฑ๏ธ  Time Limit: ${timeLimit}s`);83  console.log('โ–ˆ'.repeat(80));84  85  // Try Docker first if enabled86  if (USE_DOCKER) {87    try {88      console.log('\n' + '='.repeat(80));89      console.log('๐Ÿณ ATTEMPTING DOCKER EXECUTION');90      console.log('='.repeat(80));91      const dockerResult = await submitCodeDocker(sourceCode, language, testInput, memoryLimit, timeLimit, options);92      console.log('\n' + '='.repeat(80));93      console.log('โœ… DOCKER EXECUTION SUCCESSFUL');94      console.log('='.repeat(80) + '\n');95      return dockerResult;96    } catch (dockerError) {97      console.log('\n' + '='.repeat(80));98      console.log('โš ๏ธ  DOCKER EXECUTION FAILED');99      console.log('๐Ÿ”„ FALLING BACK TO HACKEREARTH API');100      console.log('='.repeat(80));101      console.log('โŒ Error:', dockerError.message);102      console.log('='.repeat(80) + '\n');103      // Fall through to HackerEarth104    }105  } else {106    console.log('\n' + '='.repeat(80));107    console.log('โ„น๏ธ  DOCKER DISABLED - Using HackerEarth');108    console.log('='.repeat(80));109  }110 111  // Use HackerEarth (default or fallback)112  console.log('\n' + '='.repeat(80));113  console.log('๐ŸŒ USING HACKEREARTH API');114  console.log('='.repeat(80) + '\n');115  return await submitCodeHackerEarth(sourceCode, language, testInput, memoryLimit, timeLimit, options);116};117 118/**119 * Docker-based execution120 */121const submitCodeDocker = async (sourceCode, language, testInput, memoryLimit, timeLimit, options) => {122  let processedSourceCode = sourceCode;123  124  // Apply wrappers125  try {126    const wrapped = applyWrappers({ sourceCode, language, topic: options.topic });127    if (wrapped && wrapped.sourceCode) {128      processedSourceCode = wrapped.sourceCode;129    }130  } catch (e) { /* noop */ }131 132  console.log(`๐Ÿ“ฆ Language: ${language}`);133  console.log(`โฑ๏ธ  Time Limit: ${timeLimit}s`);134  console.log(`๐Ÿ’พ Memory Limit: ${Math.floor(memoryLimit / 1024)}MB`);135 136  // Execute in Docker137  const result = await dockerExecutor.executeCode({138    sourceCode: processedSourceCode,139    language,140    input: testInput,141    timeLimit,142    memoryLimit: Math.floor(memoryLimit / 1024)143  });144 145  console.log(`๐Ÿ“Š Execution Time: ${result.executionTime}ms`);146  console.log(`โœ… Status: ${result.status}`);147 148  // Convert to HackerEarth-compatible format149  return {150    he_id: `docker_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,151    result: {152      run_status: {153        status: result.status,154        output: result.output,155        stderr: result.error,156        time_used: result.executionTime,157        memory_used: result.memoryUsed158      }159    },160    request_status: {161      code: result.success ? 'REQUEST_COMPLETED' : 'REQUEST_FAILED'162    }163  };164};165 166/**167 * HackerEarth execution (original implementation)168 */169const submitCodeHackerEarth = async (sourceCode, language, testInput, memoryLimit, timeLimit, options) => {170  try {171    let processedSourceCode = sourceCode;172    let usedRunner = false;173 174    // Apply topic-specific wrappers175    try {176      const wrapped = applyWrappers({ sourceCode, language, topic: options.topic });177      if (wrapped && wrapped.sourceCode) {178        processedSourceCode = wrapped.sourceCode;179        usedRunner = wrapped.usedRunner || usedRunner;180      }181    } catch (e) { /* noop */ }182 183    const inputObj = parseTestInput(testInput);184 185    // Process based on language using optimized executors186    if (testInput !== 'all_test_cases') {187      const result = LanguageExecutorFactory.processCode(processedSourceCode, language, inputObj);188      processedSourceCode = result.processedSourceCode;189      usedRunner = result.usedRunner || usedRunner;190    }191 192    const response = await heClient.submitToHackerEarth({193      source: processedSourceCode,194      language,195      memoryLimit,196      timeLimit,197      input: testInput,198      usedRunner199    });200 201    return response;202  } catch (error) {203    console.error('โŒ Error submitting code:', error.message);204    console.error('โŒ Error details:', error.response?.data);205    throw error;206  }207};208 209/**210 * Get status of code execution from HackerEarth API211 */212const getStatus = async (heId) => heClient.getStatus(heId);213 214/**215 * Poll for completion of code execution216 */217const pollForCompletion = async (heId, maxAttempts = 10, interval = 1000) => heClient.pollForCompletion(heId, maxAttempts, interval);218 219/**220 * Get output content from HackerEarth URL221 */222const getOutputContent = async (outputUrl) => heClient.extractOutput({ output: outputUrl });223 224/**225 * Normalize output for easier comparison and UI display226 */227const normalizeOutputForCompare = heClient.normalizeOutputForCompare;228 229/**230 * Extract output text from run_status regardless of field name231 */232const extractOutput = async (runStatus) => heClient.extractOutput(runStatus);233 234/**235 * Execute code against multiple test cases - OPTIMIZED VERSION236 */237const executeTestCases = async (sourceCode, language, testCases, options = {}) => {238  console.log(`๐Ÿ“‹ Running all test cases (${testCases.length} total) for submission`);239 240  // Auto-enable optimized batch execution for compiled languages241  // BUT respect explicit runAllTestCases: false to prevent infinite loops242  const shouldUseOptimized = options.runAllTestCases === true ||243    (options.runAllTestCases !== false && (244      language.startsWith('JAVA') ||245      language.startsWith('CPP') ||246      language === 'C' ||247      language.startsWith('PYTHON') ||248      language === 'JAVASCRIPT_NODE'249    ));250 251  if (shouldUseOptimized) {252    return await executeAllTestCasesOptimized(sourceCode, language, testCases, options);253  }254 255  const results = {256    summary: {257      total: testCases.length,258      passed: 0,259      failed: 0,260      errors: 0261    },262    cases: []263  };264 265  const concurrency = Math.min(options.concurrency || 5, 10);266  const queue = [];267 268  const pushTask = async (index) => {269    const testCase = testCases[index];270    const caseResult = {271      caseNumber: index + 1,272      input: testCase.input,273      expected: testCase.expected,274      expected_output: testCase.expected, // Add for consistency275      output: '',276      status: 'Error',277      error: null,278      executionTime: null,279      memoryUsed: null,280      isHidden: testCase.isHidden || false,281      pass: false // Add pass field282    };283 284    try {285      const submission = await submitCode(sourceCode, language, testCase.input, undefined, undefined, { topic: options.topic });286      const heId = submission.he_id;287      288      // Optimized polling - Java needs more attempts289      const isJava = language.startsWith('JAVA');290      const isCompiled = isJava || language.startsWith('CPP') || language.startsWith('C');291      const maxAttempts = language === 'JAVASCRIPT_NODE' ? 28 : isJava ? 35 : isCompiled ? 25 : 28;292      const interval = language === 'JAVASCRIPT_NODE' ? 250 : isCompiled ? 200 : 300;293      294      const finalResult = await pollForCompletion(heId, maxAttempts, interval);295      const runStatus = finalResult.result?.run_status;296 297      if (runStatus) {298        caseResult.executionTime = runStatus.time_used;299        caseResult.memoryUsed = runStatus.memory_used;300 301        if (runStatus.status === 'AC' || runStatus.status === 'CODE_COMPILED') {302          caseResult.output = await extractOutput(runStatus);303          if (typeof caseResult.output === 'string') {304            caseResult.output = caseResult.output.replace(/\[\s+/g, '[').replace(/\s+\]/g, ']').replace(/\s*,\s*/g, ',').trim();305            if (testCase.expected && testCase.expected.startsWith('"') && testCase.expected.endsWith('"')) {306              if (!caseResult.output.startsWith('"')) caseResult.output = `"${caseResult.output}"`;307            } else if (testCase.expected && !testCase.expected.startsWith('"') && caseResult.output.startsWith('"') && caseResult.output.endsWith('"')) {308              caseResult.output = caseResult.output.slice(1, -1);309            }310          }311 312          const normalizedOutput = normalizeOutputForCompare(caseResult.output);313          const normalizedExpected = normalizeOutputForCompare(testCase.expected);314 315          console.log(`๐Ÿ” COMPARISON DEBUG - Case ${index + 1}:`);316          console.log(`   Raw Output: "${caseResult.output}" (type: ${typeof caseResult.output})`);317          console.log(`   Raw Expected: "${testCase.expected}" (type: ${typeof testCase.expected})`);318          console.log(`   Normalized Output: "${normalizedOutput}"`);319          console.log(`   Normalized Expected: "${normalizedExpected}"`);320          console.log(`   Match: ${normalizedOutput === normalizedExpected}`);321 322          // Check if problem uses custom verifier323          let isValid = false;324          if (options.verifierType) {325            console.log(`   ๐Ÿ”ง Using custom verifier: ${options.verifierType}`);326            const verifyResult = AnswerVerifier.verify(327              options.verifierType,328              testCase.input,329              caseResult.output,330              testCase.expected,331              options.verifierMetadata || {}332            );333            isValid = verifyResult.valid;334            console.log(`   ๐Ÿ” Verifier result: ${verifyResult.valid ? 'โœ… VALID' : 'โŒ INVALID'} - ${verifyResult.reason}`);335          } else if (normalizedOutput === normalizedExpected) {336            isValid = true;337          } else {338            // Fallback comparisons - handle quotes and type mismatches339            const outputStr = String(caseResult.output || '');340            const expectedStr = String(testCase.expected || '');341            342            // Remove quotes for comparison343            const cleanOutput = outputStr.replace(/^["']|["']$/g, '');344            const cleanExpected = expectedStr.replace(/^["']|["']$/g, '');345            346            // Try multiple comparison strategies347            if (cleanOutput === cleanExpected) {348              isValid = true;349              console.log(`   โœ… Match after removing quotes`);350            } else if (outputStr === expectedStr) {351              isValid = true;352              console.log(`   โœ… Exact match`);353            } else {354              // Try numeric comparison355              const outputNum = Number(cleanOutput);356              const expectedNum = Number(cleanExpected);357              if (!isNaN(outputNum) && !isNaN(expectedNum) && outputNum === expectedNum) {358                isValid = true;359                console.log(`   โœ… Numeric match: ${outputNum} === ${expectedNum}`);360              } else {361                // Try array comparison362                const normalizeArrayStr = (str) => str.replace(/\s+/g, '').replace(/\[/g, '[').replace(/\]/g, ']');363                const normalizedArrayOutput = normalizeArrayStr(outputStr);364                const normalizedArrayExpected = normalizeArrayStr(expectedStr);365                if (normalizedArrayOutput === normalizedArrayExpected) {366                  isValid = true;367                  console.log(`   โœ… Array match`);368                }369              }370            }371          }372 373          if (isValid) {374            caseResult.status = 'Pass';375            caseResult.pass = true;376            console.log(`   โœ… PASSED!`);377          } else {378            caseResult.status = 'Fail';379            caseResult.pass = false;380            console.log(`   โŒ FAILED!`);381          }382        } else {383          caseResult.status = STATUS_CODES[runStatus.status] || 'Error';384          caseResult.error = runStatus.stderr || runStatus.compile_status;385          caseResult.output = await extractOutput(runStatus);386        }387      } else {388        caseResult.status = 'Error';389        caseResult.error = 'No run status received';390      }391    } catch (error) {392      caseResult.status = 'Error';393      caseResult.error = error.message;394    }395 396    return caseResult;397  };398 399  const indices = Array.from({ length: testCases.length }, (_, i) => i);400  const active = new Set();401  const resultsArr = new Array(testCases.length);402 403  async function runNext() {404    if (indices.length === 0) return;405    const idx = indices.shift();406    const p = pushTask(idx).then((r) => { resultsArr[idx] = r; active.delete(p); });407    active.add(p);408    if (active.size >= concurrency) await Promise.race(Array.from(active));409    return runNext();410  }411 412  await runNext();413  await Promise.all(Array.from(active));414 415  for (const cr of resultsArr) {416    results.cases.push(cr);417    if (cr.status === 'Pass') results.summary.passed++;418    else if (cr.status === 'Fail') results.summary.failed++;419    else results.summary.errors++;420  }421 422  // โŒ DON'T filter hidden cases - we need them for submission results423  // results.cases = results.cases.filter(testCase => !testCase.isHidden);424  return results;425};426 427/**428 * OPTIMIZED: Execute all test cases in a single submission429 */430const executeAllTestCasesOptimized = async (sourceCode, language, testCases, options = {}, retryCount = 0) => {431  // Silent execution - logs only in routes432 433  const results = {434    summary: {435      total: testCases.length,436      passed: 0,437      failed: 0,438      errors: 0439    },440    cases: []441  };442 443  try {444    let testHarness = '';445    let testInput = '';446 447    // NEW: Use modular test harness factory448    if (supportsOptimizedExecution(language)) {449      testHarness = createTestHarness(sourceCode, language, testCases);450      testInput = 'all_test_cases';451    } else {452      console.log('โš ๏ธ Language not optimized, falling back to individual submissions');453      return await executeTestCases(sourceCode, language, testCases, { ...options, runAllTestCases: false });454    }455 456    // Test harness created silently457 458    // Smart batching: Check if test harness is too large459    const MAX_HARNESS_SIZE = 950 * 1024; // 950KB limit460 461    if (testHarness.length > MAX_HARNESS_SIZE) {462      console.log(`โš ๏ธ Large harness (${(testHarness.length / 1024).toFixed(2)}KB) - using smart batching...`);463 464      // Split into batches465      const batches = [];466      let currentBatch = [];467 468      for (const tc of testCases) {469        currentBatch.push(tc);470        // NEW: Use modular harness471        const batchHarness = createTestHarness(sourceCode, language, currentBatch);472 473        if (batchHarness.length > MAX_HARNESS_SIZE) {474          currentBatch.pop();475          if (currentBatch.length > 0) {476            batches.push([...currentBatch]);477          }478          currentBatch = [tc];479        }480      }481 482      if (currentBatch.length > 0) {483        batches.push(currentBatch);484      }485 486      console.log(`๐Ÿ“ฆ Split into ${batches.length} batches`);487 488      // Execute each batch489      const allResults = {490        summary: { total: testCases.length, passed: 0, failed: 0, errors: 0 },491        cases: []492      };493 494      for (let i = 0; i < batches.length; i++) {495        console.log(`๐Ÿš€ Batch ${i + 1}/${batches.length}: ${batches[i].length} cases`);496        const batchResults = await executeAllTestCasesOptimized(sourceCode, language, batches[i], options, 0);497 498        allResults.cases.push(...batchResults.cases);499        allResults.summary.passed += batchResults.summary.passed;500        allResults.summary.failed += batchResults.summary.failed;501        allResults.summary.errors += batchResults.summary.errors;502      }503 504      console.log(`โœ… All batches complete: ${allResults.summary.passed}/${allResults.summary.total} passed`);505      return allResults;506    }507 508    const submission = await submitCode(testHarness, language, testInput, undefined, undefined, { topic: options.topic });509    const heId = submission.he_id;510 511    // Optimized polling - Java needs more attempts due to compilation512    const isJava = language.startsWith('JAVA');513    const isCompiledLanguage = isJava || language.startsWith('CPP') || language.startsWith('C') || language.startsWith('PYTHON');514    const isJavaScript = language === 'JAVASCRIPT_NODE';515    516    // Java gets more attempts, others optimized517    const baseAttempts = isJavaScript ? 35 : isJava ? 40 : isCompiledLanguage ? 30 : 25;518    const scaledAttempts = Math.min(baseAttempts + Math.ceil(testCases.length / 4), 50);519    const maxAttempts = retryCount > 0 ? Math.ceil(scaledAttempts * 1.2) : scaledAttempts;520    521    // Faster intervals - 200-300ms range522    const interval = isJavaScript ? 250 : isCompiledLanguage ? 200 : 300;523 524    const finalResult = await pollForCompletion(heId, maxAttempts, interval);525 526    const runStatus = finalResult.result?.run_status;527    if (runStatus && (runStatus.status === 'AC' || runStatus.status === 'CODE_COMPILED')) {528      const output = await extractOutput(runStatus);529      const parsedResults = parseOptimizedOutput(output, testCases, language, options);530      // โŒ DON'T filter hidden cases - we need them for submission results531      // results.cases = parsedResults.cases.filter(testCase => !testCase.isHidden);532      results.cases = parsedResults.cases;533      results.summary = parsedResults.summary;534 535    } else {536      console.log('โš ๏ธ Optimized execution status:', runStatus?.status);537      console.log('โš ๏ธ Attempting to parse any available output...');538 539      try {540        const output = await extractOutput(runStatus);541        if (output && output.trim()) {542          console.log('๐Ÿ“Š PARTIAL OUTPUT:', output);543          const parsedResults = parseOptimizedOutput(output, testCases, language, options);544          console.log(`โœ… PARTIAL: ${parsedResults.summary.passed}/${parsedResults.summary.total} test cases passed`);545          return parsedResults;546        }547      } catch (error) {548        console.log('โŒ Failed to parse partial output:', error.message);549      }550 551      if (retryCount < 1) {552        console.log(`๐Ÿ”„ Retry ${retryCount + 1}/1: Optimized execution failed, retrying...`);553        return await executeAllTestCasesOptimized(sourceCode, language, testCases, options, retryCount + 1);554      } else {555        console.log('โŒ Optimized execution failed after 1 retry');556        console.log('โš ๏ธ Falling back to individual submissions...');557        return await executeTestCases(sourceCode, language, testCases, { ...options, runAllTestCases: false });558      }559    }560 561  } catch (error) {562    console.error('โŒ Optimized execution error:', error.message);563 564    // Don't retry if HackerEarth is stuck - waste of time565    if (error.message.includes('timed out') || error.message.includes('stuck')) {566      console.log('โš ๏ธ HackerEarth API is overloaded/stuck');567      console.log('โš ๏ธ Skipping retry, falling back immediately...');568      return await executeTestCases(sourceCode, language, testCases, { ...options, runAllTestCases: false });569    }570 571    console.log('โŒ Optimized execution failed completely');572    console.log('โš ๏ธ Falling back to individual test case execution...');573    return await executeTestCases(sourceCode, language, testCases, { ...options, runAllTestCases: false });574  }575 576  return results;577};578 579/**580 * Create JavaScript test harness for optimized execution581 */582const createJavaScriptTestHarness = (sourceCode, testCases) => {583  // Add helper function if not present and code uses it584  let harness = '';585  if (sourceCode.includes('isAlphaNumeric') && !sourceCode.includes('function isAlphaNumeric')) {586    harness += '// Helper function for alphanumeric check\n';587    harness += 'function isAlphaNumeric(char) { return /[a-z0-9]/i.test(char); }\n\n';588  }589 590  // Declare common global variables used in memoization591  harness += '// Global variables for memoization (reset between test cases)\n';592  harness += 'let memo, cache, dp;\n\n';593 594  harness += sourceCode + '\n\n';595  harness += '// Test harness for all test cases\n';596  harness += 'const testCases = [\n';597 598  testCases.forEach((testCase, index) => {599    const input = JSON.parse(testCase.input);600    const expected = testCase.expected;601    harness += `  { input: ${JSON.stringify(input)}, expected: ${JSON.stringify(expected)}, index: ${index} },\n`;602  });603 604  harness += `];605 606// Helper to check if string is palindrome607function isPalindromeStr(s) {608  return s === s.split('').reverse().join('');609}610 611// TreeNode helper for binary tree problems612function TreeNode(val, left, right) {613  this.val = (val===undefined ? 0 : val);614  this.left = (left===undefined ? null : left);615  this.right = (right===undefined ? null : right);616}617 618function buildBinaryTree(arr) {619  if (!arr || arr.length === 0) return null;620  const root = new TreeNode(arr[0]);621  const queue = [root];622  let i = 1;623  while (queue.length > 0 && i < arr.length) {624    const node = queue.shift();625    if (i < arr.length && arr[i] !== null) {626      node.left = new TreeNode(arr[i]);627      queue.push(node.left);628    }629    i++;630    if (i < arr.length && arr[i] !== null) {631      node.right = new TreeNode(arr[i]);632      queue.push(node.right);633    }634    i++;635  }636  return root;637}638 639console.log('TEST_RESULTS_START');640for (let i = 0; i < testCases.length; i++) {641  const testCase = testCases[i];642  try {643    // Reset global memoization variables between test cases644    // Initialize as objects/arrays to support different memoization patterns645    memo = {};646    cache = {};647    dp = [];648    649    // Convert tree inputs if needed650    const processedInput = {};651    for (const key in testCase.input) {652      if (key === 'root' && Array.isArray(testCase.input[key])) {653        processedInput[key] = buildBinaryTree(testCase.input[key]);654      } else {655        processedInput[key] = testCase.input[key];656      }657    }658    const result = ${extractFunctionName(sourceCode)}(...Object.values(processedInput));659    let output;660    let expected;661    662    // Format output based on type663    if (Array.isArray(result)) {664      output = '[' + result.join(',') + ']';665    } else if (typeof result === 'string') {666      output = JSON.stringify(result);667    } else if (typeof result === 'boolean') {668      output = String(result);669    } else {670      output = String(result);671    }672    673    // Format expected based on type - ensure it matches output format674    if (typeof testCase.expected === 'boolean') {675      expected = String(testCase.expected);676    } else if (typeof testCase.expected === 'number') {677      expected = String(testCase.expected);678    } else if (typeof testCase.expected === 'string') {679      // Check if it's already a quoted string or a plain string680      if (testCase.expected.startsWith('"') && testCase.expected.endsWith('"')) {681        expected = testCase.expected;682      } else {683        // It's a plain string value like "3" - keep it as is for comparison684        expected = testCase.expected;685      }686    } else {687      expected = String(testCase.expected);688    }689    690    // Special validation for palindrome problems - accept any valid palindrome of same length691    let passed = output === expected;692    if (!passed && typeof result === 'string' && typeof testCase.expected === 'string') {693      const expectedStr = testCase.expected.replace(/^"|"$/g, '');694      if (result.length === expectedStr.length && isPalindromeStr(result) && isPalindromeStr(expectedStr)) {695        passed = true;696      }697    }698    699    console.log(\`TEST_\${i+1}:\${passed ? 'PASS' : 'FAIL'}:\${output}:\${expected}\`);700  } catch (error) {701    console.log(\`TEST_\${i+1}:ERROR:\${error.message}\`);702  }703}704console.log('TEST_RESULTS_END');`;705 706  return harness;707};708 709/**710 * Create Python test harness for optimized execution711 */712const createPythonTestHarness = (sourceCode, testCases) => {713  // Add helper function if not present and code uses it714  let harness = '';715  if ((sourceCode.includes('is_alpha_numeric') || sourceCode.includes('isAlphaNumeric')) &&716    !sourceCode.includes('def is_alpha_numeric')) {717    harness += '# Helper function for alphanumeric check\n';718    harness += 'def is_alpha_numeric(char):\n';719    harness += '    return char.isalnum()\n\n';720  }721 722  harness += sourceCode + '\n\n';723  harness += '# Test harness for all test cases\n';724  harness += 'test_cases = [\n';725 726  testCases.forEach((testCase, index) => {727    const input = JSON.parse(testCase.input);728    const expected = testCase.expected;729    harness += `    {"input": ${JSON.stringify(input)}, "expected": ${JSON.stringify(expected)}, "index": ${index}},\n`;730  });731 732  harness += `]733 734import json735 736def is_palindrome_str(s):737    return s == s[::-1]738 739class TreeNode:740    def __init__(self, val=0, left=None, right=None):741        self.val = val742        self.left = left743        self.right = right744 745def build_binary_tree(arr):746    if not arr or len(arr) == 0:747        return None748    root = TreeNode(arr[0])749    queue = [root]750    i = 1751    while queue and i < len(arr):752        node = queue.pop(0)753        if i < len(arr) and arr[i] is not None:754            node.left = TreeNode(arr[i])755            queue.append(node.left)756        i += 1757        if i < len(arr) and arr[i] is not None:758            node.right = TreeNode(arr[i])759            queue.append(node.right)760        i += 1761    return root762 763print('TEST_RESULTS_START')764for i, test_case in enumerate(test_cases):765    try:766        # Convert tree inputs if needed767        processed_input = {}768        for key, value in test_case['input'].items():769            if key == 'root' and isinstance(value, list):770                processed_input[key] = build_binary_tree(value)771            else:772                processed_input[key] = value773        result = ${extractPythonFunctionName(sourceCode)}(**processed_input)774        if isinstance(result, list):775            output = '[' + ','.join(map(str, result)) + ']'776        elif isinstance(result, str):777            output = json.dumps(result)778        else:779            output = str(result)780        expected = test_case['expected'] if isinstance(test_case['expected'], str) and test_case['expected'].startswith('"') else json.dumps(test_case['expected'])781        782        # Special validation for palindrome problems783        passed = output == expected784        if not passed and isinstance(result, str) and isinstance(test_case['expected'], str):785            expected_str = test_case['expected'].strip('"')786            if len(result) == len(expected_str) and is_palindrome_str(result) and is_palindrome_str(expected_str):787                passed = True788        789        print(f'TEST_{i+1}:{"PASS" if passed else "FAIL"}:{output}:{expected}')790    except Exception as e:791        print(f'TEST_{i+1}:ERROR:{str(e)}')792print('TEST_RESULTS_END')`;793 794  return harness;795};796 797/**798 * Create Java test harness for optimized execution799 */800const createJavaTestHarness = (sourceCode, testCases) => {801  const functionName = extractJavaFunctionName(sourceCode);802 803  let cleanSourceCode = sourceCode804    .replace(/\bpublic\s+class\s+Main\s*\{[\s\S]*?\}/g, '')805    .replace(/\bpublic\s+static\s+void\s+main\s*\([^)]*\)\s*\{[\s\S]*?\}/g, '')806    .replace(/\bclass\s+Main\s*\{[\s\S]*?\}/g, '')807    .replace(/\bpublic\s+class\s+TestHarness\s*\{[\s\S]*?\}/g, '')808    .replace(/\bclass\s+TestHarness\s*\{[\s\S]*?\}/g, '');809 810  // Add helper method if needed811  if (cleanSourceCode.includes('isAlphaNumeric') && !cleanSourceCode.includes('isAlphaNumeric(')) {812    // Helper will be added inside Solution class813  }814 815  let harness = cleanSourceCode + '\n\n';816  harness += 'public class TestHarness {\n';817  harness += '    public static void main(String[] args) {\n';818  harness += '        Solution solution = new Solution();\n';819  harness += '        System.out.println("TEST_RESULTS_START");\n';820 821  testCases.forEach((testCase, index) => {822    const input = JSON.parse(testCase.input);823    const expected = testCase.expected;824    harness += `        // Test case ${index + 1}\n`;825    harness += `        try {\n`;826 827    let methodCall = `solution.${functionName}(`;828    const inputKeys = Object.keys(input);829 830    // Helper to safely convert value to Java literal831    const toJavaValue = (value) => {832      if (Array.isArray(value)) {833        return `new int[]{${value.join(',')}}`;834      } else if (typeof value === 'string') {835        return `"${value}"`;836      } else if (typeof value === 'number') {837        // Check if number is within int range838        if (value > 2147483647 || value < -2147483648) {839          return `(int)${value}L`; // Cast from long to int (will overflow as expected)840        }841        return value;842      } else {843        return value;844      }845    };846 847    if (inputKeys.length === 1) {848      const value = input[inputKeys[0]];849      methodCall += toJavaValue(value);850    } else {851      const args = inputKeys.map(key => toJavaValue(input[key])).join(', ');852      methodCall += args;853    }854    methodCall += ')';855 856    harness += `            Object result = ${methodCall};\n`;857    harness += `            String output;\n`;858    harness += `            if (result instanceof int[]) {\n`;859    harness += `                output = java.util.Arrays.toString((int[])result);\n`;860    harness += `            } else if (result instanceof String) {\n`;861    harness += `                output = "\\"" + result + "\\"";\n`;862    harness += `            } else {\n`;863    harness += `                output = String.valueOf(result);\n`;864    harness += `            }\n`;865    const expectedIsString = typeof expected === 'string' && expected.startsWith('"');866    const expectedStr = expectedIsString ? expected : `"${expected}"`;867    harness += `            String expectedStr = ${expectedStr};\n`;868    harness += `            boolean passed = output.equals(expectedStr);\n`;869    harness += `            // Special validation for palindrome problems\n`;870    harness += `            if (!passed && result instanceof String) {\n`;871    harness += `                String resultStr = (String)result;\n`;872    harness += `                String expStr = expectedStr.replace("\\"", "");\n`;873    harness += `                if (resultStr.length() == expStr.length()) {\n`;874    harness += `                    String revResult = new StringBuilder(resultStr).reverse().toString();\n`;875    harness += `                    String revExp = new StringBuilder(expStr).reverse().toString();\n`;876    harness += `                    if (resultStr.equals(revResult) && expStr.equals(revExp)) {\n`;877    harness += `                        passed = true;\n`;878    harness += `                    }\n`;879    harness += `                }\n`;880    harness += `            }\n`;881    harness += `            System.out.println("TEST_${index + 1}:" + (passed ? "PASS" : "FAIL") + ":" + output + ":${expected}");\n`;882    harness += `        } catch (Exception e) {\n`;883    harness += `            System.out.println("TEST_${index + 1}:ERROR:" + e.getMessage());\n`;884    harness += `        }\n`;885  });886 887  harness += '        System.out.println("TEST_RESULTS_END");\n';888  harness += '    }\n';889  harness += '}';890 891  return harness;892};893 894/**895 * Create C++ test harness for optimized execution896 */897const createCppTestHarness = (sourceCode, testCases) => {898  const functionName = extractCppFunctionName(sourceCode);899 900  // Simple approach: Split by "int main" and take only the first part901  let cleanSourceCode = sourceCode;902  const mainIndex = cleanSourceCode.indexOf('int main');903  if (mainIndex !== -1) {904    cleanSourceCode = cleanSourceCode.substring(0, mainIndex).trim();905  }906 907  // Ensure all required includes are present908  let includes = '';909  if (!cleanSourceCode.includes('#include <climits>')) includes += '#include <climits>\n';910  if (!cleanSourceCode.includes('#include <cctype>')) includes += '#include <cctype>\n';911  if (!cleanSourceCode.includes('#include <string>')) includes += '#include <string>\n';912  if (!cleanSourceCode.includes('#include <iostream>')) includes += '#include <iostream>\n';913  if (!cleanSourceCode.includes('#include <vector>')) includes += '#include <vector>\n';914  if (!cleanSourceCode.includes('#include <algorithm>')) includes += '#include <algorithm>\n';915  if (!cleanSourceCode.includes('using namespace std')) includes += 'using namespace std;\n';916 917  // Add helper function if needed918  let helpers = '';919  if (cleanSourceCode.includes('isAlphaNumeric') && !cleanSourceCode.includes('bool isAlphaNumeric')) {920    helpers += '\n// Helper function for alphanumeric check\n';921    helpers += 'bool isAlphaNumeric(char c) { return isalnum(c); }\n\n';922  }923 924  let harness = includes + helpers + cleanSourceCode + '\n\n';925  harness += 'int main() {\n';926  harness += '    std::cout << "TEST_RESULTS_START" << std::endl;\n';927 928  testCases.forEach((testCase, index) => {929    const input = JSON.parse(testCase.input);930    const expected = testCase.expected;931    harness += `    // Test case ${index + 1}\n`;932    harness += `    try {\n`;933 934    // Helper to safely convert value to C++ literal935    const toCppValue = (value) => {936      if (Array.isArray(value)) {937        return `{${value.join(',')}}`;938      } else if (typeof value === 'string') {939        return `"${value}"`;940      } else if (typeof value === 'number') {941        // Check if number is within int range942        if (value > 2147483647 || value < -2147483648) {943          return `static_cast<int>(${value}LL)`; // Cast from long long to int944        }945        return value;946      } else {947        return value;948      }949    };950 951    let functionCall = `${functionName}(`;952    const inputKeys = Object.keys(input);953    if (inputKeys.length === 1) {954      const value = input[inputKeys[0]];955      functionCall += toCppValue(value);956    } else {957      const args = inputKeys.map(key => toCppValue(input[key])).join(', ');958      functionCall += args;959    }960    functionCall += ')';961 962    harness += `        auto result = ${functionCall};\n`;963    harness += `        std::string resultStr;\n`;964    harness += `        if constexpr (std::is_same_v<decltype(result), std::string>) {\n`;965    harness += `            resultStr = "\\"" + result + "\\"";\n`;966    harness += `        } else {\n`;967    harness += `            resultStr = std::to_string(result);\n`;968    harness += `        }\n`;969    const expectedIsString = typeof expected === 'string' && expected.startsWith('"');970    const expectedStr = expectedIsString ? expected : `"${expected}"`;971    harness += `        std::string expectedStr = ${expectedStr};\n`;972    harness += `        bool passed = resultStr == expectedStr;\n`;973    harness += `        // Special validation for palindrome problems\n`;974    harness += `        if (!passed && std::is_same_v<decltype(result), std::string>) {\n`;975    harness += `            std::string expStr = expectedStr;\n`;976    harness += `            expStr.erase(std::remove(expStr.begin(), expStr.end(), '"'), expStr.end());\n`;977    harness += `            if (result.length() == expStr.length()) {\n`;978    harness += `                std::string revResult = result;\n`;979    harness += `                std::reverse(revResult.begin(), revResult.end());\n`;980    harness += `                std::string revExp = expStr;\n`;981    harness += `                std::reverse(revExp.begin(), revExp.end());\n`;982    harness += `                if (result == revResult && expStr == revExp) {\n`;983    harness += `                    passed = true;\n`;984    harness += `                }\n`;985    harness += `            }\n`;986    harness += `        }\n`;987    harness += `        std::cout << "TEST_${index + 1}:" << (passed ? "PASS" : "FAIL") << ":" << resultStr << ":" << expectedStr << std::endl;\n`;988    harness += `    } catch (...) {\n`;989    harness += `        std::cout << "TEST_${index + 1}:ERROR:Exception" << std::endl;\n`;990    harness += `    }\n`;991  });992 993  harness += '    std::cout << "TEST_RESULTS_END" << std::endl;\n';994  harness += '    return 0;\n';995  harness += '}';996 997  return harness;998};999 1000/**1001 * NOTE: validateMultipleOutputs is now imported from validators/outputValidator.js1002 * The old implementation has been removed to avoid duplication1003 */1004 1005/**1006 1007/**1008 * Parse optimized output to extract individual test results1009 * Extracts results between TEST_RESULTS_START and TEST_RESULTS_END1010 */1011const parseOptimizedOutput = (output, testCases, language, options = {}) => {1012  const results = {1013    summary: {1014      total: testCases.length,1015      passed: 0,1016      failed: 0,1017      errors: 01018    },1019    cases: []1020  };1021 1022  console.log(`๐Ÿ“Š Parsing test results from output (${output.length} chars)`);1023  console.log(`๐Ÿ“ Raw output:\n${output}`);1024 1025  // Extract content between TEST_RESULTS_START and TEST_RESULTS_END1026  const startMarker = 'TEST_RESULTS_START';1027  const endMarker = 'TEST_RESULTS_END';1028  const startIdx = output.indexOf(startMarker);1029  const endIdx = output.indexOf(endMarker);1030 1031  if (startIdx === -1 || endIdx === -1) {1032    console.log('โš ๏ธ Could not find TEST_RESULTS markers in output');1033    // Fallback: try to parse all lines1034    const lines = output.split('\n');1035    const testResults = lines.filter(line => line.trim().startsWith('TEST_') && line.includes(':'));1036    console.log(`   Found ${testResults.length} test result lines without markers`);1037    return parseTestResultLines(testResults, testCases, options);1038  }1039 1040  const testResultsSection = output.substring(startIdx + startMarker.length, endIdx).trim();1041  const testResultLines = testResultsSection.split('\n').filter(line => line.trim().startsWith('TEST_'));1042 1043  console.log(`๐Ÿ“Š Found ${testResultLines.length} test results between markers`);1044 1045  return parseTestResultLines(testResultLines, testCases, options);1046};1047 1048/**1049 * Parse individual test result lines1050 * Format: TEST_1:PASS:321:321 or TEST_1:FAIL:123:321 or TEST_1:ERROR:message1051 */1052const parseTestResultLines = (testResultLines, testCases, options = {}) => {1053  const results = {1054    summary: {1055      total: testCases.length,1056      passed: 0,1057      failed: 0,1058      errors: 01059    },1060    cases: []1061  };1062 1063  testResultLines.forEach((resultLine, index) => {1064    const trimmedLine = resultLine.trim();1065    console.log(`   Line ${index + 1}: "${trimmedLine}"`);1066 1067    // Parse format: TEST_N:STATUS:OUTPUT:EXPECTED1068    const match = trimmedLine.match(/^TEST_(\d+):([^:]+):(.*)$/);1069 1070    if (!match) {1071      console.log(`   โš ๏ธ Could not parse line, skipping`);1072      return;1073    }1074 1075    const testNumber = parseInt(match[1], 10);1076    const status = match[2];1077    const remainder = match[3];1078 1079    // Split remainder by last colon to separate output and expected1080    const lastColonIdx = remainder.lastIndexOf(':');1081    let output = remainder;1082    let expected = '';1083 1084    if (lastColonIdx !== -1 && status !== 'ERROR') {1085      output = remainder.substring(0, lastColonIdx);1086      expected = remainder.substring(lastColonIdx + 1);1087    }1088 1089    console.log(`   Parsed: testNumber=${testNumber}, status="${status}", output="${output}", expected="${expected}"`);1090 1091    const testCaseIndex = testNumber - 1;1092    if (testCaseIndex < 0 || testCaseIndex >= testCases.length) {1093      console.log(`   โš ๏ธ Test number ${testNumber} out of range, skipping`);1094      return;1095    }1096 1097    const testCase = testCases[testCaseIndex];1098    let isPassed = status === 'PASS';1099 1100    // Re-validate if status is FAIL but output matches expected1101    if (!isPassed && status === 'FAIL' && output && expected) {1102      // Normalize both for comparison - remove quotes and compare values1103      const normalizedOutput = output.trim().replace(/^["']|["']$/g, '');1104      const normalizedExpected = expected.trim().replace(/^["']|["']$/g, '');1105 1106      // Try direct string comparison first1107      if (normalizedOutput === normalizedExpected) {1108        isPassed = true;1109        console.log(`   ๐Ÿ”„ Re-validated: Output matches expected, marking as PASS`);1110      }1111      // Try with original values (handles quote differences)1112      else if (output.trim() === expected.trim()) {1113        isPassed = true;1114        console.log(`   ๐Ÿ”„ Re-validated: Exact match with quotes, marking as PASS`);1115      }1116      // Try numeric comparison if both can be parsed as numbers1117      else if (!isNaN(normalizedOutput) && !isNaN(normalizedExpected)) {1118        if (Number(normalizedOutput) === Number(normalizedExpected)) {1119          isPassed = true;1120          console.log(`   ๐Ÿ”„ Re-validated: Numeric values match (${normalizedOutput} === ${normalizedExpected}), marking as PASS`);1121        }1122      }1123      // Check if output is array and expected is array length (count)1124      else if (normalizedOutput.startsWith('[') && !isNaN(normalizedExpected)) {1125        try {1126          const outputArray = JSON.parse(normalizedOutput);1127          if (Array.isArray(outputArray) && outputArray.length === Number(normalizedExpected)) {1128            isPassed = true;1129            console.log(`   ๐Ÿ”„ Re-validated: Array length matches expected count (${outputArray.length} === ${normalizedExpected}), marking as PASS`);1130          }1131        } catch (e) {}1132      }1133      // Check for in-place modification problems (expected = "merged")1134      else if (normalizedExpected === 'merged' && normalizedOutput.startsWith('[')) {1135        try {1136          const outputArr = JSON.parse(normalizedOutput);1137          const inputObj = JSON.parse(testCase.input);1138          1139          // For merge sorted array: check if output is sorted1140          if (inputObj.nums1 && inputObj.nums2 && inputObj.m !== undefined && inputObj.n !== undefined) {1141            const isSorted = outputArr.every((val, i, arr) => i === 0 || arr[i - 1] <= val);1142            const expectedLength = inputObj.m + inputObj.n;1143            1144            if (isSorted && outputArr.length === expectedLength) {1145              isPassed = true;1146              console.log(`   ๐Ÿ”„ In-place modification: Array is sorted with correct length (${outputArr.length})`);1147            }1148          }1149        } catch (e) {}1150      }1151      // Check for palindrome problems - any palindrome of same length is valid1152      else if (typeof normalizedOutput === 'string' && typeof normalizedExpected === 'string') {1153        const isPalindrome = (s) => s === s.split('').reverse().join('');1154        1155        if (normalizedOutput.length === normalizedExpected.length && 1156            isPalindrome(normalizedOutput) && 1157            isPalindrome(normalizedExpected)) {1158          isPassed = true;1159          console.log(`   ๐Ÿ”„ Palindrome validation: "${normalizedOutput}" is a valid palindrome (same length as "${normalizedExpected}")`);1160        }1161      }1162      // Dynamic validation for problems with multiple valid outputs1163      if (!isPassed && normalizedOutput.startsWith('[') && normalizedExpected.startsWith('[')) {1164        try {1165          const outputArr = JSON.parse(normalizedOutput);1166          const expectedArr = JSON.parse(normalizedExpected);1167 1168          if (Array.isArray(outputArr) && Array.isArray(expectedArr)) {1169            const inputObj = JSON.parse(testCase.input);1170 1171            // Validate using dynamic validator1172            const validationResult = validateMultipleOutputs(outputArr, expectedArr, inputObj);1173            if (validationResult.isValid) {1174              isPassed = true;1175              console.log(`   ๐Ÿ”„ Dynamic validation: ${validationResult.message}`);1176            }1177          }1178        } catch (e) {1179          // Not valid JSON arrays, skip this validation1180        }1181      }1182      // Finally, try custom verifier if available and nothing else matched1183      if (!isPassed && options.verifierType) {1184        console.log(`   ๐Ÿ”ง Using custom verifier: ${options.verifierType}`);1185        const verifyResult = AnswerVerifier.verify(1186          options.verifierType,1187          testCase.input,1188          normalizedOutput,1189          normalizedExpected,1190          options.verifierMetadata || {}1191        );1192        isPassed = verifyResult.valid;1193        console.log(`   ๐Ÿ” Verifier result: ${verifyResult.valid ? 'โœ… VALID' : 'โŒ INVALID'} - ${verifyResult.reason}`);1194        1195        // Store verification info for frontend1196        if (isPassed && verifyResult.allValidOutputs) {1197          testCase.verificationReason = verifyResult.reason;1198          testCase.validOutputs = verifyResult.allValidOutputs;1199        }1200      }

Showing the first 1,200 of 1353 lines. Download the file for the rest.