-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
31 changed files
with
1,303 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocCover", "DocCover\DocCover.csproj", "{DC97B8FE-D074-4DB4-9572-9B470902709E}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocCoverTest", "DocCoverTest\DocCoverTest.csproj", "{6F532FE3-D4B6-4347-9330-B4042870EE6F}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocCoverTestAssembly", "DocCoverTestAssembly\DocCoverTestAssembly.csproj", "{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
Pack|Any CPU = Pack|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{DC97B8FE-D074-4DB4-9572-9B470902709E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{DC97B8FE-D074-4DB4-9572-9B470902709E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{DC97B8FE-D074-4DB4-9572-9B470902709E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{DC97B8FE-D074-4DB4-9572-9B470902709E}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{DC97B8FE-D074-4DB4-9572-9B470902709E}.Pack|Any CPU.ActiveCfg = Pack|Any CPU | ||
{DC97B8FE-D074-4DB4-9572-9B470902709E}.Pack|Any CPU.Build.0 = Pack|Any CPU | ||
{6F532FE3-D4B6-4347-9330-B4042870EE6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{6F532FE3-D4B6-4347-9330-B4042870EE6F}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{6F532FE3-D4B6-4347-9330-B4042870EE6F}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{6F532FE3-D4B6-4347-9330-B4042870EE6F}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{6F532FE3-D4B6-4347-9330-B4042870EE6F}.Pack|Any CPU.ActiveCfg = Pack|Any CPU | ||
{6F532FE3-D4B6-4347-9330-B4042870EE6F}.Pack|Any CPU.Build.0 = Pack|Any CPU | ||
{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}.Pack|Any CPU.ActiveCfg = Pack|Any CPU | ||
{A5A8E2D0-9FD0-47BF-86F1-FD0D6ADA1466}.Pack|Any CPU.Build.0 = Pack|Any CPU | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace Artees.Tools.DocCover | ||
{ | ||
public class BadgeStyle : TypesafeEnum | ||
{ | ||
public static readonly Dictionary<string, BadgeStyle> All = | ||
new Dictionary<string, BadgeStyle>(); | ||
|
||
// ReSharper disable UnusedMember.Global | ||
public static readonly BadgeStyle Plastic = new BadgeStyle("plastic"), | ||
Flat = new BadgeStyle("flat"), | ||
FlatSquare = new BadgeStyle("flat-square"), | ||
ForTheBadge = new BadgeStyle("for-the-badge"), | ||
Popout = new BadgeStyle("popout"), | ||
PopoutSquare = new BadgeStyle("popout-square"), | ||
Social = new BadgeStyle("social"); | ||
// ReSharper restore UnusedMember.Global | ||
|
||
private BadgeStyle(string name) : base(name) | ||
{ | ||
All[name] = this; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Reflection; | ||
using System.Xml; | ||
using Artees.Diagnostics.BDD; | ||
using Artees.Tools.XmlDocumentationNameGetter; | ||
|
||
namespace Artees.Tools.DocCover | ||
{ | ||
public static class DocCover | ||
{ | ||
public static DocCoverReport GetReport(string xmlPath, string dllPath) | ||
{ | ||
xmlPath.Aka("XML").Should().Not().BeNull(); | ||
var report = new DocCoverReport(); | ||
if (xmlPath == null) return report; | ||
var xml = new XmlDocument(); | ||
xml.Load(xmlPath); | ||
var dll = Assembly.LoadFile(dllPath); | ||
report.AssemblyName = dll.GetName(); | ||
var xmlMembers = new List<string>(); | ||
var xmlMembersnodeList = xml.GetElementsByTagName("member"); | ||
for (var i = 0; i < xmlMembersnodeList.Count; i++) | ||
{ | ||
var xmlMember = xmlMembersnodeList.Item(i); | ||
xmlMembers.Add(xmlMember?.Attributes?["name"].Value); | ||
} | ||
|
||
CheckIfTypesAreDocumented(dll.ExportedTypes, xmlMembers, true, report); | ||
CheckIfTypesAreDocumented(dll.DefinedTypes, xmlMembers, false, report); | ||
xmlMembers.Count.Aka("Final").Should().BeEqual(0); | ||
return report; | ||
} | ||
|
||
private static void CheckIfTypesAreDocumented(IEnumerable<Type> types, | ||
List<string> xmlMembers, bool isPublic, DocCoverReport report) | ||
{ | ||
foreach (var type in types) | ||
{ | ||
var typeName = type.GetXmlDocsName(); | ||
var success = xmlMembers.RemoveAll(s => s == typeName); | ||
report.Add(new DocCoverMember(type, isPublic, success > 0)); | ||
const BindingFlags pub = BindingFlags.DeclaredOnly | BindingFlags.Public | | ||
BindingFlags.Instance | BindingFlags.Static; | ||
var publicMembers = type.GetMembers(pub); | ||
CheckIfMembersAreDocumented(publicMembers, xmlMembers, isPublic, report); | ||
const BindingFlags nonPublic = BindingFlags.DeclaredOnly | BindingFlags.NonPublic | | ||
BindingFlags.Instance | BindingFlags.Static; | ||
var nonPublicMembers = type.GetMembers(nonPublic); | ||
CheckIfMembersAreDocumented(nonPublicMembers, xmlMembers, false, report); | ||
} | ||
} | ||
|
||
private static void CheckIfMembersAreDocumented(IEnumerable<MemberInfo> members, | ||
List<string> xmlMembers, bool isPublic, DocCoverReport report) | ||
{ | ||
foreach (var member in members) | ||
{ | ||
var mName = member.GetXmlDocsName(); | ||
var success = xmlMembers.RemoveAll(s => s.StartsWith(mName)); | ||
report.Add(new DocCoverMember(member, isPublic, success > 0)); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System; | ||
using System.Reflection; | ||
using Artees.Tools.XmlDocumentationNameGetter; | ||
|
||
namespace Artees.Tools.DocCover | ||
{ | ||
public class DocCoverMember : IComparable<DocCoverMember> | ||
{ | ||
private readonly MemberInfo _memberInfo; | ||
|
||
public readonly bool IsPublic, | ||
IsDocumented; | ||
|
||
public DocCoverMember(MemberInfo member, bool isPublic, bool isDocumented) | ||
{ | ||
_memberInfo = member; | ||
IsPublic = isPublic; | ||
IsDocumented = isDocumented; | ||
} | ||
|
||
public string Name => _memberInfo.GetXmlDocsName(); | ||
|
||
public MemberTypes Type => _memberInfo.MemberType; | ||
|
||
public int CompareTo(DocCoverMember other) | ||
{ | ||
return string.Compare(Name, other.Name, StringComparison.InvariantCulture); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Reflection; | ||
|
||
namespace Artees.Tools.DocCover | ||
{ | ||
public class DocCoverReport | ||
{ | ||
private readonly List<DocCoverMember> _members = new List<DocCoverMember>(); | ||
|
||
public IReadOnlyList<DocCoverMember> Members => _members; | ||
|
||
internal AssemblyName AssemblyName { private get; set; } = | ||
Assembly.GetExecutingAssembly().GetName(); | ||
|
||
internal void Add(DocCoverMember member) | ||
{ | ||
_members.Add(member); | ||
} | ||
|
||
public double GetCoverage() | ||
{ | ||
var documented = Members.Count(m => m.IsPublic && m.Type != MemberTypes.Constructor && | ||
m.IsDocumented); | ||
var total = Members.Count(m => m.IsPublic && m.Type != MemberTypes.Constructor); | ||
return (double) documented / total; | ||
} | ||
|
||
public string GetHtml() | ||
{ | ||
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; | ||
var path = Path.Combine(baseDirectory, "ReportTemplate.html"); | ||
var template = File.ReadAllText(path); | ||
var assemblyName = GetAssemblyNameAndVersion(AssemblyName); | ||
var documented = Members.Count(m => m.IsPublic && m.IsDocumented); | ||
var undocumented = Members.Where(m => m.IsPublic && !m.IsDocumented && | ||
m.Type != MemberTypes.Constructor).ToList(); | ||
undocumented.Sort(); | ||
var undocumentedCount = undocumented.Count; | ||
var coverage = (double) documented / (documented + undocumentedCount); | ||
var memberPath = Path.Combine(baseDirectory, "MemberTemplate.html"); | ||
var memberTemplate = File.ReadAllText(memberPath); | ||
var membersList = undocumented.Count > 0 | ||
? undocumented.Select(m => string.Format(memberTemplate, m.Name)) | ||
: new List<string> {"N/A"}; | ||
var membersHtml = string.Join(string.Empty, membersList); | ||
var generatorAssemblyName = Assembly.GetExecutingAssembly().GetName(); | ||
var generator = GetAssemblyNameAndVersion(generatorAssemblyName); | ||
var html = string.Format(template, assemblyName, DateTime.Now, documented, | ||
undocumentedCount, coverage, membersHtml, generator); | ||
return html; | ||
} | ||
|
||
private static string GetAssemblyNameAndVersion(AssemblyName assemblyName) | ||
{ | ||
return $"{assemblyName.Name} {assemblyName.Version}"; | ||
} | ||
|
||
public string GetBadge() | ||
{ | ||
return GetBadge(BadgeStyle.Flat); | ||
} | ||
|
||
public string GetBadge(BadgeStyle style) | ||
{ | ||
using (var client = new WebClient()) | ||
{ | ||
var coverage = Math.Floor(GetCoverage() * 100); | ||
var color = GetBadgeColor(coverage); | ||
var url = "https://img.shields.io/badge/" + | ||
$"documented-{coverage}%-{color}.svg?style={style}"; | ||
return client.DownloadString(url); | ||
} | ||
} | ||
|
||
private static string GetBadgeColor(double coverage) | ||
{ | ||
var colorIndex = (int) Math.Floor(coverage / (100.0 / 6.0)); | ||
switch (colorIndex) | ||
{ | ||
case 0: return "red"; | ||
case 1: return "orange"; | ||
case 2: return "yellow"; | ||
case 3: return "yellowgreen"; | ||
case 4: return "green"; | ||
case 5: return "brightgreen"; | ||
case 6: return "brightgreen"; | ||
default: return "lightgrey"; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using Artees.Diagnostics.BDD; | ||
using CommandLine; | ||
|
||
namespace Artees.Tools.DocCover | ||
{ | ||
internal static class Program | ||
{ | ||
public static void Main(string[] args) | ||
{ | ||
using (var shouldListener = new WarningShouldListener()) | ||
{ | ||
ShouldAssertions.Listeners.Add(shouldListener); | ||
using (var traceListener = new ConsoleTraceListener()) | ||
{ | ||
Trace.Listeners.Add(traceListener); | ||
Execute(args); | ||
} | ||
} | ||
} | ||
|
||
private static void Execute(IEnumerable<string> args) | ||
{ | ||
Parser.Default.ParseArguments<Options>(args).WithParsed(Execute).WithNotParsed(Fail); | ||
} | ||
|
||
private static void Execute(Options options) | ||
{ | ||
var xmlPath = options.Xml; | ||
xmlPath.Aka("XML").Should().Not().BeNull(); | ||
if (xmlPath == null) return; | ||
var dllPath = Path.GetFullPath(options.Dll); | ||
var report = DocCover.GetReport(xmlPath, dllPath); | ||
var html = report.GetHtml(); | ||
var outputPath = Path.GetFullPath(options.Output); | ||
if (Directory.Exists(outputPath)) Directory.Delete(outputPath, true); | ||
Directory.CreateDirectory(outputPath); | ||
File.WriteAllText(Path.Combine(outputPath, "index.html"), html); | ||
var reportTemplatePath = | ||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "report.css"); | ||
File.Copy(reportTemplatePath, Path.Combine(outputPath, "report.css")); | ||
var badge = report.GetBadge(BadgeStyle.All[options.Style]); | ||
File.WriteAllText(Path.Combine(outputPath, "badge.svg"), badge); | ||
} | ||
|
||
private static void Fail(IEnumerable<Error> errors) | ||
{ | ||
foreach (var error in errors) | ||
{ | ||
if (error.Tag == ErrorType.HelpRequestedError) continue; | ||
ShouldAssertions.Fail(error.ToString()); | ||
} | ||
} | ||
|
||
// ReSharper disable once ClassNeverInstantiated.Local | ||
private class Options | ||
{ | ||
// ReSharper disable UnusedAutoPropertyAccessor.Local, MemberCanBePrivate.Local | ||
[Option('x', "xml", Hidden = true)] public string XmlOption { private get; set; } | ||
|
||
[Value(0, MetaName = "-x, --xml", HelpText = "The XML document to be analyzed.")] | ||
public string XmlValue { private get; set; } | ||
|
||
public string Xml => XmlOption ?? XmlValue ?? Dll.Remove(Dll.Length - 4) + ".xml"; | ||
|
||
[Option('d', "dll", Hidden = true)] public string DllOption { private get; set; } | ||
|
||
[Value(1, MetaName = "-d, --dll", | ||
HelpText = "The assembly file to be analyzed. " + | ||
"If not specified, the path of the XML document will be used.")] | ||
public string DllValue { private get; set; } | ||
|
||
public string Dll => DllOption ?? DllValue ?? Xml.Remove(Xml.Length - 4) + ".dll"; | ||
|
||
[Option('o', "outputdir", Hidden = true)] | ||
public string OutputOption { private get; set; } | ||
|
||
[Value(2, MetaName = "-o, --outputdir", | ||
HelpText = "The directory where the generated report should be saved.")] | ||
public string OutputValue { private get; set; } | ||
|
||
public string Output => OutputOption ?? OutputValue ?? "doc_cover"; | ||
|
||
[Option('s', "badgestyle", Hidden = true)] | ||
public string StyleOption { private get; set; } | ||
|
||
[Value(3, MetaName = "-s, --badgestyle", | ||
HelpText = | ||
"The style of the generated badge. The following styles are available: " + | ||
"plastic, flat, flat-square, for-the-badge, popout, popout-square, " + | ||
"social.")] | ||
public string StyleValue { private get; set; } | ||
|
||
public string Style => StyleOption ?? StyleValue ?? "flat"; | ||
// ReSharper restore UnusedAutoPropertyAccessor.Local, MemberCanBePrivate.Local | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
namespace Artees.Tools.DocCover | ||
{ | ||
/// <summary> | ||
/// <see href="http://www.javacamp.org/designPattern/enum.html"/> | ||
/// </summary> | ||
public abstract class TypesafeEnum | ||
{ | ||
private static int _nextId; | ||
|
||
// ReSharper disable once UnusedMember.Global | ||
public readonly int Id = _nextId++; | ||
|
||
// ReSharper disable once MemberCanBePrivate.Global | ||
public readonly string Name; | ||
|
||
protected TypesafeEnum(string name) | ||
{ | ||
Name = name; | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return Name; | ||
} | ||
} | ||
} |
Oops, something went wrong.