xref: /petsc/config/testparse.py (revision e53dc769332c68db95475944e2c4dbb6eb10c6b7)
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