text: #!/usr/bin/python2
  
  import subprocess
  import sys
  import getopt
  import os
  
  # Driver program for C programming exercise
  
  
  class Tracer:
  
      traceDirectory = "./traces"
      qtest = "./qtest"
      verbLevel = 0
      autograde = False
  
      traceDict = {
          0: "trace-00-make",
          1: "trace-01-ops",
          2: "trace-02-ops",
          3: "trace-03-ops",
          4: "trace-04-ops",
          5: "trace-05-ops",
          6: "trace-06-robust",
          7: "trace-07-robust",
          8: "trace-08-robust",
          9: "trace-09-malloc",
          10: "trace-10-malloc",
          11: "trace-11-malloc",
          12: "trace-12-perf",
          13: "trace-13-perf",
          14: "trace-14-perf"
      }
  
      traceProbs = {
          0: "Trace-00",
          1: "Trace-01",
          2: "Trace-02",
          3: "Trace-03",
          4: "Trace-04",
          5: "Trace-05",
          6: "Trace-06",
          7: "Trace-07",
          8: "Trace-08",
          9: "Trace-09",
          10: "Trace-10",
          11: "Trace-11",
          12: "Trace-12",
          13: "Trace-13",
          14: "Trace-14",
      }
  
      maxScores = [7, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7]
  
      def __init__(self, qtest="", verbLevel=0, autograde=False):
          if qtest != "":
              self.qtest = qtest
          self.verbLevel = verbLevel
          self.autograde = autograde
  
      # the function to test the make file
      def runMake(self):
          # first check the make file can build the files
          commandResult = subprocess.call("make")
          if commandResult != 0:
              print "Makefile build failed"
              return False
          # the check that the make file updates qtest when queue.o is changed
          subprocess.call(["touch", "queue.c"])
          changeTime = os.path.getmtime("./qtest")
          commandResult = subprocess.call("make")
          if commandResult != 0:
              print "Makefile build failed after queue.c was changed"
              return False
          if changeTime == os.path.getmtime("./qtest"):
              print "qtest was not updated when queue.c was changed"
              return False
          return True
  
      def runTrace(self, tid):
          if not tid in self.traceDict:
              print "ERROR: No trace with id %d" % tid
              return False
          # trace 0 is not really a queue trace but instead a script to test
          # the make file
          if tid == 0:
              return self.runMake()
          else:
              fname = "%s/%s.cmd" % (self.traceDirectory, self.traceDict[tid])
              vname = "%d" % self.verbLevel
              clist = [self.qtest, "-v", vname, "-f", fname]
              try:
                  retcode = subprocess.call(clist)
              except Exception as e:
                  print "Call of '%s' failed: %s" % (" ".join(clist), e)
                  return False
              return retcode == 0
  
      def run(self, tid=0):
          scoreDict = {}
          for k in self.traceDict.keys():
              scoreDict[k] = 0
          print "---\tTrace\t\tPoints"
          if tid == 0:
              tidList = self.traceDict.keys()
          else:
              if not tid in self.traceDict:
                  print "ERROR: Invalid trace ID %d" % tid
                  return
              tidList = [tid]
          score = 0
          maxscore = 0
          for t in tidList:
              tname = self.traceDict[t]
              if self.verbLevel > 0:
                  print "+++ TESTING trace %s:" % tname
              ok = self.runTrace(t)
              maxval = self.maxScores[t]
              tval = maxval if ok else 0
              print "---\t%s\t%d/%d" % (tname, tval, maxval)
              score += tval
              maxscore += maxval
              scoreDict[t] = tval
          print "---\tTOTAL\t\t%d/%d" % (score, maxscore)
          if self.autograde:
              # Generate JSON string
              jstring = '{"scores": {'
              first = True
              for k in scoreDict.keys():
                  if not first:
                      jstring += ', '
                  first = False
                  jstring += '"%s" : %d' % (self.traceProbs[k], scoreDict[k])
              jstring += '}}'
              print jstring
  
  
  def usage(name):
      print "Usage: %s [-h] [-p PROG] [-t TID] [-v VLEVEL]" % name
      print "  -h        Print this message"
      print "  -p PROG   Program to test"
      print "  -t TID    Trace ID to test"
      print "  -v VLEVEL Set verbosity level (0-3)"
      sys.exit(0)
  
  
  def run(name, args):
      prog = ""
      tid = 0
      vlevel = 1
      levelFixed = False
      autograde = False
  
      optlist, args = getopt.getopt(args, 'hp:t:v:A')
      for (opt, val) in optlist:
          if opt == '-h':
              usage(name)
          elif opt == '-p':
              prog = val
          elif opt == '-t':
              tid = int(val)
          elif opt == '-v':
              vlevel = int(val)
              levelFixed = True
          elif opt == '-A':
              autograde = True
          else:
              print "Unrecognized option '%s'" % opt
              usage(name)
      if not levelFixed and autograde:
          vlevel = 0
      t = Tracer(qtest=prog, verbLevel=vlevel, autograde=autograde)
      t.run(tid)
  
  
  if __name__ == "__main__":
      run(sys.argv[0], sys.argv[1:])
  