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"
                );
        }
Пример #2
0
        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"
                     );
        }
Пример #3
0
        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");
        }
Пример #4
0
        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);
        }
Пример #5
0
        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));
        }
Пример #6
0
        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
            });
        }
Пример #7
0
        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"
            });
        }
Пример #8
0
        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");
        }
Пример #12
0
        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);
        }