xref: /petsc/config/testparse.py (revision cadd188b9f1d8607f42de93a16c629eb84e56a3e)
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 Krugerimport sys
4029921a8fSScott Krugerimport logging
4129921a8fSScott Krugersys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
4229921a8fSScott Kruger
4329921a8fSScott Krugerimport inspect
4429921a8fSScott Krugerthisscriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
4529921a8fSScott Krugermaintdir=os.path.join(os.path.join(os.path.dirname(thisscriptdir),'bin'),'maint')
4629921a8fSScott Krugersys.path.insert(0,maintdir)
4766db876fSScott Kruger# Don't print out trace when raise Exceptions
4866db876fSScott Krugersys.tracebacklimit = 0
4929921a8fSScott Kruger
5029921a8fSScott Kruger# These are special keys describing build
5129921a8fSScott Krugerbuildkeys="requires TODO SKIP depends".split()
5229921a8fSScott Kruger
530a091e3eSScott Krugeracceptedkeys="test nsize requires command suffix args filter filter_output localrunfiles comments TODO SKIP output_file timeoutfactor".split()
5444776d8cSScott Krugerappendlist="args requires comments".split()
5568a9e459SScott Kruger
5668a9e459SScott Krugerimport re
5768a9e459SScott Kruger
5844776d8cSScott Krugerdef _stripIndent(block,srcfile,entireBlock=False,fileNums=[]):
5929921a8fSScott Kruger  """
6029921a8fSScott Kruger  Go through and remove a level of indentation
6129921a8fSScott Kruger  Also strip of trailing whitespace
6229921a8fSScott Kruger  """
6329921a8fSScott Kruger  # The first entry should be test: but it might be indented.
6429921a8fSScott Kruger  ext=os.path.splitext(srcfile)[1]
6544776d8cSScott Kruger  stripstr=" "
6666db876fSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
678ccd5183SScott Kruger  for lline in block.split("\n"):
6866db876fSScott Kruger    if len(fileNums)>0: lineNum+=1
698ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
7029921a8fSScott Kruger    if not line.strip(): continue
71c4b80baaSScott Kruger    if line.strip().startswith('#'): continue
7244776d8cSScott Kruger    if entireBlock:
7344776d8cSScott Kruger      var=line.split(":")[0].strip()
74aec507c4SScott Kruger      if not var in ['test','testset','build']:
7566db876fSScott Kruger        raise Exception("Formatting error: Cannot find test in file: "+srcfile+" at line: "+str(lineNum)+"\n")
7629921a8fSScott Kruger    nspace=len(line)-len(line.lstrip(stripstr))
7729921a8fSScott Kruger    newline=line[nspace:]
7829921a8fSScott Kruger    break
7929921a8fSScott Kruger
8029921a8fSScott Kruger  # Strip off any indentation for the whole string and any trailing
8129921a8fSScott Kruger  # whitespace for convenience
8229921a8fSScott Kruger  newTestStr="\n"
8344776d8cSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
8444776d8cSScott Kruger  firstPass=True
858ccd5183SScott Kruger  for lline in block.split("\n"):
8644776d8cSScott Kruger    if len(fileNums)>0: lineNum+=1
878ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
8829921a8fSScott Kruger    if not line.strip(): continue
89c4b80baaSScott Kruger    if line.strip().startswith('#'):
90c4b80baaSScott Kruger      newTestStr+=line+'\n'
91c4b80baaSScott Kruger    else:
9229921a8fSScott Kruger      newline=line[nspace:]
93c4b80baaSScott Kruger      newTestStr+=newline.rstrip()+"\n"
9444776d8cSScott Kruger    # Do some basic indentation checks
9544776d8cSScott Kruger    if entireBlock:
9644776d8cSScott Kruger      # Don't need to check comment lines
9744776d8cSScott Kruger      if line.strip().startswith('#'): continue
9844776d8cSScott Kruger      if not newline.startswith(" "):
9944776d8cSScott Kruger        var=newline.split(":")[0].strip()
100aec507c4SScott Kruger        if not var in ['test','testset','build']:
10144776d8cSScott Kruger          err="Formatting error in file "+srcfile+" at line: " +line+"\n"
10244776d8cSScott Kruger          if len(fileNums)>0:
10344776d8cSScott Kruger            raise Exception(err+"Check indentation at line number: "+str(lineNum))
10444776d8cSScott Kruger          else:
10544776d8cSScott Kruger            raise Exception(err)
10644776d8cSScott Kruger      else:
10744776d8cSScott Kruger        var=line.split(":")[0].strip()
108aec507c4SScott Kruger        if var in ['test','testset','build']:
10944776d8cSScott Kruger          subnspace=len(line)-len(line.lstrip(stripstr))
11044776d8cSScott Kruger          if firstPass:
11144776d8cSScott Kruger            firstsubnspace=subnspace
11244776d8cSScott Kruger            firstPass=False
11344776d8cSScott Kruger          else:
11444776d8cSScott Kruger            if firstsubnspace!=subnspace:
11544776d8cSScott Kruger              err="Formatting subtest error in file "+srcfile+" at line: " +line+"\n"
11644776d8cSScott Kruger              if len(fileNums)>0:
11744776d8cSScott Kruger                raise Exception(err+"Check indentation at line number: "+str(lineNum))
11844776d8cSScott Kruger              else:
11944776d8cSScott Kruger                raise Exception(err)
12044776d8cSScott Kruger
12129921a8fSScott Kruger
12229921a8fSScott Kruger  return newTestStr
12329921a8fSScott Kruger
124aae9f2d9SScott Krugerdef parseLoopArgs(varset):
12544776d8cSScott Kruger  """
126aae9f2d9SScott Kruger  Given:   String containing loop variables
127aae9f2d9SScott Kruger  Return: tuple containing separate/shared and string of loop vars
12844776d8cSScott Kruger  """
129aae9f2d9SScott Kruger  keynm=varset.split("{{")[0].strip()
130aae9f2d9SScott Kruger  if not keynm.strip(): keynm='nsize'
131aae9f2d9SScott Kruger  lvars=varset.split('{{')[1].split('}')[0]
132aae9f2d9SScott Kruger  suffx=varset.split('{{')[1].split('}')[1]
133aae9f2d9SScott Kruger  ftype='separate' if suffx.startswith('separate') else 'shared'
134aae9f2d9SScott Kruger  return keynm,lvars,ftype
13544776d8cSScott Kruger
136e53dc769SScott Krugerdef _getSeparateTestvars(testDict):
137e53dc769SScott Kruger  """
138e53dc769SScott Kruger  Given: dictionary that may have
139e53dc769SScott Kruger  Return:  Variables that cause a test split
140e53dc769SScott Kruger  """
141e53dc769SScott Kruger  vals=None
142e53dc769SScott Kruger  sepvars=[]
143e53dc769SScott Kruger  # Check nsize
144e53dc769SScott Kruger  if testDict.has_key('nsize'):
145e53dc769SScott Kruger    varset=testDict['nsize']
146aae9f2d9SScott Kruger    if '{{' in varset:
147aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
148aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
149e53dc769SScott Kruger
150e53dc769SScott Kruger  # Now check args
151e53dc769SScott Kruger  if not testDict.has_key('args'): return sepvars
152e53dc769SScott Kruger  for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
153e53dc769SScott Kruger    if not varset.strip(): continue
154aae9f2d9SScott Kruger    if '{{' in varset:
155e53dc769SScott Kruger      # Assuming only one for loop per var specification
156aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
157aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
158e53dc769SScott Kruger
159e53dc769SScott Kruger  return sepvars
160e53dc769SScott 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':
169e53dc769SScott Kruger    varset=testDict[findvar]
170aae9f2d9SScott Kruger    keynm,vals,ftype=parseLoopArgs('nsize '+varset)
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
175aae9f2d9SScott Kruger      if '{{' in varset:
176aae9f2d9SScott Kruger        keyvar,vals,ftype=parseLoopArgs(varset)
17744776d8cSScott Kruger        if keyvar!=findvar:
1780bcc1aabSScott Kruger          newargs+="-"+varset.strip()+" "
17944776d8cSScott Kruger          continue
1800bcc1aabSScott Kruger      else:
1810bcc1aabSScott Kruger        newargs+="-"+varset.strip()+" "
18244776d8cSScott Kruger
18344776d8cSScott Kruger  if not vals: raise StandardError("Could not find separate_testvar: "+findvar)
18444776d8cSScott Kruger  return vals,newargs
18544776d8cSScott Kruger
18644776d8cSScott Krugerdef genTestsSeparateTestvars(intests,indicts):
18744776d8cSScott Kruger  """
188e53dc769SScott Kruger  Given: testname, sdict with 'separate_testvars
18944776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
19044776d8cSScott Kruger  """
19144776d8cSScott Kruger  testnames=[]; sdicts=[]
19244776d8cSScott Kruger  for i in range(len(intests)):
19344776d8cSScott Kruger    testname=intests[i]; sdict=indicts[i]; i+=1
194e53dc769SScott Kruger    separate_testvars=_getSeparateTestvars(sdict)
195e53dc769SScott Kruger    if len(separate_testvars)>0:
196e53dc769SScott Kruger      for kvar in separate_testvars:
19744776d8cSScott Kruger        kvals,newargs=_getVarVals(kvar,sdict)
19844776d8cSScott Kruger        # No errors means we are good to go
19944776d8cSScott Kruger        for val in kvals.split():
20044776d8cSScott Kruger          kvardict=sdict.copy()
20144776d8cSScott Kruger          gensuffix="_"+kvar+"-"+val
20244776d8cSScott Kruger          newtestnm=testname+gensuffix
2030bcc1aabSScott Kruger          if sdict.has_key('suffix'):
20444776d8cSScott Kruger            kvardict['suffix']=sdict['suffix']+gensuffix
2050bcc1aabSScott Kruger          else:
2060bcc1aabSScott Kruger            kvardict['suffix']=gensuffix
20744776d8cSScott Kruger          if kvar=='nsize':
20844776d8cSScott Kruger            kvardict[kvar]=val
20944776d8cSScott Kruger          else:
21044776d8cSScott Kruger            kvardict['args']=newargs+"-"+kvar+" "+val
21144776d8cSScott Kruger          testnames.append(newtestnm)
21244776d8cSScott Kruger          sdicts.append(kvardict)
21344776d8cSScott Kruger    else:
21444776d8cSScott Kruger      testnames.append(testname)
21544776d8cSScott Kruger      sdicts.append(sdict)
21644776d8cSScott Kruger  return testnames,sdicts
21744776d8cSScott Kruger
21844776d8cSScott Krugerdef genTestsSubtestSuffix(testnames,sdicts):
21944776d8cSScott Kruger  """
22044776d8cSScott Kruger  Given: testname, sdict with separate_testvars
22144776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
22244776d8cSScott Kruger  """
22344776d8cSScott Kruger  tnms=[]; sdcts=[]
22444776d8cSScott Kruger  for i in range(len(testnames)):
22544776d8cSScott Kruger    testname=testnames[i]
22644776d8cSScott Kruger    rmsubtests=[]; keepSubtests=False
22744776d8cSScott Kruger    if sdicts[i].has_key('subtests'):
22844776d8cSScott Kruger      for stest in sdicts[i]["subtests"]:
22944776d8cSScott Kruger        if sdicts[i][stest].has_key('suffix'):
23044776d8cSScott Kruger          rmsubtests.append(stest)
23144776d8cSScott Kruger          gensuffix="_"+sdicts[i][stest]['suffix']
23244776d8cSScott Kruger          newtestnm=testname+gensuffix
23344776d8cSScott Kruger          tnms.append(newtestnm)
23444776d8cSScott Kruger          newsdict=sdicts[i].copy()
23544776d8cSScott Kruger          del newsdict['subtests']
23644776d8cSScott Kruger          # Have to hand update
23744776d8cSScott Kruger          # Append
23844776d8cSScott Kruger          for kup in appendlist:
23944776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
24044776d8cSScott Kruger              if sdicts[i].has_key(kup):
24144776d8cSScott Kruger                newsdict[kup]=sdicts[i][kup]+" "+sdicts[i][stest][kup]
24244776d8cSScott Kruger              else:
24344776d8cSScott Kruger                newsdict[kup]=sdicts[i][stest][kup]
24444776d8cSScott Kruger          # Promote
24544776d8cSScott Kruger          for kup in acceptedkeys:
24644776d8cSScott Kruger            if kup in appendlist: continue
24744776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
24844776d8cSScott Kruger              newsdict[kup]=sdicts[i][stest][kup]
24944776d8cSScott Kruger          # Cleanup
25044776d8cSScott Kruger          for st in sdicts[i]["subtests"]: del newsdict[st]
25144776d8cSScott Kruger          sdcts.append(newsdict)
25244776d8cSScott Kruger        else:
25344776d8cSScott Kruger          keepSubtests=True
25444776d8cSScott Kruger    else:
25544776d8cSScott Kruger      tnms.append(testnames[i])
25644776d8cSScott Kruger      sdcts.append(sdicts[i])
2570bcc1aabSScott Kruger    # If a subtest without a suffix exists, then save it
25844776d8cSScott Kruger    if keepSubtests:
25944776d8cSScott Kruger      tnms.append(testnames[i])
2600bcc1aabSScott Kruger      newsdict=sdicts[i].copy()
2610bcc1aabSScott Kruger      # Prune the tests to prepare for keeping
2620bcc1aabSScott Kruger      for rmtest in rmsubtests:
2630bcc1aabSScott Kruger        newsdict['subtests'].remove(rmtest)
2640bcc1aabSScott Kruger        del newsdict[rmtest]
2650bcc1aabSScott Kruger      sdcts.append(newsdict)
26644776d8cSScott Kruger    i+=1
26744776d8cSScott Kruger  return tnms,sdcts
26844776d8cSScott Kruger
26944776d8cSScott Krugerdef splitTests(testname,sdict):
27044776d8cSScott Kruger  """
27144776d8cSScott Kruger  Given: testname and YAML-generated dictionary
27244776d8cSScott Kruger  Return: list of names and dictionaries corresponding to each test
27344776d8cSScott Kruger          given that the YAML language allows for multiple tests
27444776d8cSScott Kruger  """
27544776d8cSScott Kruger
27644776d8cSScott Kruger  # Order: Parent sep_tv, subtests suffix, subtests sep_tv
27744776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars([testname],[sdict])
27844776d8cSScott Kruger  testnames,sdicts=genTestsSubtestSuffix(testnames,sdicts)
27944776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars(testnames,sdicts)
28044776d8cSScott Kruger
28144776d8cSScott Kruger  # Because I am altering the list, I do this in passes.  Inelegant
28244776d8cSScott Kruger
28344776d8cSScott Kruger  return testnames, sdicts
28444776d8cSScott Kruger
2856cecdbdcSScott Krugerdef parseTest(testStr,srcfile,verbosity):
28629921a8fSScott Kruger  """
28729921a8fSScott Kruger  This parses an individual test
28829921a8fSScott Kruger  YAML is hierarchial so should use a state machine in the general case,
28953f2a965SBarry Smith  but in practice we only support two levels of test:
29029921a8fSScott Kruger  """
29129921a8fSScott Kruger  basename=os.path.basename(srcfile)
29229921a8fSScott Kruger  # Handle the new at the begininng
29329921a8fSScott Kruger  bn=re.sub("new_","",basename)
29429921a8fSScott Kruger  # This is the default
29529921a8fSScott Kruger  testname="run"+os.path.splitext(bn)[0]
29629921a8fSScott Kruger
29729921a8fSScott Kruger  # Tests that have default everything (so empty effectively)
29878659935SScott Kruger  if len(testStr)==0: return [testname], [{}]
29929921a8fSScott Kruger
30029921a8fSScott Kruger  striptest=_stripIndent(testStr,srcfile)
30129921a8fSScott Kruger
30229921a8fSScott Kruger  # go through and parse
30329921a8fSScott Kruger  subtestnum=0
30429921a8fSScott Kruger  subdict={}
30568a9e459SScott Kruger  comments=[]
30668a9e459SScott Kruger  indentlevel=0
30768a9e459SScott Kruger  for ln in striptest.split("\n"):
308c4b80baaSScott Kruger    line=ln.split('#')[0].rstrip()
309*cadd188bSScott Kruger    if verbosity>2: print(line)
3100bcc1aabSScott Kruger    comment=("" if len(ln.split("#"))>0 else " ".join(ln.split("#")[1:]).strip())
31168a9e459SScott Kruger    if comment: comments.append(comment)
31229921a8fSScott Kruger    if not line.strip(): continue
31344776d8cSScott Kruger    lsplit=line.split(':')
31444776d8cSScott Kruger    if len(lsplit)==0: raise Exception("Missing : in line: "+line)
31544776d8cSScott Kruger    indentcount=lsplit[0].count(" ")
31644776d8cSScott Kruger    var=lsplit[0].strip()
31740ae0433SScott Kruger    val=line[line.find(':')+1:].strip()
31844776d8cSScott Kruger    if not var in acceptedkeys: raise Exception("Not a defined key: "+var+" from:  "+line)
31929921a8fSScott Kruger    # Start by seeing if we are in a subtest
32029921a8fSScott Kruger    if line.startswith(" "):
321c0658d2aSScott Kruger      subdict[subtestname][var]=val
32268a9e459SScott Kruger      if not indentlevel: indentlevel=indentcount
323*cadd188bSScott Kruger      #if indentlevel!=indentcount: print("Error in indentation:", ln)
32429921a8fSScott Kruger    # Determine subtest name and make dict
32529921a8fSScott Kruger    elif var=="test":
32629921a8fSScott Kruger      subtestname="test"+str(subtestnum)
32729921a8fSScott Kruger      subdict[subtestname]={}
32829921a8fSScott Kruger      if not subdict.has_key("subtests"): subdict["subtests"]=[]
32929921a8fSScott Kruger      subdict["subtests"].append(subtestname)
33029921a8fSScott Kruger      subtestnum=subtestnum+1
33168a9e459SScott Kruger    # The rest are easy
33229921a8fSScott Kruger    else:
33344776d8cSScott Kruger      # For convenience, it is sometimes convenient to list twice
33444776d8cSScott Kruger      if subdict.has_key(var):
33544776d8cSScott Kruger        if var in appendlist:
33644776d8cSScott Kruger          subdict[var]+=" "+val
33744776d8cSScott Kruger        else:
33844776d8cSScott Kruger          raise Exception(var+" entered twice: "+line)
33944776d8cSScott Kruger      else:
340c0658d2aSScott Kruger        subdict[var]=val
34129921a8fSScott Kruger      if var=="suffix":
34229921a8fSScott Kruger        if len(val)>0:
34329921a8fSScott Kruger          testname=testname+"_"+val
34429921a8fSScott Kruger
34568a9e459SScott Kruger  if len(comments): subdict['comments']="\n".join(comments).lstrip("\n")
34644776d8cSScott Kruger  # A test block can create multiple tests.  This does
34744776d8cSScott Kruger  # that logic
34844776d8cSScott Kruger  testnames,subdicts=splitTests(testname,subdict)
34944776d8cSScott Kruger  return testnames,subdicts
35029921a8fSScott Kruger
3516cecdbdcSScott Krugerdef parseTests(testStr,srcfile,fileNums,verbosity):
35229921a8fSScott Kruger  """
35329921a8fSScott Kruger  Parse the yaml string describing tests and return
35429921a8fSScott Kruger  a dictionary with the info in the form of:
35529921a8fSScott Kruger    testDict[test][subtest]
35629921a8fSScott Kruger  This is an inelegant parser as we do not wish to
35729921a8fSScott Kruger  introduce a new dependency by bringing in pyyaml.
35829921a8fSScott Kruger  The advantage is that validation can be done as
35929921a8fSScott Kruger  it is parsed (e.g., 'test' is the only top-level node)
36029921a8fSScott Kruger  """
36129921a8fSScott Kruger
36229921a8fSScott Kruger  testDict={}
36329921a8fSScott Kruger
36429921a8fSScott Kruger  # The first entry should be test: but it might be indented.
36544776d8cSScott Kruger  newTestStr=_stripIndent(testStr,srcfile,entireBlock=True,fileNums=fileNums)
366*cadd188bSScott Kruger  if verbosity>2: print(srcfile)
36729921a8fSScott Kruger
368aec507c4SScott Kruger  ## Check and see if we have build reuqirements
369aec507c4SScott Kruger  if "\nbuild:" in newTestStr:
370aec507c4SScott Kruger    testDict['build']={}
371aec507c4SScott Kruger    # The file info is already here and need to append
372aec507c4SScott Kruger    Part1=newTestStr.split("build:")[1]
373aec507c4SScott Kruger    fileInfo=re.split("\ntest(?:set)?:",newTestStr)[0]
374aec507c4SScott Kruger    for bkey in buildkeys:
375aec507c4SScott Kruger      if bkey+":" in fileInfo:
376aec507c4SScott Kruger        testDict['build'][bkey]=fileInfo.split(bkey+":")[1].split("\n")[0].strip()
377aec507c4SScott Kruger        #if verbosity>1: bkey+": "+testDict['build'][bkey]
378aec507c4SScott Kruger
37929921a8fSScott Kruger  # Now go through each test.  First elem in split is blank
380e53dc769SScott Kruger  for test in re.split("\ntest(?:set)?:",newTestStr)[1:]:
3816cecdbdcSScott Kruger    testnames,subdicts=parseTest(test,srcfile,verbosity)
38244776d8cSScott Kruger    for i in range(len(testnames)):
38344776d8cSScott Kruger      if testDict.has_key(testnames[i]):
3841acf9037SMatthew G. Knepley        raise RuntimeError("Multiple test names specified: "+testnames[i]+" in file: "+srcfile)
38544776d8cSScott Kruger      testDict[testnames[i]]=subdicts[i]
38629921a8fSScott Kruger
38729921a8fSScott Kruger  return testDict
38829921a8fSScott Kruger
3896cecdbdcSScott Krugerdef parseTestFile(srcfile,verbosity):
39029921a8fSScott Kruger  """
39129921a8fSScott Kruger  Parse single example files and return dictionary of the form:
39229921a8fSScott Kruger    testDict[srcfile][test][subtest]
39329921a8fSScott Kruger  """
39429921a8fSScott Kruger  debug=False
395*cadd188bSScott Kruger  basename=os.path.basename(srcfile)
396*cadd188bSScott Kruger  if basename=='makefile': return {}
397*cadd188bSScott Kruger
39829921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
39929921a8fSScott Kruger  basedir=os.path.dirname(os.path.realpath(srcfile))
40029921a8fSScott Kruger  os.chdir(basedir)
40129921a8fSScott Kruger
40229921a8fSScott Kruger  testDict={}
403*cadd188bSScott Kruger  sh=open(basename,"r"); fileStr=sh.read(); sh.close()
40429921a8fSScott Kruger
40529921a8fSScott Kruger  ## Start with doing the tests
40629921a8fSScott Kruger  #
40729921a8fSScott Kruger  fsplit=fileStr.split("/*TEST\n")[1:]
40829921a8fSScott Kruger  if len(fsplit)==0:
409*cadd188bSScott Kruger    if debug: print("No test found in: "+srcfile)
410*cadd188bSScott Kruger    os.chdir(curdir)
41129921a8fSScott Kruger    return {}
41244776d8cSScott Kruger  fstart=len(fileStr.split("/*TEST\n")[0].split("\n"))+1
41329921a8fSScott Kruger  # Allow for multiple "/*TEST" blocks even though it really should be
4146f029658SMatthew G. Knepley  # one
41529921a8fSScott Kruger  srcTests=[]
41629921a8fSScott Kruger  for t in fsplit: srcTests.append(t.split("TEST*/")[0])
41729921a8fSScott Kruger  testString=" ".join(srcTests)
41829921a8fSScott Kruger  if len(testString.strip())==0:
419*cadd188bSScott Kruger    print("No test found in: "+srcfile)
420*cadd188bSScott Kruger    os.chdir(curdir)
42129921a8fSScott Kruger    return {}
42244776d8cSScott Kruger  flen=len(testString.split("\n"))
42344776d8cSScott Kruger  fend=fstart+flen-1
42444776d8cSScott Kruger  fileNums=range(fstart,fend)
4256cecdbdcSScott Kruger  testDict[basename]=parseTests(testString,srcfile,fileNums,verbosity)
426aec507c4SScott Kruger  # Massage dictionary for build requirements
427aec507c4SScott Kruger  if 'build' in testDict[basename]:
428aec507c4SScott Kruger    testDict[basename].update(testDict[basename]['build'])
429aec507c4SScott Kruger    del testDict[basename]['build']
43029921a8fSScott Kruger
43129921a8fSScott Kruger
43229921a8fSScott Kruger  os.chdir(curdir)
43329921a8fSScott Kruger  return testDict
43429921a8fSScott Kruger
4356cecdbdcSScott Krugerdef parseTestDir(directory,verbosity):
43629921a8fSScott Kruger  """
43729921a8fSScott Kruger  Parse single example files and return dictionary of the form:
43829921a8fSScott Kruger    testDict[srcfile][test][subtest]
43929921a8fSScott Kruger  """
44029921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
44129921a8fSScott Kruger  basedir=os.path.realpath(directory)
44229921a8fSScott Kruger  os.chdir(basedir)
44329921a8fSScott Kruger
44429921a8fSScott Kruger  tDict={}
44529921a8fSScott Kruger  for test_file in glob.glob("new_ex*.*"):
4466cecdbdcSScott Kruger    tDict.update(parseTestFile(test_file,verbosity))
44729921a8fSScott Kruger
44829921a8fSScott Kruger  os.chdir(curdir)
44929921a8fSScott Kruger  return tDict
45029921a8fSScott Kruger
45129921a8fSScott Krugerdef printExParseDict(rDict):
45229921a8fSScott Kruger  """
45329921a8fSScott Kruger  This is useful for debugging
45429921a8fSScott Kruger  """
45529921a8fSScott Kruger  indent="   "
45629921a8fSScott Kruger  for sfile in rDict:
457*cadd188bSScott Kruger    print(sfile)
45844776d8cSScott Kruger    sortkeys=rDict[sfile].keys()
45944776d8cSScott Kruger    sortkeys.sort()
46044776d8cSScott Kruger    for runex in sortkeys:
461*cadd188bSScott Kruger      print(indent+runex)
46229921a8fSScott Kruger      if type(rDict[sfile][runex])==types.StringType:
463*cadd188bSScott Kruger        print(indent*2+rDict[sfile][runex])
46429921a8fSScott Kruger      else:
46529921a8fSScott Kruger        for var in rDict[sfile][runex]:
46644776d8cSScott Kruger          if var.startswith("test"): continue
467*cadd188bSScott Kruger          print(indent*2+var+": "+str(rDict[sfile][runex][var]))
46844776d8cSScott Kruger        if rDict[sfile][runex].has_key('subtests'):
46944776d8cSScott Kruger          for var in rDict[sfile][runex]['subtests']:
470*cadd188bSScott Kruger            print(indent*2+var)
47129921a8fSScott Kruger            for var2 in rDict[sfile][runex][var]:
472*cadd188bSScott Kruger              print(indent*3+var2+": "+str(rDict[sfile][runex][var][var2]))
473*cadd188bSScott Kruger      print("\n")
47429921a8fSScott Kruger  return
47529921a8fSScott Kruger
47629921a8fSScott Krugerdef main(directory='',test_file='',verbosity=0):
47729921a8fSScott Kruger
47829921a8fSScott Kruger    if directory:
4796cecdbdcSScott Kruger      tDict=parseTestDir(directory,verbosity)
48029921a8fSScott Kruger    else:
4816cecdbdcSScott Kruger      tDict=parseTestFile(test_file,verbosity)
48229921a8fSScott Kruger    if verbosity>0: printExParseDict(tDict)
48329921a8fSScott Kruger
48429921a8fSScott Kruger    return
48529921a8fSScott Kruger
48629921a8fSScott Krugerif __name__ == '__main__':
48729921a8fSScott Kruger    import optparse
48829921a8fSScott Kruger    parser = optparse.OptionParser()
48929921a8fSScott Kruger    parser.add_option('-d', '--directory', dest='directory',
49029921a8fSScott Kruger                      default="", help='Directory containing files to parse')
49129921a8fSScott Kruger    parser.add_option('-t', '--test_file', dest='test_file',
49229921a8fSScott Kruger                      default="", help='Test file, e.g., ex1.c, to parse')
49329921a8fSScott Kruger    parser.add_option('-v', '--verbosity', dest='verbosity',
49429921a8fSScott Kruger                      help='Verbosity of output by level: 1, 2, or 3', default=0)
49529921a8fSScott Kruger    opts, extra_args = parser.parse_args()
49629921a8fSScott Kruger
49729921a8fSScott Kruger    if extra_args:
49829921a8fSScott Kruger        import sys
49929921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
50029921a8fSScott Kruger        exit(1)
50129921a8fSScott Kruger    if not opts.test_file and not opts.directory:
502*cadd188bSScott Kruger      print("test file or directory is required")
50329921a8fSScott Kruger      parser.print_usage()
50429921a8fSScott Kruger      sys.exit()
50529921a8fSScott Kruger
50629921a8fSScott Kruger    # Need verbosity to be an integer
50729921a8fSScott Kruger    try:
50829921a8fSScott Kruger      verbosity=int(opts.verbosity)
50929921a8fSScott Kruger    except:
51029921a8fSScott Kruger      raise Exception("Error: Verbosity must be integer")
51129921a8fSScott Kruger
51229921a8fSScott Kruger    main(directory=opts.directory,test_file=opts.test_file,verbosity=verbosity)
513