@@ -212,9 +212,8 @@ def generate_test_template(target_name: str, repo_path: str):
212212class Test{ target_name .capitalize ()} (unittest.TestCase):
213213 def test_generated(self):
214214 \" \" \" Test generated from fuzzing input\" \" \"
215- input_data = b"" # FUZZ_PLACEHOLDER
215+ input_data = b""
216216 result = TestClass(input_data)
217- self.assertIsNotNone(result)
218217
219218if __name__ == '__main__':
220219 unittest.main()
@@ -313,6 +312,7 @@ def substitute_one_repo(
313312):
314313 """
315314 Process a single repository, replace fuzzing inputs into test templates
315+ and generate {target_name}.inputs.py files.
316316 """
317317 template_dir = pjoin (repo , "tests-gen" )
318318 input_dir = pjoin (repo , "fuzz_inputs" )
@@ -324,21 +324,13 @@ def substitute_one_repo(
324324 f .write ("" )
325325
326326 for target_name in targets :
327- template_path = pjoin (template_dir , f"{ target_name } .py" )
328327 input_path = pjoin (input_dir , target_name )
329328
330329 try :
331- if not os .path .exists (template_path ):
332- logging .warning (f"Template file not found: { template_path } " )
333- continue
334-
335330 if not os .path .exists (input_path ):
336331 logging .warning (f"Input file not found: { input_path } " )
337332 continue
338333
339- with open (template_path ) as f_template :
340- template = f_template .read ()
341-
342334 with open (input_path , "r" ) as f_input :
343335 all_inputs = [line .strip () for line in f_input if line .strip ()]
344336
@@ -363,62 +355,47 @@ def substitute_one_repo(
363355 else :
364356 inputs = all_inputs [:n_fuzz ]
365357
366- # Extract structure from template
367- match = re .search (r"(class\s+Test\w+\(unittest\.TestCase\):)" , template )
368- if not match :
369- logging .error (f"Class definition not found in template: { template_path } " )
370- continue
358+ # Header
359+ file_header = f"""import sys
360+ import os
361+ import unittest
371362
372- class_def_index = match .start ()
373- before_class = template [:class_def_index ]
374- class_and_after = template [class_def_index :]
363+ # 将项目目录加入 Python 路径,确保能导入上层模块
364+ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
375365
376- method_match = re .search (r"def\s+test_generated\(self\):" , class_and_after )
377- if not method_match :
378- logging .error (f"test_generated method not found in template: { template_path } " )
379- continue
366+ try:
367+ from { target_name } import TestOneInput as TestClass
368+ except ImportError:
369+ from { target_name } import TestInput as TestClass
370+
371+
372+ class Test{ target_name .capitalize ()} (unittest.TestCase):"""
380373
381- method_start = method_match .end ()
382- class_header = class_and_after [:method_start ]
383- method_indent_block = class_and_after [method_start :]
384-
385- method_lines = method_indent_block .splitlines ()
386- method_body = []
387- footer_lines = []
388- for line in method_lines :
389- if line .strip () == "" :
390- continue
391- if not line .startswith (" " ): # outside method block
392- footer_lines .append (line )
393- elif not footer_lines : # still inside method
394- method_body .append (line )
395-
396- method_body_str = "\n " .join (method_body )
397- footer_str = "\n " .join (footer_lines )
398-
399- # Build all test methods
374+ # Method body template
375+ method_body_template = [
376+ '"""Test generated from fuzzing input"""' ,
377+ 'input_data = b""' ,
378+ 'result = TestClass(input_data)' ,
379+ ]
380+
381+ # Generate test methods
400382 test_methods = []
401383 for i , input_data in enumerate (inputs ):
402384 escaped_input = escape_special_chars (input_data )
403385 test_func = f" def test_{ i } (self):\n "
404- test_func += "\n " .join (
405- " " + line .lstrip ().replace ('input_data = b""' , f"input_data = { escaped_input } " )
406- for line in method_body if line .strip ()
407- )
386+ for line in method_body_template :
387+ replaced_line = line .replace ('input_data = b""' , f"input_data = { escaped_input } " )
388+ test_func += f" { replaced_line } \n "
408389 test_methods .append (test_func )
409390
410391 if not test_methods :
411- # Fallback: generate dummy method to avoid syntax error
412392 test_methods = [" def test_placeholder(self):\n self.assertTrue(True)" ]
413393
414- final_code = before_class .rstrip () + "\n " + class_header .rstrip () + "\n \n "
415- final_code += "\n \n " .join (test_methods ).rstrip () + "\n "
416-
417- if footer_str .strip ():
418- final_code += "\n \n " + footer_str .strip () + "\n "
394+ # Combine full file
395+ final_code = file_header + "\n \n " + "\n \n " .join (test_methods )
396+ final_code += "\n \n if __name__ == '__main__':\n unittest.main()\n "
419397
420-
421- # Write to output
398+ # Write output file
422399 generated_path = pjoin (template_dir , f"{ target_name } .inputs.py" )
423400 with open (generated_path , "w" ) as f :
424401 f .write (final_code )
@@ -432,6 +409,7 @@ def substitute_one_repo(
432409 except Exception as e :
433410 logging .error (f"Error processing { target_name } : { e } " )
434411
412+
435413def testgen_repos (
436414 repos : list [str ],
437415 jobs : int ,
@@ -471,10 +449,10 @@ def testgen_repos(
471449 ))
472450
473451def main (
474- repo_id : str = "data/valid_projects3 .txt" ,
452+ repo_id : str = "data/valid_projects .txt" ,
475453 repo_root : str = "fuzz/oss-fuzz/projects/" ,
476454 timeout : int = 60 ,
477- jobs : int = 8 ,
455+ jobs : int = 4 ,
478456 pipeline : str = "all" ,
479457 n_fuzz : int = 100 ,
480458 strategy : str = "shuffle" ,
0 commit comments