xref: /petsc/config/testparse.py (revision 09a6cbfc19aa11a41a0a44f530073aa8432f53ec)
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 KrugerExample language
1429921a8fSScott Kruger----------------
1529921a8fSScott Kruger
1629921a8fSScott Kruger/*TEST
17aec507c4SScott Kruger   build:
18aec507c4SScott Kruger     requires: moab
19e53dc769SScott Kruger   # This is equivalent to test:
20e53dc769SScott Kruger   testset:
2129921a8fSScott 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
2229921a8fSScott Kruger
23e53dc769SScott Kruger   testset:
2429921a8fSScott Kruger      suffix: 2
2529921a8fSScott Kruger      nsize: 2
2629921a8fSScott 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
2729921a8fSScott Kruger
28e53dc769SScott Kruger   testset:
29e53dc769SScott Kruger      suffix: 2
30e53dc769SScott Kruger      nsize: 2
31e53dc769SScott 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
32e53dc769SScott Kruger      test:
33e53dc769SScott Kruger
3429921a8fSScott KrugerTEST*/
3529921a8fSScott Kruger
3629921a8fSScott Kruger"""
3729921a8fSScott Kruger
3829921a8fSScott Krugerimport os, re, glob, types
3929921a8fSScott Krugerfrom distutils.sysconfig import parse_makefile
4029921a8fSScott Krugerimport sys
4129921a8fSScott Krugerimport logging
4229921a8fSScott Krugersys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
4329921a8fSScott Kruger
4429921a8fSScott Krugerimport inspect
4529921a8fSScott Krugerthisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
4629921a8fSScott Krugermaintdir=os.path.join(os.path.join(os.path.dirname(thisscriptdir),'bin'),'maint')
4729921a8fSScott Krugersys.path.insert(0,maintdir)
4866db876fSScott Kruger# Don't print out trace when raise Exceptions
4966db876fSScott Krugersys.tracebacklimit = 0
5029921a8fSScott Kruger
5129921a8fSScott Kruger# These are special keys describing build
5229921a8fSScott Krugerbuildkeys="requires TODO SKIP depends".split()
5329921a8fSScott Kruger
540a091e3eSScott Krugeracceptedkeys="test nsize requires command suffix args filter filter_output localrunfiles comments TODO SKIP output_file timeoutfactor".split()
5544776d8cSScott Krugerappendlist="args requires comments".split()
5668a9e459SScott Kruger
5768a9e459SScott Krugerimport re
5868a9e459SScott Kruger
5944776d8cSScott Krugerdef _stripIndent(block,srcfile,entireBlock=False,fileNums=[]):
6029921a8fSScott Kruger  """
6129921a8fSScott Kruger  Go through and remove a level of indentation
6229921a8fSScott Kruger  Also strip of trailing whitespace
6329921a8fSScott Kruger  """
6429921a8fSScott Kruger  # The first entry should be test: but it might be indented.
6529921a8fSScott Kruger  ext=os.path.splitext(srcfile)[1]
6644776d8cSScott Kruger  stripstr=" "
6766db876fSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
688ccd5183SScott Kruger  for lline in block.split("\n"):
6966db876fSScott Kruger    if len(fileNums)>0: lineNum+=1
708ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
7129921a8fSScott Kruger    if not line.strip(): continue
72c4b80baaSScott Kruger    if line.strip().startswith('#'): continue
7344776d8cSScott Kruger    if entireBlock:
7444776d8cSScott Kruger      var=line.split(":")[0].strip()
75aec507c4SScott Kruger      if not var in ['test','testset','build']:
7666db876fSScott Kruger        raise Exception("Formatting error: Cannot find test in file: "+srcfile+" at line: "+str(lineNum)+"\n")
7729921a8fSScott Kruger    nspace=len(line)-len(line.lstrip(stripstr))
7829921a8fSScott Kruger    newline=line[nspace:]
7929921a8fSScott Kruger    break
8029921a8fSScott Kruger
8129921a8fSScott Kruger  # Strip off any indentation for the whole string and any trailing
8229921a8fSScott Kruger  # whitespace for convenience
8329921a8fSScott Kruger  newTestStr="\n"
8444776d8cSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
8544776d8cSScott Kruger  firstPass=True
868ccd5183SScott Kruger  for lline in block.split("\n"):
8744776d8cSScott Kruger    if len(fileNums)>0: lineNum+=1
888ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
8929921a8fSScott Kruger    if not line.strip(): continue
90c4b80baaSScott Kruger    if line.strip().startswith('#'):
91c4b80baaSScott Kruger      newTestStr+=line+'\n'
92c4b80baaSScott Kruger    else:
9329921a8fSScott Kruger      newline=line[nspace:]
94c4b80baaSScott Kruger      newTestStr+=newline.rstrip()+"\n"
9544776d8cSScott Kruger    # Do some basic indentation checks
9644776d8cSScott Kruger    if entireBlock:
9744776d8cSScott Kruger      # Don't need to check comment lines
9844776d8cSScott Kruger      if line.strip().startswith('#'): continue
9944776d8cSScott Kruger      if not newline.startswith(" "):
10044776d8cSScott Kruger        var=newline.split(":")[0].strip()
101aec507c4SScott Kruger        if not var in ['test','testset','build']:
10244776d8cSScott Kruger          err="Formatting error in file "+srcfile+" at line: " +line+"\n"
10344776d8cSScott Kruger          if len(fileNums)>0:
10444776d8cSScott Kruger            raise Exception(err+"Check indentation at line number: "+str(lineNum))
10544776d8cSScott Kruger          else:
10644776d8cSScott Kruger            raise Exception(err)
10744776d8cSScott Kruger      else:
10844776d8cSScott Kruger        var=line.split(":")[0].strip()
109aec507c4SScott Kruger        if var in ['test','testset','build']:
11044776d8cSScott Kruger          subnspace=len(line)-len(line.lstrip(stripstr))
11144776d8cSScott Kruger          if firstPass:
11244776d8cSScott Kruger            firstsubnspace=subnspace
11344776d8cSScott Kruger            firstPass=False
11444776d8cSScott Kruger          else:
11544776d8cSScott Kruger            if firstsubnspace!=subnspace:
11644776d8cSScott Kruger              err="Formatting subtest error in file "+srcfile+" at line: " +line+"\n"
11744776d8cSScott Kruger              if len(fileNums)>0:
11844776d8cSScott Kruger                raise Exception(err+"Check indentation at line number: "+str(lineNum))
11944776d8cSScott Kruger              else:
12044776d8cSScott Kruger                raise Exception(err)
12144776d8cSScott Kruger
12229921a8fSScott Kruger
12329921a8fSScott Kruger  return newTestStr
12429921a8fSScott Kruger
125aae9f2d9SScott Krugerdef parseLoopArgs(varset):
12644776d8cSScott Kruger  """
127aae9f2d9SScott Kruger  Given:   String containing loop variables
128aae9f2d9SScott Kruger  Return: tuple containing separate/shared and string of loop vars
12944776d8cSScott Kruger  """
130aae9f2d9SScott Kruger  keynm=varset.split("{{")[0].strip()
131aae9f2d9SScott Kruger  if not keynm.strip(): keynm='nsize'
132aae9f2d9SScott Kruger  lvars=varset.split('{{')[1].split('}')[0]
133aae9f2d9SScott Kruger  suffx=varset.split('{{')[1].split('}')[1]
134aae9f2d9SScott Kruger  ftype='separate' if suffx.startswith('separate') else 'shared'
135aae9f2d9SScott Kruger  return keynm,lvars,ftype
13644776d8cSScott Kruger
137e53dc769SScott Krugerdef _getSeparateTestvars(testDict):
138e53dc769SScott Kruger  """
139e53dc769SScott Kruger  Given: dictionary that may have
140e53dc769SScott Kruger  Return:  Variables that cause a test split
141e53dc769SScott Kruger  """
142e53dc769SScott Kruger  vals=None
143e53dc769SScott Kruger  sepvars=[]
144e53dc769SScott Kruger  # Check nsize
145e53dc769SScott Kruger  if testDict.has_key('nsize'):
146e53dc769SScott Kruger    varset=testDict['nsize']
147aae9f2d9SScott Kruger    if '{{' in varset:
148aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
149aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
150e53dc769SScott Kruger
151e53dc769SScott Kruger  # Now check args
152e53dc769SScott Kruger  if not testDict.has_key('args'): return sepvars
153e53dc769SScott Kruger  for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
154e53dc769SScott Kruger    if not varset.strip(): continue
155aae9f2d9SScott Kruger    if '{{' in varset:
156e53dc769SScott Kruger      # Assuming only one for loop per var specification
157aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
158aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
159e53dc769SScott Kruger
160e53dc769SScott Kruger  return sepvars
161e53dc769SScott Kruger
16244776d8cSScott Krugerdef _getVarVals(findvar,testDict):
16344776d8cSScott Kruger  """
16444776d8cSScott Kruger  Given: variable that is either nsize or in args
16544776d8cSScott Kruger  Return:  Values to loop over
16644776d8cSScott Kruger  """
16744776d8cSScott Kruger  vals=None
16844776d8cSScott Kruger  newargs=''
16944776d8cSScott Kruger  if findvar=='nsize':
170e53dc769SScott Kruger    varset=testDict[findvar]
171aae9f2d9SScott Kruger    keynm,vals,ftype=parseLoopArgs('nsize '+varset)
17244776d8cSScott Kruger  else:
17344776d8cSScott Kruger    varlist=[]
17444776d8cSScott Kruger    for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
17544776d8cSScott Kruger      if not varset.strip(): continue
176aae9f2d9SScott Kruger      if '{{' in varset:
177aae9f2d9SScott Kruger        keyvar,vals,ftype=parseLoopArgs(varset)
17844776d8cSScott Kruger        if keyvar!=findvar:
1790bcc1aabSScott Kruger          newargs+="-"+varset.strip()+" "
18044776d8cSScott Kruger          continue
1810bcc1aabSScott Kruger      else:
1820bcc1aabSScott Kruger        newargs+="-"+varset.strip()+" "
18344776d8cSScott Kruger
18444776d8cSScott Kruger  if not vals: raise StandardError("Could not find separate_testvar: "+findvar)
18544776d8cSScott Kruger  return vals,newargs
18644776d8cSScott Kruger
18744776d8cSScott Krugerdef genTestsSeparateTestvars(intests,indicts):
18844776d8cSScott Kruger  """
189e53dc769SScott Kruger  Given: testname, sdict with 'separate_testvars
19044776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
19144776d8cSScott Kruger  """
19244776d8cSScott Kruger  testnames=[]; sdicts=[]
19344776d8cSScott Kruger  for i in range(len(intests)):
19444776d8cSScott Kruger    testname=intests[i]; sdict=indicts[i]; i+=1
195e53dc769SScott Kruger    separate_testvars=_getSeparateTestvars(sdict)
196e53dc769SScott Kruger    if len(separate_testvars)>0:
197e53dc769SScott Kruger      for kvar in separate_testvars:
19844776d8cSScott Kruger        kvals,newargs=_getVarVals(kvar,sdict)
19944776d8cSScott Kruger        # No errors means we are good to go
20044776d8cSScott Kruger        for val in kvals.split():
20144776d8cSScott Kruger          kvardict=sdict.copy()
20244776d8cSScott Kruger          gensuffix="_"+kvar+"-"+val
20344776d8cSScott Kruger          newtestnm=testname+gensuffix
2040bcc1aabSScott Kruger          if sdict.has_key('suffix'):
20544776d8cSScott Kruger            kvardict['suffix']=sdict['suffix']+gensuffix
2060bcc1aabSScott Kruger          else:
2070bcc1aabSScott Kruger            kvardict['suffix']=gensuffix
20844776d8cSScott Kruger          if kvar=='nsize':
20944776d8cSScott Kruger            kvardict[kvar]=val
21044776d8cSScott Kruger          else:
21144776d8cSScott Kruger            kvardict['args']=newargs+"-"+kvar+" "+val
21244776d8cSScott Kruger          testnames.append(newtestnm)
21344776d8cSScott Kruger          sdicts.append(kvardict)
21444776d8cSScott Kruger    else:
21544776d8cSScott Kruger      testnames.append(testname)
21644776d8cSScott Kruger      sdicts.append(sdict)
21744776d8cSScott Kruger  return testnames,sdicts
21844776d8cSScott Kruger
21944776d8cSScott Krugerdef genTestsSubtestSuffix(testnames,sdicts):
22044776d8cSScott Kruger  """
22144776d8cSScott Kruger  Given: testname, sdict with separate_testvars
22244776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
22344776d8cSScott Kruger  """
22444776d8cSScott Kruger  tnms=[]; sdcts=[]
22544776d8cSScott Kruger  for i in range(len(testnames)):
22644776d8cSScott Kruger    testname=testnames[i]
22744776d8cSScott Kruger    rmsubtests=[]; keepSubtests=False
22844776d8cSScott Kruger    if sdicts[i].has_key('subtests'):
22944776d8cSScott Kruger      for stest in sdicts[i]["subtests"]:
23044776d8cSScott Kruger        if sdicts[i][stest].has_key('suffix'):
23144776d8cSScott Kruger          rmsubtests.append(stest)
23244776d8cSScott Kruger          gensuffix="_"+sdicts[i][stest]['suffix']
23344776d8cSScott Kruger          newtestnm=testname+gensuffix
23444776d8cSScott Kruger          tnms.append(newtestnm)
23544776d8cSScott Kruger          newsdict=sdicts[i].copy()
23644776d8cSScott Kruger          del newsdict['subtests']
23744776d8cSScott Kruger          # Have to hand update
23844776d8cSScott Kruger          # Append
23944776d8cSScott Kruger          for kup in appendlist:
24044776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
24144776d8cSScott Kruger              if sdicts[i].has_key(kup):
24244776d8cSScott Kruger                newsdict[kup]=sdicts[i][kup]+" "+sdicts[i][stest][kup]
24344776d8cSScott Kruger              else:
24444776d8cSScott Kruger                newsdict[kup]=sdicts[i][stest][kup]
24544776d8cSScott Kruger          # Promote
24644776d8cSScott Kruger          for kup in acceptedkeys:
24744776d8cSScott Kruger            if kup in appendlist: continue
24844776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
24944776d8cSScott Kruger              newsdict[kup]=sdicts[i][stest][kup]
25044776d8cSScott Kruger          # Cleanup
25144776d8cSScott Kruger          for st in sdicts[i]["subtests"]: del newsdict[st]
25244776d8cSScott Kruger          sdcts.append(newsdict)
25344776d8cSScott Kruger        else:
25444776d8cSScott Kruger          keepSubtests=True
25544776d8cSScott Kruger    else:
25644776d8cSScott Kruger      tnms.append(testnames[i])
25744776d8cSScott Kruger      sdcts.append(sdicts[i])
2580bcc1aabSScott Kruger    # If a subtest without a suffix exists, then save it
25944776d8cSScott Kruger    if keepSubtests:
26044776d8cSScott Kruger      tnms.append(testnames[i])
2610bcc1aabSScott Kruger      newsdict=sdicts[i].copy()
2620bcc1aabSScott Kruger      # Prune the tests to prepare for keeping
2630bcc1aabSScott Kruger      for rmtest in rmsubtests:
2640bcc1aabSScott Kruger        newsdict['subtests'].remove(rmtest)
2650bcc1aabSScott Kruger        del newsdict[rmtest]
2660bcc1aabSScott Kruger      sdcts.append(newsdict)
26744776d8cSScott Kruger    i+=1
26844776d8cSScott Kruger  return tnms,sdcts
26944776d8cSScott Kruger
27044776d8cSScott Krugerdef splitTests(testname,sdict):
27144776d8cSScott Kruger  """
27244776d8cSScott Kruger  Given: testname and YAML-generated dictionary
27344776d8cSScott Kruger  Return: list of names and dictionaries corresponding to each test
27444776d8cSScott Kruger          given that the YAML language allows for multiple tests
27544776d8cSScott Kruger  """
27644776d8cSScott Kruger
27744776d8cSScott Kruger  # Order: Parent sep_tv, subtests suffix, subtests sep_tv
27844776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars([testname],[sdict])
27944776d8cSScott Kruger  testnames,sdicts=genTestsSubtestSuffix(testnames,sdicts)
28044776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars(testnames,sdicts)
28144776d8cSScott Kruger
28244776d8cSScott Kruger  # Because I am altering the list, I do this in passes.  Inelegant
28344776d8cSScott Kruger
28444776d8cSScott Kruger  return testnames, sdicts
28544776d8cSScott Kruger
2866cecdbdcSScott Krugerdef parseTest(testStr,srcfile,verbosity):
28729921a8fSScott Kruger  """
28829921a8fSScott Kruger  This parses an individual test
28929921a8fSScott Kruger  YAML is hierarchial so should use a state machine in the general case,
29053f2a965SBarry Smith  but in practice we only support two levels of test:
29129921a8fSScott Kruger  """
29229921a8fSScott Kruger  basename=os.path.basename(srcfile)
29329921a8fSScott Kruger  # Handle the new at the begininng
29429921a8fSScott Kruger  bn=re.sub("new_","",basename)
29529921a8fSScott Kruger  # This is the default
29629921a8fSScott Kruger  testname="run"+os.path.splitext(bn)[0]
29729921a8fSScott Kruger
29829921a8fSScott Kruger  # Tests that have default everything (so empty effectively)
29929921a8fSScott Kruger  if len(testStr)==0: return testname, {}
30029921a8fSScott Kruger
30129921a8fSScott Kruger  striptest=_stripIndent(testStr,srcfile)
30229921a8fSScott Kruger
30329921a8fSScott Kruger  # go through and parse
30429921a8fSScott Kruger  subtestnum=0
30529921a8fSScott Kruger  subdict={}
30668a9e459SScott Kruger  comments=[]
30768a9e459SScott Kruger  indentlevel=0
30868a9e459SScott Kruger  for ln in striptest.split("\n"):
309c4b80baaSScott Kruger    line=ln.split('#')[0].rstrip()
3106cecdbdcSScott Kruger    if verbosity>2: print line
3110bcc1aabSScott Kruger    comment=("" if len(ln.split("#"))>0 else " ".join(ln.split("#")[1:]).strip())
31268a9e459SScott Kruger    if comment: comments.append(comment)
31329921a8fSScott Kruger    if not line.strip(): continue
31444776d8cSScott Kruger    lsplit=line.split(':')
31544776d8cSScott Kruger    if len(lsplit)==0: raise Exception("Missing : in line: "+line)
31644776d8cSScott Kruger    indentcount=lsplit[0].count(" ")
31744776d8cSScott Kruger    var=lsplit[0].strip()
31840ae0433SScott Kruger    val=line[line.find(':')+1:].strip()
31944776d8cSScott Kruger    if not var in acceptedkeys: raise Exception("Not a defined key: "+var+" from:  "+line)
32029921a8fSScott Kruger    # Start by seeing if we are in a subtest
32129921a8fSScott Kruger    if line.startswith(" "):
322c0658d2aSScott Kruger      subdict[subtestname][var]=val
32368a9e459SScott Kruger      if not indentlevel: indentlevel=indentcount
32468a9e459SScott Kruger      #if indentlevel!=indentcount: print "Error in indentation:", ln
32529921a8fSScott Kruger    # Determine subtest name and make dict
32629921a8fSScott Kruger    elif var=="test":
32729921a8fSScott Kruger      subtestname="test"+str(subtestnum)
32829921a8fSScott Kruger      subdict[subtestname]={}
32929921a8fSScott Kruger      if not subdict.has_key("subtests"): subdict["subtests"]=[]
33029921a8fSScott Kruger      subdict["subtests"].append(subtestname)
33129921a8fSScott Kruger      subtestnum=subtestnum+1
33268a9e459SScott Kruger    # The rest are easy
33329921a8fSScott Kruger    else:
33444776d8cSScott Kruger      # For convenience, it is sometimes convenient to list twice
33544776d8cSScott Kruger      if subdict.has_key(var):
33644776d8cSScott Kruger        if var in appendlist:
33744776d8cSScott Kruger          subdict[var]+=" "+val
33844776d8cSScott Kruger        else:
33944776d8cSScott Kruger          raise Exception(var+" entered twice: "+line)
34044776d8cSScott Kruger      else:
341c0658d2aSScott Kruger        subdict[var]=val
34229921a8fSScott Kruger      if var=="suffix":
34329921a8fSScott Kruger        if len(val)>0:
34429921a8fSScott Kruger          testname=testname+"_"+val
34529921a8fSScott Kruger
34668a9e459SScott Kruger  if len(comments): subdict['comments']="\n".join(comments).lstrip("\n")
34744776d8cSScott Kruger  # A test block can create multiple tests.  This does
34844776d8cSScott Kruger  # that logic
34944776d8cSScott Kruger  testnames,subdicts=splitTests(testname,subdict)
35044776d8cSScott Kruger  return testnames,subdicts
35129921a8fSScott Kruger
3526cecdbdcSScott Krugerdef parseTests(testStr,srcfile,fileNums,verbosity):
35329921a8fSScott Kruger  """
35429921a8fSScott Kruger  Parse the yaml string describing tests and return
35529921a8fSScott Kruger  a dictionary with the info in the form of:
35629921a8fSScott Kruger    testDict[test][subtest]
35729921a8fSScott Kruger  This is an inelegant parser as we do not wish to
35829921a8fSScott Kruger  introduce a new dependency by bringing in pyyaml.
35929921a8fSScott Kruger  The advantage is that validation can be done as
36029921a8fSScott Kruger  it is parsed (e.g., 'test' is the only top-level node)
36129921a8fSScott Kruger  """
36229921a8fSScott Kruger
36329921a8fSScott Kruger  testDict={}
36429921a8fSScott Kruger
36529921a8fSScott Kruger  # The first entry should be test: but it might be indented.
36644776d8cSScott Kruger  newTestStr=_stripIndent(testStr,srcfile,entireBlock=True,fileNums=fileNums)
3676cecdbdcSScott Kruger  if verbosity>2: print srcfile
36829921a8fSScott Kruger
369aec507c4SScott Kruger  ## Check and see if we have build reuqirements
370aec507c4SScott Kruger  if "\nbuild:" in newTestStr:
371aec507c4SScott Kruger    testDict['build']={}
372aec507c4SScott Kruger    # The file info is already here and need to append
373aec507c4SScott Kruger    Part1=newTestStr.split("build:")[1]
374aec507c4SScott Kruger    fileInfo=re.split("\ntest(?:set)?:",newTestStr)[0]
375aec507c4SScott Kruger    for bkey in buildkeys:
376aec507c4SScott Kruger      if bkey+":" in fileInfo:
377aec507c4SScott Kruger        testDict['build'][bkey]=fileInfo.split(bkey+":")[1].split("\n")[0].strip()
378aec507c4SScott Kruger        #if verbosity>1: bkey+": "+testDict['build'][bkey]
379aec507c4SScott Kruger
38029921a8fSScott Kruger  # Now go through each test.  First elem in split is blank
381e53dc769SScott Kruger  for test in re.split("\ntest(?:set)?:",newTestStr)[1:]:
3826cecdbdcSScott Kruger    testnames,subdicts=parseTest(test,srcfile,verbosity)
38344776d8cSScott Kruger    for i in range(len(testnames)):
38444776d8cSScott Kruger      if testDict.has_key(testnames[i]):
3851acf9037SMatthew G. Knepley        raise RuntimeError("Multiple test names specified: "+testnames[i]+" in file: "+srcfile)
38644776d8cSScott Kruger      testDict[testnames[i]]=subdicts[i]
38729921a8fSScott Kruger
38829921a8fSScott Kruger  return testDict
38929921a8fSScott Kruger
3906cecdbdcSScott Krugerdef parseTestFile(srcfile,verbosity):
39129921a8fSScott Kruger  """
39229921a8fSScott Kruger  Parse single example files and return dictionary of the form:
39329921a8fSScott Kruger    testDict[srcfile][test][subtest]
39429921a8fSScott Kruger  """
39529921a8fSScott Kruger  debug=False
39629921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
39729921a8fSScott Kruger  basedir=os.path.dirname(os.path.realpath(srcfile))
39829921a8fSScott Kruger  basename=os.path.basename(srcfile)
39929921a8fSScott Kruger  os.chdir(basedir)
40029921a8fSScott Kruger
40129921a8fSScott Kruger  testDict={}
40229921a8fSScott Kruger  sh=open(srcfile,"r"); fileStr=sh.read(); sh.close()
40329921a8fSScott Kruger
40429921a8fSScott Kruger  ## Start with doing the tests
40529921a8fSScott Kruger  #
40629921a8fSScott Kruger  fsplit=fileStr.split("/*TEST\n")[1:]
40729921a8fSScott Kruger  if len(fsplit)==0:
40829921a8fSScott Kruger    if debug: print "No test found in: "+srcfile
40929921a8fSScott Kruger    return {}
41044776d8cSScott Kruger  fstart=len(fileStr.split("/*TEST\n")[0].split("\n"))+1
41129921a8fSScott Kruger  # Allow for multiple "/*TEST" blocks even though it really should be
4126f029658SMatthew G. Knepley  # one
41329921a8fSScott Kruger  srcTests=[]
41429921a8fSScott Kruger  for t in fsplit: srcTests.append(t.split("TEST*/")[0])
41529921a8fSScott Kruger  testString=" ".join(srcTests)
41629921a8fSScott Kruger  if len(testString.strip())==0:
41729921a8fSScott Kruger    print "No test found in: "+srcfile
41829921a8fSScott Kruger    return {}
41944776d8cSScott Kruger  flen=len(testString.split("\n"))
42044776d8cSScott Kruger  fend=fstart+flen-1
42144776d8cSScott Kruger  fileNums=range(fstart,fend)
4226cecdbdcSScott Kruger  testDict[basename]=parseTests(testString,srcfile,fileNums,verbosity)
423aec507c4SScott Kruger  # Massage dictionary for build requirements
424aec507c4SScott Kruger  if 'build' in testDict[basename]:
425aec507c4SScott Kruger    testDict[basename].update(testDict[basename]['build'])
426aec507c4SScott Kruger    del testDict[basename]['build']
42729921a8fSScott Kruger
42829921a8fSScott Kruger
42929921a8fSScott Kruger  os.chdir(curdir)
43029921a8fSScott Kruger  return testDict
43129921a8fSScott Kruger
4326cecdbdcSScott Krugerdef parseTestDir(directory,verbosity):
43329921a8fSScott Kruger  """
43429921a8fSScott Kruger  Parse single example files and return dictionary of the form:
43529921a8fSScott Kruger    testDict[srcfile][test][subtest]
43629921a8fSScott Kruger  """
43729921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
43829921a8fSScott Kruger  basedir=os.path.realpath(directory)
43929921a8fSScott Kruger  os.chdir(basedir)
44029921a8fSScott Kruger
44129921a8fSScott Kruger  tDict={}
442*09a6cbfcSBernhard M. Wiedemann  for test_file in sorted(glob.glob("new_ex*.*")):
4436cecdbdcSScott Kruger    tDict.update(parseTestFile(test_file,verbosity))
44429921a8fSScott Kruger
44529921a8fSScott Kruger  os.chdir(curdir)
44629921a8fSScott Kruger  return tDict
44729921a8fSScott Kruger
44829921a8fSScott Krugerdef printExParseDict(rDict):
44929921a8fSScott Kruger  """
45029921a8fSScott Kruger  This is useful for debugging
45129921a8fSScott Kruger  """
45229921a8fSScott Kruger  indent="   "
45329921a8fSScott Kruger  for sfile in rDict:
45444776d8cSScott Kruger    print sfile
45544776d8cSScott Kruger    sortkeys=rDict[sfile].keys()
45644776d8cSScott Kruger    sortkeys.sort()
45744776d8cSScott Kruger    for runex in sortkeys:
45829921a8fSScott Kruger      print indent+runex
45929921a8fSScott Kruger      if type(rDict[sfile][runex])==types.StringType:
46029921a8fSScott Kruger        print indent*2+rDict[sfile][runex]
46129921a8fSScott Kruger      else:
46229921a8fSScott Kruger        for var in rDict[sfile][runex]:
46344776d8cSScott Kruger          if var.startswith("test"): continue
46444776d8cSScott Kruger          print indent*2+var+": "+str(rDict[sfile][runex][var])
46544776d8cSScott Kruger        if rDict[sfile][runex].has_key('subtests'):
46644776d8cSScott Kruger          for var in rDict[sfile][runex]['subtests']:
46729921a8fSScott Kruger            print indent*2+var
46829921a8fSScott Kruger            for var2 in rDict[sfile][runex][var]:
46929921a8fSScott Kruger              print indent*3+var2+": "+str(rDict[sfile][runex][var][var2])
47044776d8cSScott Kruger      print "\n"
47129921a8fSScott Kruger  return
47229921a8fSScott Kruger
47329921a8fSScott Krugerdef main(directory='',test_file='',verbosity=0):
47429921a8fSScott Kruger
47529921a8fSScott Kruger    if directory:
4766cecdbdcSScott Kruger      tDict=parseTestDir(directory,verbosity)
47729921a8fSScott Kruger    else:
4786cecdbdcSScott Kruger      tDict=parseTestFile(test_file,verbosity)
47929921a8fSScott Kruger    if verbosity>0: printExParseDict(tDict)
48029921a8fSScott Kruger
48129921a8fSScott Kruger    return
48229921a8fSScott Kruger
48329921a8fSScott Krugerif __name__ == '__main__':
48429921a8fSScott Kruger    import optparse
48529921a8fSScott Kruger    parser = optparse.OptionParser()
48629921a8fSScott Kruger    parser.add_option('-d', '--directory', dest='directory',
48729921a8fSScott Kruger                      default="", help='Directory containing files to parse')
48829921a8fSScott Kruger    parser.add_option('-t', '--test_file', dest='test_file',
48929921a8fSScott Kruger                      default="", help='Test file, e.g., ex1.c, to parse')
49029921a8fSScott Kruger    parser.add_option('-v', '--verbosity', dest='verbosity',
49129921a8fSScott Kruger                      help='Verbosity of output by level: 1, 2, or 3', default=0)
49229921a8fSScott Kruger    opts, extra_args = parser.parse_args()
49329921a8fSScott Kruger
49429921a8fSScott Kruger    if extra_args:
49529921a8fSScott Kruger        import sys
49629921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
49729921a8fSScott Kruger        exit(1)
49829921a8fSScott Kruger    if not opts.test_file and not opts.directory:
49929921a8fSScott Kruger      print "test file or directory is required"
50029921a8fSScott Kruger      parser.print_usage()
50129921a8fSScott Kruger      sys.exit()
50229921a8fSScott Kruger
50329921a8fSScott Kruger    # Need verbosity to be an integer
50429921a8fSScott Kruger    try:
50529921a8fSScott Kruger      verbosity=int(opts.verbosity)
50629921a8fSScott Kruger    except:
50729921a8fSScott Kruger      raise Exception("Error: Verbosity must be integer")
50829921a8fSScott Kruger
50929921a8fSScott Kruger    main(directory=opts.directory,test_file=opts.test_file,verbosity=verbosity)
510