< Summary

Class:Mklinker.Commands.ScanCommand
Assembly:Mklinker
File(s):/home/travis/build/rubenchristoffer/Mklinker/Mklinker/Commands/ScanCommand.cs
Covered lines:62
Uncovered lines:36
Coverable lines:98
Total lines:156
Line coverage:63.2% (62 of 98)
Covered branches:27
Total branches:36
Branch coverage:75% (27 of 36)

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
.ctor()100%100%
.ctor(...)10100%100%
Execute(...)60100%100%
ScanRecursive(...)16023.8%43.75%
CountDirectoryWords(...)140100%100%

File(s)

/home/travis/build/rubenchristoffer/Mklinker/Mklinker/Commands/ScanCommand.cs

#LineLine coverage
 1using System.Linq;
 2using CommandLine;
 3using System.IO.Abstractions;
 4using Mklinker.Abstractions;
 5using System.Collections.Generic;
 6using System.IO;
 7using System;
 8using System.Text;
 9using System.Runtime.CompilerServices;
 10
 11namespace Mklinker.Commands {
 12
 13    [Verb("scan", HelpText = "Detect if circular paths (loops) exist for a given root folder by scanning all directories
 14    class ScanCommand {
 15
 016        private List<string> cases = new List<string>();
 017        private bool error = false;
 18
 19        [Value (0, Default = ".", HelpText = "The root folder that should be scanned. Default will scan current working 
 1920        public string rootFolder { get; private set; }
 21
 22        [Option('l', "limit", Default = 30, HelpText = "Maximum amount of subfolders used for detecting loop (recursion 
 2123        public int recursionLimit { get; private set; }
 24
 25        [Option('v', "verbose", Default = false, HelpText = "Will display detailed output including every path that has 
 526        public bool verbose { get; private set; }
 27
 28        [Option('i', "ignore", Default = false, HelpText = "Will ignore folders Mklinker does not have access to and con
 029        public bool ignoreUnauthorizedFolders { get; private set; }
 30
 031        public ScanCommand () {}
 32
 833        public ScanCommand (string rootFolder, int recursionLimit, bool verbose, bool ignoreUnauthorizedFolders) {
 434            this.rootFolder = rootFolder;
 435            this.recursionLimit = recursionLimit;
 436            this.verbose = verbose;
 437            this.ignoreUnauthorizedFolders = ignoreUnauthorizedFolders;
 438        }
 39
 440        internal void Execute (IConsole console, IFileSystem fileSystem, IPathResolver pathResolver) {
 541            if (!fileSystem.Directory.Exists(rootFolder)) {
 142                console.WriteLine ($"Root folder '{rootFolder}' does not exist", IConsole.ContentType.Negative);
 143                return;
 44            }
 45
 346            console.WriteLine ($"### Running recursion limit test (limit = {recursionLimit}) ###", IConsole.ContentType.
 347            ScanRecursive (console, fileSystem, pathResolver, rootFolder, rootFolder, 0);
 48
 649            if (!error) {
 550                if (cases.Count == 0) {
 251                    console.WriteLine ("No loops found!", IConsole.ContentType.Positive);
 352                } else {
 153                    console.WriteLine ("Possible loops found!", IConsole.ContentType.Negative);
 154                    console.WriteLine ();
 55
 156                    console.WriteLine ($"### Collecting word count for directory names ###", IConsole.ContentType.Header
 157                    CountDirectoryWords (console);
 158                }
 359            }
 460        }
 61
 1662        internal void ScanRecursive (IConsole console, IFileSystem fileSystem, IPathResolver pathResolver, string rootFo
 1663            if (error)
 064                return;
 65
 1666            try {
 67                // Try to find loops by using a recursion limit
 9068                foreach (string directory in fileSystem.Directory.GetDirectories (currentFolder)) {
 1569                    if (recursionLevel >= recursionLimit) {
 070                        if (verbose) {
 071                            console.WriteLine (directory);
 072                            console.WriteLine ();
 073                        }
 74
 175                        cases.Add (directory.Replace ('\\', '/'));
 76
 177                        continue;
 78                    }
 79
 1380                    ScanRecursive (console, fileSystem, pathResolver, rootFolder, directory, recursionLevel + 1);
 1381                }
 082            } catch(IOException e) {
 83                // Most common error is when recursion liimt is too high
 084                console.WriteLine ("An error has occured!", IConsole.ContentType.Negative);
 085                console.WriteLine ($"Perhaps recursion limit ({recursionLimit}) is set too high?", IConsole.ContentType.
 086                console.WriteLine ($"Try setting recursion limit to {recursionLevel - 1} or lower", IConsole.ContentType
 87
 088                if (verbose) {
 089                    console.WriteLine ();
 090                    console.WriteLine (e.ToString(), IConsole.ContentType.Negative);
 091                }
 92
 093                cases.Clear ();
 094                error = true;
 095            } catch (UnauthorizedAccessException e) {
 096                if (ignoreUnauthorizedFolders) {
 097                    if (verbose) {
 098                        console.WriteLine ("Ignoring folder Mklinker does not have access to");
 099                    }
 0100                } else {
 0101                    console.WriteLine ("An error has occured!", IConsole.ContentType.Negative);
 0102                    console.WriteLine ("Mklinker does not have access to a directory", IConsole.ContentType.Negative);
 0103                    console.WriteLine ("Try again with admin privileges or run with --ignore flag", IConsole.ContentType
 104
 0105                    if (verbose) {
 0106                        console.WriteLine ();
 0107                        console.WriteLine (e.ToString (), IConsole.ContentType.Negative);
 0108                    }
 109
 0110                    cases.Clear ();
 0111                    error = true;
 0112                }
 0113            }
 16114        }
 115
 1116        internal void CountDirectoryWords (IConsole console) {
 1117            Dictionary<string, int> wordCount = new Dictionary<string, int> ();
 1118            Dictionary<string, List<string>> wordAndPaths = new Dictionary<string, List<string>> ();
 119
 120            // Count how often directory words occur in the paths
 121            // Directory names that appear often have a higher chance
 122            // of being the cause of the loop or near the cause of the loop
 5123            for (int i = 0; i < cases.Count; i++) {
 1124                string @case = cases[i];
 1125                string[] pathDirectories = @case.Split ('/');
 126
 26127                for (int ii = 0; ii < pathDirectories.Length; ii++) {
 8128                    string word = pathDirectories[ii];
 129
 12130                    if (wordCount.ContainsKey (word)) {
 4131                        wordCount[word]++;
 12132                    } else if (!word.Equals(rootFolder)) {
 4133                        wordCount.Add (word, 1);
 4134                    }
 8135                }
 1136            }
 137
 138            // Write all word counts at the end
 1139            var wordCollection = wordCount
 5140                .OrderByDescending(wc => wc.Value)
 5141                .Select (wc => $"{wc.Key} ({wc.Value})");
 142
 1143            console.WriteLine ($"Directory name(s) ordered by word count:");
 1144            console.Write ("| ");
 145
 15146            foreach (string word in wordCollection) {
 4147                console.Write (word, IConsole.ContentType.Negative);
 4148                console.Write (" | ");
 4149            }
 150
 1151            console.WriteLine ();
 1152        }
 153
 154    }
 155
 156}