public void CalculateCoverage_FileExists_WithLines_ReturnsCodeCoverageTable() { var annotations = new[] { new { fileName = "first", id = 1, index = 2, hitCount = 1, coverage = 100.0m, line = "first_1" }, new { fileName = "second", id = 2, index = 8, hitCount = 3, coverage = 100.0m, line = "second_2" }, new { fileName = "third", id = 3, index = 13, hitCount = 0, coverage = 0.0m, line = string.Empty } }; var annotationTable = new AnnotationTable(); foreach (var a in annotations) { annotationTable.Add(a.fileName); annotationTable[a.fileName].Add(new Annotation(a.id, a.index, a.hitCount)); } var calculator = new CodeCoverageCalculator(null, annotationTable) { FileReader = new StubFileReader { ExistsValue = true, GetLinesValue = annotations.Select(a => a.line) } }; var actualCoverage = calculator.CalculateCoverage(); var expectedCoverage = new CodeCoverageTable { Total = (decimal)2 / 3 * 100 }; foreach (var a in annotations) expectedCoverage.Add(a.fileName, a.coverage); Assert.AreEqual(expectedCoverage.Plugin, actualCoverage.Plugin); Assert.AreEqual(expectedCoverage.Total, actualCoverage.Total); Assert.AreEqual(expectedCoverage.ToString(), actualCoverage.ToString()); CollectionAssert.AreEqual(expectedCoverage, actualCoverage); }
public void CalculateCoverage_DoNotReadAnnotations_ReturnsCodeCoverageTable() { var annotations = new[] { new { fileName = "first", hitCount = 3, totalCount = 3, coverage = 100.0m, line = "first_1" }, new { fileName = "second", hitCount = 4, totalCount = 5, coverage = 80.0m, line = "second_2" }, new { fileName = "third", hitCount = 8, totalCount = 10, coverage = 80.0m, line = "third_3" }, new { fileName = "fourth", hitCount = 1, totalCount = 5, coverage = 20.0m, line = "fourth_4" }, new { fileName = "fifth", hitCount = 3, totalCount = 30, coverage = 10.0m, line = "fifth_5" } }; var annotationTable = new AnnotationTable(); int id = 0; foreach (var a in annotations) { annotationTable.Add(a.fileName); int hitCount = a.hitCount; for (int i = 0; i < a.totalCount; i++) annotationTable[a.fileName].Add(new Annotation(id++, id, hitCount-- > 0 ? 1 : 0)); } var calculator = new CodeCoverageCalculator(annotationTable); var actualCoverage = calculator.CalculateCoverage(false); var expectedCoverage = new CodeCoverageTable { Total = 35.84905660377358490566037736m }; foreach (var a in annotations) expectedCoverage.Add(a.fileName, a.coverage); Assert.AreEqual(expectedCoverage.Plugin, actualCoverage.Plugin); Assert.AreEqual(expectedCoverage.Total, actualCoverage.Total); Assert.AreEqual(expectedCoverage.ToString(), actualCoverage.ToString()); CollectionAssert.AreEqual(expectedCoverage, actualCoverage); }
public CodeCoverageTable LoadCoverage() { var report = GetTestReports() .First() .GetFiles() .FirstOrDefault(x => x.FullName.ToLower().EndsWith("annotation.axml")); var table = PluginAnnotationTable.Load(report.FullName); var annotationTable = table.Items.First(); var calculator = new CodeCoverageCalculator(annotationTable); return calculator.CalculateCoverage(false); }
public void CalculateCoverage_FileExists_WithoutLines_ReturnsDefault() { var calculator = new CodeCoverageCalculator(null, new AnnotationTable()) { FileReader = new StubFileReader { ExistsValue = false } }; var coverageTable = calculator.CalculateCoverage(); Assert.AreEqual(new CodeCoverageTable(), coverageTable); }
static void ScanDirectory(DirectoryInfo AppDirectory, string RelativeAppPath) { var ignoreExtensions = new[] { "png", "jpg", "jpeg", "gif", "ico", "js", "css", }; var urlDictionary = CreateUrlDictionary(RelativeAppPath, AppDirectory); var urlCollections = new[] { urlDictionary.Select(x => x.Key).ToList(), new List<string>() }; var traceTable = new TraceTable(); var report = new StringBuilder(); var coverageReport = new StringBuilder(); var map = new ApplicationMap(); var alerts = new ScanAlertCollection(); int requestCount = 0; MessageDumper messageDumper = null; if (Config.DumpMessages) { messageDumper = new MessageDumper(_reportWriter.ReportPath.FullName); } for (int urlCollectionIndex = 0; urlCollectionIndex < 2; urlCollectionIndex++) foreach (ScanPluginBase plugin in Config.ScanPlugins) { if (Config.CodeCoverageReport > 0) { ScanMetrics.Default.Annotator.Reset(); ScanMetrics.Default.Annotator.AnnotationTable = ScanMetrics.Default.PluginAnnotations[plugin.ToString()]; } if (!urlCollections[urlCollectionIndex].Any()) continue; ScannerCli.DisplayScanPlugin(plugin); foreach (var remotePath in urlCollections[urlCollectionIndex]) { ScannerCli.DisplayResourcePath(remotePath); IEnumerable<IEnumerable<TracedFunctionCall>> calls = null; if (urlCollectionIndex == 0) { var key = urlDictionary[remotePath]; if (Program.PageFieldTable.ContainsKey(key)) calls = Program.PageFieldTable[key] .Select(x => x.Value.Select(y => new TracedFunctionCall() { Name = x.Key, ParameterValues = new List<string>() { y } })); } for (int i = 0; i < plugin.ModeCount; i++) { foreach (var useStaticAnalysisInputs in new[] { false, true }) { var trace = new FileTrace(); if (useStaticAnalysisInputs && calls != null) { if (!calls.Any(x => x.Any())) continue; foreach (var c in calls) trace.Calls.AddRange(c); } bool discoveredVars = true; while (discoveredVars) { var traceFile = new FileInfo(TraceFileName); IOHelper.TryAction(traceFile.Delete); var client = new TcpClient() { ReceiveTimeout = Config.Timeout, SendTimeout = Config.Timeout }; while (!client.Connected) try { client.Connect(Config.Server, Config.Port); } catch (SocketException ex) { ScannerCli.DisplayError(ex.Message); Thread.Sleep(5000); } client.LingerState = new LingerOption(true, 0); HttpResponse resp = null; string req, respString = ""; using (var stream = client.GetStream()) { req = plugin.BuildRequest(i, remotePath, trace); if (Config.DumpMessages) { messageDumper.Dump(req, requestCount, MessageType.Request); } var stopwatch = new Stopwatch(); stopwatch.Start(); stream.WriteString(req); try { var sgs = trace.Calls .Superglobals() .Select(x => new { x.Name, Value = x.ParameterValues.Count > 0 ? x.ParameterValues[0] : null }) .Distinct(); var discoveredVarCount = sgs.Count(); var reader = new HttpResponseReader(stream); resp = reader.Read(); stopwatch.Stop(); respString = resp.CompleteResponse; ScannerCli.DisplayResponse( resp, i, discoveredVarCount, stopwatch.ElapsedMilliseconds, resp.CompleteResponse.Length); } catch (SocketException) { ScannerCli.DisplayResponseError(respString); } catch (IOException) { ScannerCli.DisplayResponseError(respString); } } if (urlCollectionIndex == 0 && resp != null) { var abs = "http://" + Config.Server + remotePath; var urls = new UriScraper() { Regex = new Regex(@"[/.]" + Config.Server + @"($|/)", RegexOptions.IgnoreCase | RegexOptions.Compiled), } .Parse(resp.Body, abs) .Select(x => new Uri(x).LocalPath); foreach (var url in urls) { if (!ignoreExtensions.Any(x => url.ToLower().EndsWith("." + x)) && !urlCollections[0].Contains(url) && !urlCollections[1].Contains(url)) { urlCollections[1].Add(url); ScannerCli.DisplayDiscoveredUrl(url); } } } client.Close(); if (Config.DumpMessages) { messageDumper.Dump(respString, requestCount, MessageType.Response); } requestCount++; traceFile = new FileInfo(TraceFileName); FileTrace newTrace = null; IOHelper.TryAction(() => { if (traceFile.Exists) using (var reader = traceFile.OpenText()) newTrace = FileTrace.Parse(reader); }); if (newTrace == null) { newTrace = new FileTrace(); } newTrace.Request = req; newTrace.Response = respString; newTrace.File = remotePath; var alert = plugin.ScanTrace(newTrace); if (alert != null) { if (Config.BeepOnAlert) Console.Beep(); ScannerCli.DisplayAlert(alert); alerts.Add(alert); report.Append(alert.ToString()); } discoveredVars = false; foreach (TracedFunctionCall c in newTrace.Calls .Superglobals() .Where(x => x.ParameterValues.Any())) { var oldCalls = trace.Calls.Where(x => x.Name == c.Name && x.ParameterValues.SequenceEqual(c.ParameterValues)); if (!oldCalls.Any()) { discoveredVars = true; break; } } var orphanedInputs = trace.Calls .Superglobals() .Where(x => !newTrace.Calls .Any(y => x.Name == y.Name && x.ParameterValues .SequenceEqual(y.ParameterValues))) .ToArray(); newTrace.Calls.AddRange(orphanedInputs); trace = newTrace; } var superglobals = trace.Calls.Superglobals(); map.AddTrace(trace); if (Config.DiscoveryReport) { if (!traceTable.ContainsKey(plugin)) { traceTable.Add(plugin, new Dictionary<int, Dictionary<string, FileTrace>>()); } if (!traceTable[plugin].ContainsKey(i)) { traceTable[plugin].Add(i, new Dictionary<string, FileTrace>()); } if (!traceTable[plugin][i].ContainsKey(trace.File)) { traceTable[plugin][i].Add(trace.File, trace); } else { traceTable[plugin][i][trace.File] = trace; } } } } } if (Config.CodeCoverageReport > 0 && urlCollectionIndex == 0) { Cli.WriteLine("Calculating code coverage..."); CodeCoverageTable coverage = null; IOHelper.TryAction(() => { var calculator = new CodeCoverageCalculator( ScanMetrics.Default.Annotator.AnnotationFile, ScanMetrics.Default.PluginAnnotations[plugin.ToString()]); coverage = calculator.CalculateCoverage(); }); coverage.Plugin = plugin.ToString(); coverageReport.AppendLine(coverage.ToString() + "\r\n"); } Cli.WriteLine(); } _reportWriter.Write("Vulnerability Report", report.ToString()); _reportWriter.Write("Input Map Report", map.ToXml(), "xml"); if (alerts.Any()) { _reportWriter.Write("Vulnerability Report", alerts.ToXml(), "pxml"); } if (Config.DiscoveryReport) { _reportWriter.Write("Scan Overview Report", DiscoveryReport.Create(traceTable)); } if (Config.CodeCoverageReport > 0) { _reportWriter.Write("Code Coverage Report", coverageReport.ToString()); var annotationXml = ScanMetrics.Default.PluginAnnotations.ToXml(); var annotationFile = _reportWriter.Write( "Annotation", annotationXml, "axml"); Cli.WriteLine(); var commenter = new CoverageCommenter(ScanMetrics.Default.PluginAnnotations); commenter.LoadTable(annotationFile); commenter.WriteCommentedFiles(_reportWriter.ReportPath.FullName); _reportWriter.ReportFiles.Add( new ReportFile( "Coverage Comments", Path.Combine("Code Coverage", "index.html"))); } }