public void CheckContractIsOther(string contract, ContractKind kind) { var root = Syntax.ParseExpression(contract); var req = new CodeContractCollector(kind, Categories.SemanticCategories); req.Visit(root); Assert.IsTrue(req.Labels.Count == 1, "Expected a single contract clause for contract {0}", contract); Assert.IsFalse( req.Labels[0].Labels.Any(), string.Format("Contract '{0}' miscategorized. Label(s): {1}", contract, string.Join(",", req.Labels[0].Labels))); }
public void CheckContract(string contract, ContractKind kind, Category expected) { var root = Syntax.ParseExpression(contract); var collector = new CodeContractCollector(kind, Categories.SemanticCategories); collector.Visit(root); Assert.AreEqual(1, collector.Labels.Count, "Expected a single top-level contract clause"); var labels = collector.Labels[0].Labels.ToList(); Assert.IsTrue(labels.Count > 0, string.Format("Contract {0} not labeled", contract)); Assert.AreEqual(1, labels.Count, "Expected a single label for the contract"); Assert.AreEqual(expected.Name, labels[0], string.Format("Contract {0} miscategorized", contract)); }
public void Combined_bounds_check_test() { // This test fails because the categorization is considering each top-level clause separately var root = Syntax.ParseExpression("Contract.Requires(idx >= 0 && idx < array.Length);"); var req = new CodeContractCollector(ContractKind.Requires, Categories.SemanticCategories); req.Visit(root); Assert.AreEqual(2, req.Labels.Count(), "Expected categorization for both clauses"); Assert.AreEqual(1, req.Labels[0].Labels.Count(), "Expected first clause to have a single label"); Assert.AreEqual(1, req.Labels[1].Labels.Count(), "Expected second clause to have a single label"); Assert.AreEqual(Categories.BoundsCheck.Name, req.Labels[0].Labels.First()); Assert.AreEqual(Categories.BoundsCheck.Name, req.Labels[1].Labels.First()); }
public static void Main(string[] args) { if (args.Length != 2) { ShowHelpMessage(); return; } var targetDirectory = args[0]; var outputDirectory = args[1]; // Create project records for each of the subdirectories in the target directory. var projects = Directory.GetDirectories(targetDirectory); var subjects = new List<SubjectProgram>(); foreach (var path in projects) { var project = Path.GetFileName(path); Log.Info("Added project " + project); subjects.Add(new SubjectProgram() { Name = project, Path = path }); } var categories = Categories.SemanticCategories; // Delete the old category log files foreach (var cat in categories) { var path = Path.Combine(outputDirectory, CategoryLogName(cat)); if (File.Exists(path)) { File.Delete(path); } } // Aggregate statistic counters var agg = new Dictionary<string, int>(); var reqCnt = 0; var ensCnt = 0; var invCnt = 0; using (var csvStatsByProject = new StreamWriter(Path.Combine(outputDirectory, SummaryFileName))) { // Write the header. csvStatsByProject.WriteLine(string.Join(",", new[] { " " }.Concat(categories.Select(x => x.Name)))); using (var uncategorizedContractListing = new StreamWriter(Path.Combine(outputDirectory, UncategorizedContractFileName))) { foreach (var subject in subjects) { Log.InfoFormat("Computing counts for project {0}.", subject.Name); var req = new CodeContractCollector(ContractKind.Requires, categories); var ens = new CodeContractCollector(ContractKind.Ensures, categories); var obj = new CodeContractCollector(ContractKind.Invariant, categories); var all = new CodeContractCollector( ContractKind.Invariant | ContractKind.Ensures | ContractKind.Requires, categories); ProcessDirectory(subject.Path, path => { try { if (path.EndsWith(".cs")) VisitFile(path, new[] { req, ens, obj, all }); else return; } catch (Exception ex) { Log.Warn("Error processing file " + path, ex); } }); using (var csv = File.CreateText(Path.Combine(outputDirectory, subject.Name + ".stats"))) { var projRow = new List<string>(); projRow.Add(subject.Name); foreach (var cat in categories) { csv.Write(cat.Name + ","); csv.Write(req.Labels.Count(t => t.Labels.Contains(cat.Name)) + ","); csv.Write(ens.Labels.Count(t => t.Labels.Contains(cat.Name)) + ","); csv.Write(obj.Labels.Count(t => t.Labels.Contains(cat.Name))); csv.WriteLine(); if (!agg.ContainsKey(cat.Name)) agg.Add(cat.Name, 0); agg[cat.Name] = agg[cat.Name] + ens.Labels.Count(t => t.Labels.Contains(cat.Name)); projRow.Add(all.Labels.Count(t => t.Labels.Contains(cat.Name)).ToString()); // Dump all the contracts for the category using (var log = File.AppendText(Path.Combine(outputDirectory, CategoryLogName(cat)))) { foreach(var clause in all.Labels.Where(t => t.Labels.Contains(cat.Name))) { log.WriteLine(clause.ContractText); } } } csv.Write("Other" + ","); csv.Write(req.Labels.Count(t => t.Labels.Count == 0) + ","); csv.Write(ens.Labels.Count(t => t.Labels.Count == 0) + ","); csv.Write(obj.Labels.Count(t => t.Labels.Count == 0)); csv.WriteLine(); reqCnt += req.Labels.Count; ensCnt += ens.Labels.Count; invCnt += obj.Labels.Count; projRow.Add(all.Labels.Count(t => t.Labels.Count == 0).ToString()); if (!agg.ContainsKey("Other")) agg.Add("Other", 0); agg["Other"] = agg["Other"] + ens.Labels.Count(t => t.Labels.Count == 0); csvStatsByProject.WriteLine(string.Join(",", projRow)); } // Print uncatagorized contracts foreach (var u in all.Labels.Where(c => c.Labels.Count == 0)) { uncategorizedContractListing.WriteLine(u.ContractText); Log.DebugFormat("[Project {0}] No category for contract: {1}", subject.Name, u.ContractText); } } } } // Dump out aggregate counts foreach (var category in agg) { Console.WriteLine(category.Key + ": " + category.Value); } }
public static void Main(string[] args) { if (args.Length != 2) { ShowHelpMessage(); return; } var targetDirectory = args[0]; var outputDirectory = args[1]; // Create project records for each of the subdirectories in the target directory. var projects = Directory.GetDirectories(targetDirectory); var subjects = new List <SubjectProgram>(); foreach (var path in projects) { var project = Path.GetFileName(path); Log.Info("Added project " + project); subjects.Add(new SubjectProgram() { Name = project, Path = path }); } var categories = Categories.SemanticCategories; // Delete the old category log files foreach (var cat in categories) { var path = Path.Combine(outputDirectory, CategoryLogName(cat)); if (File.Exists(path)) { File.Delete(path); } } // Aggregate statistic counters var agg = new Dictionary <string, int>(); var reqCnt = 0; var ensCnt = 0; var invCnt = 0; using (var csvStatsByProject = new StreamWriter(Path.Combine(outputDirectory, SummaryFileName))) { // Write the header. csvStatsByProject.WriteLine(string.Join(",", new[] { " " }.Concat(categories.Select(x => x.Name)))); using (var uncategorizedContractListing = new StreamWriter(Path.Combine(outputDirectory, UncategorizedContractFileName))) { foreach (var subject in subjects) { Log.InfoFormat("Computing counts for project {0}.", subject.Name); var req = new CodeContractCollector(ContractKind.Requires, categories); var ens = new CodeContractCollector(ContractKind.Ensures, categories); var obj = new CodeContractCollector(ContractKind.Invariant, categories); var all = new CodeContractCollector( ContractKind.Invariant | ContractKind.Ensures | ContractKind.Requires, categories); ProcessDirectory(subject.Path, path => { try { if (path.EndsWith(".cs")) { VisitFile(path, new[] { req, ens, obj, all }); } else { return; } } catch (Exception ex) { Log.Warn("Error processing file " + path, ex); } }); using (var csv = File.CreateText(Path.Combine(outputDirectory, subject.Name + ".stats"))) { var projRow = new List <string>(); projRow.Add(subject.Name); foreach (var cat in categories) { csv.Write(cat.Name + ","); csv.Write(req.Labels.Count(t => t.Labels.Contains(cat.Name)) + ","); csv.Write(ens.Labels.Count(t => t.Labels.Contains(cat.Name)) + ","); csv.Write(obj.Labels.Count(t => t.Labels.Contains(cat.Name))); csv.WriteLine(); if (!agg.ContainsKey(cat.Name)) { agg.Add(cat.Name, 0); } agg[cat.Name] = agg[cat.Name] + ens.Labels.Count(t => t.Labels.Contains(cat.Name)); projRow.Add(all.Labels.Count(t => t.Labels.Contains(cat.Name)).ToString()); // Dump all the contracts for the category using (var log = File.AppendText(Path.Combine(outputDirectory, CategoryLogName(cat)))) { foreach (var clause in all.Labels.Where(t => t.Labels.Contains(cat.Name))) { log.WriteLine(clause.ContractText); } } } csv.Write("Other" + ","); csv.Write(req.Labels.Count(t => t.Labels.Count == 0) + ","); csv.Write(ens.Labels.Count(t => t.Labels.Count == 0) + ","); csv.Write(obj.Labels.Count(t => t.Labels.Count == 0)); csv.WriteLine(); reqCnt += req.Labels.Count; ensCnt += ens.Labels.Count; invCnt += obj.Labels.Count; projRow.Add(all.Labels.Count(t => t.Labels.Count == 0).ToString()); if (!agg.ContainsKey("Other")) { agg.Add("Other", 0); } agg["Other"] = agg["Other"] + ens.Labels.Count(t => t.Labels.Count == 0); csvStatsByProject.WriteLine(string.Join(",", projRow)); } // Print uncatagorized contracts foreach (var u in all.Labels.Where(c => c.Labels.Count == 0)) { uncategorizedContractListing.WriteLine(u.ContractText); Log.DebugFormat("[Project {0}] No category for contract: {1}", subject.Name, u.ContractText); } } } } // Dump out aggregate counts foreach (var category in agg) { Console.WriteLine(category.Key + ": " + category.Value); } }
public void Top_level_enumerable_clauses_tests() { var root = Syntax.ParseExpression("Contract.Requires(Contract.ForAll(xs, x => x >= 0 && x < array.Length));"); var req = new CodeContractCollector(ContractKind.Requires, Categories.SemanticCategories); req.Visit(root); Assert.AreEqual(2, req.Labels.Count(), "Expected categorization for both top-level clauses"); Assert.AreEqual(1, req.Labels[0].Labels.Count(), "Expected first clause to have a single label"); Assert.AreEqual(1, req.Labels[1].Labels.Count(), "Expected second clause to have a single label"); }
public void Top_level_cojunct_and_enumerable_clauses_tests() { var root = Syntax.ParseExpression("Contract.Requires(y != null && Contract.ForAll(xs, x => x >= 0 && x < array.Length));"); var req = new CodeContractCollector(ContractKind.Requires, Categories.SemanticCategories); req.Visit(root); Assert.AreEqual(3, req.Labels.Count(), "Expected categorization for both top-level clauses"); }
public void Top_level_clause_tests() { var root = Syntax.ParseExpression("Contract.Requires(x > 5 && y > 1);"); var req = new CodeContractCollector(ContractKind.Requires, Categories.SemanticCategories); req.Visit(root); Assert.AreEqual(2, req.Labels.Count(), "Expected categorization for both clauses"); Assert.AreEqual(1, req.Labels[0].Labels.Count(), "Expected first clause to have a single label"); Assert.AreEqual(1, req.Labels[1].Labels.Count(), "Expected second clause to have a single label"); }
public void Three_clause_tests() { var root = Syntax.ParseExpression("Contract.Requires(x != null && (y != null && (z != null)));"); var req = new CodeContractCollector(ContractKind.Requires, Categories.SemanticCategories); req.Visit(root); Assert.AreEqual(3, req.Labels.Count(), "Expected categorization for all three clauses"); }
public void Invalid_contract_tests() { var root = Syntax.ParseExpression("Contract.Requires(false);"); var req = new CodeContractCollector(ContractKind.Requires, Categories.SemanticCategories); req.Visit(root); Assert.AreEqual(0, req.Labels.Count, "Invalid requires contract should be skipped"); }