129921a8fSScott Kruger#!/usr/bin/env python 229921a8fSScott Kruger""" 329921a8fSScott KrugerParse the test file and return a dictionary. 429921a8fSScott Kruger 529921a8fSScott KrugerQuick usage:: 629921a8fSScott Kruger 729921a8fSScott Kruger bin/maint/testparse.py -t src/ksp/ksp/examples/tutorials/ex1.c 829921a8fSScott Kruger 929921a8fSScott KrugerFrom the command line, it prints out the dictionary. 1029921a8fSScott KrugerThis is meant to be used by other scripts, but it is 1129921a8fSScott Krugeruseful to debug individual files. 1229921a8fSScott Kruger 1329921a8fSScott Kruger 1429921a8fSScott Kruger 1529921a8fSScott KrugerExample language 1629921a8fSScott Kruger---------------- 1729921a8fSScott Kruger/*T 1829921a8fSScott Kruger Concepts: 1929921a8fSScott Kruger requires: moab 2029921a8fSScott KrugerT*/ 2129921a8fSScott Kruger 2229921a8fSScott Kruger 2329921a8fSScott Kruger 2429921a8fSScott Kruger/*TEST 2529921a8fSScott Kruger 26*e53dc769SScott Kruger # This is equivalent to test: 27*e53dc769SScott Kruger testset: 2829921a8fSScott Kruger args: -pc_type mg -ksp_type fgmres -da_refine 2 -ksp_monitor_short -mg_levels_ksp_monitor_short -mg_levels_ksp_norm_type unpreconditioned -ksp_view -pc_mg_type full 2929921a8fSScott Kruger 30*e53dc769SScott Kruger testset: 3129921a8fSScott Kruger suffix: 2 3229921a8fSScott Kruger nsize: 2 3329921a8fSScott Kruger args: -pc_type mg -ksp_type fgmres -da_refine 2 -ksp_monitor_short -mg_levels_ksp_monitor_short -mg_levels_ksp_norm_type unpreconditioned -ksp_view -pc_mg_type full 3429921a8fSScott Kruger 35*e53dc769SScott Kruger testset: 36*e53dc769SScott Kruger suffix: 2 37*e53dc769SScott Kruger nsize: 2 38*e53dc769SScott Kruger args: -pc_type mg -ksp_type fgmres -da_refine 2 -ksp_monitor_short -mg_levels_ksp_monitor_short -mg_levels_ksp_norm_type unpreconditioned -ksp_view -pc_mg_type full 39*e53dc769SScott Kruger test: 40*e53dc769SScott Kruger 4129921a8fSScott KrugerTEST*/ 4229921a8fSScott Kruger 4329921a8fSScott Kruger""" 4429921a8fSScott Kruger 4529921a8fSScott Krugerimport os, re, glob, types 4629921a8fSScott Krugerfrom distutils.sysconfig import parse_makefile 4729921a8fSScott Krugerimport sys 4829921a8fSScott Krugerimport logging 4929921a8fSScott Krugersys.path.insert(0, os.path.abspath(os.path.dirname(__file__))) 5029921a8fSScott Kruger 5129921a8fSScott Krugerimport inspect 5229921a8fSScott Krugerthisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) 5329921a8fSScott Krugermaintdir=os.path.join(os.path.join(os.path.dirname(thisscriptdir),'bin'),'maint') 5429921a8fSScott Krugersys.path.insert(0,maintdir) 5529921a8fSScott Kruger 5629921a8fSScott Kruger# These are special keys describing build 5729921a8fSScott Krugerbuildkeys="requires TODO SKIP depends".split() 5829921a8fSScott Kruger 59*e53dc769SScott Krugeracceptedkeys="test nsize requires command suffix args filter filter_output localrunfiles comments TODO SKIP output_file".split() 6044776d8cSScott Krugerappendlist="args requires comments".split() 6168a9e459SScott Kruger 6268a9e459SScott Krugerimport re 6368a9e459SScott Kruger 6444776d8cSScott Krugerdef _stripIndent(block,srcfile,entireBlock=False,fileNums=[]): 6529921a8fSScott Kruger """ 6629921a8fSScott Kruger Go through and remove a level of indentation 6729921a8fSScott Kruger Also strip of trailing whitespace 6829921a8fSScott Kruger """ 6929921a8fSScott Kruger # The first entry should be test: but it might be indented. 7029921a8fSScott Kruger ext=os.path.splitext(srcfile)[1] 7144776d8cSScott Kruger stripstr=" " 728ccd5183SScott Kruger for lline in block.split("\n"): 738ccd5183SScott Kruger line=lline[1:] if lline.startswith("!") else lline 7429921a8fSScott Kruger if not line.strip(): continue 75c4b80baaSScott Kruger if line.strip().startswith('#'): continue 7644776d8cSScott Kruger if entireBlock: 7744776d8cSScott Kruger var=line.split(":")[0].strip() 78*e53dc769SScott Kruger if not (var=='test' or var=='testset'): 7944776d8cSScott Kruger raise Exception("Formatting error in finding test in file: "+srcfile+"\n") 8029921a8fSScott Kruger nspace=len(line)-len(line.lstrip(stripstr)) 8129921a8fSScott Kruger newline=line[nspace:] 8229921a8fSScott Kruger break 8329921a8fSScott Kruger 8429921a8fSScott Kruger # Strip off any indentation for the whole string and any trailing 8529921a8fSScott Kruger # whitespace for convenience 8629921a8fSScott Kruger newTestStr="\n" 8744776d8cSScott Kruger if len(fileNums)>0: lineNum=fileNums[0]-1 8844776d8cSScott Kruger firstPass=True 898ccd5183SScott Kruger for lline in block.split("\n"): 9044776d8cSScott Kruger if len(fileNums)>0: lineNum+=1 918ccd5183SScott Kruger line=lline[1:] if lline.startswith("!") else lline 9229921a8fSScott Kruger if not line.strip(): continue 93c4b80baaSScott Kruger if line.strip().startswith('#'): 94c4b80baaSScott Kruger newTestStr+=line+'\n' 95c4b80baaSScott Kruger else: 9629921a8fSScott Kruger newline=line[nspace:] 97c4b80baaSScott Kruger newTestStr+=newline.rstrip()+"\n" 9844776d8cSScott Kruger # Do some basic indentation checks 9944776d8cSScott Kruger if entireBlock: 10044776d8cSScott Kruger # Don't need to check comment lines 10144776d8cSScott Kruger if line.strip().startswith('#'): continue 10244776d8cSScott Kruger if not newline.startswith(" "): 10344776d8cSScott Kruger var=newline.split(":")[0].strip() 104*e53dc769SScott Kruger if not (var=='test' or var=='testset'): 10544776d8cSScott Kruger err="Formatting error in file "+srcfile+" at line: " +line+"\n" 10644776d8cSScott Kruger if len(fileNums)>0: 10744776d8cSScott Kruger raise Exception(err+"Check indentation at line number: "+str(lineNum)) 10844776d8cSScott Kruger else: 10944776d8cSScott Kruger raise Exception(err) 11044776d8cSScott Kruger else: 11144776d8cSScott Kruger var=line.split(":")[0].strip() 112*e53dc769SScott Kruger if var=='test' or var=='testset': 11344776d8cSScott Kruger subnspace=len(line)-len(line.lstrip(stripstr)) 11444776d8cSScott Kruger if firstPass: 11544776d8cSScott Kruger firstsubnspace=subnspace 11644776d8cSScott Kruger firstPass=False 11744776d8cSScott Kruger else: 11844776d8cSScott Kruger if firstsubnspace!=subnspace: 11944776d8cSScott Kruger err="Formatting subtest error in file "+srcfile+" at line: " +line+"\n" 12044776d8cSScott Kruger if len(fileNums)>0: 12144776d8cSScott Kruger raise Exception(err+"Check indentation at line number: "+str(lineNum)) 12244776d8cSScott Kruger else: 12344776d8cSScott Kruger raise Exception(err) 12444776d8cSScott Kruger 12529921a8fSScott Kruger 12629921a8fSScott Kruger return newTestStr 12729921a8fSScott Kruger 12844776d8cSScott Krugerdef _getNewArgs(kvar,val,argStr): 12944776d8cSScott Kruger """ 13044776d8cSScott Kruger Given: String containing arguments 13144776d8cSScott Kruger Return: String without the value in it 13244776d8cSScott Kruger """ 13344776d8cSScott Kruger return newTestStr 13444776d8cSScott Kruger 135*e53dc769SScott Krugerdef _getSeparateTestvars(testDict): 136*e53dc769SScott Kruger """ 137*e53dc769SScott Kruger Given: dictionary that may have 138*e53dc769SScott Kruger Return: Variables that cause a test split 139*e53dc769SScott Kruger """ 140*e53dc769SScott Kruger vals=None 141*e53dc769SScott Kruger sepvars=[] 142*e53dc769SScott Kruger # Check nsize 143*e53dc769SScott Kruger if testDict.has_key('nsize'): 144*e53dc769SScott Kruger varset=testDict['nsize'] 145*e53dc769SScott Kruger if len(re.findall('{{(.*?)}(?:[\w\s]*)?}',varset))>0: 146*e53dc769SScott Kruger if 'separate' in re.findall('{{(?:.*?)}([\w\s]*)?}',varset)[0]: 147*e53dc769SScott Kruger sepvars.append('nsize') 148*e53dc769SScott Kruger 149*e53dc769SScott Kruger # Now check args 150*e53dc769SScott Kruger if not testDict.has_key('args'): return sepvars 151*e53dc769SScott Kruger for varset in re.split('-(?=[a-zA-Z])',testDict['args']): 152*e53dc769SScott Kruger if not varset.strip(): continue 153*e53dc769SScott Kruger if len(re.findall('{{(.*?)}(?:[\w\s]*)?}',varset))>0: 154*e53dc769SScott Kruger # Assuming only one for loop per var specification 155*e53dc769SScott Kruger keyvar=varset.split("{{")[0].strip() 156*e53dc769SScott Kruger fortype=re.findall('{{(?:.*?)}([\w\s]*)?}',varset)[0] 157*e53dc769SScott Kruger if 'separate' in fortype: sepvars.append(keyvar) 158*e53dc769SScott Kruger 159*e53dc769SScott Kruger return sepvars 160*e53dc769SScott Kruger 16144776d8cSScott Krugerdef _getVarVals(findvar,testDict): 16244776d8cSScott Kruger """ 16344776d8cSScott Kruger Given: variable that is either nsize or in args 16444776d8cSScott Kruger Return: Values to loop over 16544776d8cSScott Kruger """ 16644776d8cSScott Kruger vals=None 16744776d8cSScott Kruger newargs='' 16844776d8cSScott Kruger if findvar=='nsize': 169*e53dc769SScott Kruger varset=testDict[findvar] 170*e53dc769SScott Kruger vals=re.findall('{{(.*?)}(?:[\w\s]*)?}',varset)[0] 17144776d8cSScott Kruger else: 17244776d8cSScott Kruger varlist=[] 17344776d8cSScott Kruger for varset in re.split('-(?=[a-zA-Z])',testDict['args']): 17444776d8cSScott Kruger if not varset.strip(): continue 175*e53dc769SScott Kruger if len(re.findall('{{(.*?)}(?:[\w\s]*)?}',varset))>0: 17644776d8cSScott Kruger # Assuming only one for loop per var specification 17744776d8cSScott Kruger keyvar=varset.split("{{")[0].strip() 17844776d8cSScott Kruger if keyvar!=findvar: 1790bcc1aabSScott Kruger newargs+="-"+varset.strip()+" " 18044776d8cSScott Kruger continue 181*e53dc769SScott Kruger vals=re.findall('{{(.*?)}(?:[\w\s]*)?}',varset)[0] 1820bcc1aabSScott Kruger else: 1830bcc1aabSScott Kruger newargs+="-"+varset.strip()+" " 18444776d8cSScott Kruger 18544776d8cSScott Kruger if not vals: raise StandardError("Could not find separate_testvar: "+findvar) 18644776d8cSScott Kruger return vals,newargs 18744776d8cSScott Kruger 18844776d8cSScott Krugerdef genTestsSeparateTestvars(intests,indicts): 18944776d8cSScott Kruger """ 190*e53dc769SScott Kruger Given: testname, sdict with 'separate_testvars 19144776d8cSScott Kruger Return: testnames,sdicts: List of generated tests 19244776d8cSScott Kruger """ 19344776d8cSScott Kruger testnames=[]; sdicts=[] 19444776d8cSScott Kruger for i in range(len(intests)): 19544776d8cSScott Kruger testname=intests[i]; sdict=indicts[i]; i+=1 196*e53dc769SScott Kruger separate_testvars=_getSeparateTestvars(sdict) 197*e53dc769SScott Kruger if len(separate_testvars)>0: 198*e53dc769SScott Kruger for kvar in separate_testvars: 19944776d8cSScott Kruger kvals,newargs=_getVarVals(kvar,sdict) 20044776d8cSScott Kruger # No errors means we are good to go 20144776d8cSScott Kruger for val in kvals.split(): 20244776d8cSScott Kruger kvardict=sdict.copy() 20344776d8cSScott Kruger gensuffix="_"+kvar+"-"+val 20444776d8cSScott Kruger newtestnm=testname+gensuffix 2050bcc1aabSScott Kruger if sdict.has_key('suffix'): 20644776d8cSScott Kruger kvardict['suffix']=sdict['suffix']+gensuffix 2070bcc1aabSScott Kruger else: 2080bcc1aabSScott Kruger kvardict['suffix']=gensuffix 20944776d8cSScott Kruger if kvar=='nsize': 21044776d8cSScott Kruger kvardict[kvar]=val 21144776d8cSScott Kruger else: 21244776d8cSScott Kruger kvardict['args']=newargs+"-"+kvar+" "+val 21344776d8cSScott Kruger testnames.append(newtestnm) 21444776d8cSScott Kruger sdicts.append(kvardict) 21544776d8cSScott Kruger else: 21644776d8cSScott Kruger testnames.append(testname) 21744776d8cSScott Kruger sdicts.append(sdict) 21844776d8cSScott Kruger return testnames,sdicts 21944776d8cSScott Kruger 22044776d8cSScott Krugerdef genTestsSubtestSuffix(testnames,sdicts): 22144776d8cSScott Kruger """ 22244776d8cSScott Kruger Given: testname, sdict with separate_testvars 22344776d8cSScott Kruger Return: testnames,sdicts: List of generated tests 22444776d8cSScott Kruger """ 22544776d8cSScott Kruger tnms=[]; sdcts=[] 22644776d8cSScott Kruger for i in range(len(testnames)): 22744776d8cSScott Kruger testname=testnames[i] 22844776d8cSScott Kruger rmsubtests=[]; keepSubtests=False 22944776d8cSScott Kruger if sdicts[i].has_key('subtests'): 23044776d8cSScott Kruger for stest in sdicts[i]["subtests"]: 23144776d8cSScott Kruger if sdicts[i][stest].has_key('suffix'): 23244776d8cSScott Kruger rmsubtests.append(stest) 23344776d8cSScott Kruger gensuffix="_"+sdicts[i][stest]['suffix'] 23444776d8cSScott Kruger newtestnm=testname+gensuffix 23544776d8cSScott Kruger tnms.append(newtestnm) 23644776d8cSScott Kruger newsdict=sdicts[i].copy() 23744776d8cSScott Kruger del newsdict['subtests'] 23844776d8cSScott Kruger # Have to hand update 23944776d8cSScott Kruger # Append 24044776d8cSScott Kruger for kup in appendlist: 24144776d8cSScott Kruger if sdicts[i][stest].has_key(kup): 24244776d8cSScott Kruger if sdicts[i].has_key(kup): 24344776d8cSScott Kruger newsdict[kup]=sdicts[i][kup]+" "+sdicts[i][stest][kup] 24444776d8cSScott Kruger else: 24544776d8cSScott Kruger newsdict[kup]=sdicts[i][stest][kup] 24644776d8cSScott Kruger # Promote 24744776d8cSScott Kruger for kup in acceptedkeys: 24844776d8cSScott Kruger if kup in appendlist: continue 24944776d8cSScott Kruger if sdicts[i][stest].has_key(kup): 25044776d8cSScott Kruger newsdict[kup]=sdicts[i][stest][kup] 25144776d8cSScott Kruger # Cleanup 25244776d8cSScott Kruger for st in sdicts[i]["subtests"]: del newsdict[st] 25344776d8cSScott Kruger sdcts.append(newsdict) 25444776d8cSScott Kruger else: 25544776d8cSScott Kruger keepSubtests=True 25644776d8cSScott Kruger else: 25744776d8cSScott Kruger tnms.append(testnames[i]) 25844776d8cSScott Kruger sdcts.append(sdicts[i]) 2590bcc1aabSScott Kruger # If a subtest without a suffix exists, then save it 26044776d8cSScott Kruger if keepSubtests: 26144776d8cSScott Kruger tnms.append(testnames[i]) 2620bcc1aabSScott Kruger newsdict=sdicts[i].copy() 2630bcc1aabSScott Kruger # Prune the tests to prepare for keeping 2640bcc1aabSScott Kruger for rmtest in rmsubtests: 2650bcc1aabSScott Kruger newsdict['subtests'].remove(rmtest) 2660bcc1aabSScott Kruger del newsdict[rmtest] 2670bcc1aabSScott Kruger sdcts.append(newsdict) 26844776d8cSScott Kruger i+=1 26944776d8cSScott Kruger return tnms,sdcts 27044776d8cSScott Kruger 27144776d8cSScott Krugerdef splitTests(testname,sdict): 27244776d8cSScott Kruger """ 27344776d8cSScott Kruger Given: testname and YAML-generated dictionary 27444776d8cSScott Kruger Return: list of names and dictionaries corresponding to each test 27544776d8cSScott Kruger given that the YAML language allows for multiple tests 27644776d8cSScott Kruger """ 27744776d8cSScott Kruger 27844776d8cSScott Kruger # Order: Parent sep_tv, subtests suffix, subtests sep_tv 27944776d8cSScott Kruger testnames,sdicts=genTestsSeparateTestvars([testname],[sdict]) 28044776d8cSScott Kruger testnames,sdicts=genTestsSubtestSuffix(testnames,sdicts) 28144776d8cSScott Kruger testnames,sdicts=genTestsSeparateTestvars(testnames,sdicts) 28244776d8cSScott Kruger 28344776d8cSScott Kruger # Because I am altering the list, I do this in passes. Inelegant 28444776d8cSScott Kruger 28544776d8cSScott Kruger return testnames, sdicts 28644776d8cSScott Kruger 2876cecdbdcSScott Krugerdef parseTest(testStr,srcfile,verbosity): 28829921a8fSScott Kruger """ 28929921a8fSScott Kruger This parses an individual test 29029921a8fSScott Kruger YAML is hierarchial so should use a state machine in the general case, 29153f2a965SBarry Smith but in practice we only support two levels of test: 29229921a8fSScott Kruger """ 29329921a8fSScott Kruger basename=os.path.basename(srcfile) 29429921a8fSScott Kruger # Handle the new at the begininng 29529921a8fSScott Kruger bn=re.sub("new_","",basename) 29629921a8fSScott Kruger # This is the default 29729921a8fSScott Kruger testname="run"+os.path.splitext(bn)[0] 29829921a8fSScott Kruger 29929921a8fSScott Kruger # Tests that have default everything (so empty effectively) 30029921a8fSScott Kruger if len(testStr)==0: return testname, {} 30129921a8fSScott Kruger 30229921a8fSScott Kruger striptest=_stripIndent(testStr,srcfile) 30329921a8fSScott Kruger 30429921a8fSScott Kruger # go through and parse 30529921a8fSScott Kruger subtestnum=0 30629921a8fSScott Kruger subdict={} 30768a9e459SScott Kruger comments=[] 30868a9e459SScott Kruger indentlevel=0 30968a9e459SScott Kruger for ln in striptest.split("\n"): 310c4b80baaSScott Kruger line=ln.split('#')[0].rstrip() 3116cecdbdcSScott Kruger if verbosity>2: print line 3120bcc1aabSScott Kruger comment=("" if len(ln.split("#"))>0 else " ".join(ln.split("#")[1:]).strip()) 31368a9e459SScott Kruger if comment: comments.append(comment) 31429921a8fSScott Kruger if not line.strip(): continue 31544776d8cSScott Kruger lsplit=line.split(':') 31644776d8cSScott Kruger if len(lsplit)==0: raise Exception("Missing : in line: "+line) 31744776d8cSScott Kruger indentcount=lsplit[0].count(" ") 31844776d8cSScott Kruger var=lsplit[0].strip() 31944776d8cSScott Kruger val=lsplit[1].strip() 32044776d8cSScott Kruger if not var in acceptedkeys: raise Exception("Not a defined key: "+var+" from: "+line) 32129921a8fSScott Kruger # Start by seeing if we are in a subtest 32229921a8fSScott Kruger if line.startswith(" "): 323c0658d2aSScott Kruger subdict[subtestname][var]=val 32468a9e459SScott Kruger if not indentlevel: indentlevel=indentcount 32568a9e459SScott Kruger #if indentlevel!=indentcount: print "Error in indentation:", ln 32629921a8fSScott Kruger # Determine subtest name and make dict 32729921a8fSScott Kruger elif var=="test": 32829921a8fSScott Kruger subtestname="test"+str(subtestnum) 32929921a8fSScott Kruger subdict[subtestname]={} 33029921a8fSScott Kruger if not subdict.has_key("subtests"): subdict["subtests"]=[] 33129921a8fSScott Kruger subdict["subtests"].append(subtestname) 33229921a8fSScott Kruger subtestnum=subtestnum+1 33368a9e459SScott Kruger # The rest are easy 33429921a8fSScott Kruger else: 33544776d8cSScott Kruger # For convenience, it is sometimes convenient to list twice 33644776d8cSScott Kruger if subdict.has_key(var): 33744776d8cSScott Kruger if var in appendlist: 33844776d8cSScott Kruger subdict[var]+=" "+val 33944776d8cSScott Kruger else: 34044776d8cSScott Kruger raise Exception(var+" entered twice: "+line) 34144776d8cSScott Kruger else: 342c0658d2aSScott Kruger subdict[var]=val 34329921a8fSScott Kruger if var=="suffix": 34429921a8fSScott Kruger if len(val)>0: 34529921a8fSScott Kruger testname=testname+"_"+val 34629921a8fSScott Kruger 34768a9e459SScott Kruger if len(comments): subdict['comments']="\n".join(comments).lstrip("\n") 34844776d8cSScott Kruger # A test block can create multiple tests. This does 34944776d8cSScott Kruger # that logic 35044776d8cSScott Kruger testnames,subdicts=splitTests(testname,subdict) 35144776d8cSScott Kruger return testnames,subdicts 35229921a8fSScott Kruger 3536cecdbdcSScott Krugerdef parseTests(testStr,srcfile,fileNums,verbosity): 35429921a8fSScott Kruger """ 35529921a8fSScott Kruger Parse the yaml string describing tests and return 35629921a8fSScott Kruger a dictionary with the info in the form of: 35729921a8fSScott Kruger testDict[test][subtest] 35829921a8fSScott Kruger This is an inelegant parser as we do not wish to 35929921a8fSScott Kruger introduce a new dependency by bringing in pyyaml. 36029921a8fSScott Kruger The advantage is that validation can be done as 36129921a8fSScott Kruger it is parsed (e.g., 'test' is the only top-level node) 36229921a8fSScott Kruger """ 36329921a8fSScott Kruger 36429921a8fSScott Kruger testDict={} 36529921a8fSScott Kruger 36629921a8fSScott Kruger # The first entry should be test: but it might be indented. 36744776d8cSScott Kruger newTestStr=_stripIndent(testStr,srcfile,entireBlock=True,fileNums=fileNums) 3686cecdbdcSScott Kruger if verbosity>2: print srcfile 36929921a8fSScott Kruger 37029921a8fSScott Kruger # Now go through each test. First elem in split is blank 371*e53dc769SScott Kruger for test in re.split("\ntest(?:set)?:",newTestStr)[1:]: 3726cecdbdcSScott Kruger testnames,subdicts=parseTest(test,srcfile,verbosity) 37344776d8cSScott Kruger for i in range(len(testnames)): 37444776d8cSScott Kruger if testDict.has_key(testnames[i]): 37544776d8cSScott Kruger raise Error("Multiple test names specified: "+testname+" in file: "+srcfile) 37644776d8cSScott Kruger testDict[testnames[i]]=subdicts[i] 37729921a8fSScott Kruger 37829921a8fSScott Kruger return testDict 37929921a8fSScott Kruger 3806cecdbdcSScott Krugerdef parseTestFile(srcfile,verbosity): 38129921a8fSScott Kruger """ 38229921a8fSScott Kruger Parse single example files and return dictionary of the form: 38329921a8fSScott Kruger testDict[srcfile][test][subtest] 38429921a8fSScott Kruger """ 38529921a8fSScott Kruger debug=False 38629921a8fSScott Kruger curdir=os.path.realpath(os.path.curdir) 38729921a8fSScott Kruger basedir=os.path.dirname(os.path.realpath(srcfile)) 38829921a8fSScott Kruger basename=os.path.basename(srcfile) 38929921a8fSScott Kruger os.chdir(basedir) 39029921a8fSScott Kruger 39129921a8fSScott Kruger testDict={} 39229921a8fSScott Kruger sh=open(srcfile,"r"); fileStr=sh.read(); sh.close() 39329921a8fSScott Kruger 39429921a8fSScott Kruger ## Start with doing the tests 39529921a8fSScott Kruger # 39629921a8fSScott Kruger fsplit=fileStr.split("/*TEST\n")[1:] 39729921a8fSScott Kruger if len(fsplit)==0: 39829921a8fSScott Kruger if debug: print "No test found in: "+srcfile 39929921a8fSScott Kruger return {} 40044776d8cSScott Kruger fstart=len(fileStr.split("/*TEST\n")[0].split("\n"))+1 40129921a8fSScott Kruger # Allow for multiple "/*TEST" blocks even though it really should be 40229921a8fSScott Kruger # on 40329921a8fSScott Kruger srcTests=[] 40429921a8fSScott Kruger for t in fsplit: srcTests.append(t.split("TEST*/")[0]) 40529921a8fSScott Kruger testString=" ".join(srcTests) 40629921a8fSScott Kruger if len(testString.strip())==0: 40729921a8fSScott Kruger print "No test found in: "+srcfile 40829921a8fSScott Kruger return {} 40944776d8cSScott Kruger flen=len(testString.split("\n")) 41044776d8cSScott Kruger fend=fstart+flen-1 41144776d8cSScott Kruger fileNums=range(fstart,fend) 4126cecdbdcSScott Kruger testDict[basename]=parseTests(testString,srcfile,fileNums,verbosity) 41329921a8fSScott Kruger 41429921a8fSScott Kruger ## Check and see if we have build reuqirements 41529921a8fSScott Kruger # 41629921a8fSScott Kruger if "/*T\n" in fileStr or "/*T " in fileStr: 41729921a8fSScott Kruger # The file info is already here and need to append 41829921a8fSScott Kruger Part1=fileStr.split("T*/")[0] 41929921a8fSScott Kruger fileInfo=Part1.split("/*T")[1] 42029921a8fSScott Kruger for bkey in buildkeys: 42129921a8fSScott Kruger if bkey+":" in fileInfo: 42229921a8fSScott Kruger testDict[basename][bkey]=fileInfo.split(bkey+":")[1].split("\n")[0].strip() 42329921a8fSScott Kruger 42429921a8fSScott Kruger os.chdir(curdir) 42529921a8fSScott Kruger return testDict 42629921a8fSScott Kruger 4276cecdbdcSScott Krugerdef parseTestDir(directory,verbosity): 42829921a8fSScott Kruger """ 42929921a8fSScott Kruger Parse single example files and return dictionary of the form: 43029921a8fSScott Kruger testDict[srcfile][test][subtest] 43129921a8fSScott Kruger """ 43229921a8fSScott Kruger curdir=os.path.realpath(os.path.curdir) 43329921a8fSScott Kruger basedir=os.path.realpath(directory) 43429921a8fSScott Kruger os.chdir(basedir) 43529921a8fSScott Kruger 43629921a8fSScott Kruger tDict={} 43729921a8fSScott Kruger for test_file in glob.glob("new_ex*.*"): 4386cecdbdcSScott Kruger tDict.update(parseTestFile(test_file,verbosity)) 43929921a8fSScott Kruger 44029921a8fSScott Kruger os.chdir(curdir) 44129921a8fSScott Kruger return tDict 44229921a8fSScott Kruger 44329921a8fSScott Krugerdef printExParseDict(rDict): 44429921a8fSScott Kruger """ 44529921a8fSScott Kruger This is useful for debugging 44629921a8fSScott Kruger """ 44729921a8fSScott Kruger indent=" " 44829921a8fSScott Kruger for sfile in rDict: 44944776d8cSScott Kruger print sfile 45044776d8cSScott Kruger sortkeys=rDict[sfile].keys() 45144776d8cSScott Kruger sortkeys.sort() 45244776d8cSScott Kruger for runex in sortkeys: 45329921a8fSScott Kruger print indent+runex 45429921a8fSScott Kruger if type(rDict[sfile][runex])==types.StringType: 45529921a8fSScott Kruger print indent*2+rDict[sfile][runex] 45629921a8fSScott Kruger else: 45729921a8fSScott Kruger for var in rDict[sfile][runex]: 45844776d8cSScott Kruger if var.startswith("test"): continue 45944776d8cSScott Kruger print indent*2+var+": "+str(rDict[sfile][runex][var]) 46044776d8cSScott Kruger if rDict[sfile][runex].has_key('subtests'): 46144776d8cSScott Kruger for var in rDict[sfile][runex]['subtests']: 46229921a8fSScott Kruger print indent*2+var 46329921a8fSScott Kruger for var2 in rDict[sfile][runex][var]: 46429921a8fSScott Kruger print indent*3+var2+": "+str(rDict[sfile][runex][var][var2]) 46544776d8cSScott Kruger print "\n" 46629921a8fSScott Kruger return 46729921a8fSScott Kruger 46829921a8fSScott Krugerdef main(directory='',test_file='',verbosity=0): 46929921a8fSScott Kruger 47029921a8fSScott Kruger if directory: 4716cecdbdcSScott Kruger tDict=parseTestDir(directory,verbosity) 47229921a8fSScott Kruger else: 4736cecdbdcSScott Kruger tDict=parseTestFile(test_file,verbosity) 47429921a8fSScott Kruger if verbosity>0: printExParseDict(tDict) 47529921a8fSScott Kruger 47629921a8fSScott Kruger return 47729921a8fSScott Kruger 47829921a8fSScott Krugerif __name__ == '__main__': 47929921a8fSScott Kruger import optparse 48029921a8fSScott Kruger parser = optparse.OptionParser() 48129921a8fSScott Kruger parser.add_option('-d', '--directory', dest='directory', 48229921a8fSScott Kruger default="", help='Directory containing files to parse') 48329921a8fSScott Kruger parser.add_option('-t', '--test_file', dest='test_file', 48429921a8fSScott Kruger default="", help='Test file, e.g., ex1.c, to parse') 48529921a8fSScott Kruger parser.add_option('-v', '--verbosity', dest='verbosity', 48629921a8fSScott Kruger help='Verbosity of output by level: 1, 2, or 3', default=0) 48729921a8fSScott Kruger opts, extra_args = parser.parse_args() 48829921a8fSScott Kruger 48929921a8fSScott Kruger if extra_args: 49029921a8fSScott Kruger import sys 49129921a8fSScott Kruger sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args)) 49229921a8fSScott Kruger exit(1) 49329921a8fSScott Kruger if not opts.test_file and not opts.directory: 49429921a8fSScott Kruger print "test file or directory is required" 49529921a8fSScott Kruger parser.print_usage() 49629921a8fSScott Kruger sys.exit() 49729921a8fSScott Kruger 49829921a8fSScott Kruger # Need verbosity to be an integer 49929921a8fSScott Kruger try: 50029921a8fSScott Kruger verbosity=int(opts.verbosity) 50129921a8fSScott Kruger except: 50229921a8fSScott Kruger raise Exception("Error: Verbosity must be integer") 50329921a8fSScott Kruger 50429921a8fSScott Kruger main(directory=opts.directory,test_file=opts.test_file,verbosity=verbosity) 505