Commits

Wez Furlong committed a315ae6

add crappy file view and summary command

Comments (0)

Files changed (1)

 
 function zero_counters($dir)
 {
-  echo "zero_counters: $dir\n";
+  if (!strlen($dir)) $dir = '.';
+  # echo "zero_counters: $dir\n";
   find($dir, 'zero_counter', '/\.gcda$/');
 }
 
 
   function loadFromGCOV($filename) {
     $fp = fopen($filename, 'r');
-    
+
     $ANON_BLOCK = 99999;
     $last_line = 0;
     $last_block = $ANON_BLOCK;
     if (count($this->branch)) {
       $taken = 0;
       foreach ($this->branch as $b) {
-        if ($b[3] != '-') $taken++;
+        if ($b[3] != '-' && $b[3] > 0) $taken++;
       }
       $this->branch_cov = $taken / count($this->branch) * 100;
     } else {
     $db = get_db();
     $st = $db->prepare(<<<SQL
 insert into by_src (srcfile, line_cov, lines, instr_lines, func_cov,
-  branch_cov, branches_taken, branches, instr, exec, funcs, branch) 
+  branch_cov, branches_taken, branches, instr, exec, funcs, branch)
 values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
 SQL
     );
       $F->comp = $M[2];
       $F->first_line = $M[4];
       $F->lines = $M[5];
-      $F->name = $M[6];
+      $F->name = preg_replace("/^unnamed::/", '', $M[6]);
 
       /* we know which lines were executed for the whole file; intersect that
        * data with the first line and number of lines to determine the exec
             continue;
           }
           $total++;
-          if ($b[3] != '-') $taken++;
+          if ($b[3] != '-' && $b[3] > 0) $taken++;
           $branch[] = $b;
         }
         if ($total) {
           $F->branch_cov = $taken / $total * 100;
         }
-      } 
+      }
 
       // CRAP(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)
       $F->crap = $F->comp^2 * (1 - $F->line_cov/100.0)^3 + $F->comp;
       $st->execute(array(
         $this->source, $F->name, $F->mcomp, $F->comp,
         $F->line_cov, $F->branch_cov, $F->crap, $F->first_line,
-        $F->lines, $F->exec_lines, 
+        $F->lines, $F->exec_lines,
         json_encode(array_keys($exec)),
         json_encode($branch)
       ));
     }
-
-    /*
-    printf("\tLines:  %.0f%%\n", $this->line_cov);
-    printf("\tFuncs:  %.0f%%\n", $this->func_cov);
-    printf("\tBranch: %.0f%%\n", $this->branch_cov);
-     */
   }
 
   function mergeFrom(FileCovData $other)
 
   function saveRawToDB($testname) {
     $this->cleanup();
-    
+
     $db = get_db();
     $st = $db->prepare(<<<SQL
 INSERT INTO raw_data (
 
     $st = $db->prepare("select testname, srcfile, instr, exec, funcs, branch from raw_data where testname = ?");
     $st->execute(array($testname));
-    foreach ($st->fetchAll() as $row) {
+    foreach ($st as $row) {
       $C = new FileCovData;
       $C->loadFromDBRow($row);
 
     $db->exec("delete from func_data");
     $db->exec("delete from by_src");
 
-    /* First compute totals by source file */
+    /* compute totals by source file */
+    foreach ($db->query("select distinct srcfile from raw_data")->fetchAll()
+        as $row) {
+      $srcfile = $row['srcfile'];
+      $st = $db->prepare("select srcfile, instr, exec, funcs, branch from raw_data where srcfile = ?");
+      $st->execute(array($srcfile));
 
+      $F = null;
+      while ($srow = $st->fetch()) {
+        $N = new FileCovData;
+        $N->loadFromDBRow($srow);
+        if ($F) {
+          $F->mergeFrom($N);
+        } else {
+          $F = $N;
+        }
+      }
+      $F->compute_totals();
+    }
+
+    /*
     foreach ($this->by_test as $T) {
       foreach ($T->by_file as $F) {
         if (isset($this->by_file[$F->source])) {
     foreach ($this->by_file as $F) {
       $F->compute_totals();
     }
+     */
     $db->commit();
 
   }
     }
   }
   $cmd = join(' ', $cmd) . $redir;
-  echo "$cmd\n";
+  #echo "$cmd\n";
   return system($cmd);
 }
 
 {
   global $TEST_NAME;
 
+  if (!strlen($dir)) $dir = '.';
+
   echo "Capturing coverage data from $dir\n";
   $T = new TestCovData;
   $T->testname = $TEST_NAME;
       unlink($cov_file);
     }
   }
