xref: /petsc/config/testparse.py (revision 66db876f2e3db452cd01db58d46938a71ec45d38)
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
26e53dc769SScott Kruger   # This is equivalent to test:
27e53dc769SScott 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
30e53dc769SScott 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
35e53dc769SScott Kruger   testset:
36e53dc769SScott Kruger      suffix: 2
37e53dc769SScott Kruger      nsize: 2
38e53dc769SScott 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
39e53dc769SScott Kruger      test:
40e53dc769SScott 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)
55*66db876fSScott Kruger# Don't print out trace when raise Exceptions
56*66db876fSScott Krugersys.tracebacklimit = 0
5729921a8fSScott Kruger
5829921a8fSScott Kruger# These are special keys describing build
5929921a8fSScott Krugerbuildkeys="requires TODO SKIP depends".split()
6029921a8fSScott Kruger
61e53dc769SScott Krugeracceptedkeys="test nsize requires command suffix args filter filter_output localrunfiles comments TODO SKIP output_file".split()
6244776d8cSScott Krugerappendlist="args requires comments".split()
6368a9e459SScott Kruger
6468a9e459SScott Krugerimport re
6568a9e459SScott Kruger
6644776d8cSScott Krugerdef _stripIndent(block,srcfile,entireBlock=False,fileNums=[]):
6729921a8fSScott Kruger  """
6829921a8fSScott Kruger  Go through and remove a level of indentation
6929921a8fSScott Kruger  Also strip of trailing whitespace
7029921a8fSScott Kruger  """
7129921a8fSScott Kruger  # The first entry should be test: but it might be indented.
7229921a8fSScott Kruger  ext=os.path.splitext(srcfile)[1]
7344776d8cSScott Kruger  stripstr=" "
74*66db876fSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
758ccd5183SScott Kruger  for lline in block.split("\n"):
76*66db876fSScott Kruger    if len(fileNums)>0: lineNum+=1
778ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
7829921a8fSScott Kruger    if not line.strip(): continue
79c4b80baaSScott Kruger    if line.strip().startswith('#'): continue
8044776d8cSScott Kruger    if entireBlock:
8144776d8cSScott Kruger      var=line.split(":")[0].strip()
82e53dc769SScott Kruger      if not (var=='test' or var=='testset'):
83*66db876fSScott Kruger        raise Exception("Formatting error: Cannot find test in file: "+srcfile+" at line: "+str(lineNum)+"\n")
8429921a8fSScott Kruger    nspace=len(line)-len(line.lstrip(stripstr))
8529921a8fSScott Kruger    newline=line[nspace:]
8629921a8fSScott Kruger    break
8729921a8fSScott Kruger
8829921a8fSScott Kruger  # Strip off any indentation for the whole string and any trailing
8929921a8fSScott Kruger  # whitespace for convenience
9029921a8fSScott Kruger  newTestStr="\n"
9144776d8cSScott Kruger  if len(fileNums)>0: lineNum=fileNums[0]-1
9244776d8cSScott Kruger  firstPass=True
938ccd5183SScott Kruger  for lline in block.split("\n"):
9444776d8cSScott Kruger    if len(fileNums)>0: lineNum+=1
958ccd5183SScott Kruger    line=lline[1:] if lline.startswith("!") else lline
9629921a8fSScott Kruger    if not line.strip(): continue
97c4b80baaSScott Kruger    if line.strip().startswith('#'):
98c4b80baaSScott Kruger      newTestStr+=line+'\n'
99c4b80baaSScott Kruger    else:
10029921a8fSScott Kruger      newline=line[nspace:]
101c4b80baaSScott Kruger      newTestStr+=newline.rstrip()+"\n"
10244776d8cSScott Kruger    # Do some basic indentation checks
10344776d8cSScott Kruger    if entireBlock:
10444776d8cSScott Kruger      # Don't need to check comment lines
10544776d8cSScott Kruger      if line.strip().startswith('#'): continue
10644776d8cSScott Kruger      if not newline.startswith(" "):
10744776d8cSScott Kruger        var=newline.split(":")[0].strip()
108e53dc769SScott Kruger        if not (var=='test' or var=='testset'):
10944776d8cSScott Kruger          err="Formatting error in file "+srcfile+" at line: " +line+"\n"
11044776d8cSScott Kruger          if len(fileNums)>0:
11144776d8cSScott Kruger            raise Exception(err+"Check indentation at line number: "+str(lineNum))
11244776d8cSScott Kruger          else:
11344776d8cSScott Kruger            raise Exception(err)
11444776d8cSScott Kruger      else:
11544776d8cSScott Kruger        var=line.split(":")[0].strip()
116e53dc769SScott Kruger        if var=='test' or var=='testset':
11744776d8cSScott Kruger          subnspace=len(line)-len(line.lstrip(stripstr))
11844776d8cSScott Kruger          if firstPass:
11944776d8cSScott Kruger            firstsubnspace=subnspace
12044776d8cSScott Kruger            firstPass=False
12144776d8cSScott Kruger          else:
12244776d8cSScott Kruger            if firstsubnspace!=subnspace:
12344776d8cSScott Kruger              err="Formatting subtest error in file "+srcfile+" at line: " +line+"\n"
12444776d8cSScott Kruger              if len(fileNums)>0:
12544776d8cSScott Kruger                raise Exception(err+"Check indentation at line number: "+str(lineNum))
12644776d8cSScott Kruger              else:
12744776d8cSScott Kruger                raise Exception(err)
12844776d8cSScott Kruger
12929921a8fSScott Kruger
13029921a8fSScott Kruger  return newTestStr
13129921a8fSScott Kruger
132aae9f2d9SScott Krugerdef parseLoopArgs(varset):
13344776d8cSScott Kruger  """
134aae9f2d9SScott Kruger  Given:   String containing loop variables
135aae9f2d9SScott Kruger  Return: tuple containing separate/shared and string of loop vars
13644776d8cSScott Kruger  """
137aae9f2d9SScott Kruger  keynm=varset.split("{{")[0].strip()
138aae9f2d9SScott Kruger  if not keynm.strip(): keynm='nsize'
139aae9f2d9SScott Kruger  lvars=varset.split('{{')[1].split('}')[0]
140aae9f2d9SScott Kruger  suffx=varset.split('{{')[1].split('}')[1]
141aae9f2d9SScott Kruger  ftype='separate' if suffx.startswith('separate') else 'shared'
142aae9f2d9SScott Kruger  return keynm,lvars,ftype
14344776d8cSScott Kruger
144e53dc769SScott Krugerdef _getSeparateTestvars(testDict):
145e53dc769SScott Kruger  """
146e53dc769SScott Kruger  Given: dictionary that may have
147e53dc769SScott Kruger  Return:  Variables that cause a test split
148e53dc769SScott Kruger  """
149e53dc769SScott Kruger  vals=None
150e53dc769SScott Kruger  sepvars=[]
151e53dc769SScott Kruger  # Check nsize
152e53dc769SScott Kruger  if testDict.has_key('nsize'):
153e53dc769SScott Kruger    varset=testDict['nsize']
154aae9f2d9SScott Kruger    if '{{' in varset:
155aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
156aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
157e53dc769SScott Kruger
158e53dc769SScott Kruger  # Now check args
159e53dc769SScott Kruger  if not testDict.has_key('args'): return sepvars
160e53dc769SScott Kruger  for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
161e53dc769SScott Kruger    if not varset.strip(): continue
162aae9f2d9SScott Kruger    if '{{' in varset:
163e53dc769SScott Kruger      # Assuming only one for loop per var specification
164aae9f2d9SScott Kruger      keynm,lvars,ftype=parseLoopArgs(varset)
165aae9f2d9SScott Kruger      if ftype=='separate': sepvars.append(keynm)
166e53dc769SScott Kruger
167e53dc769SScott Kruger  return sepvars
168e53dc769SScott Kruger
16944776d8cSScott Krugerdef _getVarVals(findvar,testDict):
17044776d8cSScott Kruger  """
17144776d8cSScott Kruger  Given: variable that is either nsize or in args
17244776d8cSScott Kruger  Return:  Values to loop over
17344776d8cSScott Kruger  """
17444776d8cSScott Kruger  vals=None
17544776d8cSScott Kruger  newargs=''
17644776d8cSScott Kruger  if findvar=='nsize':
177e53dc769SScott Kruger    varset=testDict[findvar]
178aae9f2d9SScott Kruger    keynm,vals,ftype=parseLoopArgs('nsize '+varset)
17944776d8cSScott Kruger  else:
18044776d8cSScott Kruger    varlist=[]
18144776d8cSScott Kruger    for varset in re.split('-(?=[a-zA-Z])',testDict['args']):
18244776d8cSScott Kruger      if not varset.strip(): continue
183aae9f2d9SScott Kruger      if '{{' in varset:
184aae9f2d9SScott Kruger        keyvar,vals,ftype=parseLoopArgs(varset)
18544776d8cSScott Kruger        if keyvar!=findvar:
1860bcc1aabSScott Kruger          newargs+="-"+varset.strip()+" "
18744776d8cSScott Kruger          continue
1880bcc1aabSScott Kruger      else:
1890bcc1aabSScott Kruger        newargs+="-"+varset.strip()+" "
19044776d8cSScott Kruger
19144776d8cSScott Kruger  if not vals: raise StandardError("Could not find separate_testvar: "+findvar)
19244776d8cSScott Kruger  return vals,newargs
19344776d8cSScott Kruger
19444776d8cSScott Krugerdef genTestsSeparateTestvars(intests,indicts):
19544776d8cSScott Kruger  """
196e53dc769SScott Kruger  Given: testname, sdict with 'separate_testvars
19744776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
19844776d8cSScott Kruger  """
19944776d8cSScott Kruger  testnames=[]; sdicts=[]
20044776d8cSScott Kruger  for i in range(len(intests)):
20144776d8cSScott Kruger    testname=intests[i]; sdict=indicts[i]; i+=1
202e53dc769SScott Kruger    separate_testvars=_getSeparateTestvars(sdict)
203e53dc769SScott Kruger    if len(separate_testvars)>0:
204e53dc769SScott Kruger      for kvar in separate_testvars:
20544776d8cSScott Kruger        kvals,newargs=_getVarVals(kvar,sdict)
20644776d8cSScott Kruger        # No errors means we are good to go
20744776d8cSScott Kruger        for val in kvals.split():
20844776d8cSScott Kruger          kvardict=sdict.copy()
20944776d8cSScott Kruger          gensuffix="_"+kvar+"-"+val
21044776d8cSScott Kruger          newtestnm=testname+gensuffix
2110bcc1aabSScott Kruger          if sdict.has_key('suffix'):
21244776d8cSScott Kruger            kvardict['suffix']=sdict['suffix']+gensuffix
2130bcc1aabSScott Kruger          else:
2140bcc1aabSScott Kruger            kvardict['suffix']=gensuffix
21544776d8cSScott Kruger          if kvar=='nsize':
21644776d8cSScott Kruger            kvardict[kvar]=val
21744776d8cSScott Kruger          else:
21844776d8cSScott Kruger            kvardict['args']=newargs+"-"+kvar+" "+val
21944776d8cSScott Kruger          testnames.append(newtestnm)
22044776d8cSScott Kruger          sdicts.append(kvardict)
22144776d8cSScott Kruger    else:
22244776d8cSScott Kruger      testnames.append(testname)
22344776d8cSScott Kruger      sdicts.append(sdict)
22444776d8cSScott Kruger  return testnames,sdicts
22544776d8cSScott Kruger
22644776d8cSScott Krugerdef genTestsSubtestSuffix(testnames,sdicts):
22744776d8cSScott Kruger  """
22844776d8cSScott Kruger  Given: testname, sdict with separate_testvars
22944776d8cSScott Kruger  Return: testnames,sdicts: List of generated tests
23044776d8cSScott Kruger  """
23144776d8cSScott Kruger  tnms=[]; sdcts=[]
23244776d8cSScott Kruger  for i in range(len(testnames)):
23344776d8cSScott Kruger    testname=testnames[i]
23444776d8cSScott Kruger    rmsubtests=[]; keepSubtests=False
23544776d8cSScott Kruger    if sdicts[i].has_key('subtests'):
23644776d8cSScott Kruger      for stest in sdicts[i]["subtests"]:
23744776d8cSScott Kruger        if sdicts[i][stest].has_key('suffix'):
23844776d8cSScott Kruger          rmsubtests.append(stest)
23944776d8cSScott Kruger          gensuffix="_"+sdicts[i][stest]['suffix']
24044776d8cSScott Kruger          newtestnm=testname+gensuffix
24144776d8cSScott Kruger          tnms.append(newtestnm)
24244776d8cSScott Kruger          newsdict=sdicts[i].copy()
24344776d8cSScott Kruger          del newsdict['subtests']
24444776d8cSScott Kruger          # Have to hand update
24544776d8cSScott Kruger          # Append
24644776d8cSScott Kruger          for kup in appendlist:
24744776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
24844776d8cSScott Kruger              if sdicts[i].has_key(kup):
24944776d8cSScott Kruger                newsdict[kup]=sdicts[i][kup]+" "+sdicts[i][stest][kup]
25044776d8cSScott Kruger              else:
25144776d8cSScott Kruger                newsdict[kup]=sdicts[i][stest][kup]
25244776d8cSScott Kruger          # Promote
25344776d8cSScott Kruger          for kup in acceptedkeys:
25444776d8cSScott Kruger            if kup in appendlist: continue
25544776d8cSScott Kruger            if sdicts[i][stest].has_key(kup):
25644776d8cSScott Kruger              newsdict[kup]=sdicts[i][stest][kup]
25744776d8cSScott Kruger          # Cleanup
25844776d8cSScott Kruger          for st in sdicts[i]["subtests"]: del newsdict[st]
25944776d8cSScott Kruger          sdcts.append(newsdict)
26044776d8cSScott Kruger        else:
26144776d8cSScott Kruger          keepSubtests=True
26244776d8cSScott Kruger    else:
26344776d8cSScott Kruger      tnms.append(testnames[i])
26444776d8cSScott Kruger      sdcts.append(sdicts[i])
2650bcc1aabSScott Kruger    # If a subtest without a suffix exists, then save it
26644776d8cSScott Kruger    if keepSubtests:
26744776d8cSScott Kruger      tnms.append(testnames[i])
2680bcc1aabSScott Kruger      newsdict=sdicts[i].copy()
2690bcc1aabSScott Kruger      # Prune the tests to prepare for keeping
2700bcc1aabSScott Kruger      for rmtest in rmsubtests:
2710bcc1aabSScott Kruger        newsdict['subtests'].remove(rmtest)
2720bcc1aabSScott Kruger        del newsdict[rmtest]
2730bcc1aabSScott Kruger      sdcts.append(newsdict)
27444776d8cSScott Kruger    i+=1
27544776d8cSScott Kruger  return tnms,sdcts
27644776d8cSScott Kruger
27744776d8cSScott Krugerdef splitTests(testname,sdict):
27844776d8cSScott Kruger  """
27944776d8cSScott Kruger  Given: testname and YAML-generated dictionary
28044776d8cSScott Kruger  Return: list of names and dictionaries corresponding to each test
28144776d8cSScott Kruger          given that the YAML language allows for multiple tests
28244776d8cSScott Kruger  """
28344776d8cSScott Kruger
28444776d8cSScott Kruger  # Order: Parent sep_tv, subtests suffix, subtests sep_tv
28544776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars([testname],[sdict])
28644776d8cSScott Kruger  testnames,sdicts=genTestsSubtestSuffix(testnames,sdicts)
28744776d8cSScott Kruger  testnames,sdicts=genTestsSeparateTestvars(testnames,sdicts)
28844776d8cSScott Kruger
28944776d8cSScott Kruger  # Because I am altering the list, I do this in passes.  Inelegant
29044776d8cSScott Kruger
29144776d8cSScott Kruger  return testnames, sdicts
29244776d8cSScott Kruger
2936cecdbdcSScott Krugerdef parseTest(testStr,srcfile,verbosity):
29429921a8fSScott Kruger  """
29529921a8fSScott Kruger  This parses an individual test
29629921a8fSScott Kruger  YAML is hierarchial so should use a state machine in the general case,
29753f2a965SBarry Smith  but in practice we only support two levels of test:
29829921a8fSScott Kruger  """
29929921a8fSScott Kruger  basename=os.path.basename(srcfile)
30029921a8fSScott Kruger  # Handle the new at the begininng
30129921a8fSScott Kruger  bn=re.sub("new_","",basename)
30229921a8fSScott Kruger  # This is the default
30329921a8fSScott Kruger  testname="run"+os.path.splitext(bn)[0]
30429921a8fSScott Kruger
30529921a8fSScott Kruger  # Tests that have default everything (so empty effectively)
30629921a8fSScott Kruger  if len(testStr)==0: return testname, {}
30729921a8fSScott Kruger
30829921a8fSScott Kruger  striptest=_stripIndent(testStr,srcfile)
30929921a8fSScott Kruger
31029921a8fSScott Kruger  # go through and parse
31129921a8fSScott Kruger  subtestnum=0
31229921a8fSScott Kruger  subdict={}
31368a9e459SScott Kruger  comments=[]
31468a9e459SScott Kruger  indentlevel=0
31568a9e459SScott Kruger  for ln in striptest.split("\n"):
316c4b80baaSScott Kruger    line=ln.split('#')[0].rstrip()
3176cecdbdcSScott Kruger    if verbosity>2: print line
3180bcc1aabSScott Kruger    comment=("" if len(ln.split("#"))>0 else " ".join(ln.split("#")[1:]).strip())
31968a9e459SScott Kruger    if comment: comments.append(comment)
32029921a8fSScott Kruger    if not line.strip(): continue
32144776d8cSScott Kruger    lsplit=line.split(':')
32244776d8cSScott Kruger    if len(lsplit)==0: raise Exception("Missing : in line: "+line)
32344776d8cSScott Kruger    indentcount=lsplit[0].count(" ")
32444776d8cSScott Kruger    var=lsplit[0].strip()
32540ae0433SScott Kruger    val=line[line.find(':')+1:].strip()
32644776d8cSScott Kruger    if not var in acceptedkeys: raise Exception("Not a defined key: "+var+" from:  "+line)
32729921a8fSScott Kruger    # Start by seeing if we are in a subtest
32829921a8fSScott Kruger    if line.startswith(" "):
329c0658d2aSScott Kruger      subdict[subtestname][var]=val
33068a9e459SScott Kruger      if not indentlevel: indentlevel=indentcount
33168a9e459SScott Kruger      #if indentlevel!=indentcount: print "Error in indentation:", ln
33229921a8fSScott Kruger    # Determine subtest name and make dict
33329921a8fSScott Kruger    elif var=="test":
33429921a8fSScott Kruger      subtestname="test"+str(subtestnum)
33529921a8fSScott Kruger      subdict[subtestname]={}
33629921a8fSScott Kruger      if not subdict.has_key("subtests"): subdict["subtests"]=[]
33729921a8fSScott Kruger      subdict["subtests"].append(subtestname)
33829921a8fSScott Kruger      subtestnum=subtestnum+1
33968a9e459SScott Kruger    # The rest are easy
34029921a8fSScott Kruger    else:
34144776d8cSScott Kruger      # For convenience, it is sometimes convenient to list twice
34244776d8cSScott Kruger      if subdict.has_key(var):
34344776d8cSScott Kruger        if var in appendlist:
34444776d8cSScott Kruger          subdict[var]+=" "+val
34544776d8cSScott Kruger        else:
34644776d8cSScott Kruger          raise Exception(var+" entered twice: "+line)
34744776d8cSScott Kruger      else:
348c0658d2aSScott Kruger        subdict[var]=val
34929921a8fSScott Kruger      if var=="suffix":
35029921a8fSScott Kruger        if len(val)>0:
35129921a8fSScott Kruger          testname=testname+"_"+val
35229921a8fSScott Kruger
35368a9e459SScott Kruger  if len(comments): subdict['comments']="\n".join(comments).lstrip("\n")
35444776d8cSScott Kruger  # A test block can create multiple tests.  This does
35544776d8cSScott Kruger  # that logic
35644776d8cSScott Kruger  testnames,subdicts=splitTests(testname,subdict)
35744776d8cSScott Kruger  return testnames,subdicts
35829921a8fSScott Kruger
3596cecdbdcSScott Krugerdef parseTests(testStr,srcfile,fileNums,verbosity):
36029921a8fSScott Kruger  """
36129921a8fSScott Kruger  Parse the yaml string describing tests and return
36229921a8fSScott Kruger  a dictionary with the info in the form of:
36329921a8fSScott Kruger    testDict[test][subtest]
36429921a8fSScott Kruger  This is an inelegant parser as we do not wish to
36529921a8fSScott Kruger  introduce a new dependency by bringing in pyyaml.
36629921a8fSScott Kruger  The advantage is that validation can be done as
36729921a8fSScott Kruger  it is parsed (e.g., 'test' is the only top-level node)
36829921a8fSScott Kruger  """
36929921a8fSScott Kruger
37029921a8fSScott Kruger  testDict={}
37129921a8fSScott Kruger
37229921a8fSScott Kruger  # The first entry should be test: but it might be indented.
37344776d8cSScott Kruger  newTestStr=_stripIndent(testStr,srcfile,entireBlock=True,fileNums=fileNums)
3746cecdbdcSScott Kruger  if verbosity>2: print srcfile
37529921a8fSScott Kruger
37629921a8fSScott Kruger  # Now go through each test.  First elem in split is blank
377e53dc769SScott Kruger  for test in re.split("\ntest(?:set)?:",newTestStr)[1:]:
3786cecdbdcSScott Kruger    testnames,subdicts=parseTest(test,srcfile,verbosity)
37944776d8cSScott Kruger    for i in range(len(testnames)):
38044776d8cSScott Kruger      if testDict.has_key(testnames[i]):
38144776d8cSScott Kruger        raise Error("Multiple test names specified: "+testname+" in file: "+srcfile)
38244776d8cSScott Kruger      testDict[testnames[i]]=subdicts[i]
38329921a8fSScott Kruger
38429921a8fSScott Kruger  return testDict
38529921a8fSScott Kruger
3866cecdbdcSScott Krugerdef parseTestFile(srcfile,verbosity):
38729921a8fSScott Kruger  """
38829921a8fSScott Kruger  Parse single example files and return dictionary of the form:
38929921a8fSScott Kruger    testDict[srcfile][test][subtest]
39029921a8fSScott Kruger  """
39129921a8fSScott Kruger  debug=False
39229921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
39329921a8fSScott Kruger  basedir=os.path.dirname(os.path.realpath(srcfile))
39429921a8fSScott Kruger  basename=os.path.basename(srcfile)
39529921a8fSScott Kruger  os.chdir(basedir)
39629921a8fSScott Kruger
39729921a8fSScott Kruger  testDict={}
39829921a8fSScott Kruger  sh=open(srcfile,"r"); fileStr=sh.read(); sh.close()
39929921a8fSScott Kruger
40029921a8fSScott Kruger  ## Start with doing the tests
40129921a8fSScott Kruger  #
40229921a8fSScott Kruger  fsplit=fileStr.split("/*TEST\n")[1:]
40329921a8fSScott Kruger  if len(fsplit)==0:
40429921a8fSScott Kruger    if debug: print "No test found in: "+srcfile
40529921a8fSScott Kruger    return {}
40644776d8cSScott Kruger  fstart=len(fileStr.split("/*TEST\n")[0].split("\n"))+1
40729921a8fSScott Kruger  # Allow for multiple "/*TEST" blocks even though it really should be
40829921a8fSScott Kruger  # on
40929921a8fSScott Kruger  srcTests=[]
41029921a8fSScott Kruger  for t in fsplit: srcTests.append(t.split("TEST*/")[0])
41129921a8fSScott Kruger  testString=" ".join(srcTests)
41229921a8fSScott Kruger  if len(testString.strip())==0:
41329921a8fSScott Kruger    print "No test found in: "+srcfile
41429921a8fSScott Kruger    return {}
41544776d8cSScott Kruger  flen=len(testString.split("\n"))
41644776d8cSScott Kruger  fend=fstart+flen-1
41744776d8cSScott Kruger  fileNums=range(fstart,fend)
4186cecdbdcSScott Kruger  testDict[basename]=parseTests(testString,srcfile,fileNums,verbosity)
41929921a8fSScott Kruger
42029921a8fSScott Kruger  ## Check and see if we have build reuqirements
42129921a8fSScott Kruger  #
42229921a8fSScott Kruger  if "/*T\n" in fileStr or "/*T " in fileStr:
42329921a8fSScott Kruger    # The file info is already here and need to append
42429921a8fSScott Kruger    Part1=fileStr.split("T*/")[0]
42529921a8fSScott Kruger    fileInfo=Part1.split("/*T")[1]
42629921a8fSScott Kruger    for bkey in buildkeys:
42729921a8fSScott Kruger      if bkey+":" in fileInfo:
42829921a8fSScott Kruger        testDict[basename][bkey]=fileInfo.split(bkey+":")[1].split("\n")[0].strip()
42929921a8fSScott Kruger
43029921a8fSScott Kruger  os.chdir(curdir)
43129921a8fSScott Kruger  return testDict
43229921a8fSScott Kruger
4336cecdbdcSScott Krugerdef parseTestDir(directory,verbosity):
43429921a8fSScott Kruger  """
43529921a8fSScott Kruger  Parse single example files and return dictionary of the form:
43629921a8fSScott Kruger    testDict[srcfile][test][subtest]
43729921a8fSScott Kruger  """
43829921a8fSScott Kruger  curdir=os.path.realpath(os.path.curdir)
43929921a8fSScott Kruger  basedir=os.path.realpath(directory)
44029921a8fSScott Kruger  os.chdir(basedir)
44129921a8fSScott Kruger
44229921a8fSScott Kruger  tDict={}
44329921a8fSScott Kruger  for test_file in glob.glob("new_ex*.*"):
4446cecdbdcSScott Kruger    tDict.update(parseTestFile(test_file,verbosity))
44529921a8fSScott Kruger
44629921a8fSScott Kruger  os.chdir(curdir)
44729921a8fSScott Kruger  return tDict
44829921a8fSScott Kruger
44929921a8fSScott Krugerdef printExParseDict(rDict):
45029921a8fSScott Kruger  """
45129921a8fSScott Kruger  This is useful for debugging
45229921a8fSScott Kruger  """
45329921a8fSScott Kruger  indent="   "
45429921a8fSScott Kruger  for sfile in rDict:
45544776d8cSScott Kruger    print sfile
45644776d8cSScott Kruger    sortkeys=rDict[sfile].keys()
45744776d8cSScott Kruger    sortkeys.sort()
45844776d8cSScott Kruger    for runex in sortkeys:
45929921a8fSScott Kruger      print indent+runex
46029921a8fSScott Kruger      if type(rDict[sfile][runex])==types.StringType:
46129921a8fSScott Kruger        print indent*2+rDict[sfile][runex]
46229921a8fSScott Kruger      else:
46329921a8fSScott Kruger        for var in rDict[sfile][runex]:
46444776d8cSScott Kruger          if var.startswith("test"): continue
46544776d8cSScott Kruger          print indent*2+var+": "+str(rDict[sfile][runex][var])
46644776d8cSScott Kruger        if rDict[sfile][runex].has_key('subtests'):
46744776d8cSScott Kruger          for var in rDict[sfile][runex]['subtests']:
46829921a8fSScott Kruger            print indent*2+var
46929921a8fSScott Kruger            for var2 in rDict[sfile][runex][var]:
47029921a8fSScott Kruger              print indent*3+var2+": "+str(rDict[sfile][runex][var][var2])
47144776d8cSScott Kruger      print "\n"
47229921a8fSScott Kruger  return
47329921a8fSScott Kruger
47429921a8fSScott Krugerdef main(directory='',test_file='',verbosity=0):
47529921a8fSScott Kruger
47629921a8fSScott Kruger    if directory:
4776cecdbdcSScott Kruger      tDict=parseTestDir(directory,verbosity)
47829921a8fSScott Kruger    else:
4796cecdbdcSScott Kruger      tDict=parseTestFile(test_file,verbosity)
48029921a8fSScott Kruger    if verbosity>0: printExParseDict(tDict)
48129921a8fSScott Kruger
48229921a8fSScott Kruger    return
48329921a8fSScott Kruger
48429921a8fSScott Krugerif __name__ == '__main__':
48529921a8fSScott Kruger    import optparse
48629921a8fSScott Kruger    parser = optparse.OptionParser()
48729921a8fSScott Kruger    parser.add_option('-d', '--directory', dest='directory',
48829921a8fSScott Kruger                      default="", help='Directory containing files to parse')
48929921a8fSScott Kruger    parser.add_option('-t', '--test_file', dest='test_file',
49029921a8fSScott Kruger                      default="", help='Test file, e.g., ex1.c, to parse')
49129921a8fSScott Kruger    parser.add_option('-v', '--verbosity', dest='verbosity',
49229921a8fSScott Kruger                      help='Verbosity of output by level: 1, 2, or 3', default=0)
49329921a8fSScott Kruger    opts, extra_args = parser.parse_args()
49429921a8fSScott Kruger
49529921a8fSScott Kruger    if extra_args:
49629921a8fSScott Kruger        import sys
49729921a8fSScott Kruger        sys.stderr.write('Unknown arguments: %s\n' % ' '.join(extra_args))
49829921a8fSScott Kruger        exit(1)
49929921a8fSScott Kruger    if not opts.test_file and not opts.directory:
50029921a8fSScott Kruger      print "test file or directory is required"
50129921a8fSScott Kruger      parser.print_usage()
50229921a8fSScott Kruger      sys.exit()
50329921a8fSScott Kruger
50429921a8fSScott Kruger    # Need verbosity to be an integer
50529921a8fSScott Kruger    try:
50629921a8fSScott Kruger      verbosity=int(opts.verbosity)
50729921a8fSScott Kruger    except:
50829921a8fSScott Kruger      raise Exception("Error: Verbosity must be integer")
50929921a8fSScott Kruger
51029921a8fSScott Kruger    main(directory=opts.directory,test_file=opts.test_file,verbosity=verbosity)
511