156 lines
5.7 KiB
C#
156 lines
5.7 KiB
C#
/*
|
||
* Program.cs
|
||
*
|
||
* This source file is part of the FoundationDB open source project
|
||
*
|
||
* Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
||
*
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.IO;
|
||
using System.Xml.Linq;
|
||
using System.Text.RegularExpressions;
|
||
|
||
namespace coveragetool
|
||
{
|
||
class CoverageCase
|
||
{
|
||
public string File;
|
||
public int Line;
|
||
public string Comment;
|
||
public string Condition;
|
||
};
|
||
|
||
class Program
|
||
{
|
||
public static int Main(string[] args)
|
||
{
|
||
if (args.Length < 2)
|
||
{
|
||
Console.WriteLine("Usage:");
|
||
Console.WriteLine(" coveragetool [coveragefile] [inputpath]*");
|
||
return 100;
|
||
}
|
||
Console.WriteLine("coveragetool {0}", string.Join(" ", args));
|
||
|
||
string output = args[0];
|
||
string[] inputPaths = args.Skip(1).Where(p=>!p.Contains(".g.") && !p.Contains(".amalgamation.")).ToArray();
|
||
|
||
var outputFile = new FileInfo( output );
|
||
|
||
/*var allFiles = inputPaths.SelectMany( path =>
|
||
new DirectoryInfo( Path.GetDirectoryName(path) )
|
||
.EnumerateFiles( Path.GetFileName(path), SearchOption.AllDirectories )
|
||
).ToArray();*/
|
||
|
||
var exists = inputPaths.ToLookup(n=>n);
|
||
|
||
CoverageCase[] cases = new CoverageCase[0];
|
||
var outputTime = DateTime.MinValue;
|
||
if (outputFile.Exists)
|
||
{
|
||
string[] oldArgs;
|
||
ParseOutput(output, out cases, out oldArgs);
|
||
if (oldArgs.Length == inputPaths.Length && !oldArgs.Zip(inputPaths,(a,b)=>a!=b).Any(b=>b))
|
||
outputTime = outputFile.LastWriteTimeUtc;
|
||
}
|
||
|
||
var changedFiles = inputPaths
|
||
.Where( fi=>new FileInfo(fi).LastWriteTimeUtc > outputTime )
|
||
.ToLookup(n=>n);
|
||
|
||
cases = cases
|
||
.Where(c => exists.Contains(c.File) && !changedFiles.Contains(c.File))
|
||
.Concat( changedFiles.SelectMany( f => ParseSource( f.Key ) ) )
|
||
.ToArray();
|
||
|
||
Console.WriteLine(" {0}/{1} files scanned", changedFiles.Count, inputPaths.Length);
|
||
Console.WriteLine(" {0} coverage cases found", cases.Length);
|
||
|
||
WriteOutput(output, cases, inputPaths);
|
||
|
||
return 0;
|
||
}
|
||
|
||
private static string ValueOrDefault(XAttribute attr, string def)
|
||
{
|
||
if (attr == null) return def;
|
||
else return attr.Value;
|
||
}
|
||
|
||
public static void ParseOutput(string filename, out CoverageCase[] cases, out string[] args)
|
||
{
|
||
var doc = XDocument.Load(filename).Element("CoverageTool");
|
||
cases =
|
||
doc.Element("CoverageCases")
|
||
.Elements("Case")
|
||
.Select(c =>
|
||
new CoverageCase { File = c.Attribute("File").Value, Line = int.Parse(c.Attribute("Line").Value), Comment=c.Attribute("Comment").Value, Condition=ValueOrDefault(c.Attribute("Condition"),"") }
|
||
)
|
||
.ToArray();
|
||
args =
|
||
doc.Element("Inputs")
|
||
.Elements("Input")
|
||
.Select(i => i.Value)
|
||
.ToArray();
|
||
}
|
||
public static void WriteOutput(string filename, CoverageCase[] cases, string[] args)
|
||
{
|
||
var doc = new XDocument(
|
||
new XElement("CoverageTool",
|
||
new XElement("CoverageCases",
|
||
cases.Select(c =>
|
||
new XElement("Case",
|
||
new XAttribute("File", c.File),
|
||
new XAttribute("Line", c.Line.ToString()),
|
||
new XAttribute("Comment", c.Comment),
|
||
new XAttribute("Condition", c.Condition)
|
||
)
|
||
)
|
||
),
|
||
new XElement("Inputs",
|
||
args.Select(a => new XElement("Input", a)))
|
||
));
|
||
doc.Save(filename);
|
||
}
|
||
public static CoverageCase[] ParseSource(string filename)
|
||
{
|
||
var regex = new Regex( @"^([^/]|/[^/])*(TEST|INJECT_FAULT|SHOULD_INJECT_FAULT)[ \t]*\(([^)]*)\)" );
|
||
|
||
var lines = File.ReadAllLines(filename);
|
||
return Enumerable.Range(0, lines.Length)
|
||
.Where( i=>regex.IsMatch(lines[i]) && !lines[i].StartsWith("#define") )
|
||
.Select( i=>new CoverageCase {
|
||
File = filename,
|
||
Line = i+1,
|
||
Comment = FindComment(lines[i]),
|
||
Condition = regex.Match(lines[i]).Groups[3].Value
|
||
} )
|
||
.ToArray();
|
||
}
|
||
public static string FindComment(string line)
|
||
{
|
||
int comment = line.IndexOf("//");
|
||
if (comment == -1)
|
||
return "";
|
||
else
|
||
return line.Substring(comment + 2).Trim();
|
||
}
|
||
}
|
||
}
|