-  
+
   global $TEST_NAME;
   $T->save($filename);
 }
   $P = new ProjCovData;
 
   echo "Summarize test data\n";
-  $P->loadAllTestData();
   $P->compute_totals();
 }
 
 
   -- modified complexity
   mcomp num,
-  -- complexity
+  -- apparent complexity
   comp num,
   -- computed line coverage percent
   line_cov num,
   );
 }
 
+function query_file()
+{
+  global $argv;
+  $db = get_db();
+
+  $compact = false;
+
+  while (count($argv)) {
+    $pat = array_shift($argv);
+
+    if ($pat == '--compact') {
+      $compact = true;
+    }
+
+    foreach ($db->query("select * from by_src where srcfile like '%$pat%'")
+        ->fetchAll() as $row) {
+      printf("file: %s\n", $row['srcfile']);
+      printf("\tLine coverage:   %3.0f%%\n", $row['line_cov']);
+      printf("\tFunc coverage:   %3.0f%%\n", $row['func_cov']);
+      printf("\tBranch coverage: %3.0f%%\n", $row['branch_cov']);
+
+      $instr = array();
+      foreach (json_decode($row['instr']) as $line) {
+        $instr[$line] = true;
+      }
+      $exec = array();
+      foreach ((array)json_decode($row['exec']) as $line => $count) {
+        $exec[$line] = $count;
+      }
+      $branch_miss = array();
+      foreach (json_decode($row['branch']) as $b) {
+        if ($b[3] == '-' || $b[3] == 0) {
+          $branch_miss[$b[0]]++;
+        }
+      }
+
+      /* get function range information as well */
+      $func_by_line = array();
+      $st = $db->prepare(
+        "select funcname, first_line, lines, line_cov, branch_cov, crap, comp
+        from func_data where srcfile = ?");
+      $funcdata = array();
+
+      $st->execute(array($row['srcfile']));
+      foreach ($st->fetchAll() as $frow) {
+        $funcdata[$frow['funcname']] = $frow;
+
+        for ($line = $frow['first_line'];
+            $line < $frow['first_line'] + $frow['lines']; $line++) {
+          $func_by_line[$line] = $frow['funcname'];
+        }
+      }
+
+      $lines = file($row['srcfile']);
+
+      if ($compact) {
+        /* in compact mode, we identify each function that has missed
+         * coverage */
+        $missed = array();
+        foreach ($instr as $line => $ignored) {
+          $func = $func_by_line[$line];
+          if (!isset($exec[$line]) || isset($branch_miss[$line])) {
+            $missed[$func][] = $line;
+          }
+        }
+        $printed = array();
+        foreach ($missed as $func => $missed_lines) {
+          printf("\n%s:\n", $func);
+          $last_printed = null;
+          printf("\tLine coverage:   %3.0f%%   CRAP:        %3.0f\n",
+              $funcdata[$func]['line_cov'], $funcdata[$func]['crap']);
+          printf("\tBranch coverage: %3.0f%%   Complexity:  %3.0f\n",
+              $funcdata[$func]['branch_cov'],
+              $funcdata[$func]['comp']);
+          printf("\n");
+
+          foreach ($missed_lines as $line) {
+            # 3 lines of context
+            $first = $line - 3;
+            if ($first < $funcdata[$func]['first_line']) {
+              $first = $funcdata[$func]['first_line'];
+            }
+            while ($first < $line) {
+              if ($printed[$first]) {
+                $first++;
+              }
+              break;
+            }
+            for ($i = $first; $i < $line + 3; $i++) {
+              if ($func_by_line[$i] != $func) break;
+              if ($printed[$i]) continue;
+              $printed[$i] = true;
+
+              $glyph = ' ';
+              if (isset($instr[$i]) && !isset($exec[$i])) {
+                $glyph = '-';
+              } else if (isset($branch_miss[$i])) {
+                $glyph = '/';
+              }
+              if ($last_printed !== null && $last_printed + 1 < $i) {
+                printf("  ...\n");
+              }
+              printf("%5d %s %s", $i, $glyph, $lines[$i - 1]);
+              $last_printed = $i;
+            }
+          }
+          printf("\n");
+        }
+      } else {
+        foreach ($lines as $i => $text) {
+          $line = $i + 1;
+
+          $glyph = ' ';
+          if (isset($instr[$line]) && !isset($exec[$line])) {
+            $glyph = '-';
+          } else if (isset($branch_miss[$line])) {
+            $glyph = '/';
+          }
+          printf("%s%s", $glyph, $text);
+          $line++;
+        }
+      }
+    }
+  }
+
+  echo "\nLegend:\n\t- indicates a line with no coverage\n" .
+    "\t/ indicates a line with less than 100% branch coverage\n\n";
+}
+
+function crap_report()
+{
+  $db = get_db();
+  /* how many methods are crappy ? */
+  foreach ($db->query("select (select count(*) from func_data where crap > 30) as crappy, (select count(*) from func_data) as funcs")->fetchAll() as $row)
+  {
+    $crappy = $row[0];
+    $total = $row[1];
+  }
+  /* overall coverage health */
+  foreach ($db->query(<<<SQL
+select sum(lines), sum(instr_lines),
+  sum(branches_taken), sum(branches)
+from by_src
+SQL
+      )->fetchAll() as $row) {
+    $cov = $row[0] / $row[1] * 100;
+    $bcov = $row[2] / $row[3] * 100;
+  }
+
+  /* crapload represents the "cost" of making the code less crappy.
+   * crapload is 0 when none of the methods are crappy.  You score
+   * a point of crapload per missing point of coverage per point of
+   * complexity, plus a point of crapload per point of crap above the
+   * crap threshold */
+  foreach ($db->query("select sum((comp * (100 - line_cov)) + (comp / 30))
+      from func_data where crap > 30")->fetchAll() as $row) {
+    $crapload = $row[0];
+  }
+
+  printf("Line Coverage:    %3.0f%%\n", $cov);
+  printf("Branch Coverage:  %3.0f%%\n", $bcov);
+  printf("CRAP functions:   %3.0f%% (%d)\n",
+    $crappy / $total * 100,
+    $crappy);
+  printf("CRAPload:       %6d\n", ceil($crapload));
+
+
+  $crap_funcs = $db->query("select srcfile, funcname, line_cov, crap, comp
+    from func_data order by crap desc, comp desc limit 15")->fetchAll();
+  if (count($crap_funcs)) {
+    printf(" CRAP | COMP | CRAPLOAD | FUNC\n");
+    foreach ($crap_funcs as $row) {
+      $cov = $row['line_cov'];
+      $comp = $row['comp'];
+      $crap = $row['crap'];
+      if ($crap > 30) {
+        $crapload = ($comp * (100 - $cov)) + ($comp / 30);
+      } else {
+        $crapload = 0;
+      }
+      printf(" %4d   %4d       %4d   %s:%s\n", $crap, $comp, $crapload,
+        $row['srcfile'], $row['funcname']);
+    }
+  }
+}
+
 $cmds = array(
   "init" => array(0, "init_storage"),
   "zero" => array(1, "zero_counters"),
   "capture" => array(1, "capture_data"),
   "testname" => array(1, "set_test_name"),
   "compute" => array(0, "compute_summary"),
+  "file" => array(0, "query_file"),
+  "summary" => array(0, "crap_report"),
 );
 
 array_shift($argv);