public void Should_map_added_lines() { blameStub = new BlameStub(); blameStub[1] = "abc"; blameStub[2] = "abc"; blameStub[3] = "abc"; scmData.Stub(x => x.Blame("abc", "file1")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .AddFile("file1").Modified() ); SubmitChanges(); Queryable<CodeBlock>().Count() .Should().Be(1); Queryable<CodeBlock>().Single() .Satisfy(x => x.Size == 3 && x.AddedInitiallyInCommit.Revision == "abc" ); }
public void Should_map_added_lines() { blameStub = new BlameStub(); blameStub[1] = "abc"; blameStub[2] = "abc"; blameStub[3] = "abc"; scmData.Stub(x => x.Blame("abc", "file1")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .AddFile("file1").Modified() ); SubmitChanges(); Queryable <CodeBlock>().Count() .Should().Be(1); Queryable <CodeBlock>().Single() .Satisfy(x => x.Size == 3 && x.AddedInitiallyInCommit.Revision == "abc" ); }
public void Should_map_new_code_in_copied_file_as_new() { mappingDSL .AddCommit("a") .AddFile("file1").Modified() .Code(10) .Submit(); blameStub = new BlameStub(); for (int i = 1; i <= 10; i++) { blameStub[i] = "a"; } for (int i = 11; i <= 15; i++) { blameStub[i] = "abc"; } scmData.Stub(x => x.Blame("abc", "file2")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .AddFile("file2").CopiedFrom("file1", "a").Modified() ); SubmitChanges(); var code = Queryable <CodeBlock>() .Single(cb => cb.Size == 5) .AddedInitiallyInCommit.Revision .Should().Be("abc"); }
private IDictionary <string, IEnumerable <int> > LinesByRevisionTheyWereAddedIn( IEnumerable <int> lines, IBlame blame ) { SmartDictionary <string, IEnumerable <int> > result = new SmartDictionary <string, IEnumerable <int> >((x) => new List <int>()); foreach (int line in lines) { (result[blame[line]] as List <int>).Add(line); } return(result); }
public static IDictionary <string, double> Diff(this IBlame blame1, IBlame blame2) { var revisions = blame1.Keys.Union(blame2.Keys); var diff = revisions.Select(x => new { Revision = x, Delta = (blame2.ContainsKey(x) ? blame2[x] : 0) - (blame1.ContainsKey(x) ? blame1[x] : 0) }).ToArray(); return(diff .Where(x => x.Delta != 0) .ToDictionary(x => x.Revision, x => x.Delta)); }
public void Should_remove_code_that_no_more_exists() { mappingDSL .AddCommit("a") .AddFile("file1").Modified() .Code(10) .Submit() .AddCommit("ab") .File("file1").Modified() .Code(20) .Submit(); blameStub = new BlameStub(); for (int i = 1; i <= 10; i++) { blameStub[i] = "abc"; } for (int i = 11; i <= 25; i++) { blameStub[i] = "ab"; } scmData.Stub(x => x.Blame("abc", "file1")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .File("file1").Modified() ); SubmitChanges(); var code = Queryable <CodeBlock>() .Where(cb => cb.Modification.Commit.Revision == "abc"); code.Select(cb => cb.Size).ToArray() .Should().Have.SameValuesAs(new double[] { 10, -10, -5 }); code.Where(cb => cb.Size < 0) .Select(cb => cb.TargetCodeBlock.Size).ToArray() .Should().Have.SameValuesAs(new double[] { 10, 20 }); }
public void Should_map_all_code_as_is_for_copied_file() { mappingDSL .AddCommit("a") .AddFile("file1").Modified() .Code(10) .Submit() .AddCommit("ab") .File("file1").Modified() .Code(5) .Submit(); blameStub = new BlameStub(); for (int i = 1; i <= 10; i++) { blameStub[i] = "a"; } for (int i = 11; i <= 15; i++) { blameStub[i] = "ab"; } scmData.Stub(x => x.Blame("abc", "file2")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .AddFile("file2").CopiedFrom("file1", "ab").Modified() ); SubmitChanges(); var code = Queryable <CodeBlock>() .Where(cb => cb.Modification.Commit.Revision == "abc"); code.Select(cb => cb.Size).ToArray() .Should().Have.SameValuesAs(new double[] { 10, 5 }); code.Select(cb => cb.AddedInitiallyInCommit.Revision).ToArray() .Should().Have.SameValuesAs(new string[] { "a", "ab" }); }
public override IEnumerable <CodeBlockMappingExpression> Map(ModificationMappingExpression expression) { List <CodeBlockMappingExpression> codeBlockExpressions = new List <CodeBlockMappingExpression>(); string revision = expression.CurrentEntity <Commit>().Revision; ProjectFile file = expression.CurrentEntity <ProjectFile>(); bool fileIsNew = (file.AddedInCommit != null) && (file.AddedInCommit.Revision == revision); bool fileCopied = fileIsNew && (file.SourceFile != null); bool fileDeleted = file.DeletedInCommit != null; IMetricsLanguage metricsCalculator = new MetricsLanguageC(new KeyTokensSetCPlus()); if (fileDeleted) { codeBlockExpressions.Add( expression.DeleteCode() ); } else { IBlame blame = scmData.Blame(revision, file.Path); var linesByRevision = from l in blame group l.Key by l.Value; IBodyFile bodyFile = scmData.Show(revision, file.Path); if (fileCopied) { foreach (var linesForRevision in linesByRevision) { double totalValueMetric = 0; foreach (int indexLineCode in linesForRevision) { var lineCode = bodyFile.ElementAt(indexLineCode - 1); totalValueMetric += metricsCalculator.CalculateMetrics(lineCode); } codeBlockExpressions.Add( expression.Code(totalValueMetric) ); if (linesForRevision.Key != revision) { codeBlockExpressions.Last().CopiedFrom(linesForRevision.Key); } } } else { var addedCode = linesByRevision.SingleOrDefault(x => x.Key == revision); if (addedCode != null) { double totalValueMetric = 0; foreach (int indexLineCode in addedCode) { var lineCode = bodyFile.ElementAt(indexLineCode - 1); totalValueMetric += metricsCalculator.CalculateMetrics(lineCode); } codeBlockExpressions.Add( expression.Code(totalValueMetric) ); } foreach (var existentCode in ( from cb in expression.Queryable <CodeBlock>() join m in expression.Queryable <Modification>() on cb.ModificationID equals m.ID join f in expression.Queryable <ProjectFile>() on m.FileID equals f.ID join c in expression.Queryable <Commit>() on m.CommitID equals c.ID let addedCodeID = cb.Size < 0 ? cb.TargetCodeBlockID : cb.ID let addedCodeRevision = expression.Queryable <Commit>() .Single(x => x.ID == expression.Queryable <CodeBlock>() .Single(y => y.ID == addedCodeID).AddedInitiallyInCommitID ).Revision where f.ID == file.ID group cb.Size by addedCodeRevision into g select new { Revision = g.Key, CodeSize = g.Sum() } )) { var linesForRevision = linesByRevision.SingleOrDefault(x => x.Key == existentCode.Revision); IBodyFile bodyFileForRevision = scmData.Show(revision, file.Path); double totalValueMetric = 0; try { foreach (int indexLineCodeForRevision in linesForRevision) { var lineCode = bodyFileForRevision.ElementAt(indexLineCodeForRevision - 1); totalValueMetric += metricsCalculator.CalculateMetrics(lineCode); } } catch { } double realCodeSize = linesForRevision == null ? 0 : totalValueMetric; if (existentCode.CodeSize > realCodeSize) { codeBlockExpressions.Add( expression.Code(realCodeSize - existentCode.CodeSize) ); codeBlockExpressions.Last().ForCodeAddedInitiallyInRevision(existentCode.Revision); } } } } return(codeBlockExpressions); }
public void Should_map_all_code_as_is_for_copied_file() { mappingDSL .AddCommit("a") .AddFile("file1").Modified() .Code(10) .Submit() .AddCommit("ab") .File("file1").Modified() .Code(5) .Submit(); blameStub = new BlameStub(); for (int i = 1; i <= 10; i++) { blameStub[i] = "a"; } for (int i = 11; i <= 15; i++) { blameStub[i] = "ab"; } scmData.Stub(x => x.Blame("abc", "file2")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .AddFile("file2").CopiedFrom("file1", "ab").Modified() ); SubmitChanges(); var code = Queryable<CodeBlock>() .Where(cb => cb.Modification.Commit.Revision == "abc"); code.Select(cb => cb.Size).ToArray() .Should().Have.SameValuesAs(new double[] { 10, 5 }); code.Select(cb => cb.AddedInitiallyInCommit.Revision).ToArray() .Should().Have.SameValuesAs(new string[] { "a", "ab" }); }
public void Should_remove_code_that_no_more_exists() { mappingDSL .AddCommit("a") .AddFile("file1").Modified() .Code(10) .Submit() .AddCommit("ab") .File("file1").Modified() .Code(20) .Submit(); blameStub = new BlameStub(); for (int i = 1; i <= 10; i++) { blameStub[i] = "abc"; } for (int i = 11; i <= 25; i++) { blameStub[i] = "ab"; } scmData.Stub(x => x.Blame("abc", "file1")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .File("file1").Modified() ); SubmitChanges(); var code = Queryable<CodeBlock>() .Where(cb => cb.Modification.Commit.Revision == "abc"); code.Select(cb => cb.Size).ToArray() .Should().Have.SameValuesAs(new double[] { 10, -10, -5 }); code.Where(cb => cb.Size < 0) .Select(cb => cb.TargetCodeBlock.Size).ToArray() .Should().Have.SameValuesAs(new double[] { 10, 20 }); }
public void Should_map_new_code_in_copied_file_as_new() { mappingDSL .AddCommit("a") .AddFile("file1").Modified() .Code(10) .Submit(); blameStub = new BlameStub(); for (int i = 1; i <= 10; i++) { blameStub[i] = "a"; } for (int i = 11; i <= 15; i++) { blameStub[i] = "abc"; } scmData.Stub(x => x.Blame("abc", "file2")) .Return(blameStub); mapper.Map( mappingDSL.AddCommit("abc") .AddFile("file2").CopiedFrom("file1", "a").Modified() ); SubmitChanges(); var code = Queryable<CodeBlock>() .Single(cb => cb.Size == 5) .AddedInitiallyInCommit.Revision .Should().Be("abc"); }
private bool CheckLinesContent(IRepository repository, IScmData scmData, string testRevision, ProjectFile file, bool resultOnly) { IBlame fileBlame = null; try { fileBlame = scmData.Blame(testRevision, file.Path); } catch { } if (fileBlame == null) { if (!resultOnly) { Console.WriteLine("File {0} does not exist.", file.Path); } return(false); } double currentLOC = repository.SelectionDSL() .Commits().TillRevision(testRevision) .Files().IdIs(file.ID) .Modifications().InCommits().InFiles() .CodeBlocks().InModifications() .CalculateLOC(); bool correct = currentLOC == fileBlame.Count; if (!correct) { if (!resultOnly) { Console.WriteLine("Incorrect number of lines in file {0}. {1} should be {2}", file.Path, currentLOC, fileBlame.Count ); } else { return(false); } } SmartDictionary <string, int> linesByRevision = new SmartDictionary <string, int>(x => 0); foreach (var line in fileBlame) { linesByRevision[line.Value]++; } var codeBySourceRevision = ( from f in repository.Queryable <ProjectFile>() join m in repository.Queryable <Modification>() on f.ID equals m.FileID join cb in repository.Queryable <CodeBlock>() on m.ID equals cb.ModificationID join c in repository.Queryable <Commit>() on m.CommitID equals c.ID let addedCodeBlock = repository.Queryable <CodeBlock>() .Single(x => x.ID == (cb.Size < 0 ? cb.TargetCodeBlockID : cb.ID)) let codeAddedInitiallyInRevision = repository.Queryable <Commit>() .Single(x => x.ID == addedCodeBlock.AddedInitiallyInCommitID) .Revision let testRevisionNumber = repository.Queryable <Commit>() .Single(x => x.Revision == testRevision) .OrderedNumber where f.ID == file.ID && c.OrderedNumber <= testRevisionNumber group cb.Size by codeAddedInitiallyInRevision into g select new { FromRevision = g.Key, CodeSize = g.Sum() } ).Where(x => x.CodeSize != 0).ToList(); var errorCode = ( from codeFromRevision in codeBySourceRevision where codeFromRevision.CodeSize != linesByRevision[codeFromRevision.FromRevision] select new { SourceRevision = codeFromRevision.FromRevision, CodeSize = codeFromRevision.CodeSize, RealCodeSize = linesByRevision[codeFromRevision.FromRevision] } ).ToList(); correct = correct && codeBySourceRevision.Count() == linesByRevision.Count && errorCode.Count == 0; if (!resultOnly) { if (codeBySourceRevision.Count() != linesByRevision.Count) { Console.WriteLine("Number of revisions file {0} contains code from is incorrect. {1} should be {2}", file.Path, codeBySourceRevision.Count(), linesByRevision.Count ); } foreach (var error in errorCode) { Console.WriteLine("Incorrect number of lines in file {0} from revision {1}. {2} should be {3}", file.Path, error.SourceRevision, error.CodeSize, error.RealCodeSize ); } if ((!correct) && (errorCode.Count > 0)) { string latestCodeRevision = repository.LastRevision(errorCode.Select(x => x.SourceRevision)); var commitsFileTouchedIn = repository.SelectionDSL() .Files().IdIs(file.ID) .Commits().FromRevision(latestCodeRevision).TouchFiles() .OrderBy(c => c.OrderedNumber); foreach (var commit in commitsFileTouchedIn) { if (!CheckLinesContent(repository, scmData, commit.Revision, file, true)) { Console.WriteLine("{0} - incorrectly mapped commit.", commit.Revision); if ((automaticallyFixDiffErrors) && (errorCode.Sum(x => x.CodeSize - x.RealCodeSize) == 0)) { var incorrectDeleteCodeBlocks = from cb in repository.SelectionDSL() .Commits().RevisionIs(commit.Revision) .Files().PathIs(file.Path) .Modifications().InCommits().InFiles() .CodeBlocks().InModifications().Deleted() join tcb in repository.Queryable <CodeBlock>() on cb.TargetCodeBlockID equals tcb.ID join m in repository.Queryable <Modification>() on tcb.ModificationID equals m.ID join c in repository.Queryable <Commit>() on m.CommitID equals c.ID where errorCode.Select(x => x.SourceRevision).Contains(c.Revision) select new { Code = cb, TargetRevision = c.Revision }; foreach (var error in errorCode) { var incorrectDeleteCodeBlock = incorrectDeleteCodeBlocks.SingleOrDefault(x => x.TargetRevision == error.SourceRevision); var codeBlock = incorrectDeleteCodeBlock == null ? null : incorrectDeleteCodeBlock.Code; double difference = error.CodeSize - error.RealCodeSize; if (codeBlock == null) { codeBlock = new CodeBlock() { Size = 0, Modification = repository.SelectionDSL() .Commits().RevisionIs(commit.Revision) .Files().PathIs(file.Path) .Modifications().InCommits().InFiles().Single(), }; repository.Add(codeBlock); } Console.WriteLine("Fix code block size for file {0} in revision {1}:", file.Path, commit.Revision); Console.Write("Was {0}", codeBlock.Size); codeBlock.Size -= difference; if (codeBlock.Size == 0) { repository.Delete(codeBlock); } else if ((codeBlock.Size > 0) && (codeBlock.AddedInitiallyInCommitID == null)) { codeBlock.AddedInitiallyInCommit = commit; } else if ((codeBlock.Size < 0) && (codeBlock.TargetCodeBlockID == null)) { codeBlock.TargetCodeBlock = repository.SelectionDSL() .Commits().RevisionIs(error.SourceRevision) .Files().PathIs(file.Path) .Modifications().InFiles() .CodeBlocks().InModifications().AddedInitiallyInCommits().Single(); } Console.WriteLine(", now {0}", codeBlock.Size); } } break; } } } } return(correct); }
public override IEnumerable <CodeBlockMappingExpression> Map(ModificationMappingExpression expression) { List <CodeBlockMappingExpression> codeBlockExpressions = new List <CodeBlockMappingExpression>(); string revision = expression.CurrentEntity <Commit>().Revision; ProjectFile file = expression.CurrentEntity <ProjectFile>(); bool fileIsNew = (file.AddedInCommit != null) && (file.AddedInCommit.Revision == revision); bool fileCopied = fileIsNew && (file.SourceFile != null); bool fileDeleted = file.DeletedInCommit != null; if (fileDeleted) { codeBlockExpressions.Add( expression.DeleteCode() ); } else { IBlame blame = scmData.Blame(revision, file.Path); var linesByRevision = from l in blame group l.Key by l.Value; if (fileCopied) { foreach (var linesForRevision in linesByRevision) { codeBlockExpressions.Add( expression.Code(linesForRevision.Count()) ); if (linesForRevision.Key != revision) { codeBlockExpressions.Last().CopiedFrom(linesForRevision.Key); } } } else { var addedCode = linesByRevision.SingleOrDefault(x => x.Key == revision); if (addedCode != null) { /////////////////////////////////////////////////// int linesNumber = addedCode.Count(); int[] lines = new int [linesNumber]; for (int i = 0; i < linesNumber; i++) { lines[i] = addedCode.ElementAt(i); } string hashTree = scmData.CatFile_Commit(revision); string[] parts = file.Path.Split('/'); int partsNumber = parts.Count(); for (int i = 1; i < partsNumber; i++) { hashTree = scmData.CatFile_Tree(hashTree, parts[i]); } string hashBlob = hashTree; int commentLinesNumber = scmData.CatFile_Blob(hashBlob, lines, linesNumber); /////////////////////////////////////////////////// codeBlockExpressions.Add( expression.Code(linesNumber - commentLinesNumber) //кол-во строк минус кол-во строк с комментариями ); } foreach (var existentCode in ( from cb in expression.Queryable <CodeBlock>() join m in expression.Queryable <Modification>() on cb.ModificationID equals m.ID join f in expression.Queryable <ProjectFile>() on m.FileID equals f.ID join c in expression.Queryable <Commit>() on m.CommitID equals c.ID let addedCodeID = cb.Size < 0 ? cb.TargetCodeBlockID : cb.ID let addedCodeRevision = expression.Queryable <Commit>() .Single(x => x.ID == expression.Queryable <CodeBlock>() .Single(y => y.ID == addedCodeID).AddedInitiallyInCommitID ).Revision where f.ID == file.ID group cb.Size by addedCodeRevision into g select new { Revision = g.Key, CodeSize = g.Sum() } )) { var linesForRevision = linesByRevision.SingleOrDefault(x => x.Key == existentCode.Revision); double realCodeSize = linesForRevision == null ? 0 : linesForRevision.Count(); /////////////////////////////////////////////////// if (linesForRevision != null) { int linesNumber = linesForRevision.Count(); int[] lines = new int[linesNumber]; for (int i = 0; i < linesNumber; i++) { lines[i] = linesForRevision.ElementAt(i); } string hashTree = scmData.CatFile_Commit(existentCode.Revision); string[] parts = file.Path.Split('/'); int partsNumber = parts.Count(); for (int i = 1; i < partsNumber; i++) { hashTree = scmData.CatFile_Tree(hashTree, parts[i]); } string hashBlob = hashTree; if (!String.IsNullOrEmpty(hashBlob)) { int commentLinesNumber = scmData.CatFile_Blob(hashBlob, lines, linesNumber); realCodeSize -= commentLinesNumber; } } /////////////////////////////////////////////////// if (existentCode.CodeSize > realCodeSize) { codeBlockExpressions.Add( expression.Code(realCodeSize - existentCode.CodeSize) ); codeBlockExpressions.Last().ForCodeAddedInitiallyInRevision(existentCode.Revision); } } } } return(codeBlockExpressions); }