xref: /petsc/config/testparse.py (revision e465398351c8a19bfc0bba70933f76b2a1488f1d)
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)
4729921a8fSScott Kruger
4829921a8fSScott Kruger# These are special keys describing build
4929921a8fSScott Krugerbuildkeys="requires TODO SKIP depends".split()
5029921a8fSScott Kruger
510a091e3eSScott Krugeracceptedkeys="test nsize requires command suffix args filter filter_output localrunfiles comments TODO SKIP output_file timeoutfactor".split()
5244776d8cSScott Krugerappendlist="args requires comments".split()
5368a9e459SScott Kruger
5468a9e459SScott Krugerimport re
5568a9e459SScott Kruger
5644776d8cSScott Krugerdef _stripIndent(block,srcfile,entireBlock=False,fileNums=[]):
5729921a8fSScott Kruger  """
5829921a8fSScott Kruger  Go through and remove a level of indentation
5929921a8fSScott Kruger  Also strip of trailing whitespace
6029921a8fSScott Kruger  """
6129921a8fSScott Kruger  # The first entry should be test: but it might be indented.
6229921a8fSScott Kruger  ext=os.path.splitext(srcfile)[1]
6344776d8cSScott Kruger  stripstr=" "
6466db876fSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
658ccd5183SScott Kruger  for lline in block.split("\n"):
6666db876fSScott Kruger    if len(fileNums)>0: lineNum+=1
678ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
6829921a8fSScott Kruger    if not line.strip(): continue
69c4b80baaSScott Kruger    if line.strip().startswith('#'): continue
7044776d8cSScott Kruger    if entireBlock:
7144776d8cSScott Kruger      var=line.split(":")[0].strip()
72aec507c4SScott Kruger      if not var in ['test','testset','build']:
7366db876fSScott Kruger        raise Exception("Formatting error: Cannot find test in file: "+srcfile+" at line: "+str(lineNum)+"\n")
7429921a8fSScott Kruger    nspace=len(line)-len(line.lstrip(stripstr))
7529921a8fSScott Kruger    newline=line[nspace:]
7629921a8fSScott Kruger    break
7729921a8fSScott Kruger
7829921a8fSScott Kruger  # Strip off any indentation for the whole string and any trailing
7929921a8fSScott Kruger  # whitespace for convenience
8029921a8fSScott Kruger  newTestStr="\n"
8144776d8cSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
8244776d8cSScott Kruger  firstPass=True
838ccd5183SScott Kruger  for lline in block.split("\n"):
8444776d8cSScott Kruger    if len(fileNums)>0: lineNum+=1
858ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
8629921a8fSScott Kruger    if not line.strip(): continue
87c4b80baaSScott Kruger    if line.strip().startswith('#'):
88c4b80baaSScott Kruger      newTestStr+=line+'\n'
89c4b80baaSScott Kruger    else:
9029921a8fSScott Kruger      newline=line[nspace:]
91c4b80baaSScott Kruger      newTestStr+=newline.rstrip()+"\n"
9244776d8cSScott Kruger    # Do some basic indentation checks
9344776d8cSScott Kruger    if entireBlock:
9444776d8cSScott Kruger      # Don't need to check comment lines
9544776d8cSScott Kruger      if line.strip().startswith('#'): continue
9644776d8cSScott Kruger      if not newline.startswith(" "):
9744776d8cSScott Kruger        var=newline.split(":")[0].strip()
98aec507c4SScott Kruger        if not var in ['test','testset','build']:
9944776d8cSScott Kruger          err="Formatting error in file "+srcfile+" at line: " +line+"\n"
10044776d8cSScott Kruger          if len(fileNums)>0:
10144776d8cSScott Kruger            raise Exception(err+"Check indentation at line number: "+str(lineNum))
10244776d8cSScott Kruger          else:
10344776d8cSScott Kruger            raise Exception(err)
10444776d8cSScott Kruger      else:
10544776d8cSScott Kruger        var=line.split(":")[0].strip()
106aec507c4SScott Kruger        if var in ['test','testset','build']:
10744776d8cSScott Kruger          subnspace=len(line)-len(line.lstrip(stripstr))
10844776d8cSScott Kruger          if firstPass:
10944776d8cSScott Kruger            firstsubnspace=subnspace
11044776d8cSScott Kruger            firstPass=False
11144776d8cSScott Kruger          else:
11244776d8cSScott Kruger            if firstsubnspace!=subnspace:
11344776d8cSScott Kruger              err="Formatting subtest error in file "+srcfile+" at line: " +line+"\n"
11444776d8cSScott Kruger              if len(fileNums)>0:
11544776d8cSScott Kruger                raise Exception(err+"Check indentation at line number: "+str(lineNum))
11644776d8cSScott Kruger              else:
11744776d8cSScott Kruger                raise Exception(err)
11844776d8cSScott Kruger
11929921a8fSScott Kruger
12029921a8fSScott Kruger  return newTestStr
12129921a8fSScott Kruger
122aae9f2d9SScott Krugerdef parseLoopArgs(varset):
12344776d8cSScott Kruger  """
124aae9f2d9SScott Kruger  Given:   String containing loop variables
125aae9f2d9SScott Kruger  Return: tuple containing separate/shared and string of loop vars
12644776d8cSScott Kruger  """
127aae9f2d9SScott Kruger  keynm=varset.split("{{")[0].strip()
128aae9f2d9SScott Kruger  if not keynm.strip(): keynm='nsize'
129aae9f2d9SScott Kruger  lvars=varset.split('{{')[1].split('}')[0]
130aae9f2d9SScott Kruger  suffx=varset.split('{{')[1].split('}')[1]
131aae9f2d9SScott Kruger  ftype='separate' if suffx.startswith('separate') else 'shared'
132aae9f2d9SScott Kruger  return keynm,lvars,ftype
13344776d8cSScott Kruger
134e53dc769SScott Krugerdef _getSeparateTestvars(testDict):
135e53dc769SScott Kruger  """
136e53dc769SScott Kruger  Given: dictionary that may have
137e53dc769SScott Kruger  Return:  Variables that cause a test split
138e53dc769SScott Kruger  """
139e53dc769SScott Kruger  vals=None
140e53dc769SScott Kruger  sepvars=[]
141e53dc769SScott Kruger  # Check nsize
142e53dc769SScott Kruger  if testDict.has_key('nsize'):
143e53dc769SScott Kruger    varset=testDict['nsize']
144aae9f2d9SScott Kruger    if '{{' in varset:
145aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
146aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
147e53dc769SScott Kruger
148e53dc769SScott Kruger  # Now check args
149e53dc769SScott Kruger  if not testDict.has_key('args'): return sepvars
150e53dc769SScott Kruger  for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
151e53dc769SScott Kruger    if not varset.strip(): continue
152aae9f2d9SScott Kruger    if '{{' in varset:
153e53dc769SScott Kruger      # Assuming only one for loop per var specification
154aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
155aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
156e53dc769SScott Kruger
157e53dc769SScott Kruger  return sepvars
158e53dc769SScott Kruger
15944776d8cSScott Krugerdef _getVarVals(findvar,testDict):
16044776d8cSScott Kruger  """
16144776d8cSScott Kruger  Given: variable that is either nsize or in args
16244776d8cSScott Kruger  Return:  Values to loop over
16344776d8cSScott Kruger  """
16444776d8cSScott Kruger  vals=None
16544776d8cSScott Kruger  newargs=''
16644776d8cSScott Kruger  if findvar=='nsize':
167e53dc769SScott Kruger    varset=testDict[findvar]
168aae9f2d9SScott Kruger    keynm,vals,ftype=parseLoopArgs('nsize '+varset)
16944776d8cSScott Kruger  else:
17044776d8cSScott Kruger    varlist=[]
17144776d8cSScott Kruger    for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
17244776d8cSScott Kruger      if not varset.strip(): continue
173aae9f2d9SScott Kruger      if '{{' in varset:
174aae9f2d9SScott Kruger        keyvar,vals,ftype=parseLoopArgs(varset)
17544776d8cSScott Kruger        if keyvar!=findvar:
1760bcc1aabSScott Kruger          newargs+="-"+varset.strip()+" "
17744776d8cSScott Kruger          continue
1780bcc1aabSScott Kruger      else:
1790bcc1aabSScott Kruger        newargs+="-"+varset.strip()+" "
18044776d8cSScott Kruger
18144776d8cSScott Kruger  if not vals: raise StandardError("Could not find separate_testvar: "+findvar)
18244776d8cSScott Kruger  return vals,newargs
18344776d8cSScott Kruger
18444776d8cSScott Krugerdef genTestsSeparateTestvars(intests,indicts):
18544776d8cSScott Kruger  """
186e53dc769SScott Kruger  Given: testname, sdict with 'separate_testvars
18744776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
18844776d8cSScott Kruger  """
18944776d8cSScott Kruger  testnames=[]; sdicts=[]
19044776d8cSScott Kruger  for i in range(len(intests)):
19144776d8cSScott Kruger    testname=intests[i]; sdict=indicts[i]; i+=1
192e53dc769SScott Kruger    separate_testvars=_getSeparateTestvars(sdict)
193e53dc769SScott Kruger    if len(separate_testvars)>0:
194e53dc769SScott Kruger      for kvar in separate_testvars:
19544776d8cSScott Kruger        kvals,newargs=_getVarVals(kvar,sdict)
19644776d8cSScott Kruger        # No errors means we are good to go
19744776d8cSScott Kruger        for val in kvals.split():
19844776d8cSScott Kruger          kvardict=sdict.copy()
19944776d8cSScott Kruger          gensuffix="_"+kvar+"-"+val
20044776d8cSScott Kruger          newtestnm=testname+gensuffix
2010bcc1aabSScott Kruger          if sdict.has_key('suffix'):
20244776d8cSScott Kruger            kvardict['suffix']=sdict['suffix']+gensuffix
2030bcc1aabSScott Kruger          else:
2040bcc1aabSScott Kruger            kvardict['suffix']=gensuffix
20544776d8cSScott Kruger          if kvar=='nsize':
20644776d8cSScott Kruger            kvardict[kvar]=val
20744776d8cSScott Kruger          else:
20844776d8cSScott Kruger            kvardict['args']=newargs+"-"+kvar+" "+val
20944776d8cSScott Kruger          testnames.append(newtestnm)
21044776d8cSScott Kruger          sdicts.append(kvardict)
21144776d8cSScott Kruger    else:
21244776d8cSScott Kruger      testnames.append(testname)
21344776d8cSScott Kruger      sdicts.append(sdict)
21444776d8cSScott Kruger  return testnames,sdicts
21544776d8cSScott Kruger
21644776d8cSScott Krugerdef genTestsSubtestSuffix(testnames,sdicts):
21744776d8cSScott Kruger  """
21844776d8cSScott Kruger  Given: testname, sdict with separate_testvars
21944776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
22044776d8cSScott Kruger  """
22144776d8cSScott Kruger  tnms=[]; sdcts=[]
22244776d8cSScott Kruger  for i in range(len(testnames)):
22344776d8cSScott Kruger    testname=testnames[i]
22444776d8cSScott Kruger    rmsubtests=[]; keepSubtests=False
22544776d8cSScott Kruger    if sdicts[i].has_key('subtests'):
22644776d8cSScott Kruger      for stest in sdicts[i]["subtests"]:
22744776d8cSScott Kruger        if sdicts[i][stest].has_key('suffix'):
22844776d8cSScott Kruger          rmsubtests.append(stest)
22944776d8cSScott Kruger          gensuffix="_"+sdicts[i][stest]['suffix']
23044776d8cSScott Kruger          newtestnm=testname+gensuffix
23144776d8cSScott Kruger          tnms.append(newtestnm)
23244776d8cSScott Kruger          newsdict=sdicts[i].copy()
23344776d8cSScott Kruger          del newsdict['subtests']
23444776d8cSScott Kruger          # Have to hand update
23544776d8cSScott Kruger          # Append
23644776d8cSScott Kruger          for kup in appendlist:
23744776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
23844776d8cSScott Kruger              if sdicts[i].has_key(kup):
23944776d8cSScott Kruger                newsdict[kup]=sdicts[i][kup]+" "+sdicts[i][stest][kup]
24044776d8cSScott Kruger              else:
24144776d8cSScott Kruger                newsdict[kup]=sdicts[i][stest][kup]
24244776d8cSScott Kruger          # Promote
24344776d8cSScott Kruger          for kup in acceptedkeys:
24444776d8cSScott Kruger            if kup in appendlist: continue
24544776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
24644776d8cSScott Kruger              newsdict[kup]=sdicts[i][stest][kup]
24744776d8cSScott Kruger          # Cleanup
24844776d8cSScott Kruger          for st in sdicts[i]["subtests"]: del newsdict[st]
24944776d8cSScott Kruger          sdcts.append(newsdict)
25044776d8cSScott Kruger        else:
25144776d8cSScott Kruger          keepSubtests=True
25244776d8cSScott Kruger    else:
25344776d8cSScott Kruger      tnms.append(testnames[i])
25444776d8cSScott Kruger      sdcts.append(sdicts[i])
2550bcc1aabSScott Kruger    # If a subtest without a suffix exists, then save it
25644776d8cSScott Kruger    if keepSubtests:
25744776d8cSScott Kruger      tnms.append(testnames[i])
2580bcc1aabSScott Kruger      newsdict=sdicts[i].copy()
2590bcc1aabSScott Kruger      # Prune the tests to prepare for keeping
2600bcc1aabSScott Kruger      for rmtest in rmsubtests:
2610bcc1aabSScott Kruger        newsdict['subtests'].remove(rmtest)
2620bcc1aabSScott Kruger        del newsdict[rmtest]
2630bcc1aabSScott Kruger      sdcts.append(newsdict)
26444776d8cSScott Kruger    i+=1
26544776d8cSScott Kruger  return tnms,sdcts
26644776d8cSScott Kruger
26744776d8cSScott Krugerdef splitTests(testname,sdict):
26844776d8cSScott Kruger  """
26944776d8cSScott Kruger  Given: testname and YAML-generated dictionary
27044776d8cSScott Kruger  Return: list of names and dictionaries corresponding to each test
27144776d8cSScott Kruger          given that the YAML language allows for multiple tests
27244776d8cSScott Kruger  """
27344776d8cSScott Kruger
27444776d8cSScott Kruger  # Order: Parent sep_tv, subtests suffix, subtests sep_tv
27544776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars([testname],[sdict])
27644776d8cSScott Kruger  testnames,sdicts=genTestsSubtestSuffix(testnames,sdicts)
27744776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars(testnames,sdicts)
27844776d8cSScott Kruger
27944776d8cSScott Kruger  # Because I am altering the list, I do this in passes.  Inelegant
28044776d8cSScott Kruger
28144776d8cSScott Kruger  return testnames, sdicts
28244776d8cSScott Kruger
2836cecdbdcSScott Krugerdef parseTest(testStr,srcfile,verbosity):
28429921a8fSScott Kruger  """
28529921a8fSScott Kruger  This parses an individual test
28629921a8fSScott Kruger  YAML is hierarchial so should use a state machine in the general case,
28753f2a965SBarry Smith  but in practice we only support two levels of test:
28829921a8fSScott Kruger  """
28929921a8fSScott Kruger  basename=os.path.basename(srcfile)
29029921a8fSScott Kruger  # Handle the new at the begininng
29129921a8fSScott Kruger  bn=re.sub("new_","",basename)
29229921a8fSScott Kruger  # This is the default
29329921a8fSScott Kruger  testname="run"+os.path.splitext(bn)[0]
29429921a8fSScott Kruger
29529921a8fSScott Kruger  # Tests that have default everything (so empty effectively)
29678659935SScott Kruger  if len(testStr)==0: return [testname], [{}]
29729921a8fSScott Kruger
29829921a8fSScott Kruger  striptest=_stripIndent(testStr,srcfile)
29929921a8fSScott Kruger
30029921a8fSScott Kruger  # go through and parse
30129921a8fSScott Kruger  subtestnum=0
30229921a8fSScott Kruger  subdict={}
30368a9e459SScott Kruger  comments=[]
30468a9e459SScott Kruger  indentlevel=0
30568a9e459SScott Kruger  for ln in striptest.split("\n"):
306c4b80baaSScott Kruger    line=ln.split('#')[0].rstrip()
307cadd188bSScott Kruger    if verbosity>2: print(line)
3080bcc1aabSScott Kruger    comment=("" if len(ln.split("#"))>0 else " ".join(ln.split("#")[1:]).strip())
30968a9e459SScott Kruger    if comment: comments.append(comment)
31029921a8fSScott Kruger    if not line.strip(): continue
31144776d8cSScott Kruger    lsplit=line.split(':')
31244776d8cSScott Kruger    if len(lsplit)==0: raise Exception("Missing : in line: "+line)
31344776d8cSScott Kruger    indentcount=lsplit[0].count(" ")
31444776d8cSScott Kruger    var=lsplit[0].strip()
31540ae0433SScott Kruger    val=line[line.find(':')+1:].strip()
31644776d8cSScott Kruger    if not var in acceptedkeys: raise Exception("Not a defined key: "+var+" from:  "+line)
31729921a8fSScott Kruger    # Start by seeing if we are in a subtest
31829921a8fSScott Kruger    if line.startswith(" "):
319c0658d2aSScott Kruger      subdict[subtestname][var]=val
32068a9e459SScott Kruger      if not indentlevel: indentlevel=indentcount
321cadd188bSScott Kruger      #if indentlevel!=indentcount: print("Error in indentation:", ln)
32229921a8fSScott Kruger    # Determine subtest name and make dict
32329921a8fSScott Kruger    elif var=="test":
32429921a8fSScott Kruger      subtestname="test"+str(subtestnum)
32529921a8fSScott Kruger      subdict[subtestname]={}
32629921a8fSScott Kruger      if not subdict.has_key("subtests"): subdict["subtests"]=[]
32729921a8fSScott Kruger      subdict["subtests"].append(subtestname)
32829921a8fSScott Kruger      subtestnum=subtestnum+1
32968a9e459SScott Kruger    # The rest are easy
33029921a8fSScott Kruger    else:
33144776d8cSScott Kruger      # For convenience, it is sometimes convenient to list twice
33244776d8cSScott Kruger      if subdict.has_key(var):
33344776d8cSScott Kruger        if var in appendlist:
33444776d8cSScott Kruger          subdict[var]+=" "+val
33544776d8cSScott Kruger        else:
33644776d8cSScott Kruger          raise Exception(var+" entered twice: "+line)
33744776d8cSScott Kruger      else:
338c0658d2aSScott Kruger        subdict[var]=val
33929921a8fSScott Kruger      if var=="suffix":
34029921a8fSScott Kruger        if len(val)>0:
34129921a8fSScott Kruger          testname=testname+"_"+val
34229921a8fSScott Kruger
34368a9e459SScott Kruger  if len(comments): subdict['comments']="\n".join(comments).lstrip("\n")
34444776d8cSScott Kruger  # A test block can create multiple tests.  This does
34544776d8cSScott Kruger  # that logic
34644776d8cSScott Kruger  testnames,subdicts=splitTests(testname,subdict)
34744776d8cSScott Kruger  return testnames,subdicts
34829921a8fSScott Kruger
3496cecdbdcSScott Krugerdef parseTests(testStr,srcfile,fileNums,verbosity):
35029921a8fSScott Kruger  """
35129921a8fSScott Kruger  Parse the yaml string describing tests and return
35229921a8fSScott Kruger  a dictionary with the info in the form of:
35329921a8fSScott Kruger    testDict[test][subtest]
35429921a8fSScott Kruger  This is an inelegant parser as we do not wish to
35529921a8fSScott Kruger  introduce a new dependency by bringing in pyyaml.
35629921a8fSScott Kruger  The advantage is that validation can be done as
35729921a8fSScott Kruger  it is parsed (e.g., 'test' is the only top-level node)
35829921a8fSScott Kruger  """
35929921a8fSScott Kruger
36029921a8fSScott Kruger  testDict={}
36129921a8fSScott Kruger
36229921a8fSScott Kruger  # The first entry should be test: but it might be indented.
36344776d8cSScott Kruger  newTestStr=_stripIndent(testStr,srcfile,entireBlock=True,fileNums=fileNums)
364cadd188bSScott Kruger  if verbosity>2: print(srcfile)
36529921a8fSScott Kruger
366*e4653983SScott Kruger  ## Check and see if we have build requirements
367*e4653983SScott Kruger  addToRunRequirements=None
368aec507c4SScott Kruger  if "\nbuild:" in newTestStr:
369aec507c4SScott Kruger    testDict['build']={}
370aec507c4SScott Kruger    # The file info is already here and need to append
371aec507c4SScott Kruger    Part1=newTestStr.split("build:")[1]
372aec507c4SScott Kruger    fileInfo=re.split("\ntest(?:set)?:",newTestStr)[0]
373aec507c4SScott Kruger    for bkey in buildkeys:
374aec507c4SScott Kruger      if bkey+":" in fileInfo:
375aec507c4SScott Kruger        testDict['build'][bkey]=fileInfo.split(bkey+":")[1].split("\n")[0].strip()
376aec507c4SScott Kruger        #if verbosity>1: bkey+": "+testDict['build'][bkey]
377*e4653983SScott Kruger      # If a runtime requires are put into build, push them down to all run tests
378*e4653983SScott Kruger      # At this point, we are working with strings and not lists
379*e4653983SScott Kruger      if 'requires' in testDict['build']:
380*e4653983SScott Kruger         if 'datafilespath' in testDict['build']['requires']:
381*e4653983SScott Kruger             newreqs=re.sub('datafilespath','',testDict['build']['requires'])
382*e4653983SScott Kruger             testDict['build']['requires']=newreqs.strip()
383*e4653983SScott Kruger             addToRunRequirements='datafilespath'
384*e4653983SScott Kruger
385aec507c4SScott Kruger
38629921a8fSScott Kruger  # Now go through each test.  First elem in split is blank
387e53dc769SScott Kruger  for test in re.split("\ntest(?:set)?:",newTestStr)[1:]:
3886cecdbdcSScott Kruger    testnames,subdicts=parseTest(test,srcfile,verbosity)
38944776d8cSScott Kruger    for i in range(len(testnames)):
39044776d8cSScott Kruger      if testDict.has_key(testnames[i]):
3911acf9037SMatthew G. Knepley        raise RuntimeError("Multiple test names specified: "+testnames[i]+" in file: "+srcfile)
392*e4653983SScott Kruger      # Add in build requirements that need to be moved
393*e4653983SScott Kruger      if addToRunRequirements:
394*e4653983SScott Kruger          if 'requires' in subdicts[i]:
395*e4653983SScott Kruger              subdicts[i]['requires']+=addToRunRequirements
396*e4653983SScott Kruger          else:
397*e4653983SScott Kruger              subdicts[i]['requires']=addToRunRequirements
39844776d8cSScott Kruger      testDict[testnames[i]]=subdicts[i]
39929921a8fSScott Kruger
40029921a8fSScott Kruger  return testDict
40129921a8fSScott Kruger
4026cecdbdcSScott Krugerdef parseTestFile(srcfile,verbosity):
40329921a8fSScott Kruger  """
40429921a8fSScott Kruger  Parse single example files and return dictionary of the form:
40529921a8fSScott Kruger    testDict[srcfile][test][subtest]
40629921a8fSScott Kruger  """
40729921a8fSScott Kruger  debug=False
408cadd188bSScott Kruger  basename=os.path.basename(srcfile)
409cadd188bSScott Kruger  if basename=='makefile': return {}
410cadd188bSScott Kruger
41129921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
41229921a8fSScott Kruger  basedir=os.path.dirname(os.path.realpath(srcfile))
41329921a8fSScott Kruger  os.chdir(basedir)
41429921a8fSScott Kruger
41529921a8fSScott Kruger  testDict={}
416cadd188bSScott Kruger  sh=open(basename,"r"); fileStr=sh.read(); sh.close()
41729921a8fSScott Kruger
41829921a8fSScott Kruger  ## Start with doing the tests
41929921a8fSScott Kruger  #
42029921a8fSScott Kruger  fsplit=fileStr.split("/*TEST\n")[1:]
42144776d8cSScott Kruger  fstart=len(fileStr.split("/*TEST\n")[0].split("\n"))+1
42229921a8fSScott Kruger  # Allow for multiple "/*TEST" blocks even though it really should be
4236f029658SMatthew G. Knepley  # one
42429921a8fSScott Kruger  srcTests=[]
42529921a8fSScott Kruger  for t in fsplit: srcTests.append(t.split("TEST*/")[0])
42629921a8fSScott Kruger  testString=" ".join(srcTests)
42744776d8cSScott Kruger  flen=len(testString.split("\n"))
42844776d8cSScott Kruger  fend=fstart+flen-1
42944776d8cSScott Kruger  fileNums=range(fstart,fend)
4306cecdbdcSScott Kruger  testDict[basename]=parseTests(testString,srcfile,fileNums,verbosity)
431aec507c4SScott Kruger  # Massage dictionary for build requirements
432aec507c4SScott Kruger  if 'build' in testDict[basename]:
433aec507c4SScott Kruger    testDict[basename].update(testDict[basename]['build'])
434aec507c4SScott Kruger    del testDict[basename]['build']
43529921a8fSScott Kruger
43629921a8fSScott Kruger
43729921a8fSScott Kruger  os.chdir(curdir)
43829921a8fSScott Kruger  return testDict
43929921a8fSScott Kruger
4406cecdbdcSScott Krugerdef parseTestDir(directory,verbosity):
44129921a8fSScott Kruger  """
44229921a8fSScott Kruger  Parse single example files and return dictionary of the form:
44329921a8fSScott Kruger    testDict[srcfile][test][subtest]
44429921a8fSScott Kruger  """
44529921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
44629921a8fSScott Kruger  basedir=os.path.realpath(directory)
44729921a8fSScott Kruger  os.chdir(basedir)
44829921a8fSScott Kruger
44929921a8fSScott Kruger  tDict={}
45029921a8fSScott Kruger  for test_file in glob.glob("new_ex*.*"):
4516cecdbdcSScott Kruger    tDict.update(parseTestFile(test_file,verbosity))
45229921a8fSScott Kruger
45329921a8fSScott Kruger  os.chdir(curdir)
45429921a8fSScott Kruger  return tDict
45529921a8fSScott Kruger
45629921a8fSScott Krugerdef printExParseDict(rDict):
45729921a8fSScott Kruger  """
45829921a8fSScott Kruger  This is useful for debugging
45929921a8fSScott Kruger  """
46029921a8fSScott Kruger  indent="   "
46129921a8fSScott Kruger  for sfile in rDict:
462cadd188bSScott Kruger    print(sfile)
46344776d8cSScott Kruger    sortkeys=rDict[sfile].keys()
46444776d8cSScott Kruger    sortkeys.sort()
46544776d8cSScott Kruger    for runex in sortkeys:
466cadd188bSScott Kruger      print(indent+runex)
46729921a8fSScott Kruger      if type(rDict[sfile][runex])==types.StringType:
468cadd188bSScott Kruger        print(indent*2+rDict[sfile][runex])
46929921a8fSScott Kruger      else:
47029921a8fSScott Kruger        for var in rDict[sfile][runex]:
47144776d8cSScott Kruger          if var.startswith("test"): continue
472cadd188bSScott Kruger          print(indent*2+var+": "+str(rDict[sfile][runex][var]))
47344776d8cSScott Kruger        if rDict[sfile][runex].has_key('subtests'):
47444776d8cSScott Kruger          for var in rDict[sfile][runex]['subtests']:
475cadd188bSScott Kruger            print(indent*2+var)
47629921a8fSScott Kruger            for var2 in rDict[sfile][runex][var]:
477cadd188bSScott Kruger              print(indent*3+var2+": "+str(rDict[sfile][runex][var][var2]))
478cadd188bSScott Kruger      print("\n")
47929921a8fSScott Kruger  return
48029921a8fSScott Kruger
48129921a8fSScott Krugerdef main(directory='',test_file='',verbosity=0):
48229921a8fSScott Kruger
48329921a8fSScott Kruger    if directory:
4846cecdbdcSScott Kruger      tDict=parseTestDir(directory,verbosity)
48529921a8fSScott Kruger    else:
4866cecdbdcSScott Kruger      tDict=parseTestFile(test_file,verbosity)
48729921a8fSScott Kruger    if verbosity>0: printExParseDict(tDict)
48829921a8fSScott Kruger
48929921a8fSScott Kruger    return
49029921a8fSScott Kruger
49129921a8fSScott Krugerif __name__ == '__main__':
49229921a8fSScott Kruger    import optparse
49329921a8fSScott Kruger    parser = optparse.OptionParser()
49429921a8fSScott Kruger    parser.add_option('-d', '--directory', dest='directory',
49529921a8fSScott Kruger                      default="", help='Directory containing files to parse')
49629921a8fSScott Kruger    parser.add_option('-t', '--test_file', dest='test_file',
49729921a8fSScott Kruger                      default="", help='Test file, e.g., ex1.c, to parse')
49829921a8fSScott Kruger    parser.add_option('-v', '--verbosity', dest='verbosity',
49929921a8fSScott Kruger                      help='Verbosity of output by level: 1, 2, or 3', default=0)
50029921a8fSScott Kruger    opts, extra_args = parser.parse_args()
50129921a8fSScott Kruger
50229921a8fSScott Kruger    if extra_args:
50329921a8fSScott Kruger        import sys
50429921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
50529921a8fSScott Kruger        exit(1)
50629921a8fSScott Kruger    if not opts.test_file and not opts.directory:
507cadd188bSScott Kruger      print("test file or directory is required")
50829921a8fSScott Kruger      parser.print_usage()
50929921a8fSScott Kruger      sys.exit()
51029921a8fSScott Kruger
51129921a8fSScott Kruger    # Need verbosity to be an integer
51229921a8fSScott Kruger    try:
51329921a8fSScott Kruger      verbosity=int(opts.verbosity)
51429921a8fSScott Kruger    except:
51529921a8fSScott Kruger      raise Exception("Error: Verbosity must be integer")
51629921a8fSScott Kruger
51729921a8fSScott Kruger    main(directory=opts.directory,test_file=opts.test_file,verbosity=verbosity)
518