From ddea77a806f3d9360178824935b7133f0b802310 Mon Sep 17 00:00:00 2001 From: Adam Ralph Date: Sun, 12 May 2013 14:19:47 +0200 Subject: [PATCH 001/993] #137 added guard clauses installed LiteGuard.Source package into ScriptCs.Core only and linked from other projects created ScriptCs.ruleset based on MS recommended rules and added CA1062: Validate arguments of public methods --- ScriptCs.sln | 1 + build/ScriptCs.ruleset | 68 +++++++++++++ .../ScriptCs.Contracts.csproj | 1 + src/ScriptCs.Core/Guard.cs | 98 +++++++++++++++++++ .../NugetInstallationProvider.cs | 4 + src/ScriptCs.Core/Package/PackageContainer.cs | 2 + src/ScriptCs.Core/PreProcessorUtil.cs | 8 ++ src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs.Core/ScriptPackManager.cs | 2 + src/ScriptCs.Core/packages.config | 2 + .../RoslynScriptDebuggerEngine.cs | 2 + .../RoslynScriptEngine.cs | 4 + .../ScriptCs.Engine.Roslyn.csproj | 4 + src/ScriptCs/Command/CommandFactory.cs | 2 + src/ScriptCs/CompositionRoot.cs | 2 + src/ScriptCs/ScriptCs.csproj | 4 + 16 files changed, 206 insertions(+) create mode 100644 build/ScriptCs.ruleset create mode 100644 src/ScriptCs.Core/Guard.cs diff --git a/ScriptCs.sln b/ScriptCs.sln index 24acd26f..79d00af5 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -25,6 +25,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{9659F354 build\Build.proj = build\Build.proj build\Build.tasks = build\Build.tasks build\ScriptCs.Common.props = build\ScriptCs.Common.props + build\ScriptCs.ruleset = build\ScriptCs.ruleset build\ScriptCs.Version.props = build\ScriptCs.Version.props EndProjectSection EndProject diff --git a/build/ScriptCs.ruleset b/build/ScriptCs.ruleset new file mode 100644 index 00000000..ee4724e6 --- /dev/null +++ b/build/ScriptCs.ruleset @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 94e645aa..3f667d25 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -7,6 +7,7 @@ ScriptCs.Contracts ScriptCs.Contracts ..\..\ + ..\..\build\ScriptCs.ruleset diff --git a/src/ScriptCs.Core/Guard.cs b/src/ScriptCs.Core/Guard.cs new file mode 100644 index 00000000..c4076255 --- /dev/null +++ b/src/ScriptCs.Core/Guard.cs @@ -0,0 +1,98 @@ +namespace ScriptCs +{ + using System; + using System.Diagnostics; + using System.Globalization; + + /// + /// Provides guard clauses. + /// + internal static class Guard + { + /// + /// Guards against a null argument. + /// + /// The type of the argument. + /// Name of the parameter. + /// The argument. + /// is null. + /// is restricted to reference types to avoid boxing of value type objects. + [DebuggerStepThrough] + public static void AgainstNullArgument(string parameterName, [ValidatedNotNull]TArgument argument) where TArgument : class + { + if (argument == null) + { + throw new ArgumentNullException(parameterName, string.Format(CultureInfo.InvariantCulture, "{0} is null.", parameterName)); + } + } + + /// + /// Guards against a null argument if can be null. + /// + /// The type of the argument. + /// Name of the parameter. + /// The argument. + /// is null. + /// + /// Performs a type check to avoid boxing of value type objects. + /// + [DebuggerStepThrough] + public static void AgainstNullArgumentIfNullable(string parameterName, [ValidatedNotNull]TArgument argument) + { + if (typeof(TArgument).IsNullableType() && argument == null) + { + throw new ArgumentNullException(parameterName, string.Format(CultureInfo.InvariantCulture, "{0} is null.", parameterName)); + } + } + + /// + /// Guards against a null argument property value. + /// + /// The type of the property. + /// Name of the parameter. + /// Name of the property. + /// The argument property. + /// is null. + /// is restricted to reference types to avoid boxing of value type objects. + [DebuggerStepThrough] + public static void AgainstNullArgumentProperty(string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) + where TProperty : class + { + if (argumentProperty == null) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "{0}.{1} is null.", parameterName, propertyName), parameterName); + } + } + + /// + /// Guards against a null argument property value if can be null. + /// + /// The type of the property. + /// Name of the parameter. + /// Name of the property. + /// The argument property. + /// is null. + /// + /// Performs a type check to avoid boxing of value type objects. + /// + [DebuggerStepThrough] + public static void AgainstNullArgumentPropertyIfNullable( + string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) + { + if (typeof(TProperty).IsNullableType() && argumentProperty == null) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "{0}.{1} is null.", parameterName, propertyName), parameterName); + } + } + + private static bool IsNullableType(this Type type) + { + return !type.IsValueType || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + + // NOTE: when applied to a parameter, this attribute provides an indication to code analysis that the argument has been null checked + private sealed class ValidatedNotNullAttribute : Attribute + { + } + } +} diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 804276a5..44d0c5ac 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -14,6 +14,8 @@ public class NugetInstallationProvider : IInstallationProvider public NugetInstallationProvider(IFileSystem fileSystem) { + Guard.AgainstNullArgument("fileSystem", fileSystem); + _fileSystem = fileSystem; var path = Path.Combine(fileSystem.CurrentDirectory, Constants.PackagesFolder); _repositoryUrls = GetRepositorySources(path); @@ -47,6 +49,8 @@ public IEnumerable GetRepositorySources(string path) public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null) { + Guard.AgainstNullArgument("packageId", packageId); + var useVersion = packageId.Version.CompareTo(new Version()) != 0; try { diff --git a/src/ScriptCs.Core/Package/PackageContainer.cs b/src/ScriptCs.Core/Package/PackageContainer.cs index 6954fbd7..802153af 100644 --- a/src/ScriptCs.Core/Package/PackageContainer.cs +++ b/src/ScriptCs.Core/Package/PackageContainer.cs @@ -47,6 +47,8 @@ public IEnumerable CreatePackageFile() public IPackageObject FindPackage(string path, IPackageReference packageRef) { + Guard.AgainstNullArgument("packageRef", packageRef); + var repository = new LocalPackageRepository(path); var package = packageRef.Version != null diff --git a/src/ScriptCs.Core/PreProcessorUtil.cs b/src/ScriptCs.Core/PreProcessorUtil.cs index d9ad5016..a155cf05 100644 --- a/src/ScriptCs.Core/PreProcessorUtil.cs +++ b/src/ScriptCs.Core/PreProcessorUtil.cs @@ -13,21 +13,29 @@ public static bool IsNonDirectiveLine(string line) public static bool IsUsingLine(string line) { + Guard.AgainstNullArgument("line", line); + return line.TrimStart(' ').StartsWith(UsingString) && !line.Contains("{") && line.Contains(";"); } public static bool IsRLine(string line) { + Guard.AgainstNullArgument("line", line); + return line.TrimStart(' ').StartsWith(RString); } public static bool IsLoadLine(string line) { + Guard.AgainstNullArgument("line", line); + return line.TrimStart(' ').StartsWith(LoadString); } public static string GetPath(string replaceString, string line) { + Guard.AgainstNullArgument("line", line); + var filepath = line.Trim(' ').Replace(replaceString, string.Empty).Replace("\"", string.Empty).Replace(";", string.Empty); return filepath; } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index adf91081..e6a0aa08 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -7,6 +7,7 @@ ScriptCs ScriptCs.Core ..\..\ + ..\..\build\ScriptCs.ruleset @@ -49,6 +50,7 @@ + diff --git a/src/ScriptCs.Core/ScriptPackManager.cs b/src/ScriptCs.Core/ScriptPackManager.cs index 6f4c6ad9..9015751a 100644 --- a/src/ScriptCs.Core/ScriptPackManager.cs +++ b/src/ScriptCs.Core/ScriptPackManager.cs @@ -10,6 +10,8 @@ public class ScriptPackManager : IScriptPackManager public ScriptPackManager(IEnumerable contexts) { + Guard.AgainstNullArgument("contexts", contexts); + foreach (var context in contexts) { _contexts.Add(context.GetType(), context); diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 9e7aca92..953a2ce5 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -3,5 +3,7 @@ + + \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index 51fdff79..f1043270 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -22,6 +22,8 @@ public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog log protected override object Execute(string code, Session session) { + Guard.AgainstNullArgument("session", session); + _logger.Debug("Compiling submission"); var submission = session.CompileSubmission(code); var exeBytes = new byte[0]; diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index a3d0b4fd..50036033 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -30,6 +30,8 @@ public string BaseDirectory public object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { + Guard.AgainstNullArgument("scriptPackSession", scriptPackSession); + _logger.Info("Starting to create execution components"); _logger.Debug("Creating script host"); @@ -82,6 +84,8 @@ public object Execute(string code, IEnumerable references, IEnumerableScriptCs.Engine.Roslyn ScriptCs.Engine.Roslyn ..\..\ + ..\..\build\ScriptCs.ruleset @@ -33,6 +34,9 @@ Properties\CommonVersionInfo.cs + + Guard.cs + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 83e9afc4..644f2256 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -13,6 +13,8 @@ public CommandFactory(ScriptServiceRoot scriptServiceRoot) public ICommand CreateCommand(ScriptCsArgs args) { + Guard.AgainstNullArgument("args", args); + if (args.Help) { return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: true); diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index e327b61d..cb244732 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -20,6 +20,8 @@ public class CompositionRoot public CompositionRoot(ScriptCsArgs args) { + Guard.AgainstNullArgument("args", args); + _debug = args.Debug; _logLevel = args.LogLevel; _shouldInitDrirectoryCatalog = ShouldInitDrirectoryCatalog(args); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index e2249072..47286cee 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -7,6 +7,7 @@ ScriptCs scriptcs ..\..\ + ..\..\build\ScriptCs.ruleset ..\..\common\Icon.ico @@ -57,6 +58,9 @@ Properties\CommonVersionInfo.cs + + Guard.cs + From 1a65856fb7e3aabd8859f9a27eb5aa326bc0b24f Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 13 May 2013 17:41:44 -0300 Subject: [PATCH 002/993] Bump the version to v0.5.0-alpha --- build/ScriptCs.Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 7dae5744..81cd5a30 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -4,12 +4,12 @@ 0 - 4 + 5 0 - + alpha From 3fed85bdb04c15c01580082896d92cf99f3e32ef Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 13 May 2013 17:55:44 -0400 Subject: [PATCH 003/993] Respect the allowPreRelease flag even if no version is provided --- .../Package/InstallationProvider/NugetInstallationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 44d0c5ac..930554b7 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -62,7 +62,7 @@ public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = f } else { - _manager.InstallPackage(packageId.PackageId); + _manager.InstallPackage(packageId.PackageId, null, false, allowPreRelease); } if (packageInstalled != null) From 1fa1b849bcf8cb832fb5a92ab6e35e560b60d63b Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 14 May 2013 10:55:55 +0200 Subject: [PATCH 004/993] Refactored FilePreProcessor to remove #r directives and return them in result --- src/ScriptCs.Core/FilePreProcessor.cs | 201 +++++++++++------- src/ScriptCs.Core/FilePreProcessorResult.cs | 22 ++ src/ScriptCs.Core/IFilePreProcessor.cs | 2 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptExecutor.cs | 19 +- src/ScriptCs/Repl.cs | 17 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 109 ++++------ .../ScriptExecutorTests.cs | 30 +-- test/ScriptCs.Tests/ReplTests.cs | 3 + 9 files changed, 225 insertions(+), 179 deletions(-) create mode 100644 src/ScriptCs.Core/FilePreProcessorResult.cs diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 1a7763d2..54496f35 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -1,5 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text; + using Common.Logging; namespace ScriptCs @@ -7,8 +11,8 @@ namespace ScriptCs public class FilePreProcessor : IFilePreProcessor { private readonly ILog _logger; - - protected readonly IFileSystem _fileSystem; + + private readonly IFileSystem _fileSystem; public FilePreProcessor(IFileSystem fileSystem, ILog logger) { @@ -16,106 +20,145 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) _logger = logger; } - public string ProcessFile(string path) + public FilePreProcessorResult ProcessFile(string path) { - _logger.DebugFormat("{0} - Reading lines", path); - var entryFile = _fileSystem.ReadFileLines(path); - var usings = new List(); - var rs = new List(); - var loads = new List(); - - _logger.DebugFormat("{0} - Parsing ", path); - var parsed = ParseFile(path, entryFile, ref usings, ref rs, ref loads); - - _logger.DebugFormat("{0} - Generating references (#r)", path); - var result = GenerateRs(rs); - if (!string.IsNullOrWhiteSpace(result)) - { - result += _fileSystem.NewLine; - } + var context = new FilePreProcessContext(); - _logger.DebugFormat("{0} - Generating using statements", path); - result += GenerateUsings(usings); - if (!string.IsNullOrWhiteSpace(result)) - { - result += _fileSystem.NewLine; - } + _logger.DebugFormat("Starting pre-processing"); + + ParseFile(path, context); + + var code = GenerateScript(context); - result += parsed; + _logger.DebugFormat("Pre-processing finished successfully"); - return result; + return new FilePreProcessorResult + { + Usings = context.Usings, + LoadedFiles = context.LoadedScripts, + References = context.References, + Code = code + }; } - protected virtual string GenerateUsings(ICollection usingLines) + private static string GenerateScript(FilePreProcessContext context) { - return string.Join(_fileSystem.NewLine, usingLines.Distinct()); + var stringBuilder = new StringBuilder(); + + AppendUsings(stringBuilder, context.Usings); + + stringBuilder.Append(string.Join(Environment.NewLine, context.Body)); + + return stringBuilder.ToString(); } - protected virtual string GenerateRs(ICollection rLines) + private static void AppendUsings(StringBuilder stringBuilder, IEnumerable items) { - return string.Join(_fileSystem.NewLine, rLines.Distinct()); + var lines = items.Distinct().Select(item => string.Format("using {0};", item)).ToList(); + + if (lines.Count == 0) return; + + stringBuilder.AppendLine(string.Join(Environment.NewLine, lines)); + stringBuilder.AppendLine(); // Insert a blank separator line } - private string ParseFile(string path, IEnumerable file, ref List usings, ref List rs, ref List loads) + private void ParseFile(string path, FilePreProcessContext context) { - var fileList = file.ToList(); - var firstCode = fileList.FindIndex(l => PreProcessorUtil.IsNonDirectiveLine(l)); - - var firstBody = fileList.FindIndex(l => PreProcessorUtil.IsNonDirectiveLine(l) && !PreProcessorUtil.IsUsingLine(l)); - - // add #line before the actual code begins - // +1 because we are in a zero indexed list, but line numbers are 1 indexed - // we need to keep the original position of the actual line - if (firstBody != -1) - { - _logger.DebugFormat("Added #line statement for file {0} at line {1}", path, firstBody); - fileList.Insert(firstBody, string.Format(@"#line {0} ""{1}""", firstBody + 1, path)); + _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); + + var fileLines = _fileSystem.ReadFileLines(path).ToList(); + + InsertLineDirective(path, fileLines); + + var codeIndex = fileLines.FindIndex(PreProcessorUtil.IsNonDirectiveLine); + + for (var index = 0; index < fileLines.Count; index++) + { + ProcessLine(context, fileLines[index], index < codeIndex || codeIndex < 0); } - - for (var i = 0; i < fileList.Count; i++) + + context.LoadedScripts.Add(path); + } + + private static void InsertLineDirective(string path, List fileLines) + { + var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); + if (bodyIndex == -1) return; + + var directiveLine = string.Format("#line {0} \"{1}\"", bodyIndex + 1, path); + fileLines.Insert(bodyIndex, directiveLine); + } + + private void ProcessLine(FilePreProcessContext context, string line, bool isBeforeCode) + { + if (PreProcessorUtil.IsUsingLine(line)) { - var line = fileList[i]; - if (PreProcessorUtil.IsUsingLine(line)) + var @using = GetUsing(line); + if (!context.Usings.Contains(@using)) { - usings.Add(line); + context.Usings.Add(@using); } - else if (PreProcessorUtil.IsRLine(line)) + + return; + } + + if (PreProcessorUtil.IsRLine(line)) + { + if (isBeforeCode) { - if (i < firstCode) - { - rs.Add(line); - } - else + var reference = GetReference(line); + if (!context.References.Contains(reference)) { - fileList[i] = string.Empty; + context.References.Add(reference); } - } - else if (PreProcessorUtil.IsLoadLine(line)) + } + + return; + } + + if (PreProcessorUtil.IsLoadLine(line)) + { + var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); + + if (isBeforeCode && !context.LoadedScripts.Contains(filePath)) { - if ((i < firstCode || firstCode < 0) && !loads.Contains(line)) - { - var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - var filecontent = _fileSystem.IsPathRooted(filepath) - ? _fileSystem.ReadFileLines(filepath) - : _fileSystem.ReadFileLines(_fileSystem.CurrentDirectory + @"\" + filepath); - - if (filecontent != null) - { - loads.Add(line); - _logger.DebugFormat("Parsing file {0}", path); - var parsed = ParseFile(filepath, filecontent, ref usings, ref rs, ref loads); - fileList[i] = parsed; - } - } - else - { - fileList[i] = string.Empty; - } + ParseFile(filePath, context); } + + return; } - var result = string.Join(_fileSystem.NewLine, fileList.Where(line => !PreProcessorUtil.IsUsingLine(line) && !PreProcessorUtil.IsRLine(line))); - return result; + // If we've reached this, the line is part of the body... + context.Body.Add(line); + } + + private static string GetUsing(string line) + { + return line.TrimStart(' ').Replace(PreProcessorUtil.UsingString, string.Empty).Replace(";", string.Empty); + } + + private static string GetReference(string line) + { + return line.TrimStart(' ').Replace(PreProcessorUtil.RString, string.Empty).Replace("\"", string.Empty); + } + + private class FilePreProcessContext + { + public FilePreProcessContext() + { + Usings = new List(); + References = new List(); + LoadedScripts = new List(); + Body = new List(); + } + + public List Usings { get; private set; } + + public List References { get; private set; } + + public List LoadedScripts { get; private set; } + + public List Body { get; private set; } } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/FilePreProcessorResult.cs b/src/ScriptCs.Core/FilePreProcessorResult.cs new file mode 100644 index 00000000..7b46f9c9 --- /dev/null +++ b/src/ScriptCs.Core/FilePreProcessorResult.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class FilePreProcessorResult + { + public FilePreProcessorResult() + { + Usings = new List(); + LoadedFiles = new List(); + References = new List(); + } + + public List Usings { get; set; } + + public List LoadedFiles { get; set; } + + public List References { get; set; } + + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IFilePreProcessor.cs b/src/ScriptCs.Core/IFilePreProcessor.cs index 1929da65..b136cc24 100644 --- a/src/ScriptCs.Core/IFilePreProcessor.cs +++ b/src/ScriptCs.Core/IFilePreProcessor.cs @@ -2,6 +2,6 @@ { public interface IFilePreProcessor { - string ProcessFile(string path); + FilePreProcessorResult ProcessFile(string path); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index e6a0aa08..416e6c8d 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -49,6 +49,7 @@ Properties\CommonVersionInfo.cs + diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index c4a15e4d..e6e675fc 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -8,14 +8,14 @@ namespace ScriptCs { public class ScriptExecutor : IScriptExecutor { - private static readonly string[] DefaultReferences = new[] {"System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq"}; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks"}; + private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; private readonly IScriptEngine _scriptEngine; private readonly ILog _logger; - + public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { _fileSystem = fileSystem; @@ -27,23 +27,22 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) { var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); - - var references = DefaultReferences.Union(paths); _scriptEngine.BaseDirectory = bin; _logger.Debug("Initializing script packs"); var scriptPackSession = new ScriptPackSession(scriptPacks); - + scriptPackSession.InitializePacks(); var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - - _logger.DebugFormat("File to process: {0}", path); - var code = _filePreProcessor.ProcessFile(path); + + var result = _filePreProcessor.ProcessFile(path); + + var references = DefaultReferences.Union(paths).Union(result.References); _logger.Debug("Starting execution in engine"); - _scriptEngine.Execute(code, references, DefaultNamespaces, scriptPackSession); + _scriptEngine.Execute(result.Code, references, DefaultNamespaces, scriptPackSession); _logger.Debug("Terminating packs"); scriptPackSession.TerminatePacks(); diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 10aa99cf..d360e2ea 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -8,18 +8,18 @@ namespace ScriptCs { - public class Repl + public class Repl { public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } - public IFilePreProcessor FilePreProcessor { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } public ILog Logger { get; private set; } - public IConsole Console { get; private set; } + public IConsole Console { get; private set; } public ScriptPackSession ScriptPackSession { get; private set; } - public IEnumerable References { get; private set; } + public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) { @@ -60,7 +60,8 @@ public void Execute(string script) if (PreProcessorUtil.IsLoadLine(script)) { var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, script); - script = FilePreProcessor.ProcessFile(filepath); + var processorResult = FilePreProcessor.ProcessFile(filepath); + script = processorResult.Code; } else if (PreProcessorUtil.IsRLine(script)) { @@ -74,9 +75,7 @@ public void Execute(string script) if (result != null) { Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv() - - ); + Console.WriteLine(result.ToJsv()); } } catch (Exception ex) @@ -87,4 +86,4 @@ public void Execute(string script) Console.ForegroundColor = foregroundColor; } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index aad6ca55..52b65e44 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -59,13 +59,13 @@ public ProcessFileMethod() { _fileSystem = new Mock(); _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))) .Returns(_file1.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script2.csx"))) .Returns(_file2.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script3.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script3.csx"))) .Returns(_file3.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script4.csx"))) .Returns(_file4.ToArray()); _logger = new Mock(); @@ -75,11 +75,11 @@ public ProcessFileMethod() public void MultipleUsingStatementsShouldProduceDistinctOutput() { var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); + var result = processor.ProcessFile("script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("\\script"))), Times.Exactly(3)); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i.StartsWith("script"))), Times.Exactly(3)); Assert.Equal(2, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); } @@ -87,9 +87,9 @@ public void MultipleUsingStatementsShouldProduceDistinctOutput() public void UsingStateMentsShoulAllBeAtTheTop() { var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); + var result = processor.ProcessFile("script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); @@ -100,12 +100,12 @@ public void UsingStateMentsShoulAllBeAtTheTop() public void ShouldNotLoadInlineLoads() { var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - processor.ProcessFile("\\script1.csx"); + processor.ProcessFile("script1.csx"); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Once()); } [Fact] @@ -120,18 +120,18 @@ public void ShouldNotLoadSameFileTwice() var fs = new Mock(); fs.Setup(i => i.NewLine).Returns(Environment.NewLine); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))) + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "script2.csx"))) .Returns(file.ToArray()); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script4.csx"))) + fs.Setup(x => x.ReadFileLines(It.Is(f => f == "script4.csx"))) .Returns(_file4.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - processor.ProcessFile("\\script1.csx"); + processor.ProcessFile("script1.csx"); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script1.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script2.csx")), Times.Once()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script4.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script1.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script2.csx")), Times.Once()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Once()); } [Fact] @@ -145,12 +145,12 @@ public void LoadBeforeUsingShouldBeAllowed() @"Console.WriteLine(""abc"");" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "file.csx"))).Returns(file.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\file.csx"); + var result = processor.ProcessFile("file.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var lastUsing = splitOutput.ToList().FindLastIndex(x => x.TrimStart(' ').StartsWith("using ")); var firsNotUsing = splitOutput.ToList().FindIndex(x => !x.TrimStart(' ').StartsWith("using ")); @@ -167,17 +167,18 @@ public void ShouldNotBeAllowedToLoadAfterUsing() @"Console.WriteLine(""abc"");", @"#load ""script4.csx""" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "file.csx"))).Returns(file.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\file.csx"); + var result = processor.ProcessFile("file.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); Assert.Equal(1, splitOutput.Count(x => x.TrimStart(' ').StartsWith("using "))); // consider #line directive Assert.Equal(4, splitOutput.Length); - _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "\\script3.csx")), Times.Never()); + _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Never()); } [Fact] @@ -194,12 +195,12 @@ public void UsingInCodeDoesNotCountAsUsingImport() @"//do stuff", @"}" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\file.csx"))).Returns(file.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "file.csx"))).Returns(file.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\file.csx"); + var result = processor.ProcessFile("file.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); + var splitOutput = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var firstNonImportUsing = splitOutput.ToList().FindIndex(x => x.TrimStart(' ').StartsWith("using ") && !x.Contains(";")); var firstCodeLine = splitOutput.ToList().FindIndex(x => x.Contains("Console")); @@ -207,33 +208,6 @@ public void UsingInCodeDoesNotCountAsUsingImport() Assert.True(firstNonImportUsing > firstCodeLine); } - [Fact] - public void ShouldHaveReferencesOnTop() - { - var file1 = new List - { - @"#r ""My.dll""", - @"#load ""script2.csx""", - "using System;", - @"Console.WriteLine(""Hi!"");" - }; - - var fs = new Mock(); - fs.Setup(i => i.NewLine).Returns(Environment.NewLine); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))).Returns(file1.ToArray()); - fs.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script2.csx"))).Returns(_file2.ToArray()); - - var processor = new FilePreProcessor(fs.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None).ToList(); - - var lastR = splitOutput.FindLastIndex(line => line.StartsWith("#r ")); - var firstNotR = splitOutput.FindIndex(line => !line.StartsWith("#r ")); - - lastR.ShouldNotEqual(-1); - Assert.True(lastR < firstNotR); - } - [Fact] public void ShouldHaveReferencesFromAllFiles() { @@ -252,16 +226,15 @@ public void ShouldHaveReferencesFromAllFiles() @"Console.WriteLine(""Hi!"");" }; - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\script1.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))) .Returns(file1.ToArray()); - _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "\\scriptX.csx"))) + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "scriptX.csx"))) .Returns(file2.ToArray()); var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var output = processor.ProcessFile("\\script1.csx"); + var result = processor.ProcessFile("script1.csx"); - var splitOutput = output.Split(new[] {Environment.NewLine}, StringSplitOptions.None); - splitOutput.Count(line => line.StartsWith("#r ")).ShouldEqual(2); + result.References.Count.ShouldEqual(2); } [Fact] @@ -321,15 +294,17 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() var preProcessor = new FilePreProcessor(_fileSystem.Object, _logger.Object); - var file = preProcessor.ProcessFile(@"C:\f1.csx"); - - var fileLines = file.Split(new[]{ Environment.NewLine }, StringSplitOptions.None); + var result = preProcessor.ProcessFile(@"C:\f1.csx"); + + var fileLines = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); // using statements go first, after that f4 -> f5 -> f2 -> f3 -> f1 var line = 0; fileLines[line++].ShouldEqual("using System;"); fileLines[line++].ShouldEqual("using System.Diagnostics;"); + line++; // Skip blank separator line between usings and body... + fileLines[line++].ShouldEqual(@"#line 1 ""C:\f4.csx"""); fileLines[line++].ShouldEqual(f4[0]); @@ -347,4 +322,4 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() } } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index e303c23d..19bd6806 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -46,7 +46,7 @@ public void ConstructsAbsolutePathBeforePreProcessingFile() fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); @@ -62,7 +62,7 @@ public void DoNotChangePathIfAbsolute() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); @@ -76,6 +76,8 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() // arrange var scriptEngine = new Mock(); var fileSystem = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); @@ -83,7 +85,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() scriptEngine.SetupProperty(e => e.BaseDirectory); - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); var scriptName = "script.csx"; var paths = new string[0]; @@ -120,7 +122,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var paths = new string[0]; var recipes = Enumerable.Empty(); - preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(code).Verifiable(); + preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(new FilePreProcessorResult { Code = code }).Verifiable(); scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); // act @@ -130,18 +132,20 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); - + } [Fact] public void ShouldAddReferenceToEachDestinationFile() { // arrange - var defaultReferences = new[] {"System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq"}; + var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; var fileSystem = new Mock(); var scriptEngine = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); - var scriptExecutor = CreateScriptExecutor(fileSystem: fileSystem, scriptEngine: scriptEngine); + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); var currentDirectory = @"C:\"; var destinationFilePath1 = Path.Combine(currentDirectory, @"bin\fileName1.cs"); @@ -175,7 +179,7 @@ public void ShouldInitializeScriptPacks() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); @@ -196,7 +200,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); @@ -213,18 +217,18 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { - var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks"}; + var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var engine = new Mock(); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine:engine); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); @@ -241,7 +245,7 @@ public void ExecutorShouldPassDefaultReferencesToEngine() fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns("var a = 0;"); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var engine = new Mock(); diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 248040dd..5f5dd495 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -175,6 +175,9 @@ public void ShouldProcessFileIfLineIsALoad() public void ShouldExecuteLoadedFileIfLineIsALoad() { var mocks = new Mocks(); + mocks.FilePreProcessor.Setup(x => x.ProcessFile(It.IsAny())) + .Returns(new FilePreProcessorResult()); + _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); From 3e72bd8d996cd5fc1615833ee174499869d5d65f Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 15 May 2013 16:57:25 +0200 Subject: [PATCH 005/993] Replaced methods with PreProcessorUtil methods. Added tests --- src/ScriptCs.Core/FilePreProcessor.cs | 26 +++--- src/ScriptCs.Core/FilePreProcessorResult.cs | 4 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 79 +++++++++++++++++++ 3 files changed, 90 insertions(+), 19 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 54496f35..db03bacd 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -35,7 +35,7 @@ public FilePreProcessorResult ProcessFile(string path) return new FilePreProcessorResult { Usings = context.Usings, - LoadedFiles = context.LoadedScripts, + LoadedScripts = context.LoadedScripts, References = context.References, Code = code }; @@ -93,7 +93,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo { if (PreProcessorUtil.IsUsingLine(line)) { - var @using = GetUsing(line); + var @using = PreProcessorUtil.GetPath(PreProcessorUtil.UsingString, line); if (!context.Usings.Contains(@using)) { context.Usings.Add(@using); @@ -106,7 +106,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo { if (isBeforeCode) { - var reference = GetReference(line); + var reference = PreProcessorUtil.GetPath(PreProcessorUtil.RString, line); if (!context.References.Contains(reference)) { context.References.Add(reference); @@ -118,11 +118,13 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo if (PreProcessorUtil.IsLoadLine(line)) { - var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - - if (isBeforeCode && !context.LoadedScripts.Contains(filePath)) + if (isBeforeCode) { - ParseFile(filePath, context); + var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); + if (!context.LoadedScripts.Contains(filePath)) + { + ParseFile(filePath, context); + } } return; @@ -132,16 +134,6 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo context.Body.Add(line); } - private static string GetUsing(string line) - { - return line.TrimStart(' ').Replace(PreProcessorUtil.UsingString, string.Empty).Replace(";", string.Empty); - } - - private static string GetReference(string line) - { - return line.TrimStart(' ').Replace(PreProcessorUtil.RString, string.Empty).Replace("\"", string.Empty); - } - private class FilePreProcessContext { public FilePreProcessContext() diff --git a/src/ScriptCs.Core/FilePreProcessorResult.cs b/src/ScriptCs.Core/FilePreProcessorResult.cs index 7b46f9c9..94c27ee9 100644 --- a/src/ScriptCs.Core/FilePreProcessorResult.cs +++ b/src/ScriptCs.Core/FilePreProcessorResult.cs @@ -7,13 +7,13 @@ public class FilePreProcessorResult public FilePreProcessorResult() { Usings = new List(); - LoadedFiles = new List(); + LoadedScripts = new List(); References = new List(); } public List Usings { get; set; } - public List LoadedFiles { get; set; } + public List LoadedScripts { get; set; } public List References { get; set; } diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 52b65e44..3fdd1d68 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -108,6 +108,85 @@ public void ShouldNotLoadInlineLoads() _fileSystem.Verify(x => x.ReadFileLines(It.Is(i => i == "script4.csx")), Times.Once()); } + [Fact] + public void ShouldReturnResultWithAllLoadedFiles() + { + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.LoadedScripts.Count.ShouldEqual(3); + result.LoadedScripts.ShouldContain("script1.csx"); + result.LoadedScripts.ShouldContain("script2.csx"); + result.LoadedScripts.ShouldContain("script4.csx"); + } + + [Fact] + public void ShouldReturnResultWithAllUsings() + { + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.Usings.Count.ShouldEqual(2); + result.Usings.ShouldContain("System"); + result.Usings.ShouldContain("System.Core"); + } + + [Fact] + public void ShouldReturnResultWithAllReferences() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""scriptX.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var file2 = new List + { + @"#r ""My2.dll""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))).Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "scriptX.csx"))).Returns(file2.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.References.Count.ShouldEqual(2); + result.References.ShouldContain("My.dll"); + result.References.ShouldContain("My2.dll"); + } + + [Fact] + public void ShouldNotIncludeReferencesInCode() + { + var file1 = new List + { + @"#r ""My.dll""", + @"#load ""scriptX.csx""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + var file2 = new List + { + @"#r ""My2.dll""", + "using System;", + @"Console.WriteLine(""Hi!"");" + }; + + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "script1.csx"))).Returns(file1.ToArray()); + _fileSystem.Setup(x => x.ReadFileLines(It.Is(f => f == "scriptX.csx"))).Returns(file2.ToArray()); + + var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); + var result = processor.ProcessFile("script1.csx"); + + result.Code.ShouldNotContain("#r"); + } + [Fact] public void ShouldNotLoadSameFileTwice() { From 542844a14c493c510339a3bf195597bd47d1dfe2 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Wed, 15 May 2013 18:30:08 +0200 Subject: [PATCH 006/993] Console colors are now properly reset when exiting the REPL. --- src/ScriptCs/IConsole.cs | 2 ++ src/ScriptCs/Repl.cs | 17 ++++++++-------- src/ScriptCs/ReplConsole.cs | 21 ++++++++++++++++++++ test/ScriptCs.Tests/ReplTests.cs | 34 +++++++++++++++++++------------- 4 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/ScriptCs/IConsole.cs b/src/ScriptCs/IConsole.cs index cde0a8b5..f7935d91 100644 --- a/src/ScriptCs/IConsole.cs +++ b/src/ScriptCs/IConsole.cs @@ -11,6 +11,8 @@ public interface IConsole void Write(string value); void WriteLine(string value); string ReadLine(); + void Exit(); + void ResetColor(); ConsoleColor ForegroundColor { get; set; } } } diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 10aa99cf..57dfc47b 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -8,18 +8,18 @@ namespace ScriptCs { - public class Repl + public class Repl { public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } - public IFilePreProcessor FilePreProcessor { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } public ILog Logger { get; private set; } - public IConsole Console { get; private set; } + public IConsole Console { get; private set; } public ScriptPackSession ScriptPackSession { get; private set; } - public IEnumerable References { get; private set; } + public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) { @@ -53,8 +53,6 @@ public void Terminate() public void Execute(string script) { - var foregroundColor = Console.ForegroundColor; - try { if (PreProcessorUtil.IsLoadLine(script)) @@ -75,7 +73,7 @@ public void Execute(string script) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(result.ToJsv() - + ); } } @@ -84,7 +82,10 @@ public void Execute(string script) Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + ex + "\r\n"); } - Console.ForegroundColor = foregroundColor; + finally + { + Console.ResetColor(); + } } } } diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ReplConsole.cs index 6100ce2b..a2eddbcb 100644 --- a/src/ScriptCs/ReplConsole.cs +++ b/src/ScriptCs/ReplConsole.cs @@ -4,6 +4,11 @@ namespace ScriptCs { public class ReplConsole : IConsole { + public ReplConsole() + { + Console.CancelKeyPress += HandleCancelKeyPress; + } + public void Write(string value) { Console.Write(value); @@ -19,6 +24,22 @@ public string ReadLine() return Console.ReadLine(); } + public void Exit() + { + ResetColor(); + Console.CancelKeyPress -= HandleCancelKeyPress; + } + + public void ResetColor() + { + Console.ResetColor(); + } + + private void HandleCancelKeyPress(object sender, ConsoleCancelEventArgs e) + { + ResetColor(); + } + public ConsoleColor ForegroundColor { get { return Console.ForegroundColor; } diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 248040dd..d434ee39 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -56,15 +56,15 @@ public class TheInitializeMethod { private Mocks _mocks; private Repl _repl; - + public TheInitializeMethod() { _mocks = new Mocks(); _repl = GetRepl(_mocks); _mocks.FileSystem.Setup(x => x.CurrentDirectory).Returns(@"c:\"); - var paths = new []{@"c:\path"}; - _repl.Initialize(paths, new[] {_mocks.ScriptPack.Object}); - } + var paths = new[] { @"c:\path" }; + _repl.Initialize(paths, new[] { _mocks.ScriptPack.Object }); + } [Fact] public void PopulatesReferences() @@ -79,7 +79,7 @@ public void PopulatesReferences() [Fact] public void SetsTheScriptEngineBaseDirectory() { - _mocks.ScriptEngine.VerifySet(x=>x.BaseDirectory = @"c:\bin"); + _mocks.ScriptEngine.VerifySet(x => x.BaseDirectory = @"c:\bin"); } [Fact] @@ -91,7 +91,7 @@ public void CreatesTheScriptPackSession() [Fact] public void InitializesScriptPacks() { - _mocks.ScriptPack.Verify(x=>x.Initialize(It.IsAny())); + _mocks.ScriptPack.Verify(x => x.Initialize(It.IsAny())); } } @@ -99,13 +99,13 @@ public class TheTerminateMethod { private Mocks _mocks; private Repl _repl; - + public TheTerminateMethod() { _mocks = new Mocks(); _repl = GetRepl(_mocks); _mocks.FileSystem.Setup(x => x.CurrentDirectory).Returns(@"c:\"); - _repl.Initialize(new List(), new[] {_mocks.ScriptPack.Object}); + _repl.Initialize(new List(), new[] { _mocks.ScriptPack.Object }); _repl.Terminate(); } @@ -120,7 +120,7 @@ public class TheExecuteMethod { private Mocks _mocks; private Repl _repl; - + public TheExecuteMethod() { _mocks = new Mocks(); @@ -132,13 +132,19 @@ public TheExecuteMethod() [Fact] public void SetsTheForegroundColorToCyan() { - _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.Cyan, Times.Once()); + _mocks.Console.VerifySet(x => x.ForegroundColor = ConsoleColor.Cyan, Times.Once()); + } + + [Fact] + public void ResetsColorAfterExecutingScript() + { + _mocks.Console.Verify(x => x.ResetColor()); } [Fact] public void CallsExecuteOnTheScriptEngine() { - _mocks.ScriptEngine.Verify(x=>x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); + _mocks.ScriptEngine.Verify(x => x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); } [Fact] @@ -154,11 +160,11 @@ public void CatchesExceptionsAndWritesThemInRed() _mocks.Console.Verify(x => x.WriteLine(It.IsAny())); } - + [Fact] public void SetsTheForegroundColorBackToTheDefault() { - _mocks.Console.VerifySet(x=>x.ForegroundColor = ConsoleColor.White); + _mocks.Console.VerifySet(x => x.ForegroundColor = ConsoleColor.White); } [Fact] @@ -167,7 +173,7 @@ public void ShouldProcessFileIfLineIsALoad() var mocks = new Mocks(); _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); - + mocks.FilePreProcessor.Verify(i => i.ProcessFile(It.Is(x => x == "file.csx")), Times.Once()); } From 9de9fe1986a837a1ea8c2783281c97031d478623 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 15 May 2013 14:16:20 -0400 Subject: [PATCH 007/993] ExecuteReplCommand should use the implementation of IConsole provided to the ctor --- src/ScriptCs/Command/ExecuteReplCommand.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 13cd792b..1d275620 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -37,7 +37,7 @@ IConsole console public CommandResult Execute() { - Console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); + _console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); repl.Initialize(GetAssemblyPaths(_fileSystem.CurrentDirectory), _scriptPackResolver.GetPacks()); try @@ -57,8 +57,8 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { - Console.Write("> "); - var line = Console.ReadLine(); + _console.Write("> "); + var line = _console.ReadLine(); if (line == "") return false; From 2cdc371871e4607311c8d73d132a9b6790927945 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 15 May 2013 14:18:44 -0400 Subject: [PATCH 008/993] Add test for ExecuteReplCommand.Execute --- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 84 +++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 2 files changed, 85 insertions(+) create mode 100644 test/ScriptCs.Tests/ExecuteReplCommandTests.cs diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs new file mode 100644 index 00000000..aca52296 --- /dev/null +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Text; +using Common.Logging; +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ExecuteReplCommandTests + { + public class TheExecuteMethod + { + [Fact] + public void ShouldPromptForInput() + { + var mockFileSystem = new Mock(); + mockFileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + + var builder = new StringBuilder(); + + var reader = new StringReader(Environment.NewLine); + var writer = new StringWriter(builder); + + var console = new FakeConsole(writer, reader); + + var root = new ScriptServiceRoot( + mockFileSystem.Object, + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + Mock.Of(), + console); + + var commandFactory = new CommandFactory(root); + + var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }); + + target.Execute(); + + Assert.True(builder.ToString().EndsWith("> ")); + Assert.Equal(1, console.ReadLineCounter); + } + } + + public class FakeConsole : IConsole + { + private readonly TextWriter writer; + private readonly TextReader reader; + + public FakeConsole(TextWriter textWriter, TextReader textReader) + { + writer = textWriter; + reader = textReader; + ReadLineCounter = 0; + } + + public ConsoleColor ForegroundColor { get; set; } + + public int ReadLineCounter { get; set; } + + public void Write(string value) + { + writer.Write(value); + } + + public void WriteLine(string value) + { + writer.WriteLine(value); + } + + public string ReadLine() + { + ReadLineCounter++; + return reader.ReadLine(); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index a7d14f0b..6b87c8ea 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -42,6 +42,7 @@ + From 4ad28cc680d3bc19c3e78ed9937db2ec0ff9aeea Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 15 May 2013 20:53:46 +0200 Subject: [PATCH 009/993] Added check for existing assembly/script in REPL. Fixes #264 --- src/ScriptCs/Repl.cs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 10aa99cf..bccd5512 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -60,12 +60,27 @@ public void Execute(string script) if (PreProcessorUtil.IsLoadLine(script)) { var filepath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, script); - script = FilePreProcessor.ProcessFile(filepath); + if (FileSystem.FileExists(filepath)) + { + script = FilePreProcessor.ProcessFile(filepath); + } + else + { + throw new FileNotFoundException(string.Format("Could not find script '{0}'", filepath), filepath); + } } else if (PreProcessorUtil.IsRLine(script)) { var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); - References = References.Union(new[] { assemblyPath }); + if (FileSystem.FileExists(assemblyPath)) + { + References = References.Union(new[] { assemblyPath }); + } + else + { + throw new FileNotFoundException(string.Format("Could not find assembly '{0}'", assemblyPath), assemblyPath); + } + return; } @@ -74,9 +89,7 @@ public void Execute(string script) if (result != null) { Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv() - - ); + Console.WriteLine(result.ToJsv()); } } catch (Exception ex) From d818a21433d8252b0a0d68765ffbaa93e2b4171c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Wed, 15 May 2013 21:13:32 +0200 Subject: [PATCH 010/993] Fixed failing tests and added two more --- test/ScriptCs.Tests/ReplTests.cs | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 248040dd..9e952683 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -165,6 +165,8 @@ public void SetsTheForegroundColorBackToTheDefault() public void ShouldProcessFileIfLineIsALoad() { var mocks = new Mocks(); + mocks.FileSystem.Setup(x => x.FileExists("file.csx")).Returns(true); + _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); @@ -175,17 +177,33 @@ public void ShouldProcessFileIfLineIsALoad() public void ShouldExecuteLoadedFileIfLineIsALoad() { var mocks = new Mocks(); + mocks.FileSystem.Setup(x => x.FileExists("file.csx")).Returns(true); + _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } + [Fact] + public void ShouldNotExecuteLoadedFileIfFileDoesNotExist() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(x => x.FileExists("file.csx")).Returns(false); + + _repl = GetRepl(mocks); + _repl.Execute("#load \"file.csx\""); + + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + } + [Fact] public void ShouldReferenceAssemblyIfLineIsAReference() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(true); + _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); @@ -194,6 +212,21 @@ public void ShouldReferenceAssemblyIfLineIsAReference() _repl.References.Count().ShouldEqual(7); } + [Fact] + public void ShouldNotReferenceAssemblyIfFileDoesNotExist() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(false); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + + //default references = 6 + _repl.References.Count().ShouldEqual(6); + } + [Fact] public void ShouldNotExecuteAnythingIfLineIsAReference() { From 5130901d51ea30a39d712b1dc25db6ad41cfc1f0 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 13 May 2013 21:05:00 +1000 Subject: [PATCH 011/993] Adding a filter for non-managed assemblies --- .../RoslynScriptEngine.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 50036033..ab65ce38 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,6 +4,7 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; +using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -35,7 +36,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -88,5 +89,20 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } + + protected bool IsManagedAssembly(string path) + { + if (!File.Exists(path)) return true; + + try + { + AssemblyName.GetAssemblyName(path); + } + catch (System.BadImageFormatException) + { + return false; + } + return true; + } } } \ No newline at end of file From fb78be84e5486765d84170fbaf481b3e4ac21b6e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 14 May 2013 10:42:44 +1000 Subject: [PATCH 012/993] Moving non-managed file detection into the IScriptCommand implementations --- .../RoslynScriptEngine.cs | 18 +----------------- src/ScriptCs/Command/ExecuteReplCommand.cs | 15 +++++++++++++++ src/ScriptCs/Command/ExecuteScriptCommand.cs | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ab65ce38..50036033 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,7 +4,6 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; -using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -36,7 +35,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -89,20 +88,5 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } - - protected bool IsManagedAssembly(string path) - { - if (!File.Exists(path)) return true; - - try - { - AssemblyName.GetAssemblyName(path); - } - catch (System.BadImageFormatException) - { - return false; - } - return true; - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 1d275620..7ace69db 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Common.Logging; +using System.Reflection; namespace ScriptCs.Command { @@ -77,6 +78,7 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .Where(IsManagedAssembly) .ToList(); foreach (var path in assemblyPaths.Select(Path.GetFileName)) @@ -86,5 +88,18 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) return assemblyPaths; } + + private bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } } } diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index ad217103..a94bc287 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using Common.Logging; +using System.Reflection; namespace ScriptCs.Command { @@ -60,6 +61,7 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) var assemblyPaths = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .Where(IsManagedAssembly) .ToList(); foreach (var path in assemblyPaths.Select(Path.GetFileName)) @@ -69,5 +71,18 @@ private IEnumerable GetAssemblyPaths(string workingDirectory) return assemblyPaths; } + + private bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } } } \ No newline at end of file From 1423f12f026b01aad3379dc62ae4f57c8b4b0c5b Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 12:27:55 +1000 Subject: [PATCH 013/993] Adding abstraction on the AssemblyName API --- src/ScriptCs.Core/IAssemblyName.cs | 13 +++++++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs/Command/CommandFactory.cs | 6 ++++-- src/ScriptCs/Command/ExecuteReplCommand.cs | 7 +++++-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 +++++-- src/ScriptCs/ScriptServiceRoot.cs | 3 +++ test/ScriptCs.Tests/CleanCommandTests.cs | 16 ++++++++++++---- test/ScriptCs.Tests/CommandFactoryTests.cs | 3 ++- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 7 +++++-- test/ScriptCs.Tests/InstallCommandTests.cs | 7 +++++-- test/ScriptCs.Tests/RestoreCommandTests.cs | 11 ++++++++--- test/ScriptCs.Tests/VersionCommandTests.cs | 4 +++- 12 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 src/ScriptCs.Core/IAssemblyName.cs diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs new file mode 100644 index 00000000..1ac11d4d --- /dev/null +++ b/src/ScriptCs.Core/IAssemblyName.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public interface IAssemblyName + { + string GetAssemblyName(string path); + } +} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index e6a0aa08..7d4a9152 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -51,6 +51,7 @@ + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 644f2256..d23cb199 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -24,7 +24,8 @@ public ICommand CreateCommand(ScriptCsArgs args) { var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console); + _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, + _scriptServiceRoot.AssemblyName); return replCommand; } @@ -35,7 +36,8 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Logger); + _scriptServiceRoot.Logger, + _scriptServiceRoot.AssemblyName); if (args.Restore) { diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 7ace69db..e62f767e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,6 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; private readonly IConsole _console; @@ -25,7 +26,8 @@ public ExecuteReplCommand( IScriptEngine scriptEngine, IFilePreProcessor filePreProcessor, ILog logger, - IConsole console + IConsole console, + IAssemblyName assemblyName ) { _fileSystem = fileSystem; @@ -34,6 +36,7 @@ IConsole console _filePreProcessor = filePreProcessor; _logger = logger; _console = console; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -93,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - AssemblyName.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index a94bc287..79155a19 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,6 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; @@ -20,13 +21,15 @@ public ExecuteScriptCommand(string script, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, - ILog logger) + ILog logger, + IAssemblyName assemblyName) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -76,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - AssemblyName.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index 40a83c99..ea00605a 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,6 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, + IAssemblyName assemblyName, IConsole console = null) { FileSystem = fileSystem; @@ -25,6 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; + AssemblyName = assemblyName; } public IFileSystem FileSystem { get; private set; } @@ -36,5 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } + public IAssemblyName AssemblyName { get; private set; } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 55e4b4ce..bbef0c4b 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,7 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -50,7 +52,9 @@ public void ShouldDeleteBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -76,7 +80,9 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -103,7 +109,9 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 961ea056..deb8f88a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,8 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 42d197ce..61c50a1e 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -31,7 +31,9 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -61,7 +63,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index e58dace8..0e4ed500 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,7 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -70,7 +71,9 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 947f11e7..b84aad8a 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,7 +25,9 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + const string CurrentDirectory = @"C:\"; @@ -65,7 +67,9 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + const string CurrentDirectory = @"C:\"; @@ -105,7 +109,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 29fb50e1..a0623df9 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,7 +42,9 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 7f4a5538a496e189e4952c611119eb8535eef4f4 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 13:36:01 +1000 Subject: [PATCH 014/993] Refactoring IAssemblyName to IAssembly Adding implementation for IAssembly interface and adding it to IoC --- src/ScriptCs.Core/Assembly.cs | 11 +++++++++++ src/ScriptCs.Core/IAssemblyName.cs | 11 +++-------- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs/Command/CommandFactory.cs | 4 ++-- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 ++++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 8 ++++---- src/ScriptCs/CompositionRoot.cs | 3 ++- src/ScriptCs/ScriptServiceRoot.cs | 6 +++--- test/ScriptCs.Tests/CleanCommandTests.cs | 16 ++++++++-------- test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/InstallCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 4 ++-- 14 files changed, 56 insertions(+), 48 deletions(-) create mode 100644 src/ScriptCs.Core/Assembly.cs diff --git a/src/ScriptCs.Core/Assembly.cs b/src/ScriptCs.Core/Assembly.cs new file mode 100644 index 00000000..a2b1ec6a --- /dev/null +++ b/src/ScriptCs.Core/Assembly.cs @@ -0,0 +1,11 @@ +using System.Reflection; +namespace ScriptCs +{ + public class Assembly : IAssembly + { + public AssemblyName GetAssemblyName(string path) + { + return AssemblyName.GetAssemblyName(path); + } + } +} diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs index 1ac11d4d..e4416371 100644 --- a/src/ScriptCs.Core/IAssemblyName.cs +++ b/src/ScriptCs.Core/IAssemblyName.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - +using System.Reflection; namespace ScriptCs { - public interface IAssemblyName + public interface IAssembly { - string GetAssemblyName(string path); + AssemblyName GetAssemblyName(string path); } } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 7d4a9152..494498f7 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -39,6 +39,7 @@ + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d23cb199..080cce7c 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,7 +25,7 @@ public ICommand CreateCommand(ScriptCsArgs args) var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.Assembly); return replCommand; } @@ -37,7 +37,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, _scriptServiceRoot.Logger, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.Assembly); if (args.Restore) { diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..bccaff98 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName + IAssembly assembly ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssemblyName assemblyName _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assemblyName = assemblyName; + _assembly = assembly; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 79155a19..e19c026b 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; @@ -22,14 +22,14 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssemblyName assemblyName) + IAssembly assembly) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; - _assemblyName = assemblyName; + _assembly = assembly; } public CommandResult Execute() @@ -79,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index cb244732..9ffea091 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -47,7 +47,8 @@ public void Initialize() typeof (ScriptPackResolver), typeof (NugetInstallationProvider), typeof (PackageInstaller), - typeof (ReplConsole) + typeof (ReplConsole), + typeof (Assembly) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index ea00605a..11b885b7 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssemblyName assemblyName, + IAssembly assembly, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - AssemblyName = assemblyName; + Assembly = assembly; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssemblyName AssemblyName { get; private set; } + public IAssembly Assembly { get; private set; } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index bbef0c4b..9db9f49b 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -52,8 +52,8 @@ public void ShouldDeleteBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -80,8 +80,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); @@ -109,8 +109,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index deb8f88a..fa1444f9 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 61c50a1e..07eeffd6 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -31,8 +31,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); @@ -63,8 +63,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 0e4ed500..e077bed9 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,8 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index b84aad8a..7aa7f6db 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,8 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -67,8 +67,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -109,8 +109,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index a0623df9..a5a357ea 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,8 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); From 8a3b94fc4d1e8f7c3df84623eafd1d23fc8d9a6e Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 13:47:22 +1000 Subject: [PATCH 015/993] Implementing a unit test for non-managed assemblies --- .../ExecuteScriptCommandTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 07eeffd6..173c5a2f 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -6,6 +6,8 @@ using ScriptCs.Contracts; using ScriptCs.Package; using Xunit; +using System; +using System.Linq; namespace ScriptCs.Tests { @@ -73,6 +75,45 @@ public void ShouldCreateMissingBinFolder() fs.Verify(x => x.CreateDirectory(binFolder), Times.Once()); } + + [Fact] + public void NonManagedAssembliesAreExcluded() + { + const string nonManaged = "non-managed.dll"; + + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { + "managed.dll", + nonManaged + }); + + var resolver = new Mock(); + var executor = new Mock(); + var engine = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var logger = new Mock(); + var filePreProcessor = new Mock(); + var assembly = new Mock(); + assembly.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + result.Execute(); + + executor.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + } } } } \ No newline at end of file From 53f1468a078196f13e50eee8a844432ef4d4a4bf Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Mon, 13 May 2013 21:05:00 +1000 Subject: [PATCH 016/993] Adding a filter for non-managed assemblies --- .../RoslynScriptEngine.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 50036033..ab65ce38 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,6 +4,7 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; +using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -35,7 +36,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -88,5 +89,20 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } + + protected bool IsManagedAssembly(string path) + { + if (!File.Exists(path)) return true; + + try + { + AssemblyName.GetAssemblyName(path); + } + catch (System.BadImageFormatException) + { + return false; + } + return true; + } } } \ No newline at end of file From 2e872bfd45fbb3da0f58eee1d95f79c4ac7e3908 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Tue, 14 May 2013 10:42:44 +1000 Subject: [PATCH 017/993] Moving non-managed file detection into the IScriptCommand implementations --- .../RoslynScriptEngine.cs | 18 +----------------- src/ScriptCs/Command/ExecuteScriptCommand.cs | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index ab65ce38..50036033 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -4,7 +4,6 @@ using Common.Logging; using Roslyn.Scripting; using Roslyn.Scripting.CSharp; -using System.IO; namespace ScriptCs.Engine.Roslyn { @@ -36,7 +35,7 @@ public object Execute(string code, IEnumerable references, IEnumerable sessionState; if (!scriptPackSession.State.ContainsKey(SessionKey)) @@ -89,20 +88,5 @@ protected virtual object Execute(string code, Session session) return session.Execute(code); } - - protected bool IsManagedAssembly(string path) - { - if (!File.Exists(path)) return true; - - try - { - AssemblyName.GetAssemblyName(path); - } - catch (System.BadImageFormatException) - { - return false; - } - return true; - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index e19c026b..acfb7b28 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -88,4 +88,4 @@ private bool IsManagedAssembly(string path) return true; } } -} \ No newline at end of file +} From 8f8ff161acad85c0f5ba383f31e9599cbf7f13be Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 12:27:55 +1000 Subject: [PATCH 018/993] Adding abstraction on the AssemblyName API --- src/ScriptCs/Command/CommandFactory.cs | 3 +-- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 +++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 +++---- src/ScriptCs/ScriptServiceRoot.cs | 8 +++---- test/ScriptCs.Tests/CleanCommandTests.cs | 21 ++++++++----------- test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- .../ExecuteScriptCommandTests.cs | 11 +++++----- test/ScriptCs.Tests/InstallCommandTests.cs | 11 +++++----- test/ScriptCs.Tests/RestoreCommandTests.cs | 16 +++++++------- test/ScriptCs.Tests/VersionCommandTests.cs | 7 +++---- 10 files changed, 43 insertions(+), 53 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 080cce7c..11c4e2e0 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -36,7 +36,6 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Logger, _scriptServiceRoot.Assembly); if (args.Restore) @@ -107,4 +106,4 @@ public ICommand CreateCommand(ScriptCsArgs args) return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); } } -} \ No newline at end of file +} diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index bccaff98..e62f767e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssembly assembly + IAssemblyName assemblyName ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssembly assembly _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assembly = assembly; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index acfb7b28..dab313b9 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; @@ -22,14 +22,13 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssembly assembly) + IAssemblyName assemblyName) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; - _assembly = assembly; } public CommandResult Execute() @@ -79,7 +78,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index 11b885b7..cc32788a 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssembly assembly, + IAssemblyName assemblyName, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - Assembly = assembly; + AssemblyName = assemblyName; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssembly Assembly { get; private set; } + public IAssemblyName AssemblyName { get; private set; } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 9db9f49b..54387b06 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -52,9 +52,8 @@ public void ShouldDeleteBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -80,9 +79,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -109,9 +107,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -127,4 +124,4 @@ public void ShouldDeleteAllFilesResolvedFromPackages() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index fa1444f9..deb8f88a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 173c5a2f..263de398 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -33,9 +33,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -65,8 +64,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -116,4 +115,4 @@ public void NonManagedAssembliesAreExcluded() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index e077bed9..921d29ad 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,9 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { @@ -90,4 +89,4 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index 7aa7f6db..ed5e3cfd 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,9 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -67,9 +66,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -109,8 +107,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; @@ -132,4 +130,4 @@ public void ShouldCreateBinFolderIfItDoesNotExist() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index a5a357ea..e00cf1a4 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,9 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); - + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -58,4 +57,4 @@ public void VersionCommandShouldOutputVersion() } } } -} \ No newline at end of file +} From fd663bdd0a4343e6f1e81b3995086cc9440b7cd8 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Wed, 15 May 2013 13:36:01 +1000 Subject: [PATCH 019/993] Refactoring IAssemblyName to IAssembly Adding implementation for IAssembly interface and adding it to IoC --- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 ++++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 ++++--- src/ScriptCs/ScriptServiceRoot.cs | 6 +++--- test/ScriptCs.Tests/CleanCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/InstallCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 4 ++-- 9 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..bccaff98 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName + IAssembly assembly ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssemblyName assemblyName _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assemblyName = assemblyName; + _assembly = assembly; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index dab313b9..acfb7b28 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssemblyName _assemblyName; + private readonly IAssembly _assembly; private readonly ILog _logger; @@ -22,13 +22,14 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssemblyName assemblyName) + IAssembly assembly) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; + _assembly = assembly; } public CommandResult Execute() @@ -78,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - _assemblyName.GetAssemblyName(path); + _assembly.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index cc32788a..b16b059e 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssemblyName assemblyName, + IAssembly assembly, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - AssemblyName = assemblyName; + Assembly = assembly; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssemblyName AssemblyName { get; private set; } + public IAssembly Assembly { get; private set; } } } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 54387b06..d06f617a 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -79,8 +79,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -107,8 +107,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index deb8f88a..fa1444f9 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 263de398..c5510095 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -33,8 +33,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -64,8 +64,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 921d29ad..bd840e28 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,8 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index ed5e3cfd..af9385f8 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,8 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -66,8 +66,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; @@ -107,8 +107,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index e00cf1a4..e50770fb 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,8 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assembly = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 6aa6340271e75a02f9f344bc751b143b12b4b537 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 16 May 2013 12:53:08 +1000 Subject: [PATCH 020/993] Reverting from IAssembly to IAssemblyName --- src/ScriptCs.Core/Assembly.cs | 11 ----------- src/ScriptCs.Core/AssemblyName.cs | 10 ++++++++++ src/ScriptCs.Core/IAssemblyName.cs | 7 +++---- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 +- src/ScriptCs/Command/CommandFactory.cs | 4 ++-- src/ScriptCs/Command/ExecuteReplCommand.cs | 8 ++++---- src/ScriptCs/Command/ExecuteScriptCommand.cs | 8 ++++---- src/ScriptCs/CompositionRoot.cs | 2 +- src/ScriptCs/ScriptServiceRoot.cs | 6 +++--- test/ScriptCs.Tests/CleanCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/CommandFactoryTests.cs | 4 ++-- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 14 +++++++------- test/ScriptCs.Tests/InstallCommandTests.cs | 8 ++++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 12 ++++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 4 ++-- 15 files changed, 55 insertions(+), 57 deletions(-) delete mode 100644 src/ScriptCs.Core/Assembly.cs create mode 100644 src/ScriptCs.Core/AssemblyName.cs diff --git a/src/ScriptCs.Core/Assembly.cs b/src/ScriptCs.Core/Assembly.cs deleted file mode 100644 index a2b1ec6a..00000000 --- a/src/ScriptCs.Core/Assembly.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; -namespace ScriptCs -{ - public class Assembly : IAssembly - { - public AssemblyName GetAssemblyName(string path) - { - return AssemblyName.GetAssemblyName(path); - } - } -} diff --git a/src/ScriptCs.Core/AssemblyName.cs b/src/ScriptCs.Core/AssemblyName.cs new file mode 100644 index 00000000..ffaea2b5 --- /dev/null +++ b/src/ScriptCs.Core/AssemblyName.cs @@ -0,0 +1,10 @@ +namespace ScriptCs +{ + public class AssemblyName : IAssemblyName + { + public System.Reflection.AssemblyName GetAssemblyName(string path) + { + return System.Reflection.AssemblyName.GetAssemblyName(path); + } + } +} diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs index e4416371..3d2d9dd8 100644 --- a/src/ScriptCs.Core/IAssemblyName.cs +++ b/src/ScriptCs.Core/IAssemblyName.cs @@ -1,8 +1,7 @@ -using System.Reflection; -namespace ScriptCs +namespace ScriptCs { - public interface IAssembly + public interface IAssemblyName { - AssemblyName GetAssemblyName(string path); + System.Reflection.AssemblyName GetAssemblyName(string path); } } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 494498f7..706ab230 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -39,7 +39,7 @@ - + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 11c4e2e0..a2de5da0 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,7 +25,7 @@ public ICommand CreateCommand(ScriptCsArgs args) var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, - _scriptServiceRoot.Assembly); + _scriptServiceRoot.AssemblyName); return replCommand; } @@ -36,7 +36,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Assembly); + _scriptServiceRoot.AssemblyName); if (args.Restore) { diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index bccaff98..e62f767e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -15,7 +15,7 @@ internal class ExecuteReplCommand : IScriptCommand private readonly IScriptPackResolver _scriptPackResolver; private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; private readonly IConsole _console; @@ -27,7 +27,7 @@ public ExecuteReplCommand( IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssembly assembly + IAssemblyName assemblyName ) { _fileSystem = fileSystem; @@ -36,7 +36,7 @@ IAssembly assembly _filePreProcessor = filePreProcessor; _logger = logger; _console = console; - _assembly = assembly; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -96,7 +96,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index acfb7b28..e60e2ad2 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -13,7 +13,7 @@ internal class ExecuteScriptCommand : IScriptCommand private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssembly _assembly; + private readonly IAssemblyName _assemblyName; private readonly ILog _logger; @@ -22,14 +22,14 @@ public ExecuteScriptCommand(string script, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, ILog logger, - IAssembly assembly) + IAssemblyName assemblyName) { _script = script; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; _logger = logger; - _assembly = assembly; + _assemblyName = assemblyName; } public CommandResult Execute() @@ -79,7 +79,7 @@ private bool IsManagedAssembly(string path) { try { - _assembly.GetAssemblyName(path); + _assemblyName.GetAssemblyName(path); } catch (BadImageFormatException) { diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 9ffea091..94d36a7f 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -48,7 +48,7 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (Assembly) + typeof (AssemblyName) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index b16b059e..cc32788a 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -14,7 +14,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssembly assembly, + IAssemblyName assemblyName, IConsole console = null) { FileSystem = fileSystem; @@ -26,7 +26,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - Assembly = assembly; + AssemblyName = assemblyName; } public IFileSystem FileSystem { get; private set; } @@ -38,6 +38,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssembly Assembly { get; private set; } + public IAssemblyName AssemblyName { get; private set; } } } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index d06f617a..54387b06 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -24,9 +24,9 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); @@ -79,8 +79,8 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); @@ -107,8 +107,8 @@ public void ShouldDeleteAllFilesResolvedFromPackages() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index fa1444f9..deb8f88a 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -27,9 +27,9 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); + var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c5510095..60bead91 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -33,8 +33,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -64,8 +64,8 @@ public void ShouldCreateMissingBinFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -100,10 +100,10 @@ public void NonManagedAssembliesAreExcluded() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - assembly.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + var assemblyName = new Mock(); + assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index bd840e28..921d29ad 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,8 +37,8 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); @@ -71,8 +71,8 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index af9385f8..ed5e3cfd 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -25,8 +25,8 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -66,8 +66,8 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; @@ -107,8 +107,8 @@ public void ShouldCreateBinFolderIfItDoesNotExist() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); const string CurrentDirectory = @"C:\"; const string BinFolder = @"C:\bin"; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index e50770fb..e00cf1a4 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,8 +42,8 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assembly = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assembly.Object); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args); From 83fbb5925c54f158895777999a65dc5ab46ee173 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 16 May 2013 13:28:49 +1000 Subject: [PATCH 021/993] Some fixes from a bad rebase --- common/CommonVersionInfo.cs | 21 +++++++++++++------ src/ScriptCs/Command/CommandFactory.cs | 1 + .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 590a13eb..270505b9 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,9 +1,18 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18033 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; using System.Reflection; -/** - * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the - * contents of 'build\ScriptCs.Version.props'. - **/ +[assembly: System.Reflection.AssemblyVersionAttribute("0.5.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.5.0-alpha")] + +// Generated by the MSBuild WriteCodeFragment class on 16/05/2013 1:24:46 PM. -[assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index a2de5da0..7e676bae 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -36,6 +36,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, + _scriptServiceRoot.Logger, _scriptServiceRoot.AssemblyName); if (args.Restore) diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index 9dc8d1b7..d98de537 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -35,6 +35,7 @@ public void ShouldPromptForInput() Mock.Of(), Mock.Of(), Mock.Of(), + Mock.Of(), console); var commandFactory = new CommandFactory(root); From 47d6b432bc15ac878cd975b2ae19805bdff2c7cc Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Thu, 16 May 2013 14:17:21 +0200 Subject: [PATCH 022/993] Added missing method call to IConsole.Exit(). --- src/ScriptCs/Repl.cs | 2 ++ test/ScriptCs.Tests/ReplTests.cs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index d54775de..7f47494d 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -49,6 +49,8 @@ public void Terminate() { Logger.Debug("Terminating packs"); ScriptPackSession.TerminatePacks(); + Logger.Debug("Exiting console"); + Console.Exit(); } public void Execute(string script) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 71729348..1fc45011 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -114,6 +114,12 @@ public void TerminatesScriptPacks() { _mocks.ScriptPack.Verify(x => x.Terminate()); } + + [Fact] + public void ExitsTheConsole() + { + _mocks.Console.Verify(x => x.Exit()); + } } public class TheExecuteMethod From e3fb3679cd11d800a809d0003f1bc0e50dfe0408 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 16 May 2013 22:56:13 -0400 Subject: [PATCH 023/993] added System.IO --- src/ScriptCs.Core/ScriptExecutor.cs | 2 +- src/ScriptCs/Repl.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index e6e675fc..14641fff 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -9,7 +9,7 @@ namespace ScriptCs public class ScriptExecutor : IScriptExecutor { private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; private readonly IFileSystem _fileSystem; private readonly IFilePreProcessor _filePreProcessor; diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs/Repl.cs index 1db41eb6..c6cdfa90 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs/Repl.cs @@ -11,7 +11,7 @@ namespace ScriptCs public class Repl { public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; public IFileSystem FileSystem { get; private set; } public IScriptEngine ScriptEngine { get; private set; } From b9795942cbdbe6789d0c735ee49cf9829ebd56e7 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 16 May 2013 22:57:29 -0400 Subject: [PATCH 024/993] fixed namespaces in the test --- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 19bd6806..0224b23e 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -217,7 +217,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { - var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks" }; + var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); From 17226998202c8413dd2a5bcf81e0d2537027553c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 18 May 2013 19:08:14 +0200 Subject: [PATCH 025/993] Added overload for processing in-memory script. Fixes #246. --- src/ScriptCs.Core/FilePreProcessor.cs | 75 +++++++++++-------- src/ScriptCs.Core/FilePreProcessorResult.cs | 4 +- src/ScriptCs.Core/FileSystem.cs | 5 ++ src/ScriptCs.Core/IFilePreProcessor.cs | 6 +- src/ScriptCs.Core/IFileSystem.cs | 2 + .../ScriptCs.Core.Tests/FileProcessorTests.cs | 6 +- 6 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index db03bacd..136362d9 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -22,59 +22,74 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) public FilePreProcessorResult ProcessFile(string path) { - var context = new FilePreProcessContext(); + return Parse(context => ParseFile(path, context)); + } + + public FilePreProcessorResult ProcessScript(string script) + { + var scriptLines = _fileSystem.SplitLines(script).ToList(); + return Parse(context => ParseScript(scriptLines, context)); + } + + private FilePreProcessorResult Parse(Action parseAction) + { + var context = new FilePreProcessorContext(); _logger.DebugFormat("Starting pre-processing"); - ParseFile(path, context); + parseAction(context); - var code = GenerateScript(context); + var code = GenerateCode(context); _logger.DebugFormat("Pre-processing finished successfully"); return new FilePreProcessorResult { - Usings = context.Usings, + UsingStatements = context.UsingStatements, LoadedScripts = context.LoadedScripts, References = context.References, Code = code }; } - private static string GenerateScript(FilePreProcessContext context) + private static string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); - AppendUsings(stringBuilder, context.Usings); + var usingLines = context.UsingStatements + .Select(item => string.Format("using {0};", item)) + .ToList(); + + if (usingLines.Count > 0) + { + stringBuilder.AppendLine(string.Join(Environment.NewLine, usingLines)); + stringBuilder.AppendLine(); // Insert a blank separator line + } stringBuilder.Append(string.Join(Environment.NewLine, context.Body)); return stringBuilder.ToString(); } - private static void AppendUsings(StringBuilder stringBuilder, IEnumerable items) + private void ParseFile(string path, FilePreProcessorContext context) { - var lines = items.Distinct().Select(item => string.Format("using {0};", item)).ToList(); + _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); - if (lines.Count == 0) return; + var scriptLines = _fileSystem.ReadFileLines(path).ToList(); - stringBuilder.AppendLine(string.Join(Environment.NewLine, lines)); - stringBuilder.AppendLine(); // Insert a blank separator line + ParseScript(scriptLines, context, path); } - private void ParseFile(string path, FilePreProcessContext context) + private void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { - _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); - - var fileLines = _fileSystem.ReadFileLines(path).ToList(); - - InsertLineDirective(path, fileLines); + // Insert line directive if there's a path + if (path != null) InsertLineDirective(path, scriptLines); - var codeIndex = fileLines.FindIndex(PreProcessorUtil.IsNonDirectiveLine); + var codeIndex = scriptLines.FindIndex(PreProcessorUtil.IsNonDirectiveLine); - for (var index = 0; index < fileLines.Count; index++) + for (var index = 0; index < scriptLines.Count; index++) { - ProcessLine(context, fileLines[index], index < codeIndex || codeIndex < 0); + ProcessLine(context, scriptLines[index], index < codeIndex || codeIndex < 0); } context.LoadedScripts.Add(path); @@ -89,14 +104,14 @@ private static void InsertLineDirective(string path, List fileLines) fileLines.Insert(bodyIndex, directiveLine); } - private void ProcessLine(FilePreProcessContext context, string line, bool isBeforeCode) + private void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { if (PreProcessorUtil.IsUsingLine(line)) { var @using = PreProcessorUtil.GetPath(PreProcessorUtil.UsingString, line); - if (!context.Usings.Contains(@using)) + if (!context.UsingStatements.Contains(@using)) { - context.Usings.Add(@using); + context.UsingStatements.Add(@using); } return; @@ -107,7 +122,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo if (isBeforeCode) { var reference = PreProcessorUtil.GetPath(PreProcessorUtil.RString, line); - if (!context.References.Contains(reference)) + if (!string.IsNullOrWhiteSpace(reference) && !context.References.Contains(reference)) { context.References.Add(reference); } @@ -121,7 +136,7 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo if (isBeforeCode) { var filePath = PreProcessorUtil.GetPath(PreProcessorUtil.LoadString, line); - if (!context.LoadedScripts.Contains(filePath)) + if (!string.IsNullOrWhiteSpace(filePath) && !context.LoadedScripts.Contains(filePath)) { ParseFile(filePath, context); } @@ -134,17 +149,17 @@ private void ProcessLine(FilePreProcessContext context, string line, bool isBefo context.Body.Add(line); } - private class FilePreProcessContext + private class FilePreProcessorContext { - public FilePreProcessContext() + public FilePreProcessorContext() { - Usings = new List(); + UsingStatements = new List(); References = new List(); LoadedScripts = new List(); Body = new List(); } - public List Usings { get; private set; } + public List UsingStatements { get; private set; } public List References { get; private set; } @@ -153,4 +168,4 @@ public FilePreProcessContext() public List Body { get; private set; } } } -} \ No newline at end of file +} diff --git a/src/ScriptCs.Core/FilePreProcessorResult.cs b/src/ScriptCs.Core/FilePreProcessorResult.cs index 94c27ee9..f5731ebe 100644 --- a/src/ScriptCs.Core/FilePreProcessorResult.cs +++ b/src/ScriptCs.Core/FilePreProcessorResult.cs @@ -6,12 +6,12 @@ public class FilePreProcessorResult { public FilePreProcessorResult() { - Usings = new List(); + UsingStatements = new List(); LoadedScripts = new List(); References = new List(); } - public List Usings { get; set; } + public List UsingStatements { get; set; } public List LoadedScripts { get; set; } diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index aed7e297..d8e0bb25 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -76,6 +76,11 @@ public void FileDelete(string path) File.Delete(path); } + public IEnumerable SplitLines(string value) + { + return value.Split(new[] { NewLine }, StringSplitOptions.None); + } + public Stream CreateFileStream(string filePath, FileMode mode) { return new FileStream(filePath, mode); diff --git a/src/ScriptCs.Core/IFilePreProcessor.cs b/src/ScriptCs.Core/IFilePreProcessor.cs index b136cc24..5fb0a688 100644 --- a/src/ScriptCs.Core/IFilePreProcessor.cs +++ b/src/ScriptCs.Core/IFilePreProcessor.cs @@ -1,7 +1,11 @@ -namespace ScriptCs +using System.Collections.Generic; + +namespace ScriptCs { public interface IFilePreProcessor { FilePreProcessorResult ProcessFile(string path); + + FilePreProcessorResult ProcessScript(string script); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 35ce813f..253be305 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -36,6 +36,8 @@ public interface IFileSystem void FileDelete(string path); + IEnumerable SplitLines(string value); + Stream CreateFileStream(string filePath, FileMode mode); } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index 3fdd1d68..ec669b3f 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -126,9 +126,9 @@ public void ShouldReturnResultWithAllUsings() var processor = new FilePreProcessor(_fileSystem.Object, _logger.Object); var result = processor.ProcessFile("script1.csx"); - result.Usings.Count.ShouldEqual(2); - result.Usings.ShouldContain("System"); - result.Usings.ShouldContain("System.Core"); + result.UsingStatements.Count.ShouldEqual(2); + result.UsingStatements.ShouldContain("System"); + result.UsingStatements.ShouldContain("System.Core"); } [Fact] From 73e81114c3d5c22778d0886f75e4e0a42e0b93af Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 19 May 2013 16:59:40 +0200 Subject: [PATCH 026/993] Added automatic installation of packages when packages.config is present, but no packages folder. Fixes #251 --- src/ScriptCs/Command/CommandFactory.cs | 24 +++++++++++++++++ test/ScriptCs.Tests/CommandFactoryTests.cs | 27 ++++++++++++++++++- .../ExecuteScriptCommandTests.cs | 4 +++ test/ScriptCs.Tests/RestoreCommandTests.cs | 3 +++ 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 7e676bae..4fa1c33f 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -39,6 +39,30 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.Logger, _scriptServiceRoot.AssemblyName); + var fileSystem = _scriptServiceRoot.FileSystem; + var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); + var packagesFolder = Path.Combine(currentDirectory, Constants.PackagesFolder); + + if (fileSystem.FileExists(packageFile) && !fileSystem.DirectoryExists(packagesFolder)) + { + var installCommand = new InstallCommand( + null, + false, + fileSystem, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.PackageInstaller, + _scriptServiceRoot.Logger); + + var restoreCommand = new RestoreCommand( + args.Install, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Logger); + + return new CompositeCommand(installCommand, restoreCommand, executeCommand); + } + if (args.Restore) { var restoreCommand = new RestoreCommand( diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index deb8f88a..c479b1cd 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -11,14 +11,16 @@ public class CommandFactoryTests { public class CreateCommandMethod { - private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true) + private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool packagesFolderExists = true) { const string CurrentDirectory = "C:\\"; const string PackagesFile = "C:\\packages.config"; + const string PackagesFolder = "C:\\packages"; var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.FileExists(PackagesFile)).Returns(packagesFileExists); + fs.Setup(x => x.DirectoryExists(PackagesFolder)).Returns(packagesFolderExists); var resolver = new Mock(); var executor = new Mock(); @@ -92,6 +94,29 @@ public void ShouldExecuteWhenScriptNameIsPassed() result.ShouldImplement(); } + [Fact] + public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNotExist() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = null, + ScriptName = "test.csx" + }; + + var root = CreateRoot(packagesFileExists: true, packagesFolderExists: false); + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args); + + var compositeCommand = result as ICompositeCommand; + compositeCommand.ShouldNotBeNull(); + + compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands[0].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); + compositeCommand.Commands[2].ShouldImplement(); + } + [Fact] public void ShouldExecuteWhenBothNameAndInstallArePassed() { diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 60bead91..55640149 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -26,6 +26,8 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() }; var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + var resolver = new Mock(); var executor = new Mock(); var engine = new Mock(); @@ -55,6 +57,7 @@ public void ShouldCreateMissingBinFolder() var fs = new Mock(); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); var resolver = new Mock(); @@ -88,6 +91,7 @@ public void NonManagedAssembliesAreExcluded() }; var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "managed.dll", nonManaged diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index ed5e3cfd..eb80a41a 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -37,6 +37,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi var destWriteTime = sourceWriteTime; fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); @@ -78,6 +79,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn var destWriteTime = new DateTime(2013, 2, 7); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); @@ -114,6 +116,7 @@ public void ShouldCreateBinFolderIfItDoesNotExist() const string BinFolder = @"C:\bin"; fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); var binFolderCreated = false; From 0a76954f85b82ad43ea408bddfed94f31282a909 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 19 May 2013 18:31:40 +0200 Subject: [PATCH 027/993] Minor tweak :) --- src/ScriptCs/Command/CommandFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 4fa1c33f..b35aff8f 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -40,7 +40,7 @@ public ICommand CreateCommand(ScriptCsArgs args) _scriptServiceRoot.AssemblyName); var fileSystem = _scriptServiceRoot.FileSystem; - var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var currentDirectory = fileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); var packagesFolder = Path.Combine(currentDirectory, Constants.PackagesFolder); From 22c9cd9c96df4e818fdc5a6e5072daaa8697d854 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 21 May 2013 13:25:37 +0200 Subject: [PATCH 028/993] Replaced Environment.NewLine with _fileSystem.NewLine --- src/ScriptCs.Core/FilePreProcessor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 136362d9..e50c0910 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -52,7 +52,7 @@ private FilePreProcessorResult Parse(Action parseAction }; } - private static string GenerateCode(FilePreProcessorContext context) + private string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); @@ -62,11 +62,11 @@ private static string GenerateCode(FilePreProcessorContext context) if (usingLines.Count > 0) { - stringBuilder.AppendLine(string.Join(Environment.NewLine, usingLines)); + stringBuilder.AppendLine(string.Join(_fileSystem.NewLine, usingLines)); stringBuilder.AppendLine(); // Insert a blank separator line } - stringBuilder.Append(string.Join(Environment.NewLine, context.Body)); + stringBuilder.Append(string.Join(_fileSystem.NewLine, context.Body)); return stringBuilder.ToString(); } From 0f49393fe889315c1ac0876c198349ea5eb49320 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 21 May 2013 14:02:55 +0200 Subject: [PATCH 029/993] Added tests for ProcessScript method --- src/ScriptCs.Core/FilePreProcessor.cs | 2 +- .../ScriptCs.Core.Tests/FileProcessorTests.cs | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index e50c0910..4196aca1 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -92,7 +92,7 @@ private void ParseScript(List scriptLines, FilePreProcessorContext conte ProcessLine(context, scriptLines[index], index < codeIndex || codeIndex < 0); } - context.LoadedScripts.Add(path); + if (path != null) context.LoadedScripts.Add(path); } private static void InsertLineDirective(string path, List fileLines) diff --git a/test/ScriptCs.Core.Tests/FileProcessorTests.cs b/test/ScriptCs.Core.Tests/FileProcessorTests.cs index ec669b3f..84d574b7 100644 --- a/test/ScriptCs.Core.Tests/FileProcessorTests.cs +++ b/test/ScriptCs.Core.Tests/FileProcessorTests.cs @@ -400,5 +400,55 @@ public void ShouldAddLineDirectiveRightAfterLastLoadIsIncludedInEachFile() fileLines[line].ShouldEqual(f1[4]); } } + + public class ProcessScriptMethod + { + private readonly Mock _fileSystem; + + public ProcessScriptMethod() + { + _fileSystem = new Mock(); + _fileSystem.SetupGet(x => x.NewLine).Returns(Environment.NewLine); + } + + [Fact] + public void ShouldSplitScriptIntoLines() + { + var preProcessor = new FilePreProcessor(_fileSystem.Object, Mock.Of()); + var script = @"Console.WriteLine(""Testing..."");"; + + preProcessor.ProcessScript(script); + + _fileSystem.Verify(x => x.SplitLines(script), Times.Once()); + } + + [Fact] + public void ShouldNotReadFromFile() + { + var preProcessor = new FilePreProcessor(_fileSystem.Object, Mock.Of()); + var script = @"Console.WriteLine(""Testing..."");"; + + preProcessor.ProcessScript(script); + + _fileSystem.Verify(x => x.ReadFileLines(It.IsAny()), Times.Never()); + } + + [Fact] + public void ShouldNotIncludeLineDirectiveForRootScript() + { + var script1 = new List { @"Console.WriteLine(""Hello from script1.csx""" }; + _fileSystem.Setup(x => x.ReadFileLines("script1.csx")).Returns(script1.ToArray()); + _fileSystem.Setup(x => x.SplitLines(It.IsAny())) + .Returns(x => x.Split(new[] { Environment.NewLine }, StringSplitOptions.None)); + + var preProcessor = new FilePreProcessor(_fileSystem.Object, Mock.Of()); + var script = @"#load script1.csx"; + + var result = preProcessor.ProcessScript(script); + var fileLines = result.Code.Split(new[] { Environment.NewLine }, StringSplitOptions.None); + + fileLines.Count(x => x.StartsWith("#line ")).ShouldEqual(1); + } + } } } \ No newline at end of file From 9a1d95efae055ca7e236e9530c704dd2bfa3a29e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 21 May 2013 18:45:08 +0200 Subject: [PATCH 030/993] Added ScriptPack base class --- src/ScriptCs.Contracts/IScriptPack.cs | 12 ++++++++++-- src/ScriptCs.Contracts/ScriptCs.Contracts.csproj | 1 + src/ScriptCs.Contracts/ScriptPack.cs | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/ScriptCs.Contracts/ScriptPack.cs diff --git a/src/ScriptCs.Contracts/IScriptPack.cs b/src/ScriptCs.Contracts/IScriptPack.cs index c22f6999..8c3b35b2 100644 --- a/src/ScriptCs.Contracts/IScriptPack.cs +++ b/src/ScriptCs.Contracts/IScriptPack.cs @@ -6,7 +6,15 @@ namespace ScriptCs.Contracts public interface IScriptPack { void Initialize(IScriptPackSession session); - IScriptPackContext GetContext(); + + IScriptPackContext GetContext(); + void Terminate(); } -} + + public interface IScriptPack : IScriptPack where TContext : IScriptPackContext + { + [Import] + TContext Context { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 3f667d25..707c4ecb 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -30,6 +30,7 @@ Properties\CommonVersionInfo.cs + diff --git a/src/ScriptCs.Contracts/ScriptPack.cs b/src/ScriptCs.Contracts/ScriptPack.cs new file mode 100644 index 00000000..e8dce6b1 --- /dev/null +++ b/src/ScriptCs.Contracts/ScriptPack.cs @@ -0,0 +1,16 @@ +namespace ScriptCs.Contracts +{ + public abstract class ScriptPack : IScriptPack where TContext : IScriptPackContext + { + public TContext Context { get; set; } + + public virtual void Initialize(IScriptPackSession session) { } + + public virtual IScriptPackContext GetContext() + { + return Context; + } + + public virtual void Terminate() { } + } +} \ No newline at end of file From 428b4ae690daf92e884bdc9fec79ea9a16d8f3d5 Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Thu, 2 May 2013 16:54:06 -0700 Subject: [PATCH 031/993] Implement `Args` to pass arguments to scripts. --- src/ScriptCs.Core/IScriptEngine.cs | 2 +- src/ScriptCs.Core/IScriptExecutor.cs | 2 +- src/ScriptCs.Core/IScriptHostFactory.cs | 2 +- src/ScriptCs.Core/ScriptExecutor.cs | 4 +-- src/ScriptCs.Core/ScriptHost.cs | 4 ++- src/ScriptCs.Core/ScriptHostFactory.cs | 4 +-- .../RoslynScriptEngine.cs | 4 +-- src/ScriptCs/Command/CommandFactory.cs | 7 +++-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 11 ++++--- src/ScriptCs/Program.cs | 7 ++++- src/ScriptCs/Repl.cs | 2 +- src/ScriptCs/ScriptCsArgs.cs | 5 +++- .../ScriptExecutorTests.cs | 30 +++++++++---------- test/ScriptCs.Core.Tests/ScriptHostTests.cs | 2 +- .../RoslynScriptDebuggerEngine.cs | 2 +- .../RoslynScriptEngineTests.cs | 18 +++++------ test/ScriptCs.Tests/CleanCommandTests.cs | 8 ++--- test/ScriptCs.Tests/CommandFactoryTests.cs | 20 ++++++------- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 10 +++---- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +-- test/ScriptCs.Tests/ReplTests.cs | 10 +++---- test/ScriptCs.Tests/RestoreCommandTests.cs | 6 ++-- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 24 files changed, 91 insertions(+), 77 deletions(-) diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index e22ab9c5..94740e2b 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -5,6 +5,6 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 07ca8b8f..80c8e313 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -5,6 +5,6 @@ namespace ScriptCs { public interface IScriptExecutor { - void Execute(string script, IEnumerable paths, IEnumerable recipes); + void Execute(string script, string[] scriptArgs, IEnumerable paths, IEnumerable recipes); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptHostFactory.cs b/src/ScriptCs.Core/IScriptHostFactory.cs index 469e8068..8f7f7c3a 100644 --- a/src/ScriptCs.Core/IScriptHostFactory.cs +++ b/src/ScriptCs.Core/IScriptHostFactory.cs @@ -6,6 +6,6 @@ namespace ScriptCs { public interface IScriptHostFactory { - ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager); + ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs); } } diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 14641fff..81fc0284 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -24,7 +24,7 @@ public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor _logger = logger; } - public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) + public void Execute(string script, string[] scriptArgs, IEnumerable paths, IEnumerable scriptPacks) { var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); @@ -42,7 +42,7 @@ public void Execute(string script, IEnumerable paths, IEnumerable() where T:IScriptPackContext diff --git a/src/ScriptCs.Core/ScriptHostFactory.cs b/src/ScriptCs.Core/ScriptHostFactory.cs index c2b86317..2b07f587 100644 --- a/src/ScriptCs.Core/ScriptHostFactory.cs +++ b/src/ScriptCs.Core/ScriptHostFactory.cs @@ -5,9 +5,9 @@ namespace ScriptCs { public class ScriptHostFactory : IScriptHostFactory { - public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager) + public ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs) { - return new ScriptHost(scriptPackManager); + return new ScriptHost(scriptPackManager, scriptArgs); } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 50036033..e011eb8d 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -28,7 +28,7 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public object Execute(string code, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) + public object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { Guard.AgainstNullArgument("scriptPackSession", scriptPackSession); @@ -40,7 +40,7 @@ public object Execute(string code, IEnumerable references, IEnumerable(), Enumerable.Empty()); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -65,7 +65,7 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -92,7 +92,7 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() IEnumerable recipes = Enumerable.Empty(); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Execute(scriptName, new string[0], paths, recipes); // assert string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); @@ -123,15 +123,15 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut var recipes = Enumerable.Empty(); preProcessor.Setup(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName))).Returns(new FilePreProcessorResult { Code = code }).Verifiable(); - scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(code, It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Execute(scriptName, new string[0], paths, recipes); // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); - scriptEngine.Verify(s => s.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(s => s.Execute(code, It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } @@ -162,13 +162,13 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); + scriptExecutor.Execute(scriptName, new string[0], paths, Enumerable.Empty()); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); } [Fact] @@ -187,7 +187,7 @@ public void ShouldInitializeScriptPacks() scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), new[] { scriptPack1.Object }); scriptPack1.Verify(p => p.Initialize(It.IsAny())); } @@ -209,7 +209,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); scriptPack1.Setup(p => p.Terminate()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), new[] { scriptPack1.Object }); scriptPack1.Verify(p => p.Terminate()); } @@ -230,9 +230,9 @@ public void ExecutorShouldPassDefaultNamespacesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); - engine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); + engine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); } [Fact] @@ -251,9 +251,9 @@ public void ExecutorShouldPassDefaultReferencesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx", new string[0], Enumerable.Empty(), Enumerable.Empty()); - engine.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); + engine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); } } } diff --git a/test/ScriptCs.Core.Tests/ScriptHostTests.cs b/test/ScriptCs.Core.Tests/ScriptHostTests.cs index 4f03b375..3a80cd59 100644 --- a/test/ScriptCs.Core.Tests/ScriptHostTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptHostTests.cs @@ -21,7 +21,7 @@ public class TheGetMethod public TheGetMethod() { - _scriptHost = new ScriptHost(_mockScriptPackManager.Object); + _scriptHost = new ScriptHost(_mockScriptPackManager.Object, new string[0]); _mockScriptPackManager.Setup(s => s.Get()).Returns(_mockContext.Object); } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs index 9c06e4ed..9e0d3082 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptDebuggerEngine.cs @@ -38,7 +38,7 @@ public void ShouldThrowExceptionThrownByScriptWhenErrorOccurs() var exception = Assert.Throws( () => scriptEngine.Execute( - code, Enumerable.Empty(), Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); + code, new string[0], Enumerable.Empty(), Enumerable.Empty(), new ScriptPackSession(Enumerable.Empty()))); Console.WriteLine(exception.Message); diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index ac01346b..21780bc6 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -54,7 +54,7 @@ public class TheExecuteMethod public void ShouldCreateScriptHostWithContexts() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; @@ -66,16 +66,16 @@ public void ShouldCreateScriptHostWithContexts() var scriptPackSession = new ScriptPackSession(new[] { scriptPack1.Object }); - engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); - scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny())); + scriptHostFactory.Verify(f => f.CreateScriptHost(It.IsAny(), It.IsAny())); } [Fact] public void ShouldReuseExistingSessionIfProvided() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; @@ -84,7 +84,7 @@ public void ShouldReuseExistingSessionIfProvided() var roslynEngine = new ScriptEngine(); var session = new SessionState {Session = roslynEngine.CreateSession()}; scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; - engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); engine.Session.ShouldEqual(session.Session); } @@ -92,13 +92,13 @@ public void ShouldReuseExistingSessionIfProvided() public void ShouldCreateNewSessionIfNotProvided() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); var scriptPackSession = new ScriptPackSession(new List()); - engine.Execute(code, Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], Enumerable.Empty(), Enumerable.Empty(), scriptPackSession); engine.Session.ShouldNotBeNull(); } @@ -106,7 +106,7 @@ public void ShouldCreateNewSessionIfNotProvided() public void ShouldAddNewReferencesIfTheyAreProvided() { var scriptHostFactory = new Mock(); - scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny())).Returns((IScriptPackManager p) => new ScriptHost(p)); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); var code = "var a = 0;"; @@ -115,7 +115,7 @@ public void ShouldAddNewReferencesIfTheyAreProvided() var roslynEngine = new ScriptEngine(); var session = new SessionState { Session = roslynEngine.CreateSession()}; scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; - engine.Execute(code, new[] {"System"}, Enumerable.Empty(), scriptPackSession); + engine.Execute(code, new string[0], new[] {"System"}, Enumerable.Empty(), scriptPackSession); ((SessionState)scriptPackSession.State[RoslynScriptEngine.SessionKey]).References.Count().ShouldEqual(1); } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 54387b06..cae08c14 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -31,7 +31,7 @@ public void ShouldDeletePackagesFolder() fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -58,7 +58,7 @@ public void ShouldDeleteBinFolder() fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -87,7 +87,7 @@ public void ShouldNotDeleteBinFolderIfDllsAreLeft() fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -116,7 +116,7 @@ public void ShouldDeleteAllFilesResolvedFromPackages() resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index c479b1cd..b8be9568 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -46,7 +46,7 @@ public void ShouldInstallAndRestoreWhenInstallFlagIsOn() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -67,7 +67,7 @@ public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExist }; var factory = new CommandFactory(CreateRoot(packagesFileExists: false)); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -89,7 +89,7 @@ public void ShouldExecuteWhenScriptNameIsPassed() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } @@ -106,7 +106,7 @@ public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNo var root = CreateRoot(packagesFileExists: true, packagesFolderExists: false); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -128,7 +128,7 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } @@ -139,7 +139,7 @@ public void ShouldRestoreWhenBothNameAndRestoreArePassed() var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -155,7 +155,7 @@ public void ShouldSaveAndCleanWhenCleanFlagIsPassed() var args = new ScriptCsArgs { Clean = true, ScriptName = null }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); @@ -171,7 +171,7 @@ public void ShouldSaveWhenSaveFlagIsPassed() var args = new ScriptCsArgs { Save = true, ScriptName = null }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldNotBeNull(); result.ShouldImplement(); @@ -188,7 +188,7 @@ public void ShouldReturnInvalidWhenNoNameOrInstallSet() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } @@ -202,7 +202,7 @@ public void ShouldReturnHelpCommandWhenHelpIsPassed() }; var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.ShouldImplement(); } diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d98de537..7e254743 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -40,7 +40,7 @@ public void ShouldPromptForInput() var commandFactory = new CommandFactory(root); - var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }); + var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }, new string[0]); target.Execute(); diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 55640149..453393b1 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -39,11 +39,11 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); - executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny>(), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny(), It.IsAny>(), It.IsAny>()), Times.Once()); } [Fact] @@ -71,7 +71,7 @@ public void ShouldCreateMissingBinFolder() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -111,11 +111,11 @@ public void NonManagedAssembliesAreExcluded() var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); - executor.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); } } } diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 921d29ad..13c9ebbc 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -41,7 +41,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -81,7 +81,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 002a0930..72bd8219 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -150,14 +150,14 @@ public void ResetsColorAfterExecutingScript() [Fact] public void CallsExecuteOnTheScriptEngine() { - _mocks.ScriptEngine.Verify(x => x.Execute("foo", _repl.References, Repl.DefaultNamespaces, It.IsAny())); + _mocks.ScriptEngine.Verify(x => x.Execute("foo", new string[0], _repl.References, Repl.DefaultNamespaces, It.IsAny())); } [Fact] public void CatchesExceptionsAndWritesThemInRed() { _mocks.ScriptEngine.Setup( - x => x.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())) + x => x.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())) .Throws(); _repl.Execute("foo"); @@ -196,7 +196,7 @@ public void ShouldExecuteLoadedFileIfLineIsALoad() _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); - mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); } [Fact] @@ -208,7 +208,7 @@ public void ShouldNotExecuteLoadedFileIfFileDoesNotExist() _repl = GetRepl(mocks); _repl.Execute("#load \"file.csx\""); - mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); } [Fact] @@ -250,7 +250,7 @@ public void ShouldNotExecuteAnythingIfLineIsAReference() _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); - mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); + mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); } } } diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs index eb80a41a..7ee7559a 100644 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ b/test/ScriptCs.Tests/RestoreCommandTests.cs @@ -45,7 +45,7 @@ public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBi resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -87,7 +87,7 @@ public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileIn resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); @@ -124,7 +124,7 @@ public void ShouldCreateBinFolderIfItDoesNotExist() fs.Setup(x => x.CreateDirectory(BinFolder)).Callback(() => binFolderCreated = true).Verifiable(); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); result.Execute(); diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index e00cf1a4..bbc7f11e 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -46,7 +46,7 @@ public void VersionCommandShouldOutputVersion() var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); - var result = factory.CreateCommand(args); + var result = factory.CreateCommand(args, new string[0]); // clear the fake console output _outputText.Clear(); From d9bb35bf17b9d87f27c829e446e51d17af9b89da Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Mon, 13 May 2013 09:43:05 -0700 Subject: [PATCH 032/993] Rename Args to ScriptArgs for clarity. --- src/ScriptCs.Core/ScriptHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/ScriptHost.cs b/src/ScriptCs.Core/ScriptHost.cs index 658d8ba7..02401976 100644 --- a/src/ScriptCs.Core/ScriptHost.cs +++ b/src/ScriptCs.Core/ScriptHost.cs @@ -7,12 +7,12 @@ namespace ScriptCs public class ScriptHost { private IScriptPackManager _scriptPackManager; - public string[] Args { get; private set; } + public string[] ScriptArgs { get; private set; } public ScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs) { _scriptPackManager = scriptPackManager; - Args = scriptArgs; + ScriptArgs = scriptArgs; } public T Require() where T:IScriptPackContext From 881a78eb09c5dfb21070b79535872da7607e188b Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Mon, 13 May 2013 09:44:02 -0700 Subject: [PATCH 033/993] Unit tests for `--` parsing on command line. --- src/ScriptCs/ScriptCsArgs.cs | 12 +++ test/ScriptCs.Tests/ScriptArgsTests.cs | 107 ++++++++++++++++++++++ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 + 3 files changed, 120 insertions(+) create mode 100644 test/ScriptCs.Tests/ScriptArgsTests.cs diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 78064e71..fd0440aa 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -53,5 +53,17 @@ public class ScriptCsArgs [ArgShortcut("version")] [ArgDescription("Outputs version information")] public bool Version { get; set; } + + public static void SplitScriptArgs(ref string[] args, out string[] scriptArgs) + { + // Split the arguments list on "--". + // The arguments before the "--" (or all arguments if there is no "--") are + // for ScriptCs.exe, and the arguments after that are for the csx script. + int separatorLocation = Array.IndexOf(args, "--"); + int scriptArgsCount = separatorLocation == -1 ? 0 : args.Length - separatorLocation - 1; + scriptArgs = new string[scriptArgsCount]; + Array.Copy(args, separatorLocation + 1, scriptArgs, 0, scriptArgsCount); + if (separatorLocation != -1) args = args.Take(separatorLocation).ToArray(); + } } } \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptArgsTests.cs b/test/ScriptCs.Tests/ScriptArgsTests.cs new file mode 100644 index 00000000..10e8f5b8 --- /dev/null +++ b/test/ScriptCs.Tests/ScriptArgsTests.cs @@ -0,0 +1,107 @@ +using System; +using Common.Logging; +using Moq; +using ScriptCs.Command; +using ScriptCs.Package; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptArgsTests + { + public class SplitScriptArgsMethod + { + [Fact] + public void ShouldHandleEmptyArgs() + { + string[] args = new string[0]; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[0], args); + Assert.Equal(new string[0], scriptArgs); + } + + [Fact] + public void ShouldHandleMissingDoubledash() + { + string[] args = new string[] { "scriptname.csx", "-restore" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[0], scriptArgs); + } + + [Fact] + public void ShouldHandleArgsAndScriptArgs() + { + string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "8080" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + } + + [Fact] + public void ShouldHandleJustScriptArgs() + { + string[] args = new string[] { "--", "-port", "8080" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[0], args); + Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + } + + [Fact] + public void ShouldHandleJustDoubledash() + { + string[] args = new string[] { "--" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[0], args); + Assert.Equal(new string[0], scriptArgs); + } + + [Fact] + public void ShouldHandleExtraDoubledash() + { + string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "--", "8080" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[] { "-port", "--", "8080" }, scriptArgs); + } + + [Fact] + public void ShouldHandleTrailingDoubledash() + { + string[] args = new string[] { "scriptname.csx", "-restore", "--" }; + string[] scriptArgs; + + ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + + Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); + Assert.Equal(new string[0], scriptArgs); + } + + public class ScriptArgsPlumbing { + [Fact] + public void ScriptArgsArePlumbedThrough() + { + + } + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 6b87c8ea..97db7eeb 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -44,6 +44,7 @@ + From f20f867e30b82340502342747ff535121c5ce7d3 Mon Sep 17 00:00:00 2001 From: Scott Blomquist Date: Fri, 17 May 2013 16:56:40 -0700 Subject: [PATCH 034/993] Additional unit tests. --- src/ScriptCs/Command/ExecuteReplCommand.cs | 2 ++ src/ScriptCs/Command/ExecuteScriptCommand.cs | 7 ++++--- src/ScriptCs/Command/ICommand.cs | 4 +++- test/ScriptCs.Core.Tests/ScriptHostTests.cs | 13 ++++++++++++- test/ScriptCs.Tests/CommandFactoryTests.cs | 17 +++++++++++++++++ 5 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..76303812 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -20,6 +20,8 @@ internal class ExecuteReplCommand : IScriptCommand private readonly ILog _logger; private readonly IConsole _console; + public string[] ScriptArgs { get; private set; } + public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 391e5a94..6d7b1d38 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -10,7 +10,6 @@ namespace ScriptCs.Command internal class ExecuteScriptCommand : IScriptCommand { private readonly string _script; - private readonly string[] _scriptArgs; private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; @@ -27,7 +26,7 @@ public ExecuteScriptCommand(string script, IAssemblyName assemblyName) { _script = script; - _scriptArgs = scriptArgs; + ScriptArgs = scriptArgs; _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; @@ -35,6 +34,8 @@ public ExecuteScriptCommand(string script, _assemblyName = assemblyName; } + public string[] ScriptArgs { get; private set; } + public CommandResult Execute() { try @@ -47,7 +48,7 @@ public CommandResult Execute() assemblyPaths = GetAssemblyPaths(workingDirectory); } - _scriptExecutor.Execute(_script, _scriptArgs, assemblyPaths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Execute(_script, ScriptArgs, assemblyPaths, _scriptPackResolver.GetPacks()); return CommandResult.Success; } catch (Exception ex) diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index ec1477b9..41c55ea3 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -2,7 +2,9 @@ namespace ScriptCs.Command { - public interface IScriptCommand : ICommand { } + public interface IScriptCommand : ICommand { + string[] ScriptArgs { get; } + } public interface IRestoreCommand : ICommand { } diff --git a/test/ScriptCs.Core.Tests/ScriptHostTests.cs b/test/ScriptCs.Core.Tests/ScriptHostTests.cs index 3a80cd59..b2b0c2b0 100644 --- a/test/ScriptCs.Core.Tests/ScriptHostTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptHostTests.cs @@ -29,7 +29,18 @@ public TheGetMethod() public void ShoulGetScriptPackFromScriptPackManagerWhenInvoked() { var result = _scriptHost.Require(); - _mockScriptPackManager.Verify(s=>s.Get()); + _mockScriptPackManager.Verify(s => s.Get()); + } + } + + public class TheConstructor + { + [Fact] + public void ShouldSetScriptArgsWhenConstructed() + { + var scriptArgs = new string[0]; + var scriptHost = new ScriptHost(null, scriptArgs); + scriptHost.ScriptArgs.ShouldEqual(scriptArgs); } } } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index b8be9568..47bb68e7 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -206,6 +206,23 @@ public void ShouldReturnHelpCommandWhenHelpIsPassed() result.ShouldImplement(); } + + [Fact] + public void ShouldPassScriptArgsToExecuteCommandConstructor() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = null, + ScriptName = "test.csx" + }; + + var scriptArgs = new string[0]; + var factory = new CommandFactory(CreateRoot()); + var result = factory.CreateCommand(args, scriptArgs) as IScriptCommand; + + result.ScriptArgs.ShouldEqual(scriptArgs); + } } } } From 30a9ec11ab667bd64a99f45c94fabaf85f227b4f Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:07:37 +0200 Subject: [PATCH 035/993] moved IConsole to ScriptCs.Contracts --- src/{ScriptCs => ScriptCs.Contracts}/IConsole.cs | 6 +----- src/ScriptCs.Contracts/ScriptCs.Contracts.csproj | 1 + src/ScriptCs/Command/ExecuteReplCommand.cs | 1 + src/ScriptCs/ReplConsole.cs | 1 + src/ScriptCs/ScriptCs.csproj | 1 - src/ScriptCs/ScriptServiceRoot.cs | 1 + test/ScriptCs.Tests/ExecuteReplCommandTests.cs | 1 + 7 files changed, 6 insertions(+), 6 deletions(-) rename src/{ScriptCs => ScriptCs.Contracts}/IConsole.cs (68%) diff --git a/src/ScriptCs/IConsole.cs b/src/ScriptCs.Contracts/IConsole.cs similarity index 68% rename from src/ScriptCs/IConsole.cs rename to src/ScriptCs.Contracts/IConsole.cs index f7935d91..b74bd4d4 100644 --- a/src/ScriptCs/IConsole.cs +++ b/src/ScriptCs.Contracts/IConsole.cs @@ -1,10 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace ScriptCs +namespace ScriptCs.Contracts { public interface IConsole { diff --git a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj index 3f667d25..eb9c4496 100644 --- a/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj +++ b/src/ScriptCs.Contracts/ScriptCs.Contracts.csproj @@ -20,6 +20,7 @@ + diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index e62f767e..aca38cf1 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using Common.Logging; using System.Reflection; +using ScriptCs.Contracts; namespace ScriptCs.Command { diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ReplConsole.cs index a2eddbcb..1df082ef 100644 --- a/src/ScriptCs/ReplConsole.cs +++ b/src/ScriptCs/ReplConsole.cs @@ -1,4 +1,5 @@ using System; +using ScriptCs.Contracts; namespace ScriptCs { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 47286cee..6cb6bd9e 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -74,7 +74,6 @@ - diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index cc32788a..ac2c90e7 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -1,4 +1,5 @@ using Common.Logging; +using ScriptCs.Contracts; using ScriptCs.Package; namespace ScriptCs diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d98de537..e8dbdb73 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -4,6 +4,7 @@ using Common.Logging; using Moq; using ScriptCs.Command; +using ScriptCs.Contracts; using ScriptCs.Package; using Xunit; From 948ee6e314a2d96d262bab13e498bb84aed34b97 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:19:49 +0200 Subject: [PATCH 036/993] extended IScriptExecutor with Initialize and Terminate, refactored accordingly --- src/ScriptCs.Core/IScriptExecutor.cs | 4 +- src/ScriptCs.Core/ScriptExecutor.cs | 53 +++++++++++-------- src/ScriptCs/Command/ExecuteScriptCommand.cs | 5 +- .../ScriptExecutorTests.cs | 32 +++++++---- .../ExecuteScriptCommandTests.cs | 8 ++- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 07ca8b8f..539f61df 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -5,6 +5,8 @@ namespace ScriptCs { public interface IScriptExecutor { - void Execute(string script, IEnumerable paths, IEnumerable recipes); + void Initialize(IEnumerable paths, IEnumerable scriptPacks); + void Execute(string script); + void Terminate(); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 14641fff..b07ea942 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -8,44 +8,53 @@ namespace ScriptCs { public class ScriptExecutor : IScriptExecutor { - private static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - private static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; + public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; - private readonly IFileSystem _fileSystem; - private readonly IFilePreProcessor _filePreProcessor; - private readonly IScriptEngine _scriptEngine; - private readonly ILog _logger; + public IFileSystem FileSystem { get; private set; } + public IFilePreProcessor FilePreProcessor { get; private set; } + public IScriptEngine ScriptEngine { get; private set; } + public ILog Logger { get; private set; } + public IEnumerable References { get; protected set; } + public ScriptPackSession ScriptPackSession { get; protected set; } public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { - _fileSystem = fileSystem; - _filePreProcessor = filePreProcessor; - _scriptEngine = scriptEngine; - _logger = logger; + FileSystem = fileSystem; + FilePreProcessor = filePreProcessor; + ScriptEngine = scriptEngine; + Logger = logger; } - public void Execute(string script, IEnumerable paths, IEnumerable scriptPacks) + public virtual void Initialize(IEnumerable paths, IEnumerable scriptPacks) { - var bin = Path.Combine(_fileSystem.GetWorkingDirectory(script), "bin"); + References = DefaultReferences.Union(paths); + var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); - _scriptEngine.BaseDirectory = bin; + ScriptEngine.BaseDirectory = bin; - _logger.Debug("Initializing script packs"); + Logger.Debug("Initializing script packs"); var scriptPackSession = new ScriptPackSession(scriptPacks); scriptPackSession.InitializePacks(); + ScriptPackSession = scriptPackSession; - var path = Path.IsPathRooted(script) ? script : Path.Combine(_fileSystem.CurrentDirectory, script); - - var result = _filePreProcessor.ProcessFile(path); + } - var references = DefaultReferences.Union(paths).Union(result.References); + public virtual void Terminate() + { + Logger.Debug("Terminating packs"); + ScriptPackSession.TerminatePacks(); + } - _logger.Debug("Starting execution in engine"); - _scriptEngine.Execute(result.Code, references, DefaultNamespaces, scriptPackSession); + public virtual void Execute(string script) + { + var path = Path.IsPathRooted(script) ? script : Path.Combine(FileSystem.CurrentDirectory, script); + var result = FilePreProcessor.ProcessFile(path); + var references = References.Union(result.References); - _logger.Debug("Terminating packs"); - scriptPackSession.TerminatePacks(); + Logger.Debug("Starting execution in engine"); + ScriptEngine.Execute(result.Code, references, DefaultNamespaces, ScriptPackSession); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index e60e2ad2..5501b337 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -44,7 +44,10 @@ public CommandResult Execute() assemblyPaths = GetAssemblyPaths(workingDirectory); } - _scriptExecutor.Execute(_script, assemblyPaths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Initialize(assemblyPaths, _scriptPackResolver.GetPacks()); + _scriptExecutor.Execute(_script); + _scriptExecutor.Terminate(); + return CommandResult.Success; } catch (Exception ex) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 0224b23e..13e877de 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -50,7 +50,8 @@ public void ConstructsAbsolutePathBeforePreProcessingFile() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -65,7 +66,8 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Execute(@"c:\my_script\script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } @@ -92,7 +94,8 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() IEnumerable recipes = Enumerable.Empty(); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Initialize(paths, recipes); + scriptExecutor.Execute(scriptName); // assert string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); @@ -126,7 +129,8 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut scriptEngine.Setup(e => e.Execute(code, It.IsAny>(), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, recipes); + scriptExecutor.Initialize(paths, recipes); + scriptExecutor.Execute(scriptName); // assert preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); @@ -165,7 +169,8 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Setup(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); // act - scriptExecutor.Execute(scriptName, paths, Enumerable.Empty()); + scriptExecutor.Initialize(paths, Enumerable.Empty()); + scriptExecutor.Execute(scriptName); // assert scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); @@ -187,7 +192,8 @@ public void ShouldInitializeScriptPacks() scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx"); scriptPack1.Verify(p => p.Initialize(It.IsAny())); } @@ -209,7 +215,9 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); scriptPack1.Setup(p => p.Terminate()); - executor.Execute("script.csx", Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx"); + executor.Terminate(); scriptPack1.Verify(p => p.Terminate()); } @@ -217,7 +225,7 @@ public void ShouldTerminateScriptPacksWhenScriptFinishes() [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { - var expectedNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; + var expectedNamespaces = ScriptExecutor.DefaultNamespaces; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); @@ -230,7 +238,8 @@ public void ExecutorShouldPassDefaultNamespacesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); engine.Verify(i => i.Execute(It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); } @@ -238,7 +247,7 @@ public void ExecutorShouldPassDefaultNamespacesToEngine() [Fact] public void ExecutorShouldPassDefaultReferencesToEngine() { - var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + var defaultReferences = ScriptExecutor.DefaultReferences; var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); @@ -251,7 +260,8 @@ public void ExecutorShouldPassDefaultReferencesToEngine() var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Execute("script.csx", Enumerable.Empty(), Enumerable.Empty()); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); engine.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Except(defaultReferences).Any()), It.IsAny>(), It.IsAny()), Times.Exactly(1)); } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 55640149..5e504bb4 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -43,7 +43,9 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() result.Execute(); - executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny>(), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Initialize(It.IsAny>(), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx")), Times.Once()); + executor.Verify(i => i.Terminate(), Times.Once()); } [Fact] @@ -115,7 +117,9 @@ public void NonManagedAssembliesAreExcluded() result.Execute(); - executor.Verify(i => i.Execute(It.IsAny(), It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Initialize(It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx")), Times.Once()); + executor.Verify(i => i.Terminate(), Times.Once()); } } } From 93b8713f915018639a6b445fce5253bd4f173d8d Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:30:06 +0200 Subject: [PATCH 037/993] moved Repl to ScriptCs.Core and derived it from ScriptExecutor to prevent code duplication --- src/{ScriptCs => ScriptCs.Core}/Repl.cs | 39 ++++--------------------- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +++ src/ScriptCs/ScriptCs.csproj | 4 --- 3 files changed, 9 insertions(+), 38 deletions(-) rename src/{ScriptCs => ScriptCs.Core}/Repl.cs (59%) diff --git a/src/ScriptCs/Repl.cs b/src/ScriptCs.Core/Repl.cs similarity index 59% rename from src/ScriptCs/Repl.cs rename to src/ScriptCs.Core/Repl.cs index fc38c2df..61f597af 100644 --- a/src/ScriptCs/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.IO; using Common.Logging; @@ -8,52 +7,24 @@ namespace ScriptCs { - public class Repl + public class Repl : ScriptExecutor { - public static readonly string[] DefaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; - public static readonly string[] DefaultNamespaces = new[] { "System", "System.Collections.Generic", "System.Linq", "System.Text", "System.Threading.Tasks", "System.IO" }; - - public IFileSystem FileSystem { get; private set; } - public IScriptEngine ScriptEngine { get; private set; } - public IFilePreProcessor FilePreProcessor { get; private set; } - public ILog Logger { get; private set; } public IConsole Console { get; private set; } - public ScriptPackSession ScriptPackSession { get; private set; } - public IEnumerable References { get; private set; } public Repl(IFileSystem fileSystem, IScriptEngine scriptEngine, ILog logger, IConsole console, IFilePreProcessor filePreProcessor) + : base(fileSystem, filePreProcessor, scriptEngine, logger) { - FileSystem = fileSystem; - ScriptEngine = scriptEngine; - FilePreProcessor = filePreProcessor; - Logger = logger; Console = console; } - public void Initialize(IEnumerable paths, IEnumerable scriptPacks) - { - References = DefaultReferences.Union(paths); - var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); - - ScriptEngine.BaseDirectory = bin; - - Logger.Debug("Initializing script packs"); - var scriptPackSession = new ScriptPackSession(scriptPacks); - - scriptPackSession.InitializePacks(); - ScriptPackSession = scriptPackSession; - - } - - public void Terminate() + public override void Terminate() { - Logger.Debug("Terminating packs"); - ScriptPackSession.TerminatePacks(); + base.Terminate(); Logger.Debug("Exiting console"); Console.Exit(); } - public void Execute(string script) + public override void Execute(string script) { try { diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index f8f67000..8039e66f 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -29,6 +29,9 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + @@ -76,6 +79,7 @@ + diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 6cb6bd9e..d0a48452 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,9 +38,6 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - - ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll - @@ -76,7 +73,6 @@ - From 35004b80e73d26ca16e52b58cc097a6dc85c288f Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 14:49:14 +0200 Subject: [PATCH 038/993] refactored ScriptExecutorTests to reflect the new structure --- .../ScriptExecutorTests.cs | 157 +++++++++--------- 1 file changed, 82 insertions(+), 75 deletions(-) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 13e877de..364d25ec 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -36,27 +36,64 @@ public static ScriptExecutor CreateScriptExecutor( return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, logger.Object); } - public class TheExecuteMethod + public class TheInitializeMethod { [Fact] - public void ConstructsAbsolutePathBeforePreProcessingFile() + public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() + { + // arrange + var scriptEngine = new Mock(); + var fileSystem = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); + + var currentDirectory = @"C:\"; + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + + scriptEngine.SetupProperty(e => e.BaseDirectory); + + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); + + var paths = new string[0]; + IEnumerable recipes = Enumerable.Empty(); + + // act + scriptExecutor.Initialize(paths, recipes); + + // assert + string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); + expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); + } + + [Fact] + public void ShouldInitializeScriptPacks() { var fileSystem = new Mock(); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); - executor.Execute("script.csx"); - preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + + // act + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + + // assert + scriptPack1.Verify(p => p.Initialize(It.IsAny())); } + } + public class TheTerminateMethod + { [Fact] - public void DoNotChangePathIfAbsolute() + public void ShouldTerminateScriptPacksWhenTerminateIsCalled() { var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); @@ -66,40 +103,56 @@ public void DoNotChangePathIfAbsolute() preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); - executor.Execute(@"c:\my_script\script.csx"); - preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); + var scriptPack1 = new Mock(); + scriptPack1.Setup(p => p.Initialize(It.IsAny())); + scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); + scriptPack1.Setup(p => p.Terminate()); + + // act + executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + executor.Execute("script.csx"); + executor.Terminate(); + + // assert + scriptPack1.Verify(p => p.Terminate()); } + } + public class TheExecuteMethod + { [Fact] - public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() + public void ConstructsAbsolutePathBeforePreProcessingFile() { - // arrange - var scriptEngine = new Mock(); var fileSystem = new Mock(); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + var preProcessor = new Mock(); - preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var currentDirectory = @"C:\"; - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); - fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - scriptEngine.SetupProperty(e => e.BaseDirectory); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute("script.csx"); + preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); + } - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); + [Fact] + public void DoNotChangePathIfAbsolute() + { + var fileSystem = new Mock(); + fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); + fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var scriptName = "script.csx"; - var paths = new string[0]; - IEnumerable recipes = Enumerable.Empty(); + var preProcessor = new Mock(); + preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - // act - scriptExecutor.Initialize(paths, recipes); - scriptExecutor.Execute(scriptName); + var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); + executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); + executor.Execute(@"c:\my_script\script.csx"); - // assert - string expectedBaseDirectory = Path.Combine(currentDirectory, "bin"); - expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); + preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } [Fact] @@ -143,7 +196,7 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut public void ShouldAddReferenceToEachDestinationFile() { // arrange - var defaultReferences = new[] { "System", "System.Core", "System.Data", "System.Data.DataSetExtensions", "System.Xml", "System.Xml.Linq" }; + var defaultReferences = ScriptExecutor.DefaultReferences; var fileSystem = new Mock(); var scriptEngine = new Mock(); var preProcessor = new Mock(); @@ -176,52 +229,6 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Verify(e => e.Execute(It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); } - [Fact] - public void ShouldInitializeScriptPacks() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - - executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); - executor.Execute("script.csx"); - - scriptPack1.Verify(p => p.Initialize(It.IsAny())); - } - - [Fact] - public void ShouldTerminateScriptPacksWhenScriptFinishes() - { - var fileSystem = new Mock(); - fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - - var preProcessor = new Mock(); - preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); - scriptPack1.Setup(p => p.Initialize(It.IsAny())); - scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); - scriptPack1.Setup(p => p.Terminate()); - - executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); - executor.Execute("script.csx"); - executor.Terminate(); - - scriptPack1.Verify(p => p.Terminate()); - } - [Fact] public void ExecutorShouldPassDefaultNamespacesToEngine() { From 9369b40c9c7bbdfa15030e90bd88b35843970d69 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 23 May 2013 15:35:17 +0200 Subject: [PATCH 039/993] added possibility to get full path from filesystem to facilitate #r loading in REPL --- src/ScriptCs.Core/FileSystem.cs | 5 +++++ src/ScriptCs.Core/IFileSystem.cs | 2 ++ src/ScriptCs.Core/Repl.cs | 2 +- test/ScriptCs.Tests/ReplTests.cs | 20 ++++++++++++++++++-- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index d8e0bb25..b60b5bad 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -90,5 +90,10 @@ public string GetWorkingDirectory(string path) { return IsPathRooted(path) ? Path.GetDirectoryName(path) : CurrentDirectory; } + + public string GetFullPath(string path) + { + return Path.GetFullPath(path); + } } } diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 253be305..1d6d7ddf 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -24,6 +24,8 @@ public interface IFileSystem bool IsPathRooted(string path); + string GetFullPath(string path); + string CurrentDirectory { get; } string NewLine { get; } diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 61f597af..8f7ef2ce 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -43,7 +43,7 @@ public override void Execute(string script) } else if (PreProcessorUtil.IsRLine(script)) { - var assemblyPath = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); + var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, PreProcessorUtil.GetPath(PreProcessorUtil.RString, script))); if (FileSystem.FileExists(assemblyPath)) { References = References.Union(new[] { assemblyPath }); diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index 002a0930..c835ac77 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -216,7 +216,8 @@ public void ShouldReferenceAssemblyIfLineIsAReference() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); - mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(true); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"c:/my.dll"); + mocks.FileSystem.Setup(x => x.FileExists("c:/my.dll")).Returns(true); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); @@ -231,7 +232,8 @@ public void ShouldNotReferenceAssemblyIfFileDoesNotExist() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); - mocks.FileSystem.Setup(x => x.FileExists("my.dll")).Returns(false); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"c:/my.dll"); + mocks.FileSystem.Setup(x => x.FileExists("c:/my.dll")).Returns(false); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); @@ -241,6 +243,20 @@ public void ShouldNotReferenceAssemblyIfFileDoesNotExist() _repl.References.Count().ShouldEqual(6); } + [Fact] + public void ShouldReferenceAssemblyBasedOnFullPath() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + + mocks.FileSystem.Verify(x => x.FileExists("C:/my.dll"), Times.Once()); + } + [Fact] public void ShouldNotExecuteAnythingIfLineIsAReference() { From 0f3248e2bbb9c28fefbaa49a1ef769b4d739d28e Mon Sep 17 00:00:00 2001 From: Tim Erickson Date: Thu, 23 May 2013 19:26:39 -0700 Subject: [PATCH 040/993] Added ScriptResult.cs and tests --- src/ScriptCs.Core/IScriptEngine.cs | 2 +- src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptResult.cs | 13 ++ .../RoslynScriptDebuggerEngine.cs | 27 +++- .../RoslynScriptEngine.cs | 26 +++- .../RoslynScriptEngineTests.cs | 130 +++++++++++++++++- 6 files changed, 185 insertions(+), 14 deletions(-) create mode 100644 src/ScriptCs.Core/ScriptResult.cs diff --git a/src/ScriptCs.Core/IScriptEngine.cs b/src/ScriptCs.Core/IScriptEngine.cs index 94740e2b..c98108df 100644 --- a/src/ScriptCs.Core/IScriptEngine.cs +++ b/src/ScriptCs.Core/IScriptEngine.cs @@ -5,6 +5,6 @@ namespace ScriptCs public interface IScriptEngine { string BaseDirectory { get; set; } - object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + ScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index f8f67000..685a8f61 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -82,6 +82,7 @@ + diff --git a/src/ScriptCs.Core/ScriptResult.cs b/src/ScriptCs.Core/ScriptResult.cs new file mode 100644 index 00000000..10933f69 --- /dev/null +++ b/src/ScriptCs.Core/ScriptResult.cs @@ -0,0 +1,13 @@ +using System; + +namespace ScriptCs +{ + public class ScriptResult + { + public object ReturnValue { get; set; } + + public Exception ExecuteException { get; set; } + + public Exception CompileException { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs index f1043270..0a632339 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptDebuggerEngine.cs @@ -20,12 +20,23 @@ public RoslynScriptDebuggerEngine(IScriptHostFactory scriptHostFactory, ILog log this._logger = logger; } - protected override object Execute(string code, Session session) + protected override ScriptResult Execute(string code, Session session) { Guard.AgainstNullArgument("session", session); + var scriptResult = new ScriptResult(); + Submission submission = null; + _logger.Debug("Compiling submission"); - var submission = session.CompileSubmission(code); + try + { + submission = session.CompileSubmission(code); + } + catch (Exception compileException) + { + scriptResult.CompileException = compileException; + } + var exeBytes = new byte[0]; var pdbBytes = new byte[0]; var compileSuccess = false; @@ -61,21 +72,23 @@ protected override object Execute(string code, Session session) try { _logger.Debug("Invoking method."); - return method.Invoke(null, new[] { session }); + scriptResult.ReturnValue = method.Invoke(null, new[] { session }); } - catch (Exception e) + catch (Exception executeException) { + scriptResult.ExecuteException = executeException; _logger.Error("An error occurred when executing the scripts."); var message = string.Format( "Exception Message: {0} {1}Stack Trace:{2}", - e.InnerException.Message, + executeException.InnerException.Message, Environment.NewLine, - e.InnerException.StackTrace); + executeException.InnerException.StackTrace); throw new ScriptExecutionException(message); } } - return null; + + return scriptResult; } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index e011eb8d..6ae75a46 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using Common.Logging; @@ -28,7 +29,7 @@ public string BaseDirectory set { _scriptEngine.BaseDirectory = value; } } - public object Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) + public ScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession) { Guard.AgainstNullArgument("scriptPackSession", scriptPackSession); @@ -82,11 +83,28 @@ public object Execute(string code, string[] scriptArgs, IEnumerable refe return result; } - protected virtual object Execute(string code, Session session) + protected virtual ScriptResult Execute(string code, Session session) { Guard.AgainstNullArgument("session", session); - return session.Execute(code); + var result = new ScriptResult(); + try + { + var submission = session.CompileSubmission(code); + try + { + result.ReturnValue = submission.Execute(); + } + catch (Exception ex) + { + result.ExecuteException = ex; + } + } + catch (Exception ex) + { + result.CompileException = ex; + } + return result; } } } \ No newline at end of file diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index 21780bc6..fc013f64 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -23,10 +23,10 @@ public TestRoslynScriptEngine(IScriptHostFactory scriptHostFactory, ILog logger) public Session Session { get; set; } - protected override object Execute(string code, Session session) + protected override ScriptResult Execute(string code, Session session) { Session = session; - return null; + return new ScriptResult(); } } @@ -119,6 +119,132 @@ public void ShouldAddNewReferencesIfTheyAreProvided() ((SessionState)scriptPackSession.State[RoslynScriptEngine.SessionKey]).References.Count().ShouldEqual(1); } + + [Fact] + public void ShouldReturnAScriptResult() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = ""; + + var engine = CreateTestScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + Assert.IsType(result); + } + + [Fact] + public void ShouldReturnCompileExceptionIfCodeDoesNotCompile() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "this shold not compile"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.CompileException.ShouldNotBeNull(); + } + + [Fact] + public void ShouldNotReturnCompileExceptionIfCodeDoesCompile() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var theNumber = 42; //this should compile"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.CompileException.ShouldBeNull(); + } + + [Fact] + public void ShouldReturnExecuteExceptionIfCodeExecutionThrowsException() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "throw new System.Exception(); //this should throw an Exception"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ExecuteException.ShouldNotBeNull(); + } + + [Fact] + public void ShouldNotReturnExecuteExceptionIfCodeExecutionDoesNotThrowAnException() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var theNumber = 42; //this should not throw an Exception"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ExecuteException.ShouldBeNull(); + } + + [Fact] + public void ShouldReturnReturnValueIfCodeExecutionReturnsValue() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "\"Hello\" //this should return \"Hello\""; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ReturnValue.ShouldEqual("Hello"); + } + + [Fact] + public void ShouldNotReturnReturnValueIfCodeExecutionDoesNotReturnValue() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())).Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var theNumber = 42; //this should not return a value"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), scriptPackSession); + + result.ReturnValue.ShouldBeNull(); + } } } } \ No newline at end of file From b252dffdede54784aebe6573321eca0afa6e12cb Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 24 May 2013 13:12:22 +0200 Subject: [PATCH 041/993] Fixed wrong argument passed from CommandFactory to RestoreCommand. Fixes #298 --- src/ScriptCs/Command/CommandFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 0a540e5b..d08edacb 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -56,7 +56,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.Logger); var restoreCommand = new RestoreCommand( - args.Install, + args.ScriptName, _scriptServiceRoot.FileSystem, _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger); From 8fb34deaf73405da111162536c003fbc307064df Mon Sep 17 00:00:00 2001 From: lbargaoanu Date: Fri, 24 May 2013 16:03:51 +0300 Subject: [PATCH 042/993] Add logic to grab the delta of binaries if there are changes in the installed packages Fix for https://github.com/scriptcs/scriptcs/issues/2 --- .../IInstallationProvider.cs | 1 + .../NugetInstallationProvider.cs | 35 +++++++++++-------- src/ScriptCs.Core/Package/PackageInstaller.cs | 16 +++++++-- .../PackageInstallerTests.cs | 21 +++++++++++ 4 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs index 525de7f9..5d8fe5c9 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs @@ -6,6 +6,7 @@ namespace ScriptCs.Package.InstallationProvider public interface IInstallationProvider { IEnumerable GetRepositorySources(string path); + bool IsInstalled(IPackageReference packageId, bool allowPreRelease = false); bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 930554b7..1edb0dc8 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -12,6 +12,8 @@ public class NugetInstallationProvider : IInstallationProvider private readonly PackageManager _manager; private readonly IEnumerable _repositoryUrls; + private static readonly Version EmptyVersion = new Version(); + public NugetInstallationProvider(IFileSystem fileSystem) { Guard.AgainstNullArgument("fileSystem", fileSystem); @@ -51,34 +53,39 @@ public bool InstallPackage(IPackageReference packageId, bool allowPreRelease = f { Guard.AgainstNullArgument("packageId", packageId); - var useVersion = packageId.Version.CompareTo(new Version()) != 0; + var version = GetVersion(packageId); + var packageName = packageId.PackageId + " " + (version == null ? string.Empty : packageId.Version.ToString()); try { - if (useVersion) - { - _manager.InstallPackage(packageId.PackageId, - new SemanticVersion(packageId.Version, packageId.SpecialVersion), false, - allowPreRelease); - } - else + _manager.InstallPackage(packageId.PackageId, version, allowPrereleaseVersions: allowPreRelease, ignoreDependencies: false); + if(packageInstalled != null) { - _manager.InstallPackage(packageId.PackageId, null, false, allowPreRelease); + packageInstalled("Installed: " + packageName); } - - if (packageInstalled != null) - packageInstalled("Installed: " + packageId.PackageId + " " + (useVersion ? packageId.Version.ToString() : "")); - return true; } catch (Exception e) { if (packageInstalled != null) { - packageInstalled("Installation failed: " + packageId.PackageId + " " + (useVersion ? packageId.Version.ToString() : "")); + packageInstalled("Installation failed: " + packageName); packageInstalled(e.Message); } return false; } } + + private static SemanticVersion GetVersion(IPackageReference packageReference) + { + return packageReference.Version == EmptyVersion ? null : new SemanticVersion(packageReference.Version, packageReference.SpecialVersion); + } + + public bool IsInstalled(IPackageReference packageReference, bool allowPreRelease = false) + { + Guard.AgainstNullArgument("packageReference", packageReference); + + var version = GetVersion(packageReference); + return _manager.LocalRepository.FindPackage(packageReference.PackageId, version, allowPreRelease, allowUnlisted: false) != null; + } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/PackageInstaller.cs b/src/ScriptCs.Core/Package/PackageInstaller.cs index d751b925..0bfe646a 100644 --- a/src/ScriptCs.Core/Package/PackageInstaller.cs +++ b/src/ScriptCs.Core/Package/PackageInstaller.cs @@ -29,9 +29,19 @@ public void InstallPackages(IEnumerable packageIds, bool allo return; } - var successful = packageIds.Select(packageId => _installer.InstallPackage(packageId, allowPreRelease, packageInstalled)) - .Aggregate(true, (current, result) => current && result); - + bool successful = true; + foreach(var packageId in packageIds) + { + if(_installer.IsInstalled(packageId, allowPreRelease)) + { + continue; + } + if(!_installer.InstallPackage(packageId, allowPreRelease, packageInstalled)) + { + successful = false; + } + } + if (packageInstalled != null && packageIds.Count() > 1) { packageInstalled(successful ? "Installation successful." : "Installation unsuccessful."); diff --git a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs index dd18ab8a..1cebe925 100644 --- a/test/ScriptCs.Core.Tests/PackageInstallerTests.cs +++ b/test/ScriptCs.Core.Tests/PackageInstallerTests.cs @@ -90,6 +90,27 @@ public void ShouldShowSuccessIfNoneOfPackagesFail() callbacks.Count.ShouldEqual(1); callbacks.Count(x => x.EndsWith("successful.")).ShouldEqual(1); } + + [Fact] + public void ShouldNotInstallExistingPackages() + { + var callbacks = new List(); + var provider = new Mock(); + provider.Setup( + i => i.IsInstalled(It.Is(x => x.PackageId == "testId"), It.IsAny())) + .Returns(true); + + var references = new List { + new PackageReference("testId", VersionUtility.ParseFrameworkName("net40"), new Version("3.0")), + new PackageReference("testId2", VersionUtility.ParseFrameworkName("net40"), new Version("4.0")), + new PackageReference("testId3", VersionUtility.ParseFrameworkName("net40"), new Version("5.0")) + }; + + var installer = new PackageInstaller(provider.Object); + installer.InstallPackages(references); + + provider.Verify(i => i.InstallPackage(It.Is(x => x.PackageId == "testId"), It.IsAny(), It.IsAny>()), Times.Never()); + } } } } \ No newline at end of file From f9107cf40f4674739cdc1f84402840635424441e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:13:40 +0200 Subject: [PATCH 043/993] Removed RestoreCommand --- src/ScriptCs/Command/CommandFactory.cs | 29 +---- src/ScriptCs/Command/ICommand.cs | 2 - src/ScriptCs/Command/RestoreCommand.cs | 72 ----------- src/ScriptCs/ScriptCs.csproj | 1 - src/ScriptCs/ScriptCsArgs.cs | 4 - test/ScriptCs.Tests/CommandFactoryTests.cs | 35 +----- test/ScriptCs.Tests/RestoreCommandTests.cs | 136 --------------------- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 - 8 files changed, 9 insertions(+), 271 deletions(-) delete mode 100644 src/ScriptCs/Command/RestoreCommand.cs delete mode 100644 test/ScriptCs.Tests/RestoreCommandTests.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d08edacb..d18eb06a 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -55,24 +55,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.PackageInstaller, _scriptServiceRoot.Logger); - var restoreCommand = new RestoreCommand( - args.ScriptName, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.Logger); - - return new CompositeCommand(installCommand, restoreCommand, executeCommand); - } - - if (args.Restore) - { - var restoreCommand = new RestoreCommand( - args.ScriptName, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.Logger); - - return new CompositeCommand(restoreCommand, executeCommand); + return new CompositeCommand(installCommand, executeCommand); } return executeCommand; @@ -88,22 +71,16 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.PackageInstaller, _scriptServiceRoot.Logger); - var restoreCommand = new RestoreCommand( - args.Install, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.Logger); - var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); if (!_scriptServiceRoot.FileSystem.FileExists(packageFile)) { var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); - return new CompositeCommand(installCommand, restoreCommand, saveCommand); + return new CompositeCommand(installCommand, saveCommand); } - return new CompositeCommand(installCommand, restoreCommand); + return installCommand; } if (args.Clean) diff --git a/src/ScriptCs/Command/ICommand.cs b/src/ScriptCs/Command/ICommand.cs index 41c55ea3..deef3623 100644 --- a/src/ScriptCs/Command/ICommand.cs +++ b/src/ScriptCs/Command/ICommand.cs @@ -6,8 +6,6 @@ public interface IScriptCommand : ICommand { string[] ScriptArgs { get; } } - public interface IRestoreCommand : ICommand { } - public interface ISaveCommand : ICommand { } public interface ICleanCommand : ICommand { } diff --git a/src/ScriptCs/Command/RestoreCommand.cs b/src/ScriptCs/Command/RestoreCommand.cs deleted file mode 100644 index 6f6b155b..00000000 --- a/src/ScriptCs/Command/RestoreCommand.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.IO; -using Common.Logging; - -namespace ScriptCs.Command -{ - internal class RestoreCommand : IRestoreCommand - { - private readonly string _scriptName; - private readonly IFileSystem _fileSystem; - private readonly IPackageAssemblyResolver _packageAssemblyResolver; - - private readonly ILog _logger; - - public RestoreCommand(string scriptName, IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, ILog logger) - { - _scriptName = scriptName; - _fileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; - _logger = logger; - } - - public CommandResult Execute() - { - _logger.Info("Copying assemblies to bin folder..."); - - var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); - var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); - - try - { - if (!_fileSystem.DirectoryExists(binFolder)) - _fileSystem.CreateDirectory(binFolder); - - var packages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - foreach (var package in packages) - { - CopyFile(package, binFolder); - } - - _logger.Info("Restore completed successfully."); - return CommandResult.Success; - } - catch (Exception e) - { - _logger.ErrorFormat("Restore failed: {0}.", e.Message); - return CommandResult.Error; - } - } - - private void CopyFile(string package, string binFolder) - { - var assemblyFileName = Path.GetFileName(package); - if (assemblyFileName == null) return; - - var destFile = Path.Combine(binFolder, assemblyFileName); - - var sourceFileLastWriteTime = _fileSystem.GetLastWriteTime(package); - var destFileLastWriteTime = _fileSystem.GetLastWriteTime(destFile); - - if (sourceFileLastWriteTime == destFileLastWriteTime) - { - _logger.InfoFormat("Skipped: {0}.", assemblyFileName); - return; - } - - _fileSystem.Copy(package, destFile, true); - - _logger.InfoFormat("Copied: {0}.", assemblyFileName); - } - } -} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 47286cee..b2605a4d 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -71,7 +71,6 @@ - diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index fd0440aa..0b75acee 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -34,10 +34,6 @@ public class ScriptCsArgs [ArgDescription("Installs and restores packages which are specified in packages.config")] public string Install { get; set; } - [ArgShortcut("restore")] - [ArgDescription("Restores installed packages, making them ready for using by the script")] - public bool Restore { get; set; } - [ArgShortcut("save")] [ArgDescription("Creates a packages.config file based on the packages directory")] public bool Save { get; set; } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 47bb68e7..a12b0857 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -48,16 +48,11 @@ public void ShouldInstallAndRestoreWhenInstallFlagIsOn() var factory = new CommandFactory(CreateRoot()); var result = factory.CreateCommand(args, new string[0]); - var compositeCommand = result as ICompositeCommand; - compositeCommand.ShouldNotBeNull(); - - compositeCommand.Commands.Count.ShouldEqual(2); - compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); + result.ShouldImplement(); } [Fact] - public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExists() + public void ShouldInstallAndSaveWhenInstallFlagIsOnAndNoPackagesFileExists() { var args = new ScriptCsArgs { @@ -72,10 +67,9 @@ public void ShouldInstallRestoreAndSaveWhenInstallFlagIsOnAndNoPackagesFileExist var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands.Count.ShouldEqual(2); compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); - compositeCommand.Commands[2].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] @@ -111,10 +105,9 @@ public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNo var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - compositeCommand.Commands.Count.ShouldEqual(3); + compositeCommand.Commands.Count.ShouldEqual(1); compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); - compositeCommand.Commands[2].ShouldImplement(); + compositeCommand.Commands[1].ShouldImplement(); } [Fact] @@ -133,22 +126,6 @@ public void ShouldExecuteWhenBothNameAndInstallArePassed() result.ShouldImplement(); } - [Fact] - public void ShouldRestoreWhenBothNameAndRestoreArePassed() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var factory = new CommandFactory(CreateRoot()); - var result = factory.CreateCommand(args, new string[0]); - - var compositeCommand = result as ICompositeCommand; - compositeCommand.ShouldNotBeNull(); - - compositeCommand.Commands.Count.ShouldEqual(2); - compositeCommand.Commands[0].ShouldImplement(); - compositeCommand.Commands[1].ShouldImplement(); - } - [Fact] public void ShouldSaveAndCleanWhenCleanFlagIsPassed() { diff --git a/test/ScriptCs.Tests/RestoreCommandTests.cs b/test/ScriptCs.Tests/RestoreCommandTests.cs deleted file mode 100644 index 7ee7559a..00000000 --- a/test/ScriptCs.Tests/RestoreCommandTests.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.IO; -using Common.Logging; -using Moq; -using ScriptCs.Command; -using ScriptCs.Package; -using Xunit; - -namespace ScriptCs.Tests -{ - public class RestoreCommandTests - { - public class TheExecuteMethod - { - [Fact] - public void ShouldNotCopyFilesInPathIfLastWriteTimeEqualsLastWriteTimeOfFileInBin() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - const string CurrentDirectory = @"C:\"; - - var sourceFilePath = Path.Combine(CurrentDirectory, "fileName.cs"); - var sourceWriteTime = new DateTime(2013, 3, 7); - - var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); - var destWriteTime = sourceWriteTime; - - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - - fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); - - resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.Copy(sourceFilePath, destFilePath, true), Times.Never()); - fs.Verify(x => x.GetLastWriteTime(sourceFilePath), Times.Once()); - fs.Verify(x => x.GetLastWriteTime(destFilePath), Times.Once()); - } - - [Fact] - public void ShouldCopyFilesInPathIfLastWriteTimeDiffersFromLastWriteTimeOfFileInBin() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - const string CurrentDirectory = @"C:\"; - - var sourceFilePath = Path.Combine(CurrentDirectory, "fileName.cs"); - var sourceWriteTime = new DateTime(2013, 3, 7); - - var destFilePath = Path.Combine(CurrentDirectory, "bin", "fileName.cs"); - var destWriteTime = new DateTime(2013, 2, 7); - - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - - fs.Setup(x => x.GetLastWriteTime(sourceFilePath)).Returns(sourceWriteTime).Verifiable(); - fs.Setup(x => x.GetLastWriteTime(destFilePath)).Returns(destWriteTime).Verifiable(); - - resolver.Setup(i => i.GetAssemblyNames(CurrentDirectory, It.IsAny>())).Returns(new[] { sourceFilePath }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.Copy(sourceFilePath, destFilePath, true), Times.Once()); - fs.Verify(x => x.GetLastWriteTime(sourceFilePath), Times.Once()); - fs.Verify(x => x.GetLastWriteTime(destFilePath), Times.Once()); - } - - [Fact] - public void ShouldCreateBinFolderIfItDoesNotExist() - { - var args = new ScriptCsArgs { Restore = true, ScriptName = "" }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - const string CurrentDirectory = @"C:\"; - const string BinFolder = @"C:\bin"; - - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - - var binFolderCreated = false; - - fs.Setup(x => x.DirectoryExists(BinFolder)).Returns(() => binFolderCreated).Verifiable(); - fs.Setup(x => x.CreateDirectory(BinFolder)).Callback(() => binFolderCreated = true).Verifiable(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.DirectoryExists(BinFolder), Times.AtLeastOnce()); - fs.Verify(x => x.CreateDirectory(BinFolder), Times.Once()); - } - } - } -} diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 97db7eeb..5b33244c 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -48,7 +48,6 @@ - From f85575727037cc5d10945fa6ae5ecbca81f561b2 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:14:49 +0200 Subject: [PATCH 044/993] Fixed failing test --- test/ScriptCs.Tests/CommandFactoryTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index a12b0857..cc8247dd 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -105,7 +105,7 @@ public void ShouldInstallAndExecuteWhenScriptNameIsPassedAndPackagesFolderDoesNo var compositeCommand = result as ICompositeCommand; compositeCommand.ShouldNotBeNull(); - compositeCommand.Commands.Count.ShouldEqual(1); + compositeCommand.Commands.Count.ShouldEqual(2); compositeCommand.Commands[0].ShouldImplement(); compositeCommand.Commands[1].ShouldImplement(); } From f1dccbfecff58ca90453d4d5197c7fcb17df37aa Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:18:25 +0200 Subject: [PATCH 045/993] Removed bin folder logic in CleanCommand --- src/ScriptCs/Command/CleanCommand.cs | 43 +----------- src/ScriptCs/Command/CommandFactory.cs | 1 - test/ScriptCs.Tests/CleanCommandTests.cs | 87 +----------------------- 3 files changed, 4 insertions(+), 127 deletions(-) diff --git a/src/ScriptCs/Command/CleanCommand.cs b/src/ScriptCs/Command/CleanCommand.cs index 62b62173..dcbc4d22 100644 --- a/src/ScriptCs/Command/CleanCommand.cs +++ b/src/ScriptCs/Command/CleanCommand.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using Common.Logging; namespace ScriptCs.Command @@ -8,17 +7,15 @@ namespace ScriptCs.Command internal class CleanCommand : ICleanCommand { private readonly string _scriptName; + private readonly IFileSystem _fileSystem; - private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly ILog _logger; - public CleanCommand(string scriptName, - IFileSystem fileSystem, - IPackageAssemblyResolver packageAssemblyResolver, ILog logger) + public CleanCommand(string scriptName, IFileSystem fileSystem, ILog logger) { _scriptName = scriptName; _fileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; _logger = logger; } @@ -29,32 +26,11 @@ public CommandResult Execute() var workingDirectory = _fileSystem.GetWorkingDirectory(_scriptName); _logger.TraceFormat("Working directory: {0}", workingDirectory); - var binFolder = Path.Combine(workingDirectory, Constants.BinFolder); - _logger.TraceFormat("Bin folder: {0}", binFolder); - var packageFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); _logger.TraceFormat("Packages folder: {0}", packageFolder); try { - if (_fileSystem.DirectoryExists(binFolder)) - { - var packages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - - foreach (var package in packages) - { - _logger.DebugFormat("Deleting file: {0}", package); - DeleteFile(package, binFolder); - } - - var remaining = _fileSystem.EnumerateFiles(binFolder, "*.*").Any(); - if (!remaining) - { - _logger.DebugFormat("Deleting bin directory: {0}", binFolder); - _fileSystem.DeleteDirectory(binFolder); - } - } - if (_fileSystem.DirectoryExists(packageFolder)) { _logger.DebugFormat("Deleting package directory: {0}", packageFolder); @@ -70,18 +46,5 @@ public CommandResult Execute() return CommandResult.Error; } } - - private void DeleteFile(string package, string binFolder) - { - var assemblyFileName = Path.GetFileName(package); - if (assemblyFileName == null) return; - - var destFile = Path.Combine(binFolder, assemblyFileName); - - if (_fileSystem.FileExists(destFile)) - { - _fileSystem.FileDelete(destFile); - } - } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d18eb06a..08326c98 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -90,7 +90,6 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var cleanCommand = new CleanCommand( args.ScriptName, _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger); return new CompositeCommand(saveCommand, cleanCommand); diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index cae08c14..b4526fcd 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,5 +1,4 @@ -using System; -using Common.Logging; +using Common.Logging; using Moq; using ScriptCs.Command; using ScriptCs.Package; @@ -38,90 +37,6 @@ public void ShouldDeletePackagesFolder() fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } - - [Fact] - public void ShouldDeleteBinFolder() - { - var args = new ScriptCsArgs { Clean = true }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - } - - [Fact] - public void ShouldNotDeleteBinFolderIfDllsAreLeft() - { - var args = new ScriptCsArgs { Clean = true }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); - fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); - } - - [Fact] - public void ShouldDeleteAllFilesResolvedFromPackages() - { - var args = new ScriptCsArgs { Clean = true }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); - resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); - } } } } From 1b3ad3ac36ebd4accd8d19a0db1f136e96a9bce3 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 14:22:05 +0200 Subject: [PATCH 046/993] Added SearchOption parameter to FileSystem.EnumerateFiles --- src/ScriptCs.Core/FileSystem.cs | 4 ++-- src/ScriptCs.Core/IFileSystem.cs | 2 +- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index d8e0bb25..53de46b8 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -6,9 +6,9 @@ namespace ScriptCs { public class FileSystem : IFileSystem { - public IEnumerable EnumerateFiles(string dir, string searchPattern) + public IEnumerable EnumerateFiles(string dir, string searchPattern, SearchOption searchOption = SearchOption.AllDirectories) { - return Directory.EnumerateFiles(dir, searchPattern, SearchOption.AllDirectories); + return Directory.EnumerateFiles(dir, searchPattern, searchOption); } public void Copy(string source, string dest, bool overwrite) diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 253be305..e08db619 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -6,7 +6,7 @@ namespace ScriptCs { public interface IFileSystem { - IEnumerable EnumerateFiles(string dir, string search); + IEnumerable EnumerateFiles(string dir, string search, SearchOption searchOption = SearchOption.AllDirectories); void Copy(string source, string dest, bool overwrite); diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 453393b1..5c97be8a 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -92,7 +92,7 @@ public void NonManagedAssembliesAreExcluded() var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { + fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(new[] { "managed.dll", nonManaged }); From ecb33fb7ec4eb748ee01e34beee8cd5595138793 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 21:19:22 +0200 Subject: [PATCH 047/993] Changed registering of MEF composable part catalog --- src/ScriptCs/CompositionRoot.cs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 94d36a7f..3a0faf91 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -1,6 +1,8 @@ using System; using System.ComponentModel.Composition.Hosting; using System.IO; +using System.Linq; + using Autofac; using Autofac.Integration.Mef; using Common.Logging; @@ -66,16 +68,20 @@ public void Initialize() builder.RegisterType().As(); - if (_shouldInitDrirectoryCatalog) + if (_shouldInitDrirectoryCatalog) { - var scriptPath = Path.Combine(Environment.CurrentDirectory, "bin"); - if (Directory.Exists(scriptPath)) - { - var catalog = new DirectoryCatalog(scriptPath); - builder.RegisterComposablePartCatalog(catalog); - } + var directory = Environment.CurrentDirectory; + + var directoryCatalogs = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) + .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)) + .Select(Path.GetDirectoryName).Distinct() + .Select(x => new DirectoryCatalog(x)); + + builder.RegisterComposablePartCatalog(new AggregateCatalog(directoryCatalogs)); } + _container = builder.Build(); + _scriptServiceRoot = _container.Resolve(); } From 624c6bc53913dddb3268f027a19cf304f2bc05d9 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 21:20:20 +0200 Subject: [PATCH 048/993] Added common base class for ExecuteScript- and ExecuteReplCommand --- src/ScriptCs/Command/CommandFactory.cs | 11 ++- src/ScriptCs/Command/ExecuteReplCommand.cs | 81 +++++-------------- src/ScriptCs/Command/ExecuteScriptCommand.cs | 57 ++----------- src/ScriptCs/Command/ScriptCommand.cs | 74 +++++++++++++++++ src/ScriptCs/ScriptCs.csproj | 1 + .../ExecuteScriptCommandTests.cs | 32 -------- 6 files changed, 108 insertions(+), 148 deletions(-) create mode 100644 src/ScriptCs/Command/ScriptCommand.cs diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 08326c98..d95970ef 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,9 +23,15 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Repl) { var replCommand = new ExecuteReplCommand( - _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, + _scriptServiceRoot.FileSystem, + _scriptServiceRoot.ScriptPackResolver, + _scriptServiceRoot.PackageAssemblyResolver, + _scriptServiceRoot.Engine, + _scriptServiceRoot.FilePreProcessor, + _scriptServiceRoot.Logger, + _scriptServiceRoot.Console, _scriptServiceRoot.AssemblyName); + return replCommand; } @@ -37,6 +43,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, + _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger, _scriptServiceRoot.AssemblyName); diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 76303812..62538c4e 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -1,62 +1,52 @@ using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + using Common.Logging; -using System.Reflection; namespace ScriptCs.Command { - internal class ExecuteReplCommand : IScriptCommand + internal class ExecuteReplCommand : ScriptCommand { - private readonly IFileSystem _fileSystem; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IScriptEngine _scriptEngine; private readonly IFilePreProcessor _filePreProcessor; - private readonly IAssemblyName _assemblyName; - - private readonly ILog _logger; + private readonly IScriptEngine _scriptEngine; private readonly IConsole _console; - public string[] ScriptArgs { get; private set; } - public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, + IPackageAssemblyResolver packageAssemblyResolver, IScriptEngine scriptEngine, IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName - ) + IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) { - _fileSystem = fileSystem; _scriptPackResolver = scriptPackResolver; _scriptEngine = scriptEngine; _filePreProcessor = filePreProcessor; - _logger = logger; _console = console; - _assemblyName = assemblyName; } - public CommandResult Execute() + public override CommandResult Execute() { _console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); - var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); - repl.Initialize(GetAssemblyPaths(_fileSystem.CurrentDirectory), _scriptPackResolver.GetPacks()); + var repl = new Repl(FileSystem, _scriptEngine, Logger, _console, _filePreProcessor); + + var assemblies = GetAssemblyPaths(FileSystem.CurrentDirectory); + var scriptPacks = _scriptPackResolver.GetPacks(); + + repl.Initialize(assemblies, scriptPacks); + try { - while (ExecuteLine(repl)) - { - } + while (ExecuteLine(repl)) { } } catch (Exception ex) { - _logger.Error(ex.Message); + Logger.Error(ex.Message); return CommandResult.Error; } + repl.Terminate(); return CommandResult.Success; } @@ -64,47 +54,12 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { _console.Write("> "); + var line = _console.ReadLine(); - if (line == "") - return false; + if (line == string.Empty) return false; repl.Execute(line); return true; } - - - private IEnumerable GetAssemblyPaths(string workingDirectory) - { - var binFolder = Path.Combine(workingDirectory, "bin"); - - if (!_fileSystem.DirectoryExists(binFolder)) - _fileSystem.CreateDirectory(binFolder); - - var assemblyPaths = - _fileSystem.EnumerateFiles(binFolder, "*.dll") - .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly) - .ToList(); - - foreach (var path in assemblyPaths.Select(Path.GetFileName)) - { - _logger.DebugFormat("Found assembly reference: {0}", path); - } - - return assemblyPaths; - } - - private bool IsManagedAssembly(string path) - { - try - { - _assemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return false; - } - return true; - } } } diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 6d7b1d38..3380eb41 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -1,48 +1,37 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using Common.Logging; -using System.Reflection; namespace ScriptCs.Command { - internal class ExecuteScriptCommand : IScriptCommand + internal class ExecuteScriptCommand : ScriptCommand { private readonly string _script; - private readonly IFileSystem _fileSystem; private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; - private readonly IAssemblyName _assemblyName; - - private readonly ILog _logger; public ExecuteScriptCommand(string script, string[] scriptArgs, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, + IPackageAssemblyResolver packageAssemblyResolver, ILog logger, - IAssemblyName assemblyName) + IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) { _script = script; ScriptArgs = scriptArgs; - _fileSystem = fileSystem; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; - _logger = logger; - _assemblyName = assemblyName; } - public string[] ScriptArgs { get; private set; } - - public CommandResult Execute() + public override CommandResult Execute() { try { var assemblyPaths = Enumerable.Empty(); - var workingDirectory = _fileSystem.GetWorkingDirectory(_script); + var workingDirectory = FileSystem.GetWorkingDirectory(_script); if (workingDirectory != null) { assemblyPaths = GetAssemblyPaths(workingDirectory); @@ -53,43 +42,9 @@ public CommandResult Execute() } catch (Exception ex) { - _logger.Error(ex.Message); + Logger.Error(ex.Message); return CommandResult.Error; } } - - private IEnumerable GetAssemblyPaths(string workingDirectory) - { - var binFolder = Path.Combine(workingDirectory, "bin"); - - if (!_fileSystem.DirectoryExists(binFolder)) - _fileSystem.CreateDirectory(binFolder); - - var assemblyPaths = - _fileSystem.EnumerateFiles(binFolder, "*.dll") - .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly) - .ToList(); - - foreach (var path in assemblyPaths.Select(Path.GetFileName)) - { - _logger.DebugFormat("Found assembly reference: {0}", path); - } - - return assemblyPaths; - } - - private bool IsManagedAssembly(string path) - { - try - { - _assemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return false; - } - return true; - } } } diff --git a/src/ScriptCs/Command/ScriptCommand.cs b/src/ScriptCs/Command/ScriptCommand.cs new file mode 100644 index 00000000..32fef83a --- /dev/null +++ b/src/ScriptCs/Command/ScriptCommand.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +using Common.Logging; + +namespace ScriptCs.Command +{ + public abstract class ScriptCommand : IScriptCommand + { + protected readonly IFileSystem FileSystem; + + protected readonly ILog Logger; + + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + private readonly IAssemblyName _assemblyName; + + protected ScriptCommand( + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IAssemblyName assemblyName, + ILog logger) + { + FileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; + _assemblyName = assemblyName; + Logger = logger; + } + + public string[] ScriptArgs { get; protected set; } + + public abstract CommandResult Execute(); + + protected IEnumerable GetAssemblyPaths(string workingDirectory) + { + var assemblyPaths = new List(); + + var packagesFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); + if (FileSystem.DirectoryExists(packagesFolder)) + { + var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); + assemblyPaths.AddRange(packageAssemblies); + } + + var looseAssemblies = FileSystem.EnumerateFiles(workingDirectory, "*.dll", SearchOption.TopDirectoryOnly) + .Union(FileSystem.EnumerateFiles(workingDirectory, "*.exe", SearchOption.TopDirectoryOnly)) + .Where(IsManagedAssembly); + + assemblyPaths.AddRange(looseAssemblies); + + foreach (var path in assemblyPaths) + { + Logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(path)); + } + + return assemblyPaths; + } + + private bool IsManagedAssembly(string path) + { + try + { + _assemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index b2605a4d..a3cb5465 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -66,6 +66,7 @@ + diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 5c97be8a..694a1c1c 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -46,38 +46,6 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny(), It.IsAny>(), It.IsAny>()), Times.Once()); } - [Fact] - public void ShouldCreateMissingBinFolder() - { - const string WorkingDirectory = @"C:\"; - - var binFolder = Path.Combine(WorkingDirectory, "bin"); - - var args = new ScriptCsArgs { ScriptName = "test.csx" }; - - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); - fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(x => x.CreateDirectory(binFolder), Times.Once()); - } - [Fact] public void NonManagedAssembliesAreExcluded() { From 83f21b5d38dad943286873bf94de81d143e65b5e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 26 May 2013 21:23:33 +0200 Subject: [PATCH 049/993] Added variable --- src/ScriptCs/CompositionRoot.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 3a0faf91..dbb50cad 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -72,8 +72,10 @@ public void Initialize() { var directory = Environment.CurrentDirectory; - var directoryCatalogs = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) - .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)) + var assemblies = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) + .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)); + + var directoryCatalogs = assemblies .Select(Path.GetDirectoryName).Distinct() .Select(x => new DirectoryCatalog(x)); From 13a17497dd8d2c881aa1535ccf1808b74f57ed6f Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 27 May 2013 12:24:31 +0100 Subject: [PATCH 050/993] Fixes #296 - Assembly reference missing with .. * Wrote unit test to prove failing path resolution * Implemented change suggested by @khellang (Use `GetFullPath`) --- src/ScriptCs.Core/FileSystem.cs | 2 +- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index b60b5bad..9ad83afa 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -88,7 +88,7 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { - return IsPathRooted(path) ? Path.GetDirectoryName(path) : CurrentDirectory; + return GetFullPath(path); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index a9eecca7..dc9065f2 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -155,6 +155,14 @@ public void DoNotChangePathIfAbsolute() preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } + [Fact] + public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() + { + var fileSystem = new FileSystem(); + + Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script")), fileSystem.GetWorkingDirectory(@"..\my_script")); + } + [Fact] public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() { From 14348b4b36de4160aab3bc1bdb1b01ec0037dee2 Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 27 May 2013 12:54:27 +0100 Subject: [PATCH 051/993] Refs #296 - Ensure that the method returns a directory path Ensure that the method returns a directory path and not a file path. Requires that the path have a trailing slash to indicate that it is a directory. Not really sure how to avoid this? --- src/ScriptCs.Core/FileSystem.cs | 4 +++- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 9ad83afa..bc503b7f 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -88,7 +88,9 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { - return GetFullPath(path); + var realPath = GetFullPath(path); + + return Path.GetFileName(realPath) == string.Empty ? realPath : Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index dc9065f2..1b26fbf3 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -160,7 +160,7 @@ public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() { var fileSystem = new FileSystem(); - Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script")), fileSystem.GetWorkingDirectory(@"..\my_script")); + Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script\")), fileSystem.GetWorkingDirectory(@"..\my_script\")); } [Fact] From c8df9c99d928f61849d2cdc2b0c93cb9d3f9b66d Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 17:03:07 +0200 Subject: [PATCH 052/993] Removed ScriptCommand base class and renamed IAssemblyName to IAssemblyResolver --- src/ScriptCs.Core/AssemblyName.cs | 10 --- src/ScriptCs.Core/AssemblyResolver.cs | 65 ++++++++++++++++ src/ScriptCs.Core/IAssemblyName.cs | 7 -- src/ScriptCs.Core/IAssemblyResolver.cs | 9 +++ src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +- src/ScriptCs/Command/CommandFactory.cs | 6 +- src/ScriptCs/Command/ExecuteReplCommand.cs | 28 +++++-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 30 +++++--- src/ScriptCs/Command/ScriptCommand.cs | 74 ------------------- src/ScriptCs/CompositionRoot.cs | 2 +- src/ScriptCs/ScriptCs.csproj | 1 - src/ScriptCs/ScriptServiceRoot.cs | 6 +- test/ScriptCs.Tests/CleanCommandTests.cs | 2 +- test/ScriptCs.Tests/CommandFactoryTests.cs | 2 +- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 6 +- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 18 files changed, 132 insertions(+), 128 deletions(-) delete mode 100644 src/ScriptCs.Core/AssemblyName.cs create mode 100644 src/ScriptCs.Core/AssemblyResolver.cs delete mode 100644 src/ScriptCs.Core/IAssemblyName.cs create mode 100644 src/ScriptCs.Core/IAssemblyResolver.cs delete mode 100644 src/ScriptCs/Command/ScriptCommand.cs diff --git a/src/ScriptCs.Core/AssemblyName.cs b/src/ScriptCs.Core/AssemblyName.cs deleted file mode 100644 index ffaea2b5..00000000 --- a/src/ScriptCs.Core/AssemblyName.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ScriptCs -{ - public class AssemblyName : IAssemblyName - { - public System.Reflection.AssemblyName GetAssemblyName(string path) - { - return System.Reflection.AssemblyName.GetAssemblyName(path); - } - } -} diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs new file mode 100644 index 00000000..80f42471 --- /dev/null +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +using Common.Logging; + +namespace ScriptCs +{ + public class AssemblyResolver : IAssemblyResolver + { + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + + private readonly IFileSystem _fileSystem; + + private readonly ILog _logger; + + public AssemblyResolver(IPackageAssemblyResolver packageAssemblyResolver, IFileSystem fileSystem, ILog logger) + { + _packageAssemblyResolver = packageAssemblyResolver; + _fileSystem = fileSystem; + _logger = logger; + } + + public IEnumerable GetAssemblyPaths(string path) + { + var assemblyPaths = new List(); + + var packagesFolder = Path.Combine(path, Constants.PackagesFolder); + + if (_fileSystem.DirectoryExists(packagesFolder)) + { + var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(path); + assemblyPaths.AddRange(packageAssemblies); + } + + var looseAssemblies = _fileSystem.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly) + .Union(_fileSystem.EnumerateFiles(path, "*.exe", SearchOption.TopDirectoryOnly)) + .Where(IsManagedAssembly); + + assemblyPaths.AddRange(looseAssemblies); + + foreach (var assemblyPath in assemblyPaths) + { + _logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(assemblyPath)); + } + + return assemblyPaths; + } + + private static bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + } + catch (BadImageFormatException) + { + return false; + } + return true; + } + } +} diff --git a/src/ScriptCs.Core/IAssemblyName.cs b/src/ScriptCs.Core/IAssemblyName.cs deleted file mode 100644 index 3d2d9dd8..00000000 --- a/src/ScriptCs.Core/IAssemblyName.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptCs -{ - public interface IAssemblyName - { - System.Reflection.AssemblyName GetAssemblyName(string path); - } -} diff --git a/src/ScriptCs.Core/IAssemblyResolver.cs b/src/ScriptCs.Core/IAssemblyResolver.cs new file mode 100644 index 00000000..04bc3338 --- /dev/null +++ b/src/ScriptCs.Core/IAssemblyResolver.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public interface IAssemblyResolver + { + IEnumerable GetAssemblyPaths(string path); + } +} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 6d370643..359abae1 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -42,7 +42,7 @@ - + @@ -56,7 +56,7 @@ - + diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index d95970ef..f322affb 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -25,12 +25,11 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var replCommand = new ExecuteReplCommand( _scriptServiceRoot.FileSystem, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Engine, _scriptServiceRoot.FilePreProcessor, _scriptServiceRoot.Logger, _scriptServiceRoot.Console, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.AssemblyResolver); return replCommand; } @@ -43,9 +42,8 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServiceRoot.FileSystem, _scriptServiceRoot.Executor, _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.PackageAssemblyResolver, _scriptServiceRoot.Logger, - _scriptServiceRoot.AssemblyName); + _scriptServiceRoot.AssemblyResolver); var fileSystem = _scriptServiceRoot.FileSystem; var currentDirectory = fileSystem.CurrentDirectory; diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 8efb94d7..95d5d3ed 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -5,35 +5,49 @@ namespace ScriptCs.Command { - internal class ExecuteReplCommand : ScriptCommand + internal class ExecuteReplCommand : IScriptCommand { private readonly IScriptPackResolver _scriptPackResolver; + + private readonly IAssemblyResolver _assemblyResolver; + private readonly IFilePreProcessor _filePreProcessor; + private readonly IScriptEngine _scriptEngine; + + private readonly IFileSystem _fileSystem; + private readonly IConsole _console; + private readonly ILog _logger; + public ExecuteReplCommand( IFileSystem fileSystem, IScriptPackResolver scriptPackResolver, - IPackageAssemblyResolver packageAssemblyResolver, IScriptEngine scriptEngine, IFilePreProcessor filePreProcessor, ILog logger, IConsole console, - IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) + IAssemblyResolver assemblyResolver) { + _fileSystem = fileSystem; _scriptPackResolver = scriptPackResolver; _scriptEngine = scriptEngine; _filePreProcessor = filePreProcessor; + _logger = logger; _console = console; + _assemblyResolver = assemblyResolver; } - public override CommandResult Execute() + public string[] ScriptArgs { get; private set; } + + public CommandResult Execute() { _console.WriteLine("scriptcs (ctrl-c or blank to exit)\r\n"); - var repl = new Repl(FileSystem, _scriptEngine, Logger, _console, _filePreProcessor); + var repl = new Repl(_fileSystem, _scriptEngine, _logger, _console, _filePreProcessor); - var assemblies = GetAssemblyPaths(FileSystem.CurrentDirectory); + var workingDirectory = _fileSystem.CurrentDirectory; + var assemblies = _assemblyResolver.GetAssemblyPaths(workingDirectory); var scriptPacks = _scriptPackResolver.GetPacks(); repl.Initialize(assemblies, scriptPacks); @@ -44,7 +58,7 @@ public override CommandResult Execute() } catch (Exception ex) { - Logger.Error(ex.Message); + _logger.Error(ex.Message); return CommandResult.Error; } diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 298e0f51..8bff52b7 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -4,37 +4,49 @@ namespace ScriptCs.Command { - internal class ExecuteScriptCommand : ScriptCommand + internal class ExecuteScriptCommand : IScriptCommand { - private readonly string _script; - private readonly IScriptExecutor _scriptExecutor; private readonly IScriptPackResolver _scriptPackResolver; + private readonly IAssemblyResolver _assemblyResolver; + + private readonly IScriptExecutor _scriptExecutor; + + private readonly IFileSystem _fileSystem; + + private readonly string _script; + + private readonly ILog _logger; + public ExecuteScriptCommand(string script, string[] scriptArgs, IFileSystem fileSystem, IScriptExecutor scriptExecutor, IScriptPackResolver scriptPackResolver, - IPackageAssemblyResolver packageAssemblyResolver, ILog logger, - IAssemblyName assemblyName) : base(fileSystem, packageAssemblyResolver, assemblyName, logger) + IAssemblyResolver assemblyResolver) { _script = script; + _fileSystem = fileSystem; ScriptArgs = scriptArgs; _scriptExecutor = scriptExecutor; _scriptPackResolver = scriptPackResolver; + _logger = logger; + _assemblyResolver = assemblyResolver; } - public override CommandResult Execute() + public string[] ScriptArgs { get; private set; } + + public CommandResult Execute() { try { var assemblyPaths = Enumerable.Empty(); - var workingDirectory = FileSystem.GetWorkingDirectory(_script); + var workingDirectory = _fileSystem.GetWorkingDirectory(_script); if (workingDirectory != null) { - assemblyPaths = GetAssemblyPaths(workingDirectory); + assemblyPaths = _assemblyResolver.GetAssemblyPaths(workingDirectory); } _scriptExecutor.Initialize(assemblyPaths, _scriptPackResolver.GetPacks()); _scriptExecutor.Execute(_script, ScriptArgs); @@ -44,7 +56,7 @@ public override CommandResult Execute() } catch (Exception ex) { - Logger.Error(ex.Message); + _logger.Error(ex.Message); return CommandResult.Error; } } diff --git a/src/ScriptCs/Command/ScriptCommand.cs b/src/ScriptCs/Command/ScriptCommand.cs deleted file mode 100644 index 32fef83a..00000000 --- a/src/ScriptCs/Command/ScriptCommand.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using Common.Logging; - -namespace ScriptCs.Command -{ - public abstract class ScriptCommand : IScriptCommand - { - protected readonly IFileSystem FileSystem; - - protected readonly ILog Logger; - - private readonly IPackageAssemblyResolver _packageAssemblyResolver; - - private readonly IAssemblyName _assemblyName; - - protected ScriptCommand( - IFileSystem fileSystem, - IPackageAssemblyResolver packageAssemblyResolver, - IAssemblyName assemblyName, - ILog logger) - { - FileSystem = fileSystem; - _packageAssemblyResolver = packageAssemblyResolver; - _assemblyName = assemblyName; - Logger = logger; - } - - public string[] ScriptArgs { get; protected set; } - - public abstract CommandResult Execute(); - - protected IEnumerable GetAssemblyPaths(string workingDirectory) - { - var assemblyPaths = new List(); - - var packagesFolder = Path.Combine(workingDirectory, Constants.PackagesFolder); - if (FileSystem.DirectoryExists(packagesFolder)) - { - var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - assemblyPaths.AddRange(packageAssemblies); - } - - var looseAssemblies = FileSystem.EnumerateFiles(workingDirectory, "*.dll", SearchOption.TopDirectoryOnly) - .Union(FileSystem.EnumerateFiles(workingDirectory, "*.exe", SearchOption.TopDirectoryOnly)) - .Where(IsManagedAssembly); - - assemblyPaths.AddRange(looseAssemblies); - - foreach (var path in assemblyPaths) - { - Logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(path)); - } - - return assemblyPaths; - } - - private bool IsManagedAssembly(string path) - { - try - { - _assemblyName.GetAssemblyName(path); - } - catch (BadImageFormatException) - { - return false; - } - return true; - } - } -} \ No newline at end of file diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index dbb50cad..b883d53c 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -50,7 +50,7 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (AssemblyName) + typeof (AssemblyResolver) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ad33743f..4f413311 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -63,7 +63,6 @@ - diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs/ScriptServiceRoot.cs index ac2c90e7..d8d665bb 100644 --- a/src/ScriptCs/ScriptServiceRoot.cs +++ b/src/ScriptCs/ScriptServiceRoot.cs @@ -15,7 +15,7 @@ public ScriptServiceRoot( IScriptPackResolver scriptPackResolver, IPackageInstaller packageInstaller, ILog logger, - IAssemblyName assemblyName, + IAssemblyResolver assemblyResolver, IConsole console = null) { FileSystem = fileSystem; @@ -27,7 +27,7 @@ public ScriptServiceRoot( PackageInstaller = packageInstaller; Logger = logger; Console = console; - AssemblyName = assemblyName; + AssemblyResolver = assemblyResolver; } public IFileSystem FileSystem { get; private set; } @@ -39,6 +39,6 @@ public ScriptServiceRoot( public IScriptEngine Engine { get; private set; } public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } - public IAssemblyName AssemblyName { get; private set; } + public IAssemblyResolver AssemblyResolver { get; private set; } } } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index b4526fcd..62553def 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -23,7 +23,7 @@ public void ShouldDeletePackagesFolder() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index cc8247dd..353d9030 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -29,7 +29,7 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index da9a7dd1..d86e3ed0 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -36,7 +36,7 @@ public void ShouldPromptForInput() Mock.Of(), Mock.Of(), Mock.Of(), - Mock.Of(), + Mock.Of(), console); var commandFactory = new CommandFactory(root); diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c2fa5d2f..cd35d1d0 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -6,7 +6,6 @@ using ScriptCs.Contracts; using ScriptCs.Package; using Xunit; -using System; using System.Linq; namespace ScriptCs.Tests @@ -35,7 +34,7 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -74,8 +73,7 @@ public void NonManagedAssembliesAreExcluded() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index 13c9ebbc..c1e4efaa 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -37,7 +37,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -71,7 +71,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index bbc7f11e..8546f5e8 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -42,7 +42,7 @@ public void VersionCommandShouldOutputVersion() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); From 7540fc357673db75604a7e1f54d3e225f26f3d6a Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 18:02:58 +0200 Subject: [PATCH 053/993] Added ScriptManifest, InstallCommand writes the manifest, while AssemblyResolver reads it. --- src/ScriptCs.Core/AssemblyResolver.cs | 52 ++++++++++++++++---------- src/ScriptCs.Core/Constants.cs | 2 +- src/ScriptCs.Core/FileSystem.cs | 5 +++ src/ScriptCs.Core/IFileSystem.cs | 2 + src/ScriptCs.Core/ScriptCs.Core.csproj | 1 + src/ScriptCs.Core/ScriptManifest.cs | 14 +++++++ src/ScriptCs/Command/InstallCommand.cs | 22 +++++++++++ src/ScriptCs/ScriptCs.csproj | 4 ++ 8 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/ScriptCs.Core/ScriptManifest.cs diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 80f42471..3a44186f 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -6,41 +6,31 @@ using Common.Logging; +using ServiceStack.Text; + namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { - private readonly IPackageAssemblyResolver _packageAssemblyResolver; - private readonly IFileSystem _fileSystem; private readonly ILog _logger; - public AssemblyResolver(IPackageAssemblyResolver packageAssemblyResolver, IFileSystem fileSystem, ILog logger) + public AssemblyResolver(IFileSystem fileSystem, ILog logger) { - _packageAssemblyResolver = packageAssemblyResolver; _fileSystem = fileSystem; _logger = logger; } public IEnumerable GetAssemblyPaths(string path) { - var assemblyPaths = new List(); - - var packagesFolder = Path.Combine(path, Constants.PackagesFolder); + Guard.AgainstNullArgument("path", path); - if (_fileSystem.DirectoryExists(packagesFolder)) - { - var packageAssemblies = _packageAssemblyResolver.GetAssemblyNames(path); - assemblyPaths.AddRange(packageAssemblies); - } - - var looseAssemblies = _fileSystem.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly) - .Union(_fileSystem.EnumerateFiles(path, "*.exe", SearchOption.TopDirectoryOnly)) - .Where(IsManagedAssembly); - - assemblyPaths.AddRange(looseAssemblies); + var manifestAssemblies = GetManifestAssemblies(path); + var looseAssemblies = GetLooseAssemblies(path); + var assemblyPaths = manifestAssemblies.Union(looseAssemblies).ToList(); + foreach (var assemblyPath in assemblyPaths) { _logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(assemblyPath)); @@ -49,17 +39,41 @@ public IEnumerable GetAssemblyPaths(string path) return assemblyPaths; } + private IEnumerable GetLooseAssemblies(string path) + { + var binFolder = Path.Combine(path, Constants.BinFolder); + if (!_fileSystem.DirectoryExists(binFolder)) + return Enumerable.Empty(); + + var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") + .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) + .Where(IsManagedAssembly); + + return looseAssemblies; + } + + private IEnumerable GetManifestAssemblies(string path) + { + var manifestPath = Path.Combine(path, Constants.ManifestFile); + if (!_fileSystem.FileExists(manifestPath)) + return Enumerable.Empty(); + + var manifest = _fileSystem.ReadFile(manifestPath).FromJson(); + + return manifest.PackageAssemblies; + } + private static bool IsManagedAssembly(string path) { try { AssemblyName.GetAssemblyName(path); + return true; } catch (BadImageFormatException) { return false; } - return true; } } } diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 62a745b0..3780943d 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -7,7 +7,7 @@ public static class Constants public const string PackagesFolder = "packages"; public const string BinFolder = "bin"; public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; - + public const string ManifestFile = "manifest.json"; public const string DebugContractName = "Debug"; public const string RunContractName = "Run"; } diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 3a9299cf..81fb13b9 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -81,6 +81,11 @@ public IEnumerable SplitLines(string value) return value.Split(new[] { NewLine }, StringSplitOptions.None); } + public void WriteToFile(string path, string text) + { + File.WriteAllText(path, text); + } + public Stream CreateFileStream(string filePath, FileMode mode) { return new FileStream(filePath, mode); diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index 15a975f4..fdb62ce3 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -39,6 +39,8 @@ public interface IFileSystem void FileDelete(string path); IEnumerable SplitLines(string value); + + void WriteToFile(string path, string text); Stream CreateFileStream(string filePath, FileMode mode); } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 359abae1..d689d893 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -82,6 +82,7 @@ + diff --git a/src/ScriptCs.Core/ScriptManifest.cs b/src/ScriptCs.Core/ScriptManifest.cs new file mode 100644 index 00000000..72d482db --- /dev/null +++ b/src/ScriptCs.Core/ScriptManifest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class ScriptManifest + { + public ScriptManifest() + { + PackageAssemblies = new HashSet(); + } + + public HashSet PackageAssemblies { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 319d79bf..f8d315de 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.Versioning; using Common.Logging; using ScriptCs.Package; +using ServiceStack.Text; + namespace ScriptCs.Command { internal class InstallCommand : IInstallCommand @@ -47,6 +50,8 @@ public CommandResult Execute() { _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); + UpdateManifest(workingDirectory); + _logger.Info("Installation completed successfully."); return CommandResult.Success; } @@ -57,6 +62,23 @@ public CommandResult Execute() } } + private void UpdateManifest(string workingDirectory) + { + var manifestPath = Path.Combine(workingDirectory, Constants.ManifestFile); + var manifest = GetManifest(manifestPath) ?? new ScriptManifest(); + + var installedPackages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); + manifest.PackageAssemblies.UnionWith(installedPackages); + + _fileSystem.WriteToFile(manifestPath, manifest.ToJson()); + } + + private ScriptManifest GetManifest(string manifestPath) + { + if (!_fileSystem.FileExists(manifestPath)) return null; + return _fileSystem.ReadFile(manifestPath).To(); + } + private IEnumerable GetPackages(string workingDirectory) { if (string.IsNullOrWhiteSpace(_name)) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 4f413311..92d42933 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,6 +38,10 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll + + False + ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + From e583fe0335005a1136641f764838af8df86b7758 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 18:05:50 +0200 Subject: [PATCH 054/993] Fixed bug where manifest wasn't deserialized --- src/ScriptCs/Command/InstallCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index f8d315de..a7455712 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -76,7 +76,7 @@ private void UpdateManifest(string workingDirectory) private ScriptManifest GetManifest(string manifestPath) { if (!_fileSystem.FileExists(manifestPath)) return null; - return _fileSystem.ReadFile(manifestPath).To(); + return _fileSystem.ReadFile(manifestPath).FromJson(); } private IEnumerable GetPackages(string workingDirectory) From 3f72a1ff7de7317042b14e130b84e2daadcae9bc Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 27 May 2013 23:02:06 +0200 Subject: [PATCH 055/993] Added more logging --- src/ScriptCs.Core/AssemblyResolver.cs | 25 +++++++++++++++---------- src/ScriptCs/Command/InstallCommand.cs | 2 ++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 3a44186f..985fee94 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -29,14 +29,7 @@ public IEnumerable GetAssemblyPaths(string path) var manifestAssemblies = GetManifestAssemblies(path); var looseAssemblies = GetLooseAssemblies(path); - var assemblyPaths = manifestAssemblies.Union(looseAssemblies).ToList(); - - foreach (var assemblyPath in assemblyPaths) - { - _logger.DebugFormat("Found assembly reference: {0}", Path.GetFileName(assemblyPath)); - } - - return assemblyPaths; + return manifestAssemblies.Union(looseAssemblies); } private IEnumerable GetLooseAssemblies(string path) @@ -47,7 +40,13 @@ private IEnumerable GetLooseAssemblies(string path) var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly); + .Where(IsManagedAssembly) + .ToList(); + + foreach (var looseAssembly in looseAssemblies) + { + _logger.DebugFormat("Found assembly in bin folder: {0}", Path.GetFileName(looseAssembly)); + } return looseAssemblies; } @@ -60,10 +59,15 @@ private IEnumerable GetManifestAssemblies(string path) var manifest = _fileSystem.ReadFile(manifestPath).FromJson(); + foreach (var packageAssembly in manifest.PackageAssemblies) + { + _logger.DebugFormat("Found package assembly: {0}", Path.GetFileName(packageAssembly)); + } + return manifest.PackageAssemblies; } - private static bool IsManagedAssembly(string path) + private bool IsManagedAssembly(string path) { try { @@ -72,6 +76,7 @@ private static bool IsManagedAssembly(string path) } catch (BadImageFormatException) { + _logger.DebugFormat("Skipping non-managed assembly: {0}", Path.GetFileName(path)); return false; } } diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index a7455712..8a646df2 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -71,6 +71,8 @@ private void UpdateManifest(string workingDirectory) manifest.PackageAssemblies.UnionWith(installedPackages); _fileSystem.WriteToFile(manifestPath, manifest.ToJson()); + + _logger.InfoFormat("{0} written to {1}.", Constants.ManifestFile, workingDirectory); } private ScriptManifest GetManifest(string manifestPath) From a07ea4d2006be5338d51add0fdc83caa56d3a193 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Tue, 28 May 2013 00:17:37 +0200 Subject: [PATCH 056/993] Refactored out check for managed assemblies into IAssemblyUtility, added tests for IAssemblyResolver --- src/ScriptCs.Core/AssemblyResolver.cs | 25 ++---- src/ScriptCs.Core/AssemblyUtility.cs | 21 +++++ src/ScriptCs.Core/IAssemblyUtility.cs | 7 ++ src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs/CompositionRoot.cs | 3 +- .../AssemblyResolverTests.cs | 87 +++++++++++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + 7 files changed, 126 insertions(+), 20 deletions(-) create mode 100644 src/ScriptCs.Core/AssemblyUtility.cs create mode 100644 src/ScriptCs.Core/IAssemblyUtility.cs create mode 100644 test/ScriptCs.Core.Tests/AssemblyResolverTests.cs diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 985fee94..f0e321a9 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using Common.Logging; @@ -16,10 +14,13 @@ public class AssemblyResolver : IAssemblyResolver private readonly ILog _logger; - public AssemblyResolver(IFileSystem fileSystem, ILog logger) + private readonly IAssemblyUtility _assemblyUtility; + + public AssemblyResolver(IFileSystem fileSystem, IAssemblyUtility assemblyUtility, ILog logger) { _fileSystem = fileSystem; _logger = logger; + _assemblyUtility = assemblyUtility; } public IEnumerable GetAssemblyPaths(string path) @@ -40,7 +41,7 @@ private IEnumerable GetLooseAssemblies(string path) var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) - .Where(IsManagedAssembly) + .Where(_assemblyUtility.IsManagedAssembly) .ToList(); foreach (var looseAssembly in looseAssemblies) @@ -66,19 +67,5 @@ private IEnumerable GetManifestAssemblies(string path) return manifest.PackageAssemblies; } - - private bool IsManagedAssembly(string path) - { - try - { - AssemblyName.GetAssemblyName(path); - return true; - } - catch (BadImageFormatException) - { - _logger.DebugFormat("Skipping non-managed assembly: {0}", Path.GetFileName(path)); - return false; - } - } } } diff --git a/src/ScriptCs.Core/AssemblyUtility.cs b/src/ScriptCs.Core/AssemblyUtility.cs new file mode 100644 index 00000000..5a9346eb --- /dev/null +++ b/src/ScriptCs.Core/AssemblyUtility.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; + +namespace ScriptCs +{ + public class AssemblyUtility : IAssemblyUtility + { + public bool IsManagedAssembly(string path) + { + try + { + AssemblyName.GetAssemblyName(path); + return true; + } + catch (BadImageFormatException) + { + return false; + } + } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IAssemblyUtility.cs b/src/ScriptCs.Core/IAssemblyUtility.cs new file mode 100644 index 00000000..805b4d5b --- /dev/null +++ b/src/ScriptCs.Core/IAssemblyUtility.cs @@ -0,0 +1,7 @@ +namespace ScriptCs +{ + public interface IAssemblyUtility + { + bool IsManagedAssembly(string assemblyPath); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index d689d893..49a9e148 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -43,6 +43,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index b883d53c..59b4b872 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -50,7 +50,8 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (AssemblyResolver) + typeof (AssemblyResolver), + typeof (AssemblyUtility) }; builder.RegisterTypes(types).AsImplementedInterfaces(); diff --git a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs new file mode 100644 index 00000000..1e64bb9a --- /dev/null +++ b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs @@ -0,0 +1,87 @@ +using System.IO; +using System.Linq; + +using Common.Logging; + +using Moq; + +using Should; + +using Xunit; + +namespace ScriptCs.Tests +{ + public class AssemblyResolverTests + { + public class GetAssemblyPathsMethod + { + [Fact] + public void ShouldReturnAssembliesFromManifestFile() + { + const string WorkingDirectory = @"C:\"; + + var assemblyFile = Path.Combine(WorkingDirectory, @"C:\MyAssembly.dll"); + var manifestFile = Path.Combine(WorkingDirectory, Constants.ManifestFile); + + var fileSystem = new Mock(); + fileSystem.Setup(x => x.FileExists(manifestFile)).Returns(true); + fileSystem.Setup(x => x.ReadFile(manifestFile)).Returns(@"{ ""PackageAssemblies"": [ " + assemblyFile + " ] }"); + + var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), Mock.Of()); + + var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); + + assemblies.Count.ShouldEqual(1); + assemblies[0].ShouldEqual(assemblyFile); + } + + [Fact] + public void ShouldReturnAssembliesFromBinFolder() + { + const string WorkingDirectory = @"C:\"; + + var binFolder = Path.Combine(WorkingDirectory, "bin"); + var assemblyFile = Path.Combine(binFolder, "MyAssembly.dll"); + + var fileSystem = new Mock(); + fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(true); + fileSystem.Setup(x => x.EnumerateFiles(binFolder, It.IsAny(), SearchOption.AllDirectories)).Returns(new[] { assemblyFile }); + + var assemblyUtility = new Mock(); + assemblyUtility.Setup(x => x.IsManagedAssembly(assemblyFile)).Returns(true); + + var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + + var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); + + assemblies.Count.ShouldEqual(1); + assemblies[0].ShouldEqual(assemblyFile); + } + + [Fact] + public void ShouldNotReturnNonManagedAssemblies() + { + const string WorkingDirectory = @"C:\"; + + var binFolder = Path.Combine(WorkingDirectory, "bin"); + var managed = Path.Combine(binFolder, "MyAssembly.dll"); + var nonManaged = Path.Combine(binFolder, "MyAssembly.dll"); + + var fileSystem = new Mock(); + fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(true); + fileSystem.Setup(x => x.EnumerateFiles(binFolder, It.IsAny(), SearchOption.AllDirectories)) + .Returns(new[] { managed, nonManaged }); + + var assemblyUtility = new Mock(); + assemblyUtility.Setup(x => x.IsManagedAssembly(managed)).Returns(true); + + var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + + var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); + + assemblies.Count.ShouldEqual(1); + assemblies[0].ShouldEqual(managed); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index e61da225..6e1c08e4 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -37,6 +37,7 @@ Properties\CommonVersionInfo.cs + From 172ee9bc276b0dce2ea6a3e6a0bce57f1545b089 Mon Sep 17 00:00:00 2001 From: Michael Wade Date: Tue, 28 May 2013 10:26:09 +0100 Subject: [PATCH 057/993] Using correct assertion library and returning the correct path if the path is a filename or directory. Would prefer if it was all in memory, but unsure as to how it should be designed. --- src/ScriptCs.Core/FileSystem.cs | 7 ++++++- test/ScriptCs.Core.Tests/ScriptExecutorTests.cs | 15 +++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index bc503b7f..0d6bb702 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -90,7 +90,12 @@ public string GetWorkingDirectory(string path) { var realPath = GetFullPath(path); - return Path.GetFileName(realPath) == string.Empty ? realPath : Path.GetDirectoryName(realPath); + var attributes = File.GetAttributes(realPath); + + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + return realPath; + else + return Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 1b26fbf3..bbd36d24 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -158,9 +158,20 @@ public void DoNotChangePathIfAbsolute() [Fact] public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() { - var fileSystem = new FileSystem(); + const string pathToMyScriptFolder = @"..\my_script\"; - Assert.Equal(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory,@"..\my_script\")), fileSystem.GetWorkingDirectory(@"..\my_script\")); + try { + Directory.CreateDirectory(pathToMyScriptFolder); + + var fileSystem = new FileSystem(); + + fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); + } + finally { + if (Directory.Exists(pathToMyScriptFolder)) + Directory.Delete(pathToMyScriptFolder); + } } [Fact] From ffcc6bf445129589710ce1303ec0c0a315283d24 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 28 May 2013 15:53:37 -0400 Subject: [PATCH 058/993] Update ServiceStack.Text from 3.9.44 to 3.9.47 --- src/ScriptCs/packages.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 2928ed03..9531ddb6 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -6,5 +6,5 @@ - - + + \ No newline at end of file From b87af11fbbaced38b3fcb82466d2a9b9a35c028a Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 28 May 2013 15:57:23 -0400 Subject: [PATCH 059/993] ScriptCs and ScriptCs.Core should reference ServiceStack.Text v3.9.47 instead of v3.9.44 --- src/ScriptCs.Core/ScriptCs.Core.csproj | 2 +- src/ScriptCs.Core/packages.config | 3 +-- src/ScriptCs/ScriptCs.csproj | 4 ++++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 6d370643..63f91f59 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -30,7 +30,7 @@ ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll - ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll + ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 953a2ce5..0d6dfbdf 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -3,7 +3,6 @@ - - + \ No newline at end of file diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index d0a48452..5fc6d0e2 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,6 +38,10 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll + + False + ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll + From 21458b910cbb4e6c5ebf291a79fe0d902914de73 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 30 May 2013 10:10:03 +0200 Subject: [PATCH 060/993] Fixed bad merge --- src/ScriptCs/ScriptCs.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 3e946e49..5a735557 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -38,9 +38,6 @@ False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - - False - ..\..\packages\ServiceStack.Text.3.9.44\lib\net35\ServiceStack.Text.dll False ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll From 5e8eb07dcae2cb104346328f8ce5eeb183f667f7 Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 31 May 2013 14:40:51 +0200 Subject: [PATCH 061/993] fixes #306 - if there is compile/execution exception it gets shown in the console (script mode) or REPL (repl mode) --- src/ScriptCs.Core/IScriptExecutor.cs | 4 +- src/ScriptCs.Core/Repl.cs | 21 +++++- src/ScriptCs.Core/ScriptExecutor.cs | 8 +-- src/ScriptCs/Command/ExecuteScriptCommand.cs | 21 +++++- .../ExecuteScriptCommandTests.cs | 70 +++++++++++++++++++ 5 files changed, 113 insertions(+), 11 deletions(-) diff --git a/src/ScriptCs.Core/IScriptExecutor.cs b/src/ScriptCs.Core/IScriptExecutor.cs index 8cca24d9..06e404e7 100644 --- a/src/ScriptCs.Core/IScriptExecutor.cs +++ b/src/ScriptCs.Core/IScriptExecutor.cs @@ -6,8 +6,8 @@ namespace ScriptCs public interface IScriptExecutor { void Initialize(IEnumerable paths, IEnumerable scriptPacks); - void Execute(string script, string[] scriptArgs); - void Execute(string script); + ScriptResult Execute(string script, string[] scriptArgs); + ScriptResult Execute(string script); void Terminate(); } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 04e16a75..15ab16e8 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -24,7 +24,7 @@ public override void Terminate() Console.Exit(); } - public override void Execute(string script) + public override ScriptResult Execute(string script) { try { @@ -53,21 +53,36 @@ public override void Execute(string script) throw new FileNotFoundException(string.Format("Could not find assembly '{0}'", assemblyPath), assemblyPath); } - return; + return new ScriptResult(); } Console.ForegroundColor = ConsoleColor.Cyan; var result = ScriptEngine.Execute(script, new string[0], References, DefaultNamespaces, ScriptPackSession); if (result != null) { + if (result.CompileException != null) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.Write(result.CompileException.ToString()); + } + + if (result.ExecuteException != null) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.Write(result.ExecuteException.ToString()); + } + Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv()); + Console.WriteLine(result.ReturnValue.ToJsv()); } + + return result; } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + ex + "\r\n"); + return new ScriptResult(); } finally { diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 5d77e354..46e02aa1 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -46,19 +46,19 @@ public virtual void Terminate() ScriptPackSession.TerminatePacks(); } - public virtual void Execute(string script) + public virtual ScriptResult Execute(string script) { - Execute(script, new string[0]); + return Execute(script, new string[0]); } - public virtual void Execute(string script, string[] scriptArgs) + public virtual ScriptResult Execute(string script, string[] scriptArgs) { var path = Path.IsPathRooted(script) ? script : Path.Combine(FileSystem.CurrentDirectory, script); var result = FilePreProcessor.ProcessFile(path); var references = References.Union(result.References); Logger.Debug("Starting execution in engine"); - ScriptEngine.Execute(result.Code, scriptArgs, references, DefaultNamespaces, ScriptPackSession); + return ScriptEngine.Execute(result.Code, scriptArgs, references, DefaultNamespaces, ScriptPackSession); } } } \ No newline at end of file diff --git a/src/ScriptCs/Command/ExecuteScriptCommand.cs b/src/ScriptCs/Command/ExecuteScriptCommand.cs index 163b353d..80cabf30 100644 --- a/src/ScriptCs/Command/ExecuteScriptCommand.cs +++ b/src/ScriptCs/Command/ExecuteScriptCommand.cs @@ -48,10 +48,27 @@ public CommandResult Execute() assemblyPaths = GetAssemblyPaths(workingDirectory); } _scriptExecutor.Initialize(assemblyPaths, _scriptPackResolver.GetPacks()); - _scriptExecutor.Execute(_script, ScriptArgs); + var result = _scriptExecutor.Execute(_script, ScriptArgs); _scriptExecutor.Terminate(); - return CommandResult.Success; + if (result != null) + { + if (result.CompileException != null) + { + _logger.Error(result.CompileException); + return CommandResult.Error; + } + + if (result.ExecuteException != null) + { + _logger.Error(result.ExecuteException); + return CommandResult.Error; + } + + return CommandResult.Success; + } + + return CommandResult.Error; } catch (Exception ex) { diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index a0c49a9c..f2627768 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -121,6 +121,76 @@ public void NonManagedAssembliesAreExcluded() executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); executor.Verify(i => i.Terminate(), Times.Once()); } + + [Fact] + public void ShouldReturnErrorIfThereIsCompileException() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + + var resolver = new Mock(); + var executor = new Mock(); + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult {CompileException = new Exception("test")}); + + var engine = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var logger = new Mock(); + var filePreProcessor = new Mock(); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + var commandResult = result.Execute(); + + Assert.Equal(CommandResult.Error, commandResult); + logger.Verify(i => i.Error(It.IsAny()),Times.Once()); + } + + [Fact] + public void ShouldReturnErrorIfThereIsExecuteException() + { + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + var fs = new Mock(); + fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + + var resolver = new Mock(); + var executor = new Mock(); + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult { ExecuteException = new Exception("test") }); + + var engine = new Mock(); + var scriptpackResolver = new Mock(); + var packageInstaller = new Mock(); + var logger = new Mock(); + var filePreProcessor = new Mock(); + var assemblyName = new Mock(); + var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + var commandResult = result.Execute(); + + Assert.Equal(CommandResult.Error, commandResult); + logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + } } } } From 9d92f94cf739ca6223923007d4ce37c325b5e66f Mon Sep 17 00:00:00 2001 From: Filip W Date: Fri, 31 May 2013 14:45:38 +0200 Subject: [PATCH 062/993] pass exception to REPL from the catch block too --- src/ScriptCs.Core/Repl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 15ab16e8..ef71d0a3 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -82,7 +82,7 @@ public override ScriptResult Execute(string script) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + ex + "\r\n"); - return new ScriptResult(); + return new ScriptResult { ExecuteException = ex }; } finally { From e666f7b78a87139cf314b3dcb3c2f19c0a788d48 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:35:47 +0200 Subject: [PATCH 063/993] add assembly reference to REPL reference list regardless whether it exists or not. Then catch on exception and remove reference if needed --- src/ScriptCs.Core/Repl.cs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 04e16a75..a2eb5f68 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -38,20 +38,14 @@ public override void Execute(string script) } else { - throw new FileNotFoundException(string.Format("Could not find script '{0}'", filepath), filepath); + throw new FileLoadException(string.Format("Could not find script '{0}'", filepath), filepath); } } else if (PreProcessorUtil.IsRLine(script)) { - var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, PreProcessorUtil.GetPath(PreProcessorUtil.RString, script))); - if (FileSystem.FileExists(assemblyPath)) - { - References = References.Union(new[] { assemblyPath }); - } - else - { - throw new FileNotFoundException(string.Format("Could not find assembly '{0}'", assemblyPath), assemblyPath); - } + var assemblyName = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); + var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, assemblyName)); + References = References.Union(FileSystem.FileExists(assemblyPath) ? new[] { assemblyPath } : new[] { assemblyName }); return; } @@ -61,9 +55,18 @@ public override void Execute(string script) if (result != null) { Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ToJsv()); + Console.WriteLine(result.ReturnValue.ToJsv()); } } + catch (FileNotFoundException fileEx) + { + if (References.Any(i => i == fileEx.FileName)) + { + References = References.Except(new[] {fileEx.FileName}); + } + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("\r\n" + fileEx + "\r\n"); + } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; From 9da7e3a5225d1a230dd38923e303648ee03ab474 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:36:56 +0200 Subject: [PATCH 064/993] added tests for verifying that assembly gets removed from REPL reference list if it wasnt found. Also check - if file exists reference by absolute path, otherwise try get it from GAC --- test/ScriptCs.Tests/ReplTests.cs | 35 +++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Tests/ReplTests.cs index d8b4c627..63b42a37 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Tests/ReplTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -228,33 +229,53 @@ public void ShouldReferenceAssemblyIfLineIsAReference() } [Fact] - public void ShouldNotReferenceAssemblyIfFileDoesNotExist() + public void ShouldReferenceAssemblyBasedOnFullPathIfFileExists() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); - mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"c:/my.dll"); - mocks.FileSystem.Setup(x => x.FileExists("c:/my.dll")).Returns(false); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); - //default references = 6 - _repl.References.Count().ShouldEqual(6); + mocks.FileSystem.Verify(x => x.FileExists("C:/my.dll"), Times.Once()); } [Fact] - public void ShouldReferenceAssemblyBasedOnFullPath() + public void ShouldReferenceAssemblyBasedOnNameIfFileDoesNotExistBecauseItLooksInGACThen() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); + mocks.FileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(false); _repl = GetRepl(mocks); _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); _repl.Execute("#r \"my.dll\""); - mocks.FileSystem.Verify(x => x.FileExists("C:/my.dll"), Times.Once()); + _repl.References.Contains("my.dll").ShouldBeTrue(); + } + + [Fact] + public void ShouldRemoveReferenceIfAssemblyIsNotFound() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(i => i.GetFullPath(It.IsAny())).Returns(@"C:/my.dll"); + mocks.FileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(false); + mocks.ScriptEngine.Setup( + i => + i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Throws(new FileNotFoundException("error", "my.dll")); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"my.dll\""); + _repl.References.Contains("my.dll").ShouldBeTrue(); + _repl.Execute("var x=1;"); + _repl.References.Contains("my.dll").ShouldBeFalse(); } [Fact] From 75739bbbe98e347cf06dd9ee872eb7307447331a Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:44:02 +0200 Subject: [PATCH 065/993] change fileloadexception to filenotfoundexception --- src/ScriptCs.Core/Repl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index a2eb5f68..f0ac2f87 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -38,7 +38,7 @@ public override void Execute(string script) } else { - throw new FileLoadException(string.Format("Could not find script '{0}'", filepath), filepath); + throw new FileNotFoundException(string.Format("Could not find script '{0}'", filepath), filepath); } } else if (PreProcessorUtil.IsRLine(script)) From 3b727701dfc7e78694b1d6d77cc2789cb16253bb Mon Sep 17 00:00:00 2001 From: Filip W Date: Sun, 2 Jun 2013 11:48:07 +0200 Subject: [PATCH 066/993] fixed edge case of null reference --- src/ScriptCs.Core/Repl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index f0ac2f87..452a3285 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -60,7 +60,7 @@ public override void Execute(string script) } catch (FileNotFoundException fileEx) { - if (References.Any(i => i == fileEx.FileName)) + if (References != null && References.Any(i => i == fileEx.FileName)) { References = References.Except(new[] {fileEx.FileName}); } From b1925ad2faa6c8c889a14be3b97b5c4c9b58a007 Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 3 Jun 2013 23:07:15 +0100 Subject: [PATCH 067/993] Revised filesystem test name and refactored into new class fixes test in #296 --- test/ScriptCs.Core.Tests/FileSystemTests.cs | 29 +++++++++++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptExecutorTests.cs | 21 ++------------ 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 test/ScriptCs.Core.Tests/FileSystemTests.cs diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs new file mode 100644 index 00000000..a080ba72 --- /dev/null +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class FileSystemTests + { + [Fact] + public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() + { + const string pathToMyScriptFolder = @"..\my_script\"; + + try { + Directory.CreateDirectory(pathToMyScriptFolder); + + var fileSystem = new FileSystem(); + + fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); + } + finally { + if (Directory.Exists(pathToMyScriptFolder)) + Directory.Delete(pathToMyScriptFolder); + } + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index e61da225..db99f3a1 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -37,6 +37,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index bbd36d24..14b14597 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -121,6 +121,8 @@ public void ShouldTerminateScriptPacksWhenTerminateIsCalled() public class TheExecuteMethod { + private readonly FileSystemTests FileSystemTests = new FileSystemTests(); + [Fact] public void ConstructsAbsolutePathBeforePreProcessingFile() { @@ -155,25 +157,6 @@ public void DoNotChangePathIfAbsolute() preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void ShouldResolveAssemblyReferencesCorrectlyWhenNotRunFromCSXFolder() - { - const string pathToMyScriptFolder = @"..\my_script\"; - - try { - Directory.CreateDirectory(pathToMyScriptFolder); - - var fileSystem = new FileSystem(); - - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) - .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); - } - finally { - if (Directory.Exists(pathToMyScriptFolder)) - Directory.Delete(pathToMyScriptFolder); - } - } - [Fact] public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() { From 3b5ff1e42d0f9af419dedb1854fe0817af3c5aea Mon Sep 17 00:00:00 2001 From: SpikeTheMaster Date: Mon, 3 Jun 2013 23:18:00 +0100 Subject: [PATCH 068/993] Followed XUnit convention Of putting tests in a class with the name of the method they test. --- test/ScriptCs.Core.Tests/FileSystemTests.cs | 29 +++++++++++-------- .../ScriptExecutorTests.cs | 2 -- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index a080ba72..f4004b37 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -7,22 +7,27 @@ namespace ScriptCs.Tests { public class FileSystemTests { - [Fact] - public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() + public class GetWorkingDirectoryMethod { - const string pathToMyScriptFolder = @"..\my_script\"; + [Fact] + public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() + { + const string pathToMyScriptFolder = @"..\my_script\"; - try { - Directory.CreateDirectory(pathToMyScriptFolder); + try + { + Directory.CreateDirectory(pathToMyScriptFolder); - var fileSystem = new FileSystem(); + var fileSystem = new FileSystem(); - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) - .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); - } - finally { - if (Directory.Exists(pathToMyScriptFolder)) - Directory.Delete(pathToMyScriptFolder); + fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); + } + finally + { + if (Directory.Exists(pathToMyScriptFolder)) + Directory.Delete(pathToMyScriptFolder); + } } } } diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index 14b14597..a9eecca7 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -121,8 +121,6 @@ public void ShouldTerminateScriptPacksWhenTerminateIsCalled() public class TheExecuteMethod { - private readonly FileSystemTests FileSystemTests = new FileSystemTests(); - [Fact] public void ConstructsAbsolutePathBeforePreProcessingFile() { From 28cc0dbe0a521cefa12cc89b37fa5a71d5d4ecf4 Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 6 Jun 2013 08:48:19 +0200 Subject: [PATCH 069/993] added test for #r in GAC, moved ReplTests.cs to ScriptCs.Core.Tests.csproj to reflect proper structure --- .../ReplTests.cs | 14 ++++++++++++++ .../ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj | 1 + test/ScriptCs.Tests/ScriptCs.Tests.csproj | 1 - 3 files changed, 15 insertions(+), 1 deletion(-) rename test/{ScriptCs.Tests => ScriptCs.Core.Tests}/ReplTests.cs (94%) diff --git a/test/ScriptCs.Tests/ReplTests.cs b/test/ScriptCs.Core.Tests/ReplTests.cs similarity index 94% rename from test/ScriptCs.Tests/ReplTests.cs rename to test/ScriptCs.Core.Tests/ReplTests.cs index 63b42a37..ac977553 100644 --- a/test/ScriptCs.Tests/ReplTests.cs +++ b/test/ScriptCs.Core.Tests/ReplTests.cs @@ -244,6 +244,20 @@ public void ShouldReferenceAssemblyBasedOnFullPathIfFileExists() [Fact] public void ShouldReferenceAssemblyBasedOnNameIfFileDoesNotExistBecauseItLooksInGACThen() + { + var mocks = new Mocks(); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + mocks.FileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(false); + + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("#r \"PresentationCore\""); + + _repl.References.Contains("PresentationCore").ShouldBeTrue(); + } + + [Fact] + public void ShouldReferenceAssemblyBasedOnNameWithExtensionIfFileDoesNotExistBecauseItLooksInGACThen() { var mocks = new Mocks(); mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index e61da225..4b6e98a0 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -41,6 +41,7 @@ + diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 97db7eeb..e64fa785 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -43,7 +43,6 @@ - From 29f7525598389a3e918f721888b3cd28b8552c5f Mon Sep 17 00:00:00 2001 From: Filip W Date: Thu, 6 Jun 2013 09:13:25 +0200 Subject: [PATCH 070/993] fix breaking build after latest merge --- src/ScriptCs.Core/Repl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index aa5e3887..7beeb1a5 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -80,6 +80,7 @@ public override ScriptResult Execute(string script) } Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + fileEx + "\r\n"); + return new ScriptResult { CompileException = fileEx }; } catch (Exception ex) { From 5416721a4266a7ab14925fed6d0b3180d174c53b Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Thu, 6 Jun 2013 21:55:18 +0200 Subject: [PATCH 071/993] Fixed bug where all assemblies inside working dir was picked up by MEF --- src/ScriptCs/CompositionRoot.cs | 38 ++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 59b4b872..96e89524 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -42,9 +42,6 @@ public void Initialize() var types = new[] { typeof (ScriptHostFactory), - typeof (FileSystem), - typeof (PackageAssemblyResolver), - typeof (PackageContainer), typeof (FilePreProcessor), typeof (ScriptPackResolver), typeof (NugetInstallationProvider), @@ -69,18 +66,39 @@ public void Initialize() builder.RegisterType().As(); + // Newing up these manually to get package assemblies + var fileSystem = new FileSystem(); + var packageContainer = new PackageContainer(fileSystem); + var packageAssemblyResolver = new PackageAssemblyResolver(fileSystem, packageContainer); + + builder.RegisterInstance(fileSystem).As(); + builder.RegisterInstance(packageContainer).As(); + builder.RegisterInstance(packageAssemblyResolver).As(); + if (_shouldInitDrirectoryCatalog) { - var directory = Environment.CurrentDirectory; + var currentDirectory = Environment.CurrentDirectory; + + var assemblies = packageAssemblyResolver.GetAssemblyNames(currentDirectory).ToList(); + + var binFolder = Path.Combine(currentDirectory, Constants.BinFolder); + if (Directory.Exists(binFolder)) + { + var binAssemblies = Directory.EnumerateFiles(binFolder, "*.dll") + .Union(Directory.EnumerateFiles(binFolder, "*.exe")); + + assemblies.AddRange(binAssemblies); + } - var assemblies = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories) - .Union(Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)); + var aggregateCatalog = new AggregateCatalog(); - var directoryCatalogs = assemblies - .Select(Path.GetDirectoryName).Distinct() - .Select(x => new DirectoryCatalog(x)); + var assemblyCatalogs = assemblies.Select(x => new AssemblyCatalog(x)); + foreach (var assemblyCatalog in assemblyCatalogs) + { + aggregateCatalog.Catalogs.Add(assemblyCatalog); + } - builder.RegisterComposablePartCatalog(new AggregateCatalog(directoryCatalogs)); + builder.RegisterComposablePartCatalog(aggregateCatalog); } _container = builder.Build(); From c8e57124678a52a0528a3795d15793fc654074b4 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:11:08 +0200 Subject: [PATCH 072/993] Removed manifest stuff after perf. testing NuGet API alternative --- src/ScriptCs.Core/AssemblyResolver.cs | 31 ++++++++++--------- src/ScriptCs.Core/Constants.cs | 1 - src/ScriptCs.Core/ScriptCs.Core.csproj | 1 - src/ScriptCs.Core/ScriptManifest.cs | 14 --------- src/ScriptCs/Command/InstallCommand.cs | 24 -------------- src/ScriptCs/CompositionRoot.cs | 30 ++++++------------ .../AssemblyResolverTests.cs | 21 +++++++------ 7 files changed, 38 insertions(+), 84 deletions(-) delete mode 100644 src/ScriptCs.Core/ScriptManifest.cs diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index f0e321a9..7341b83b 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -4,21 +4,22 @@ using Common.Logging; -using ServiceStack.Text; - namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { private readonly IFileSystem _fileSystem; + private readonly IPackageAssemblyResolver _packageAssemblyResolver; + private readonly ILog _logger; private readonly IAssemblyUtility _assemblyUtility; - public AssemblyResolver(IFileSystem fileSystem, IAssemblyUtility assemblyUtility, ILog logger) + public AssemblyResolver(IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IAssemblyUtility assemblyUtility, ILog logger) { _fileSystem = fileSystem; + _packageAssemblyResolver = packageAssemblyResolver; _logger = logger; _assemblyUtility = assemblyUtility; } @@ -27,10 +28,10 @@ public IEnumerable GetAssemblyPaths(string path) { Guard.AgainstNullArgument("path", path); - var manifestAssemblies = GetManifestAssemblies(path); + var packageAssemblies = GetPackageAssemblies(path); var looseAssemblies = GetLooseAssemblies(path); - return manifestAssemblies.Union(looseAssemblies); + return packageAssemblies.Union(looseAssemblies); } private IEnumerable GetLooseAssemblies(string path) @@ -39,33 +40,33 @@ private IEnumerable GetLooseAssemblies(string path) if (!_fileSystem.DirectoryExists(binFolder)) return Enumerable.Empty(); - var looseAssemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") + var assemblies = _fileSystem.EnumerateFiles(binFolder, "*.dll") .Union(_fileSystem.EnumerateFiles(binFolder, "*.exe")) .Where(_assemblyUtility.IsManagedAssembly) .ToList(); - foreach (var looseAssembly in looseAssemblies) + foreach (var assembly in assemblies) { - _logger.DebugFormat("Found assembly in bin folder: {0}", Path.GetFileName(looseAssembly)); + _logger.DebugFormat("Found assembly in bin folder: {0}", Path.GetFileName(assembly)); } - return looseAssemblies; + return assemblies; } - private IEnumerable GetManifestAssemblies(string path) + private IEnumerable GetPackageAssemblies(string path) { - var manifestPath = Path.Combine(path, Constants.ManifestFile); - if (!_fileSystem.FileExists(manifestPath)) + var packagesFolder = Path.Combine(path, Constants.PackagesFolder); + if (!_fileSystem.DirectoryExists(packagesFolder)) return Enumerable.Empty(); - var manifest = _fileSystem.ReadFile(manifestPath).FromJson(); + var assemblies = _packageAssemblyResolver.GetAssemblyNames(path).ToList(); - foreach (var packageAssembly in manifest.PackageAssemblies) + foreach (var packageAssembly in assemblies) { _logger.DebugFormat("Found package assembly: {0}", Path.GetFileName(packageAssembly)); } - return manifest.PackageAssemblies; + return assemblies; } } } diff --git a/src/ScriptCs.Core/Constants.cs b/src/ScriptCs.Core/Constants.cs index 3780943d..acfff78a 100644 --- a/src/ScriptCs.Core/Constants.cs +++ b/src/ScriptCs.Core/Constants.cs @@ -7,7 +7,6 @@ public static class Constants public const string PackagesFolder = "packages"; public const string BinFolder = "bin"; public const string DefaultRepositoryUrl = "https://nuget.org/api/v2/"; - public const string ManifestFile = "manifest.json"; public const string DebugContractName = "Debug"; public const string RunContractName = "Run"; } diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index d911bae9..9c78920e 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -84,7 +84,6 @@ - diff --git a/src/ScriptCs.Core/ScriptManifest.cs b/src/ScriptCs.Core/ScriptManifest.cs deleted file mode 100644 index 72d482db..00000000 --- a/src/ScriptCs.Core/ScriptManifest.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs -{ - public class ScriptManifest - { - public ScriptManifest() - { - PackageAssemblies = new HashSet(); - } - - public HashSet PackageAssemblies { get; set; } - } -} \ No newline at end of file diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 8a646df2..319d79bf 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using System.IO; using System.Runtime.Versioning; using Common.Logging; using ScriptCs.Package; -using ServiceStack.Text; - namespace ScriptCs.Command { internal class InstallCommand : IInstallCommand @@ -50,8 +47,6 @@ public CommandResult Execute() { _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); - UpdateManifest(workingDirectory); - _logger.Info("Installation completed successfully."); return CommandResult.Success; } @@ -62,25 +57,6 @@ public CommandResult Execute() } } - private void UpdateManifest(string workingDirectory) - { - var manifestPath = Path.Combine(workingDirectory, Constants.ManifestFile); - var manifest = GetManifest(manifestPath) ?? new ScriptManifest(); - - var installedPackages = _packageAssemblyResolver.GetAssemblyNames(workingDirectory); - manifest.PackageAssemblies.UnionWith(installedPackages); - - _fileSystem.WriteToFile(manifestPath, manifest.ToJson()); - - _logger.InfoFormat("{0} written to {1}.", Constants.ManifestFile, workingDirectory); - } - - private ScriptManifest GetManifest(string manifestPath) - { - if (!_fileSystem.FileExists(manifestPath)) return null; - return _fileSystem.ReadFile(manifestPath).FromJson(); - } - private IEnumerable GetPackages(string workingDirectory) { if (string.IsNullOrWhiteSpace(_name)) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 96e89524..dc2f45cb 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel.Composition.Hosting; using System.IO; using System.Linq; @@ -37,7 +38,7 @@ public void Initialize() loggerConfigurator.Configure(); var logger = loggerConfigurator.GetLogger(); - builder.RegisterInstance(logger); + builder.RegisterInstance(logger).As(); var types = new[] { @@ -47,8 +48,6 @@ public void Initialize() typeof (NugetInstallationProvider), typeof (PackageInstaller), typeof (ReplConsole), - typeof (AssemblyResolver), - typeof (AssemblyUtility) }; builder.RegisterTypes(types).AsImplementedInterfaces(); @@ -66,37 +65,28 @@ public void Initialize() builder.RegisterType().As(); - // Newing up these manually to get package assemblies + // Hack to resolve assemblies for MEF catalog before building Autofac container var fileSystem = new FileSystem(); + var assemblyUtility = new AssemblyUtility(); var packageContainer = new PackageContainer(fileSystem); var packageAssemblyResolver = new PackageAssemblyResolver(fileSystem, packageContainer); + var assemblyResolver = new AssemblyResolver(fileSystem, packageAssemblyResolver, assemblyUtility, logger); builder.RegisterInstance(fileSystem).As(); + builder.RegisterInstance(assemblyUtility).As(); builder.RegisterInstance(packageContainer).As(); builder.RegisterInstance(packageAssemblyResolver).As(); + builder.RegisterInstance(assemblyResolver).As(); if (_shouldInitDrirectoryCatalog) { var currentDirectory = Environment.CurrentDirectory; - - var assemblies = packageAssemblyResolver.GetAssemblyNames(currentDirectory).ToList(); - - var binFolder = Path.Combine(currentDirectory, Constants.BinFolder); - if (Directory.Exists(binFolder)) - { - var binAssemblies = Directory.EnumerateFiles(binFolder, "*.dll") - .Union(Directory.EnumerateFiles(binFolder, "*.exe")); - - assemblies.AddRange(binAssemblies); - } + var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); var aggregateCatalog = new AggregateCatalog(); - var assemblyCatalogs = assemblies.Select(x => new AssemblyCatalog(x)); - foreach (var assemblyCatalog in assemblyCatalogs) - { - aggregateCatalog.Catalogs.Add(assemblyCatalog); - } + assemblies.Select(x => new AssemblyCatalog(x)).ToList() + .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); builder.RegisterComposablePartCatalog(aggregateCatalog); } diff --git a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs index 1e64bb9a..e50f7181 100644 --- a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs +++ b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Linq; using Common.Logging; @@ -16,18 +17,20 @@ public class AssemblyResolverTests public class GetAssemblyPathsMethod { [Fact] - public void ShouldReturnAssembliesFromManifestFile() + public void ShouldReturnAssembliesFromPackagesFolder() { const string WorkingDirectory = @"C:\"; - var assemblyFile = Path.Combine(WorkingDirectory, @"C:\MyAssembly.dll"); - var manifestFile = Path.Combine(WorkingDirectory, Constants.ManifestFile); + var packagesFolder = Path.Combine(WorkingDirectory, Constants.PackagesFolder); + var assemblyFile = Path.Combine(packagesFolder, "MyAssembly.dll"); var fileSystem = new Mock(); - fileSystem.Setup(x => x.FileExists(manifestFile)).Returns(true); - fileSystem.Setup(x => x.ReadFile(manifestFile)).Returns(@"{ ""PackageAssemblies"": [ " + assemblyFile + " ] }"); + fileSystem.Setup(x => x.FileExists(packagesFolder)).Returns(true); - var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), Mock.Of()); + var packageAssemblyResolver = new Mock(); + packageAssemblyResolver.Setup(x => x.GetAssemblyNames(WorkingDirectory, It.IsAny>())).Returns(new[] { assemblyFile }); + + var resolver = new AssemblyResolver(fileSystem.Object, packageAssemblyResolver.Object, Mock.Of(), Mock.Of()); var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); @@ -50,7 +53,7 @@ public void ShouldReturnAssembliesFromBinFolder() var assemblyUtility = new Mock(); assemblyUtility.Setup(x => x.IsManagedAssembly(assemblyFile)).Returns(true); - var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), assemblyUtility.Object, Mock.Of()); var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); @@ -75,7 +78,7 @@ public void ShouldNotReturnNonManagedAssemblies() var assemblyUtility = new Mock(); assemblyUtility.Setup(x => x.IsManagedAssembly(managed)).Returns(true); - var resolver = new AssemblyResolver(fileSystem.Object, assemblyUtility.Object, Mock.Of()); + var resolver = new AssemblyResolver(fileSystem.Object, Mock.Of(), assemblyUtility.Object, Mock.Of()); var assemblies = resolver.GetAssemblyPaths(WorkingDirectory).ToList(); From f007f4286b31cea035c8ed9c27f1fc913bfb128d Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:12:41 +0200 Subject: [PATCH 073/993] Fixed failing test --- test/ScriptCs.Core.Tests/AssemblyResolverTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs index e50f7181..aa2aa503 100644 --- a/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs +++ b/test/ScriptCs.Core.Tests/AssemblyResolverTests.cs @@ -25,7 +25,7 @@ public void ShouldReturnAssembliesFromPackagesFolder() var assemblyFile = Path.Combine(packagesFolder, "MyAssembly.dll"); var fileSystem = new Mock(); - fileSystem.Setup(x => x.FileExists(packagesFolder)).Returns(true); + fileSystem.Setup(x => x.DirectoryExists(packagesFolder)).Returns(true); var packageAssemblyResolver = new Mock(); packageAssemblyResolver.Setup(x => x.GetAssemblyNames(WorkingDirectory, It.IsAny>())).Returns(new[] { assemblyFile }); From 9b850d4946b168473f33d131864d6e4626a30e9e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:19:00 +0200 Subject: [PATCH 074/993] Renamed method to a more appropriate name :) --- src/ScriptCs.Core/AssemblyResolver.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index 7341b83b..b66b40ad 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -16,7 +16,11 @@ public class AssemblyResolver : IAssemblyResolver private readonly IAssemblyUtility _assemblyUtility; - public AssemblyResolver(IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IAssemblyUtility assemblyUtility, ILog logger) + public AssemblyResolver( + IFileSystem fileSystem, + IPackageAssemblyResolver packageAssemblyResolver, + IAssemblyUtility assemblyUtility, + ILog logger) { _fileSystem = fileSystem; _packageAssemblyResolver = packageAssemblyResolver; @@ -29,12 +33,12 @@ public IEnumerable GetAssemblyPaths(string path) Guard.AgainstNullArgument("path", path); var packageAssemblies = GetPackageAssemblies(path); - var looseAssemblies = GetLooseAssemblies(path); + var binAssemblies = GetBinAssemblies(path); - return packageAssemblies.Union(looseAssemblies); + return packageAssemblies.Union(binAssemblies); } - private IEnumerable GetLooseAssemblies(string path) + private IEnumerable GetBinAssemblies(string path) { var binFolder = Path.Combine(path, Constants.BinFolder); if (!_fileSystem.DirectoryExists(binFolder)) From d46626a0b305d520456b80a0e227e3609356ce10 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:49:13 +0200 Subject: [PATCH 075/993] Added caching of assembly paths in AssemblyResolver --- src/ScriptCs.Core/AssemblyResolver.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index b66b40ad..b79fdbee 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -8,6 +8,8 @@ namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { + private static readonly Dictionary> AssemblyPathCache = new Dictionary>(); + private readonly IFileSystem _fileSystem; private readonly IPackageAssemblyResolver _packageAssemblyResolver; @@ -32,10 +34,16 @@ public IEnumerable GetAssemblyPaths(string path) { Guard.AgainstNullArgument("path", path); + List assemblies; + if (AssemblyPathCache.TryGetValue(path, out assemblies)) return assemblies; + var packageAssemblies = GetPackageAssemblies(path); var binAssemblies = GetBinAssemblies(path); - return packageAssemblies.Union(binAssemblies); + assemblies = packageAssemblies.Union(binAssemblies).ToList(); + AssemblyPathCache.Add(path, assemblies); + + return assemblies; } private IEnumerable GetBinAssemblies(string path) From c3f2403da9f1680eb2198ec2314e0cb88f60517c Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:55:05 +0200 Subject: [PATCH 076/993] Removed static cache because of failing tests --- src/ScriptCs.Core/AssemblyResolver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ScriptCs.Core/AssemblyResolver.cs b/src/ScriptCs.Core/AssemblyResolver.cs index b79fdbee..c48cb3f0 100644 --- a/src/ScriptCs.Core/AssemblyResolver.cs +++ b/src/ScriptCs.Core/AssemblyResolver.cs @@ -8,7 +8,7 @@ namespace ScriptCs { public class AssemblyResolver : IAssemblyResolver { - private static readonly Dictionary> AssemblyPathCache = new Dictionary>(); + private readonly Dictionary> _assemblyPathCache = new Dictionary>(); private readonly IFileSystem _fileSystem; @@ -35,13 +35,13 @@ public IEnumerable GetAssemblyPaths(string path) Guard.AgainstNullArgument("path", path); List assemblies; - if (AssemblyPathCache.TryGetValue(path, out assemblies)) return assemblies; + if (_assemblyPathCache.TryGetValue(path, out assemblies)) return assemblies; var packageAssemblies = GetPackageAssemblies(path); var binAssemblies = GetBinAssemblies(path); assemblies = packageAssemblies.Union(binAssemblies).ToList(); - AssemblyPathCache.Add(path, assemblies); + _assemblyPathCache.Add(path, assemblies); return assemblies; } From 80388d023cbd0a4a6a18bb569e657440ba8597a9 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Fri, 7 Jun 2013 00:59:51 +0200 Subject: [PATCH 077/993] Trigger CI build From d5a2ee84363cf3f0a45ae576c96dff044b60797e Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 8 Jun 2013 16:19:23 +0200 Subject: [PATCH 078/993] exported IConsole and ILog from Autofac to MEF Extensions --- src/ScriptCs/CompositionRoot.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 94d36a7f..0ed06d33 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -4,6 +4,7 @@ using Autofac; using Autofac.Integration.Mef; using Common.Logging; +using ScriptCs.Contracts; using ScriptCs.Engine.Roslyn; using ScriptCs.Package; using ScriptCs.Package.InstallationProvider; @@ -35,7 +36,8 @@ public void Initialize() loggerConfigurator.Configure(); var logger = loggerConfigurator.GetLogger(); - builder.RegisterInstance(logger); + builder.RegisterInstance(logger).Exported(x => x.As()); + builder.RegisterType().As().Exported(x => x.As()); var types = new[] { @@ -47,7 +49,6 @@ public void Initialize() typeof (ScriptPackResolver), typeof (NugetInstallationProvider), typeof (PackageInstaller), - typeof (ReplConsole), typeof (AssemblyName) }; From 12a04902594256b37be00ad80379a00ced39f071 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 9 Jun 2013 18:25:40 +0200 Subject: [PATCH 079/993] Fixed failing build after merge --- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 069360e1..c3363161 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using Common.Logging; using Moq; @@ -111,7 +112,7 @@ public void ShouldReturnErrorIfThereIsCompileException() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -146,7 +147,7 @@ public void ShouldReturnErrorIfThereIsExecuteException() var packageInstaller = new Mock(); var logger = new Mock(); var filePreProcessor = new Mock(); - var assemblyName = new Mock(); + var assemblyName = new Mock(); var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); From ca034fefb136c11e8969c78c3340ba8876e46513 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 10 Jun 2013 14:09:53 +0200 Subject: [PATCH 080/993] Increment version to v0.5.0 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 81cd5a30..67c61c08 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -9,7 +9,7 @@ - alpha + From bcb8f1f2860a316f48126d2874b9902620c82f77 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Mon, 10 Jun 2013 14:20:15 +0200 Subject: [PATCH 081/993] Incrementing version to v0.6.0-alpha --- build/ScriptCs.Version.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 67c61c08..1fd5fc71 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -4,12 +4,12 @@ 0 - 5 + 6 0 - + alpha From 08565fbad2a46aa9e4634bc0a49945199b88aedf Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 11 Jun 2013 21:47:09 -0700 Subject: [PATCH 082/993] Opening up FilePreProcessor to make it extensible. Fix for #322 --- src/ScriptCs.Core/FilePreProcessor.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 4196aca1..3ed2d9f9 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -20,18 +20,18 @@ public FilePreProcessor(IFileSystem fileSystem, ILog logger) _logger = logger; } - public FilePreProcessorResult ProcessFile(string path) + public virtual FilePreProcessorResult ProcessFile(string path) { return Parse(context => ParseFile(path, context)); } - public FilePreProcessorResult ProcessScript(string script) + public virtual FilePreProcessorResult ProcessScript(string script) { var scriptLines = _fileSystem.SplitLines(script).ToList(); return Parse(context => ParseScript(scriptLines, context)); } - private FilePreProcessorResult Parse(Action parseAction) + protected virtual FilePreProcessorResult Parse(Action parseAction) { var context = new FilePreProcessorContext(); @@ -52,7 +52,7 @@ private FilePreProcessorResult Parse(Action parseAction }; } - private string GenerateCode(FilePreProcessorContext context) + protected string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); @@ -71,7 +71,7 @@ private string GenerateCode(FilePreProcessorContext context) return stringBuilder.ToString(); } - private void ParseFile(string path, FilePreProcessorContext context) + protected void ParseFile(string path, FilePreProcessorContext context) { _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); @@ -80,7 +80,7 @@ private void ParseFile(string path, FilePreProcessorContext context) ParseScript(scriptLines, context, path); } - private void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) + protected void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { // Insert line directive if there's a path if (path != null) InsertLineDirective(path, scriptLines); @@ -95,7 +95,7 @@ private void ParseScript(List scriptLines, FilePreProcessorContext conte if (path != null) context.LoadedScripts.Add(path); } - private static void InsertLineDirective(string path, List fileLines) + protected void InsertLineDirective(string path, List fileLines) { var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); if (bodyIndex == -1) return; @@ -104,7 +104,7 @@ private static void InsertLineDirective(string path, List fileLines) fileLines.Insert(bodyIndex, directiveLine); } - private void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) + protected void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { if (PreProcessorUtil.IsUsingLine(line)) { @@ -149,7 +149,7 @@ private void ProcessLine(FilePreProcessorContext context, string line, bool isBe context.Body.Add(line); } - private class FilePreProcessorContext + public class FilePreProcessorContext { public FilePreProcessorContext() { From 6b6be32ab4944880d60b52fbd34482d2e52803d7 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 11 Jun 2013 22:24:38 -0700 Subject: [PATCH 083/993] Making protected members virtual --- src/ScriptCs.Core/FilePreProcessor.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 3ed2d9f9..719937cb 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -52,7 +52,7 @@ protected virtual FilePreProcessorResult Parse(Action p }; } - protected string GenerateCode(FilePreProcessorContext context) + protected virtual string GenerateCode(FilePreProcessorContext context) { var stringBuilder = new StringBuilder(); @@ -71,7 +71,7 @@ protected string GenerateCode(FilePreProcessorContext context) return stringBuilder.ToString(); } - protected void ParseFile(string path, FilePreProcessorContext context) + protected virtual void ParseFile(string path, FilePreProcessorContext context) { _logger.DebugFormat("Processing {0}...", Path.GetFileName(path)); @@ -80,7 +80,7 @@ protected void ParseFile(string path, FilePreProcessorContext context) ParseScript(scriptLines, context, path); } - protected void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) + protected virtual void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { // Insert line directive if there's a path if (path != null) InsertLineDirective(path, scriptLines); @@ -95,7 +95,7 @@ protected void ParseScript(List scriptLines, FilePreProcessorContext con if (path != null) context.LoadedScripts.Add(path); } - protected void InsertLineDirective(string path, List fileLines) + protected virtual void InsertLineDirective(string path, List fileLines) { var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); if (bodyIndex == -1) return; @@ -104,7 +104,7 @@ protected void InsertLineDirective(string path, List fileLines) fileLines.Insert(bodyIndex, directiveLine); } - protected void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) + protected virtual void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { if (PreProcessorUtil.IsUsingLine(line)) { From c6c3b646f9279355db5e5af478900531cf710169 Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 15 Jun 2013 17:31:05 +0200 Subject: [PATCH 084/993] added ScriptCs/ScriptcsConsoleAppender.cs changed unnecessary info logging to debug REPL will now respect IConsole for logging output --- .../RoslynScriptEngine.cs | 6 ++--- src/ScriptCs/CompositionRoot.cs | 4 +-- src/ScriptCs/LoggerConfigurator.cs | 6 ++--- src/ScriptCs/Program.cs | 15 ++++++++--- src/ScriptCs/ScriptCs.csproj | 1 + src/ScriptCs/ScriptcsConsoleAppender.cs | 26 +++++++++++++++++++ 6 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 src/ScriptCs/ScriptcsConsoleAppender.cs diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 6ae75a46..245d0cd9 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -33,7 +33,7 @@ public ScriptResult Execute(string code, string[] scriptArgs, IEnumerable().As().Exported(x => x.As()); var loggerConfigurator = new LoggerConfigurator(_logLevel); - loggerConfigurator.Configure(); + loggerConfigurator.Configure(new ReplConsole()); var logger = loggerConfigurator.GetLogger(); builder.RegisterInstance(logger).Exported(x => x.As()); - builder.RegisterType().As().Exported(x => x.As()); var types = new[] { diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index c49399b3..bb2597a0 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; +using ScriptCs.Contracts; using log4net; -using log4net.Appender; using log4net.Core; using log4net.Layout; using log4net.Repository.Hierarchy; @@ -25,11 +25,11 @@ public LoggerConfigurator(LogLevel logLevel) _logLevel = logLevel; } - public void Configure() + public void Configure(IConsole console) { var hierarchy = (Hierarchy)LogManager.GetRepository(); var logger = LogManager.GetLogger(LoggerName); - var consoleAppender = new ConsoleAppender + var consoleAppender = new ScriptcsConsoleAppender(console) { Layout = new PatternLayout(GetLogPattern(_logLevel)), Threshold = hierarchy.LevelMap[_logLevel.ToString().ToUpper(CultureInfo.CurrentCulture)] diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 9d555c38..cdced5ae 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -13,7 +13,7 @@ private static int Main(string[] args) string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - var commandArgs = ParseArguments(args) ?? new ScriptCsArgs { Repl = true }; + var commandArgs = ParseArguments(args); var compositionRoot = new CompositionRoot(commandArgs); compositionRoot.Initialize(); @@ -35,11 +35,20 @@ private static ScriptCsArgs ParseArguments(string[] args) { const string UnexpectedArgumentMessage = "Unexpected Argument: "; - if (args.Length <= 0) return null; + //no args initialized REPL + if (args.Length <= 0) return new ScriptCsArgs { Repl = true, LogLevel = LogLevel.Info}; try { - return Args.Parse(args); + var scriptcsArgs = Args.Parse(args); + + //if there is only 1 arg and it is a loglevel, it's also REPL + if (args.Length == 2 && args.Any(x => x.ToLowerInvariant() == "-log")) + { + scriptcsArgs.Repl = true; + } + + return scriptcsArgs; } catch (ArgException ex) { diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 5a735557..8a4d8b25 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -77,6 +77,7 @@ + diff --git a/src/ScriptCs/ScriptcsConsoleAppender.cs b/src/ScriptCs/ScriptcsConsoleAppender.cs new file mode 100644 index 00000000..f250e7f5 --- /dev/null +++ b/src/ScriptCs/ScriptcsConsoleAppender.cs @@ -0,0 +1,26 @@ +using System.Text; +using ScriptCs.Contracts; +using log4net.Appender; +using log4net.Core; + +namespace ScriptCs +{ + public class ScriptcsConsoleAppender : AppenderSkeleton + { + private readonly IConsole _console; + + public ScriptcsConsoleAppender(IConsole console) + { + _console = console; + } + + protected override void Append(LoggingEvent loggingEvent) + { + var txt = new StringBuilder(); + txt.Append(loggingEvent.Level); + txt.Append(": "); + txt.Append(loggingEvent.RenderedMessage); + _console.WriteLine(txt.ToString()); + } + } +} \ No newline at end of file From ecde0f2c8bf247f882bbd36e419c49b06cf14674 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 15 Jun 2013 15:09:19 -0600 Subject: [PATCH 085/993] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 738b6164..3a4dc65e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ We definitely want to soak up all that energy you have! ## The issue tracker and how you can contribute. * Bugs - For bugs, just go fix it. Don't ask UNLESS it starts to turn into a feature. -* Features - By default all issues tagged as enhancements will be fixed by the core team. However if you'd like to take it, please socialize the idea in our new google group (https://groups.google.com/forum/?fromgroups#!forum/scriptcs) so we can discuss before you put in a potentially wasted effort. +* Features - By default all issues tagged as enhancements which we file will be fixed by the core team. However if you'd like to take it, please comment in the issue that you'd like to implement it so we can discuss before you put in a potentially wasted effort. * YOU TAKE IT - These are items that are important, but which we'd available for the community to take. One place we use this is for investigations and prototyping for features that would be really awesome, but which the core team just don't have bandwith for. As an example @dschenkelman [investigated](https://github.com/scriptcs/scriptcs/issues/68?source=cc) a VS debugging story. This lead to him ultimately implementing the feature, however don't feel pressure that you have to that. It's extremely valuable if you can just show us how it might be done. A few other points: From c04912da92958663c6a1c1dafca856b855b262e7 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Sat, 15 Jun 2013 15:10:26 -0600 Subject: [PATCH 086/993] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 738b6164..3a4dc65e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ We definitely want to soak up all that energy you have! ## The issue tracker and how you can contribute. * Bugs - For bugs, just go fix it. Don't ask UNLESS it starts to turn into a feature. -* Features - By default all issues tagged as enhancements will be fixed by the core team. However if you'd like to take it, please socialize the idea in our new google group (https://groups.google.com/forum/?fromgroups#!forum/scriptcs) so we can discuss before you put in a potentially wasted effort. +* Features - By default all issues tagged as enhancements which we file will be fixed by the core team. However if you'd like to take it, please comment in the issue that you'd like to implement it so we can discuss before you put in a potentially wasted effort. * YOU TAKE IT - These are items that are important, but which we'd available for the community to take. One place we use this is for investigations and prototyping for features that would be really awesome, but which the core team just don't have bandwith for. As an example @dschenkelman [investigated](https://github.com/scriptcs/scriptcs/issues/68?source=cc) a VS debugging story. This lead to him ultimately implementing the feature, however don't feel pressure that you have to that. It's extremely valuable if you can just show us how it might be done. A few other points: From f2d61db1a8ab95af7a66b1c918d4bdefc4c7eb57 Mon Sep 17 00:00:00 2001 From: Michael Wade Date: Wed, 12 Jun 2013 12:43:17 +0100 Subject: [PATCH 087/993] Refs #321 scriptcs -install ScriptCs.AzureMobileServices * `GetWorkingDirectory` returns the current directory if the path is null/whitespace. * Fixed assumption that the directory/path would exist. * Added additional unit tests. --- src/ScriptCs.Core/FileSystem.cs | 16 ++++-- test/ScriptCs.Core.Tests/FileSystemTests.cs | 58 +++++++++++++++++++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index f96b8cdb..374d66ce 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -93,14 +93,22 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { + if (string.IsNullOrWhiteSpace(path)) + return CurrentDirectory; + var realPath = GetFullPath(path); - var attributes = File.GetAttributes(realPath); + if (FileExists(realPath) || DirectoryExists(realPath)) + { + var attributes = File.GetAttributes(realPath); - if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) - return realPath; - else + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + return realPath; + return Path.GetDirectoryName(realPath); + } + + return Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index f4004b37..f683eedf 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using Should; using Xunit; @@ -9,18 +10,18 @@ public class FileSystemTests { public class GetWorkingDirectoryMethod { + private readonly FileSystem _fileSystem = new FileSystem(); + [Fact] public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() { - const string pathToMyScriptFolder = @"..\my_script\"; + const string pathToMyScriptFolder = @"..\my_script"; try { Directory.CreateDirectory(pathToMyScriptFolder); - var fileSystem = new FileSystem(); - - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + _fileSystem.GetWorkingDirectory(pathToMyScriptFolder) .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); } finally @@ -29,6 +30,55 @@ public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath Directory.Delete(pathToMyScriptFolder); } } + + [Fact] + public void ShouldReturnWorkingDirectoryIfPathIsInvalid() + { + var invalidPaths = new List {"", " ", null}; + + foreach (var invalidPath in invalidPaths) + { + _fileSystem.GetWorkingDirectory(invalidPath).ShouldEqual(_fileSystem.CurrentDirectory); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectory() + { + string workingDir = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir\")); + string existingDirectoryPath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_dir\")); + string existingFilePath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_file.txt")); + + try + { + Directory.CreateDirectory(workingDir); + Directory.CreateDirectory(existingDirectoryPath); + File.Create(existingFilePath).Dispose(); + + _fileSystem.GetWorkingDirectory(existingDirectoryPath).ShouldEqual(existingDirectoryPath); + _fileSystem.GetWorkingDirectory(existingFilePath).ShouldEqual( + Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir"))); + } + finally + { + if (Directory.Exists(existingDirectoryPath)) + Directory.Delete(existingDirectoryPath); + + if (File.Exists(existingFilePath)) + File.Delete(existingFilePath); + + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectoryIfPathDoesNotExist() + { + const string nonExistantFilePath = @"C:\working_dir\i_dont_exist.txt"; + + _fileSystem.GetWorkingDirectory(nonExistantFilePath).ShouldEqual(@"C:\working_dir"); + } } } } \ No newline at end of file From 0692cacd1a350d3538d8d5694d792749ddbfb61e Mon Sep 17 00:00:00 2001 From: Michael Wade Date: Wed, 12 Jun 2013 12:43:17 +0100 Subject: [PATCH 088/993] Refs #321 scriptcs -install ScriptCs.AzureMobileServices * `GetWorkingDirectory` returns the current directory if the path is null/whitespace. * Fixed assumption that the directory/path would exist. * Added additional unit tests. Fixes #321. --- src/ScriptCs.Core/FileSystem.cs | 16 ++++-- test/ScriptCs.Core.Tests/FileSystemTests.cs | 58 +++++++++++++++++++-- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 0d6bb702..4d657f33 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -88,14 +88,22 @@ public Stream CreateFileStream(string filePath, FileMode mode) public string GetWorkingDirectory(string path) { + if (string.IsNullOrWhiteSpace(path)) + return CurrentDirectory; + var realPath = GetFullPath(path); - var attributes = File.GetAttributes(realPath); + if (FileExists(realPath) || DirectoryExists(realPath)) + { + var attributes = File.GetAttributes(realPath); - if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) - return realPath; - else + if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) + return realPath; + return Path.GetDirectoryName(realPath); + } + + return Path.GetDirectoryName(realPath); } public string GetFullPath(string path) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index f4004b37..f683eedf 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using Should; using Xunit; @@ -9,18 +10,18 @@ public class FileSystemTests { public class GetWorkingDirectoryMethod { + private readonly FileSystem _fileSystem = new FileSystem(); + [Fact] public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath() { - const string pathToMyScriptFolder = @"..\my_script\"; + const string pathToMyScriptFolder = @"..\my_script"; try { Directory.CreateDirectory(pathToMyScriptFolder); - var fileSystem = new FileSystem(); - - fileSystem.GetWorkingDirectory(pathToMyScriptFolder) + _fileSystem.GetWorkingDirectory(pathToMyScriptFolder) .ShouldEqual(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, pathToMyScriptFolder))); } finally @@ -29,6 +30,55 @@ public void ShouldProperlyConstructWorkingDirectoryIfScriptIsRunFromRelativePath Directory.Delete(pathToMyScriptFolder); } } + + [Fact] + public void ShouldReturnWorkingDirectoryIfPathIsInvalid() + { + var invalidPaths = new List {"", " ", null}; + + foreach (var invalidPath in invalidPaths) + { + _fileSystem.GetWorkingDirectory(invalidPath).ShouldEqual(_fileSystem.CurrentDirectory); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectory() + { + string workingDir = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir\")); + string existingDirectoryPath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_dir\")); + string existingFilePath = Path.GetFullPath(Path.Combine(workingDir, @".\existing_file.txt")); + + try + { + Directory.CreateDirectory(workingDir); + Directory.CreateDirectory(existingDirectoryPath); + File.Create(existingFilePath).Dispose(); + + _fileSystem.GetWorkingDirectory(existingDirectoryPath).ShouldEqual(existingDirectoryPath); + _fileSystem.GetWorkingDirectory(existingFilePath).ShouldEqual( + Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @".\working_dir"))); + } + finally + { + if (Directory.Exists(existingDirectoryPath)) + Directory.Delete(existingDirectoryPath); + + if (File.Exists(existingFilePath)) + File.Delete(existingFilePath); + + if (Directory.Exists(workingDir)) + Directory.Delete(workingDir); + } + } + + [Fact] + public void ReturnsCorrectWorkingDirectoryIfPathDoesNotExist() + { + const string nonExistantFilePath = @"C:\working_dir\i_dont_exist.txt"; + + _fileSystem.GetWorkingDirectory(nonExistantFilePath).ShouldEqual(@"C:\working_dir"); + } } } } \ No newline at end of file From d31db4c7661eda2bcbc9f39e8a70f5f1bea1e1be Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sun, 16 Jun 2013 18:52:33 -0400 Subject: [PATCH 089/993] Increment version to v0.5.1 --- build/ScriptCs.Version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/ScriptCs.Version.props b/build/ScriptCs.Version.props index 67c61c08..84963c56 100644 --- a/build/ScriptCs.Version.props +++ b/build/ScriptCs.Version.props @@ -5,7 +5,7 @@ 0 5 - 0 + 1 From 643a82ac6b4289e79700e9b9b1a942645537762e Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 20:03:06 +0200 Subject: [PATCH 090/993] Added AutoFixture.AutoMoq --- test/ScriptCs.Tests/ScriptCs.Tests.csproj | 7 +++++++ test/ScriptCs.Tests/app.config | 15 +++++++++++++++ test/ScriptCs.Tests/packages.config | 2 ++ 3 files changed, 24 insertions(+) create mode 100644 test/ScriptCs.Tests/app.config diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 7a0b535e..4c4d6d25 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -16,6 +16,12 @@ ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + + ..\..\packages\AutoFixture.3.2.0\lib\net40\Ploeh.AutoFixture.dll + + + ..\..\packages\AutoFixture.AutoMoq.3.2.0\lib\net40\Ploeh.AutoFixture.AutoMoq.dll + ..\..\packages\Should.1.1.12.0\lib\Should.dll @@ -68,6 +74,7 @@ + diff --git a/test/ScriptCs.Tests/app.config b/test/ScriptCs.Tests/app.config new file mode 100644 index 00000000..9547ab7c --- /dev/null +++ b/test/ScriptCs.Tests/app.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Tests/packages.config b/test/ScriptCs.Tests/packages.config index 667f949f..ffaabf30 100644 --- a/test/ScriptCs.Tests/packages.config +++ b/test/ScriptCs.Tests/packages.config @@ -1,5 +1,7 @@  + + From 826962699d6addaec965319d8e766374864febbf Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 20:48:56 +0200 Subject: [PATCH 091/993] Refactored command tests to use Autofixture for cleaner, less brittle tests. --- test/ScriptCs.Tests/CleanCommandTests.cs | 99 ++++++++++++++++--- test/ScriptCs.Tests/CommandFactoryTests.cs | 25 +++-- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 22 ++--- .../ExecuteScriptCommandTests.cs | 66 ++++++------- test/ScriptCs.Tests/InstallCommandTests.cs | 36 +++---- test/ScriptCs.Tests/ScriptArgsTests.cs | 55 +++++------ test/ScriptCs.Tests/VersionCommandTests.cs | 51 +++++----- 7 files changed, 203 insertions(+), 151 deletions(-) diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 62553def..92e4b40a 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,7 +1,10 @@ -using Common.Logging; +using System; using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; -using ScriptCs.Package; using Xunit; namespace ScriptCs.Tests @@ -15,20 +18,16 @@ public void ShouldDeletePackagesFolder() { var args = new ScriptCsArgs { Clean = true }; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fixture.Register(() => fs.Object); + + var root = fixture.Create(); + var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -37,6 +36,82 @@ public void ShouldDeletePackagesFolder() fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } + + [Fact] + public void ShouldDeleteBinFolder() + { + var args = new ScriptCsArgs { Clean = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var fs = new Mock(); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + + fixture.Register(() => fs.Object); + + var root = fixture.Create(); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + result.Execute(); + + fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + } + + [Fact] + public void ShouldNotDeleteBinFolderIfDllsAreLeft() + { + var args = new ScriptCsArgs { Clean = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var fs = new Mock(); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); + fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); + + fixture.Register(() => fs.Object); + + var root = fixture.Create(); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + result.Execute(); + + fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); + } + + [Fact] + public void ShouldDeleteAllFilesResolvedFromPackages() + { + var args = new ScriptCsArgs { Clean = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var fs = new Mock(); + fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); + + var resolver = new Mock(); + resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); + + fixture.Register(() => fs.Object); + fixture.Register(() => resolver.Object); + + var root = fixture.Create(); + + var factory = new CommandFactory(root); + var result = factory.CreateCommand(args, new string[0]); + + result.Execute(); + + fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); + } } } } diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 353d9030..574b3bd1 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -1,7 +1,10 @@ -using Common.Logging; -using Moq; +using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; -using ScriptCs.Package; + using Should; using Xunit; @@ -17,22 +20,16 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool const string PackagesFile = "C:\\packages.config"; const string PackagesFolder = "C:\\packages"; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); fs.Setup(x => x.FileExists(PackagesFile)).Returns(packagesFileExists); fs.Setup(x => x.DirectoryExists(PackagesFolder)).Returns(packagesFolderExists); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - return root; + fixture.Register(() => fs.Object); + + return fixture.Create(); } [Fact] diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d86e3ed0..0724bad2 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -3,6 +3,10 @@ using System.Text; using Common.Logging; using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; using ScriptCs.Contracts; using ScriptCs.Package; @@ -17,8 +21,11 @@ public class TheExecuteMethod [Fact] public void ShouldPromptForInput() { + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var mockFileSystem = new Mock(); mockFileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + fixture.Register(() => mockFileSystem.Object); var builder = new StringBuilder(); @@ -26,18 +33,9 @@ public void ShouldPromptForInput() var writer = new StringWriter(builder); var console = new FakeConsole(writer, reader); + fixture.Register(() => console); - var root = new ScriptServiceRoot( - mockFileSystem.Object, - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - Mock.Of(), - console); + var root = fixture.Create(); var commandFactory = new CommandFactory(root); @@ -91,4 +89,4 @@ public void ResetColor() } } } -} \ No newline at end of file +} diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c3363161..765ab08a 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,11 +1,15 @@ using System; using System.Collections.Generic; using System.IO; -using Common.Logging; + using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; using ScriptCs.Contracts; -using ScriptCs.Package; + using Xunit; using System.Linq; @@ -25,18 +29,16 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() ScriptName = "test.csx" }; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + fixture.Register(() => fs.Object); - var resolver = new Mock(); var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fixture.Register(() => executor.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -60,25 +62,15 @@ public void NonManagedAssembliesAreExcluded() ScriptName = "test.csx" }; - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fs.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)).Returns(new[] { - "managed.dll", - nonManaged - }); - - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); + fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); + fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); + fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); + fixture.Register(() => fs.Object); + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -134,21 +126,23 @@ public void ShouldReturnErrorIfThereIsExecuteException() ScriptName = "test.csx" }; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); + fixture.Register(() => fs.Object); - var resolver = new Mock(); - var executor = new Mock(); executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) .Returns(new ScriptResult { ExecuteException = new Exception("test") }); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var assemblyName = new Mock(); + assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); + fixture.Register(() => assemblyName.Object); + + var executor = new Mock(); + fixture.Register(() => executor.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index c1e4efaa..a9efe01b 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -4,6 +4,10 @@ using System.Runtime.Versioning; using Common.Logging; using Moq; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; using ScriptCs.Package; using Xunit; @@ -26,19 +30,17 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() const string CurrentDirectory = @"C:\"; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fixture.Register(() => fs.Object); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + fixture.Register(() => packageInstaller.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -60,25 +62,25 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() const string CurrentDirectory = @"C:\"; + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + var fs = new Mock(); fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fixture.Register(() => fs.Object); var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { new PackageReference("a", new FrameworkName(".NETFramework,Version=v4.0"), new Version()), new PackageReference("b", new FrameworkName(".NETFramework,Version=v4.0"), new Version()) }); + fixture.Register(() => resolver.Object); + + var packageInstaller = new Mock(); + fixture.Register(() => packageInstaller.Object); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); diff --git a/test/ScriptCs.Tests/ScriptArgsTests.cs b/test/ScriptCs.Tests/ScriptArgsTests.cs index 10e8f5b8..b5954a8c 100644 --- a/test/ScriptCs.Tests/ScriptArgsTests.cs +++ b/test/ScriptCs.Tests/ScriptArgsTests.cs @@ -1,8 +1,5 @@ -using System; -using Common.Logging; -using Moq; -using ScriptCs.Command; -using ScriptCs.Package; +using Should; + using Xunit; namespace ScriptCs.Tests @@ -19,88 +16,80 @@ public void ShouldHandleEmptyArgs() ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[0], args); - Assert.Equal(new string[0], scriptArgs); + args.ShouldEqual(new string[0]); + scriptArgs.ShouldEqual(new string[0]); } [Fact] public void ShouldHandleMissingDoubledash() { - string[] args = new string[] { "scriptname.csx", "-restore" }; + string[] args = new[] { "scriptname.csx", "-restore" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[0], scriptArgs); + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new string[0]); } [Fact] public void ShouldHandleArgsAndScriptArgs() { - string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "8080" }; + string[] args = new[] { "scriptname.csx", "-restore", "--", "-port", "8080" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new[] { "-port", "8080" }); } [Fact] public void ShouldHandleJustScriptArgs() { - string[] args = new string[] { "--", "-port", "8080" }; + string[] args = new[] { "--", "-port", "8080" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[0], args); - Assert.Equal(new string[] { "-port", "8080" }, scriptArgs); + args.ShouldEqual(new string[0]); + scriptArgs.ShouldEqual(new[] { "-port", "8080" }); } [Fact] public void ShouldHandleJustDoubledash() { - string[] args = new string[] { "--" }; + string[] args = new[] { "--" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[0], args); - Assert.Equal(new string[0], scriptArgs); + args.ShouldEqual(new string[0]); + scriptArgs.ShouldEqual(new string[0]); } [Fact] public void ShouldHandleExtraDoubledash() { - string[] args = new string[] { "scriptname.csx", "-restore", "--", "-port", "--", "8080" }; + string[] args = new[] { "scriptname.csx", "-restore", "--", "-port", "--", "8080" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[] { "-port", "--", "8080" }, scriptArgs); + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new[] { "-port", "--", "8080" }); } [Fact] public void ShouldHandleTrailingDoubledash() { - string[] args = new string[] { "scriptname.csx", "-restore", "--" }; + string[] args = new[] { "scriptname.csx", "-restore", "--" }; string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Assert.Equal(new string[] { "scriptname.csx", "-restore" }, args); - Assert.Equal(new string[0], scriptArgs); - } - - public class ScriptArgsPlumbing { - [Fact] - public void ScriptArgsArePlumbedThrough() - { - - } + args.ShouldEqual(new[] { "scriptname.csx", "-restore" }); + scriptArgs.ShouldEqual(new string[0]); } } } diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 8546f5e8..724fa09e 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,8 +1,16 @@ -using Common.Logging; -using Moq; +using System; +using System.Reflection; +using System.Text; + +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; + using ScriptCs.Command; -using ScriptCs.Package; + using System.IO; + +using Should; + using Xunit; namespace ScriptCs.Tests @@ -11,39 +19,28 @@ public class VersionCommandTests { public class ExecuteMethod { - private readonly System.Version _currentVersion; + private readonly Version _currentVersion; + + private readonly StringBuilder _outputText; - System.Text.StringBuilder _outputText; - StringWriter _mockConsole; - TextWriter _actualConsole; + private readonly StringWriter _mockConsole; public ExecuteMethod() { - _currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - _outputText = new System.Text.StringBuilder(); + _currentVersion = Assembly.GetExecutingAssembly().GetName().Version; + _outputText = new StringBuilder(); _mockConsole = new StringWriter(_outputText); - _actualConsole = System.Console.Out; - System.Console.SetOut(_mockConsole); + Console.SetOut(_mockConsole); } [Fact] public void VersionCommandShouldOutputVersion() { - var args = new ScriptCsArgs - { - Version = true - }; - - var fs = new Mock(); - var resolver = new Mock(); - var executor = new Mock(); - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var args = new ScriptCsArgs { Version = true }; + + var fixture = new Fixture().Customize(new AutoMoqCustomization()); + + var root = fixture.Create(); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -53,7 +50,7 @@ public void VersionCommandShouldOutputVersion() result.Execute(); - Assert.Contains("scriptcs version " + _currentVersion.ToString(), _outputText.ToString()); + _outputText.ToString().ShouldContain("scriptcs version " + _currentVersion); } } } From da224d7811b03e80e955f9d7f061e0bb85489d03 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 22:25:52 +0200 Subject: [PATCH 092/993] Cleaned up most tests to a simple AAA pattern --- test/ScriptCs.Tests/CleanCommandTests.cs | 119 +++++-------- .../ExecuteScriptCommandTests.cs | 160 +++++------------- test/ScriptCs.Tests/InstallCommandTests.cs | 100 +++++------ test/ScriptCs.Tests/ScriptCs.Tests.csproj | 7 + .../ScriptCsAutoDataAttribute.cs | 13 ++ test/ScriptCs.Tests/VersionCommandTests.cs | 24 +-- test/ScriptCs.Tests/app.config | 4 + test/ScriptCs.Tests/packages.config | 2 + 8 files changed, 166 insertions(+), 263 deletions(-) create mode 100644 test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 92e4b40a..472025f9 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,11 +1,11 @@ using System; using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; -using Xunit; + +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -13,104 +13,77 @@ public class CleanCommandTests { public class ExecuteMethod { - [Fact] - public void ShouldDeletePackagesFolder() + [Theory, ScriptCsAutoData] + public void ShouldDeletePackagesFolder([Frozen] Mock fileSystem, CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - fixture.Register(() => fs.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); + // Assert + fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); + fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } - [Fact] - public void ShouldDeleteBinFolder() + [Theory, ScriptCsAutoData] + public void ShouldDeleteBinFolder([Frozen] Mock fileSystem, CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - fixture.Register(() => fs.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fs.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + // Assert + fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); + fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); } - [Fact] - public void ShouldNotDeleteBinFolderIfDllsAreLeft() + [Theory, ScriptCsAutoData] + public void ShouldNotDeleteBinFolderIfDllsAreLeft([Frozen] Mock fileSystem, CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); + fileSystem.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); - fs.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fixture.Register(() => fs.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - fs.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); + // Assert + fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); } - [Fact] - public void ShouldDeleteAllFilesResolvedFromPackages() + [Theory, ScriptCsAutoData] + public void ShouldDeleteAllFilesResolvedFromPackages( + [Frozen] Mock fileSystem, + [Frozen] Mock resolver, + CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Clean = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); + fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); + fileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(true); - var fs = new Mock(); - fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - fs.Setup(i => i.FileExists(It.IsAny())).Returns(true); - - var resolver = new Mock(); resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); - fixture.Register(() => fs.Object); - fixture.Register(() => resolver.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - fs.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); + // Assert + fileSystem.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); } } } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index 765ab08a..b47f554c 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -4,153 +4,87 @@ using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; using ScriptCs.Contracts; -using Xunit; using System.Linq; +using Xunit.Extensions; + namespace ScriptCs.Tests { public class ExecuteScriptCommandTests { public class ExecuteMethod { - [Fact] - public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() - { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fixture.Register(() => fs.Object); - - var executor = new Mock(); - fixture.Register(() => executor.Object); + private const string CurrentDirectory = "C:\\"; - var root = fixture.Create(); + [Theory, ScriptCsAutoData] + public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs( + [Frozen] Mock fileSystem, + [Frozen] Mock executor, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert executor.Verify(i => i.Initialize(It.IsAny>(), It.IsAny>()), Times.Once()); executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); executor.Verify(i => i.Terminate(), Times.Once()); } - [Fact] - public void NonManagedAssembliesAreExcluded() + [Theory, ScriptCsAutoData] + public void ShouldCreateMissingBinFolder([Frozen] Mock fileSystem, CommandFactory factory) { - const string nonManaged = "non-managed.dll"; - - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + // Arrange + var binFolder = Path.Combine(CurrentDirectory, Constants.BinFolder); - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(WorkingDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(WorkingDirectory); - fs.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - fixture.Register(() => fs.Object); + var args = new ScriptCsArgs { ScriptName = "test.csx" }; - var root = fixture.Create(); - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); + fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - executor.Verify(i => i.Initialize(It.Is>(x => !x.Contains(nonManaged)), It.IsAny>()), Times.Once()); - executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); - executor.Verify(i => i.Terminate(), Times.Once()); + // Assert + fileSystem.Verify(x => x.CreateDirectory(binFolder), Times.Once()); } - [Fact] - public void ShouldReturnErrorIfThereIsCompileException() + [Theory, ScriptCsAutoData] + public void NonManagedAssembliesAreExcluded( + [Frozen] Mock fileSystem, + [Frozen] Mock assemblyName, + [Frozen] Mock executor, + CommandFactory factory) { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - - var resolver = new Mock(); - var executor = new Mock(); - executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) - .Returns(new ScriptResult {CompileException = new Exception("test")}); - - var engine = new Mock(); - var scriptpackResolver = new Mock(); - var packageInstaller = new Mock(); - var logger = new Mock(); - var filePreProcessor = new Mock(); - var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - var commandResult = result.Execute(); - - Assert.Equal(CommandResult.Error, commandResult); - logger.Verify(i => i.Error(It.IsAny()),Times.Once()); - } - - [Fact] - public void ShouldReturnErrorIfThereIsExecuteException() - { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = "test.csx" - }; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fixture.Register(() => fs.Object); + // Arrange + const string NonManaged = "non-managed.dll"; - executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) - .Returns(new ScriptResult { ExecuteException = new Exception("test") }); + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; - var assemblyName = new Mock(); - assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == nonManaged))).Throws(new BadImageFormatException()); - fixture.Register(() => assemblyName.Object); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + fileSystem.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())) + .Returns(new[] { "managed.dll", NonManaged }); - var executor = new Mock(); - fixture.Register(() => executor.Object); + assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == NonManaged))).Throws(new BadImageFormatException()); - var root = fixture.Create(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - var commandResult = result.Execute(); - - Assert.Equal(CommandResult.Error, commandResult); - logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + // Assert + executor.Verify(i => i.Initialize(It.Is>(x => !x.Contains(NonManaged)), It.IsAny>()), Times.Once()); + executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); + executor.Verify(i => i.Terminate(), Times.Once()); } } } diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index a9efe01b..c38837f7 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -2,15 +2,15 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Versioning; -using Common.Logging; + using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; using ScriptCs.Package; -using Xunit; + +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -18,75 +18,55 @@ public class InstallCommandTests { public class ExecuteMethod { - [Fact] - public void InstallCommandShouldInstallSinglePackageIfNamePassed() - { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "mypackage", - ScriptName = null - }; - - const string CurrentDirectory = @"C:\"; - - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fixture.Register(() => fs.Object); - - var packageInstaller = new Mock(); - fixture.Register(() => packageInstaller.Object); - - var root = fixture.Create(); + private const string CurrentDirectory = @"C:\"; - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - result.Execute(); - - packageInstaller.Verify(i => i.InstallPackages(It.Is>(x => x.Count() == 1 && x.First().PackageId == "mypackage"), It.IsAny(), It.IsAny>()), Times.Once()); + [Theory, ScriptCsAutoData] + public void InstallCommandShouldInstallSinglePackageIfNamePassed( + [Frozen] Mock fileSystem, + [Frozen] Mock packageInstaller, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "mypackage", ScriptName = null }; + + fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + + // Act + factory.CreateCommand(args, new string[0]).Execute(); + + // Assert + packageInstaller.Verify(i => + i.InstallPackages( + It.Is>(x => x.Count() == 1 && x.First().PackageId == "mypackage"), + It.IsAny(), + It.IsAny>()), + Times.Once()); } - [Fact] - public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() + [Theory, ScriptCsAutoData] + public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed( + [Frozen] Mock fileSystem, + [Frozen] Mock resolver, + [Frozen] Mock packageInstaller, + CommandFactory factory) { - var args = new ScriptCsArgs - { - AllowPreRelease = false, - Install = "", - ScriptName = null - }; - - const string CurrentDirectory = @"C:\"; + // Arrange + var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = null }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); + fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - var fs = new Mock(); - fs.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fs.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fixture.Register(() => fs.Object); - - var resolver = new Mock(); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { new PackageReference("a", new FrameworkName(".NETFramework,Version=v4.0"), new Version()), new PackageReference("b", new FrameworkName(".NETFramework,Version=v4.0"), new Version()) }); - fixture.Register(() => resolver.Object); - - var packageInstaller = new Mock(); - fixture.Register(() => packageInstaller.Object); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert packageInstaller.Verify(i => i.InstallPackages(It.Is>(x => x.Count() == 2), It.IsAny(), It.IsAny>()), Times.Once()); } } diff --git a/test/ScriptCs.Tests/ScriptCs.Tests.csproj b/test/ScriptCs.Tests/ScriptCs.Tests.csproj index 4c4d6d25..27f555ed 100644 --- a/test/ScriptCs.Tests/ScriptCs.Tests.csproj +++ b/test/ScriptCs.Tests/ScriptCs.Tests.csproj @@ -22,6 +22,9 @@ ..\..\packages\AutoFixture.AutoMoq.3.2.0\lib\net40\Ploeh.AutoFixture.AutoMoq.dll + + ..\..\packages\AutoFixture.Xunit.3.2.0\lib\net40\Ploeh.AutoFixture.Xunit.dll + ..\..\packages\Should.1.1.12.0\lib\Should.dll @@ -38,6 +41,9 @@ ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + ..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll + @@ -50,6 +56,7 @@ + diff --git a/test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs b/test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs new file mode 100644 index 00000000..9963884a --- /dev/null +++ b/test/ScriptCs.Tests/ScriptCsAutoDataAttribute.cs @@ -0,0 +1,13 @@ +using Ploeh.AutoFixture; +using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptCsAutoDataAttribute : AutoDataAttribute + { + public ScriptCsAutoDataAttribute() : this(new Fixture()) { } + + private ScriptCsAutoDataAttribute(IFixture fixture) : base(fixture.Customize(new AutoMoqCustomization())) { } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 724fa09e..8e4fbd6b 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -2,16 +2,13 @@ using System.Reflection; using System.Text; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; - using ScriptCs.Command; using System.IO; using Should; -using Xunit; +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -33,23 +30,16 @@ public ExecuteMethod() Console.SetOut(_mockConsole); } - [Fact] - public void VersionCommandShouldOutputVersion() + [Theory, ScriptCsAutoData] + public void VersionCommandShouldOutputVersion(CommandFactory factory) { + // Arrange var args = new ScriptCsArgs { Version = true }; - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var root = fixture.Create(); - - var factory = new CommandFactory(root); - var result = factory.CreateCommand(args, new string[0]); - - // clear the fake console output - _outputText.Clear(); - - result.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert _outputText.ToString().ShouldContain("scriptcs version " + _currentVersion); } } diff --git a/test/ScriptCs.Tests/app.config b/test/ScriptCs.Tests/app.config index 9547ab7c..7af0e182 100644 --- a/test/ScriptCs.Tests/app.config +++ b/test/ScriptCs.Tests/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/test/ScriptCs.Tests/packages.config b/test/ScriptCs.Tests/packages.config index ffaabf30..cebb9a12 100644 --- a/test/ScriptCs.Tests/packages.config +++ b/test/ScriptCs.Tests/packages.config @@ -2,8 +2,10 @@ + + \ No newline at end of file From ada56c0c2aea44d94f83c53ab0595008c8d6b292 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 22:29:22 +0200 Subject: [PATCH 093/993] Refactored VersionCommand and test to use IConsole --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/Command/VersionCommand.cs | 15 +++++++++-- test/ScriptCs.Tests/VersionCommandTests.cs | 30 ++++++---------------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index f322affb..abb46bfd 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -107,7 +107,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Version) { - return new VersionCommand(); + return new VersionCommand(_scriptServiceRoot.Console); } return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index d51b4a0a..ab614434 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -1,12 +1,23 @@ -using System; +using System.Reflection; + +using ScriptCs.Contracts; namespace ScriptCs.Command { internal class VersionCommand : IVersionCommand { + private readonly IConsole _console; + + public VersionCommand(IConsole console) + { + _console = console; + } + public CommandResult Execute() { - Console.WriteLine("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + var version = Assembly.GetExecutingAssembly().GetName().Version; + _console.WriteLine(string.Format("scriptcs version {0}", version)); + return CommandResult.Success; } } diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 8e4fbd6b..52eab82f 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,12 +1,11 @@ -using System; -using System.Reflection; -using System.Text; +using System.Reflection; -using ScriptCs.Command; +using Moq; -using System.IO; +using Ploeh.AutoFixture.Xunit; -using Should; +using ScriptCs.Command; +using ScriptCs.Contracts; using Xunit.Extensions; @@ -16,31 +15,18 @@ public class VersionCommandTests { public class ExecuteMethod { - private readonly Version _currentVersion; - - private readonly StringBuilder _outputText; - - private readonly StringWriter _mockConsole; - - public ExecuteMethod() - { - _currentVersion = Assembly.GetExecutingAssembly().GetName().Version; - _outputText = new StringBuilder(); - _mockConsole = new StringWriter(_outputText); - Console.SetOut(_mockConsole); - } - [Theory, ScriptCsAutoData] - public void VersionCommandShouldOutputVersion(CommandFactory factory) + public void VersionCommandShouldOutputVersion([Frozen] Mock console, CommandFactory factory) { // Arrange var args = new ScriptCsArgs { Version = true }; + var currentVersion = Assembly.GetExecutingAssembly().GetName().Version; // Act factory.CreateCommand(args, new string[0]).Execute(); // Assert - _outputText.ToString().ShouldContain("scriptcs version " + _currentVersion); + console.Verify(x => x.WriteLine("scriptcs version " + currentVersion)); } } } From a28ec0fae09200aead2816c95a461384459b5b22 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sat, 1 Jun 2013 22:47:51 +0200 Subject: [PATCH 094/993] Slimmed down ExecuteReplCommandTest by using mocks instead of fake class --- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 83 ++++--------------- 1 file changed, 17 insertions(+), 66 deletions(-) diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index 0724bad2..1cad3c93 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -1,16 +1,13 @@ using System; -using System.IO; using System.Text; -using Common.Logging; using Moq; -using Ploeh.AutoFixture; -using Ploeh.AutoFixture.AutoMoq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Command; using ScriptCs.Contracts; -using ScriptCs.Package; using Xunit; +using Xunit.Extensions; namespace ScriptCs.Tests { @@ -18,74 +15,28 @@ public class ExecuteReplCommandTests { public class TheExecuteMethod { - [Fact] - public void ShouldPromptForInput() + [Theory, ScriptCsAutoData] + public void ShouldPromptForInput( + [Frozen] Mock fileSystem, + [Frozen] Mock console, + CommandFactory factory) { - var fixture = new Fixture().Customize(new AutoMoqCustomization()); - - var mockFileSystem = new Mock(); - mockFileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - fixture.Register(() => mockFileSystem.Object); - + // Arrange + var readLines = 0; var builder = new StringBuilder(); + var args = new ScriptCsArgs { Repl = true }; - var reader = new StringReader(Environment.NewLine); - var writer = new StringWriter(builder); - - var console = new FakeConsole(writer, reader); - fixture.Register(() => console); - - var root = fixture.Create(); + fileSystem.SetupGet(x => x.CurrentDirectory).Returns("C:\\"); - var commandFactory = new CommandFactory(root); + console.Setup(x => x.ReadLine()).Returns(() => string.Empty).Callback(() => readLines++); + console.Setup(x => x.Write(It.IsAny())).Callback(value => builder.Append(value)); - var target = commandFactory.CreateCommand(new ScriptCsArgs { Repl = true }, new string[0]); - - target.Execute(); + // Act + factory.CreateCommand(args, new string[0]).Execute(); + // Assert Assert.True(builder.ToString().EndsWith("> ")); - Assert.Equal(1, console.ReadLineCounter); - } - } - - public class FakeConsole : IConsole - { - private readonly TextWriter writer; - private readonly TextReader reader; - - public FakeConsole(TextWriter textWriter, TextReader textReader) - { - writer = textWriter; - reader = textReader; - ReadLineCounter = 0; - } - - public ConsoleColor ForegroundColor { get; set; } - - public int ReadLineCounter { get; set; } - - public void Write(string value) - { - writer.Write(value); - } - - public void WriteLine(string value) - { - writer.WriteLine(value); - } - - public string ReadLine() - { - ReadLineCounter++; - return reader.ReadLine(); - } - - public void Exit() - { - } - - public void ResetColor() - { + Assert.Equal(1, readLines); } } } From 234b07b0dceec5c7952637a27acdf37c68fd22c8 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Sun, 9 Jun 2013 18:27:05 +0200 Subject: [PATCH 095/993] Fixed failing build after merge --- test/ScriptCs.Tests/ExecuteScriptCommandTests.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index b47f554c..e91c015f 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; +using Common.Logging; + using Moq; using Ploeh.AutoFixture.Xunit; @@ -11,6 +13,9 @@ using System.Linq; +using ScriptCs.Package; + +using Xunit; using Xunit.Extensions; namespace ScriptCs.Tests From 330b1baf5211bcef25bd04f7d575cb9864280552 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 17 Jun 2013 01:43:49 +0200 Subject: [PATCH 096/993] Fixed build and removed old tests for CleanCommand and ExecuteScriptCommand. --- test/ScriptCs.Tests/CleanCommandTests.cs | 59 +------------------ .../ExecuteScriptCommandTests.cs | 33 ++--------- 2 files changed, 5 insertions(+), 87 deletions(-) diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 472025f9..6ac464d7 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -1,5 +1,4 @@ -using System; -using Moq; +using Moq; using Ploeh.AutoFixture.Xunit; @@ -29,62 +28,6 @@ public void ShouldDeletePackagesFolder([Frozen] Mock fileSystem, Co fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.PackagesFolder))), Times.Once()); } - - [Theory, ScriptCsAutoData] - public void ShouldDeleteBinFolder([Frozen] Mock fileSystem, CommandFactory factory) - { - // Arrange - var args = new ScriptCsArgs { Clean = true }; - - fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Once()); - } - - [Theory, ScriptCsAutoData] - public void ShouldNotDeleteBinFolderIfDllsAreLeft([Frozen] Mock fileSystem, CommandFactory factory) - { - // Arrange - var args = new ScriptCsArgs { Clean = true }; - - fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:/"); - fileSystem.Setup(i => i.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new[] { "c:/file.dll", "c:/file2.dll" }); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(i => i.DeleteDirectory(It.Is(x => x.Contains(Constants.BinFolder))), Times.Never()); - } - - [Theory, ScriptCsAutoData] - public void ShouldDeleteAllFilesResolvedFromPackages( - [Frozen] Mock fileSystem, - [Frozen] Mock resolver, - CommandFactory factory) - { - // Arrange - var args = new ScriptCsArgs { Clean = true }; - - fileSystem.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.BinFolder)))).Returns(true); - fileSystem.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); - fileSystem.Setup(i => i.FileExists(It.IsAny())).Returns(true); - - resolver.Setup(i => i.GetAssemblyNames(It.IsAny(), It.IsAny>())).Returns(new[] { "c:\\file.dll", "c:\\file2.dll" }); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(i => i.FileDelete(It.IsAny()), Times.Exactly(2)); - } } } } diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index e91c015f..ccff00d7 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using Common.Logging; - using Moq; using Ploeh.AutoFixture.Xunit; @@ -13,9 +10,6 @@ using System.Linq; -using ScriptCs.Package; - -using Xunit; using Xunit.Extensions; namespace ScriptCs.Tests @@ -46,29 +40,10 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs( executor.Verify(i => i.Terminate(), Times.Once()); } - [Theory, ScriptCsAutoData] - public void ShouldCreateMissingBinFolder([Frozen] Mock fileSystem, CommandFactory factory) - { - // Arrange - var binFolder = Path.Combine(CurrentDirectory, Constants.BinFolder); - - var args = new ScriptCsArgs { ScriptName = "test.csx" }; - - fileSystem.Setup(x => x.GetWorkingDirectory(It.IsAny())).Returns(CurrentDirectory); - fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fileSystem.Setup(x => x.DirectoryExists(binFolder)).Returns(false); - - // Act - factory.CreateCommand(args, new string[0]).Execute(); - - // Assert - fileSystem.Verify(x => x.CreateDirectory(binFolder), Times.Once()); - } - [Theory, ScriptCsAutoData] public void NonManagedAssembliesAreExcluded( [Frozen] Mock fileSystem, - [Frozen] Mock assemblyName, + [Frozen] Mock assemblyUtility, [Frozen] Mock executor, CommandFactory factory) { @@ -78,10 +53,10 @@ public void NonManagedAssembliesAreExcluded( var args = new ScriptCsArgs { AllowPreRelease = false, Install = "", ScriptName = "test.csx" }; fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); - fileSystem.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny())) + fileSystem.Setup(x => x.EnumerateFiles(It.IsAny(), It.IsAny(), SearchOption.AllDirectories)) .Returns(new[] { "managed.dll", NonManaged }); - assemblyName.Setup(x => x.GetAssemblyName(It.Is(y => y == NonManaged))).Throws(new BadImageFormatException()); + assemblyUtility.Setup(x => x.IsManagedAssembly(It.Is(y => y == NonManaged))).Returns(false); // Act factory.CreateCommand(args, new string[0]).Execute(); From e93440979ab34c80842de580173fdb70d60bae75 Mon Sep 17 00:00:00 2001 From: Kristian Hellang Date: Mon, 17 Jun 2013 02:12:22 +0200 Subject: [PATCH 097/993] Re-added tests that got lost in merge. --- .../ExecuteScriptCommandTests.cs | 65 ++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index ccff00d7..90adda45 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -1,6 +1,9 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; +using Common.Logging; + using Moq; using Ploeh.AutoFixture.Xunit; @@ -10,6 +13,10 @@ using System.Linq; +using ScriptCs.Package; + +using Should; + using Xunit.Extensions; namespace ScriptCs.Tests @@ -66,6 +73,62 @@ public void NonManagedAssembliesAreExcluded( executor.Verify(i => i.Execute(It.Is(x => x == "test.csx"), It.IsAny()), Times.Once()); executor.Verify(i => i.Terminate(), Times.Once()); } + + [Theory, ScriptCsAutoData] + public void ShouldReturnErrorIfThereIsCompileException( + [Frozen] Mock fileSystem, + [Frozen] Mock executor, + [Frozen] Mock logger, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult { CompileException = new Exception("test") }); + + // Act + var result = factory.CreateCommand(args, new string[0]).Execute(); + + // Assert + result.ShouldEqual(CommandResult.Error); + logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + } + + [Theory, ScriptCsAutoData] + public void ShouldReturnErrorIfThereIsExecuteException( + [Frozen] Mock fileSystem, + [Frozen] Mock executor, + [Frozen] Mock logger, + CommandFactory factory) + { + // Arrange + var args = new ScriptCsArgs + { + AllowPreRelease = false, + Install = "", + ScriptName = "test.csx" + }; + + fileSystem.SetupGet(x => x.CurrentDirectory).Returns(CurrentDirectory); + + executor.Setup(i => i.Execute(It.IsAny(), It.IsAny())) + .Returns(new ScriptResult { ExecuteException = new Exception("test") }); + + // Act + var result = factory.CreateCommand(args, new string[0]).Execute(); + + // Assert + result.ShouldEqual(CommandResult.Error); + logger.Verify(i => i.Error(It.IsAny()), Times.Once()); + } } } } From ff9f3afb8dfeba3ada63ab55d8e5f36896ee216a Mon Sep 17 00:00:00 2001 From: Adam Ralph Date: Tue, 18 Jun 2013 18:47:29 +0200 Subject: [PATCH 098/993] added missing guard clauses upgraded to latest version of LiteGuard.Source --- src/ScriptCs.Core/FilePreProcessor.cs | 11 +++++++++++ src/ScriptCs.Core/FileSystem.cs | 2 ++ src/ScriptCs.Core/Guard.cs | 17 ++++++++++++++++- src/ScriptCs/ScriptCsArgs.cs | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FilePreProcessor.cs b/src/ScriptCs.Core/FilePreProcessor.cs index 719937cb..25013d4f 100644 --- a/src/ScriptCs.Core/FilePreProcessor.cs +++ b/src/ScriptCs.Core/FilePreProcessor.cs @@ -33,6 +33,8 @@ public virtual FilePreProcessorResult ProcessScript(string script) protected virtual FilePreProcessorResult Parse(Action parseAction) { + Guard.AgainstNullArgument("parseAction", parseAction); + var context = new FilePreProcessorContext(); _logger.DebugFormat("Starting pre-processing"); @@ -54,6 +56,8 @@ protected virtual FilePreProcessorResult Parse(Action p protected virtual string GenerateCode(FilePreProcessorContext context) { + Guard.AgainstNullArgument("context", context); + var stringBuilder = new StringBuilder(); var usingLines = context.UsingStatements @@ -82,6 +86,9 @@ protected virtual void ParseFile(string path, FilePreProcessorContext context) protected virtual void ParseScript(List scriptLines, FilePreProcessorContext context, string path = null) { + Guard.AgainstNullArgument("scriptLines", scriptLines); + Guard.AgainstNullArgument("context", context); + // Insert line directive if there's a path if (path != null) InsertLineDirective(path, scriptLines); @@ -97,6 +104,8 @@ protected virtual void ParseScript(List scriptLines, FilePreProcessorCon protected virtual void InsertLineDirective(string path, List fileLines) { + Guard.AgainstNullArgument("fileLines", fileLines); + var bodyIndex = fileLines.FindIndex(line => PreProcessorUtil.IsNonDirectiveLine(line) && !PreProcessorUtil.IsUsingLine(line)); if (bodyIndex == -1) return; @@ -106,6 +115,8 @@ protected virtual void InsertLineDirective(string path, List fileLines) protected virtual void ProcessLine(FilePreProcessorContext context, string line, bool isBeforeCode) { + Guard.AgainstNullArgument("context", context); + if (PreProcessorUtil.IsUsingLine(line)) { var @using = PreProcessorUtil.GetPath(PreProcessorUtil.UsingString, line); diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 374d66ce..41e9c6c3 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -78,6 +78,8 @@ public void FileDelete(string path) public IEnumerable SplitLines(string value) { + Guard.AgainstNullArgument("value", value); + return value.Split(new[] { NewLine }, StringSplitOptions.None); } diff --git a/src/ScriptCs.Core/Guard.cs b/src/ScriptCs.Core/Guard.cs index c4076255..a5cbf173 100644 --- a/src/ScriptCs.Core/Guard.cs +++ b/src/ScriptCs.Core/Guard.cs @@ -2,6 +2,7 @@ namespace ScriptCs { using System; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Globalization; /// @@ -17,6 +18,7 @@ internal static class Guard /// The argument. /// is null. /// is restricted to reference types to avoid boxing of value type objects. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgument(string parameterName, [ValidatedNotNull]TArgument argument) where TArgument : class { @@ -36,6 +38,7 @@ public static void AgainstNullArgument(string parameterName, [Validat /// /// Performs a type check to avoid boxing of value type objects. /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgumentIfNullable(string parameterName, [ValidatedNotNull]TArgument argument) { @@ -54,6 +57,7 @@ public static void AgainstNullArgumentIfNullable(string parameterName /// The argument property. /// is null. /// is restricted to reference types to avoid boxing of value type objects. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgumentProperty(string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) where TProperty : class @@ -75,6 +79,7 @@ public static void AgainstNullArgumentProperty(string parameterName, /// /// Performs a type check to avoid boxing of value type objects. /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] [DebuggerStepThrough] public static void AgainstNullArgumentPropertyIfNullable( string parameterName, string propertyName, [ValidatedNotNull]TProperty argumentProperty) @@ -85,12 +90,22 @@ public static void AgainstNullArgumentPropertyIfNullable( } } + /// + /// Determines whether the specified type is a nullable type. + /// + /// The type. + /// + /// true if the specified type is a nullable type; otherwise, false. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Distributed as a source code package.")] private static bool IsNullableType(this Type type) { return !type.IsValueType || (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); } - // NOTE: when applied to a parameter, this attribute provides an indication to code analysis that the argument has been null checked + /// + /// When applied to a parameter, this attribute provides an indication to code analysis that the argument has been null checked. + /// private sealed class ValidatedNotNullAttribute : Attribute { } diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 0b75acee..a8009099 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -52,6 +52,8 @@ public class ScriptCsArgs public static void SplitScriptArgs(ref string[] args, out string[] scriptArgs) { + Guard.AgainstNullArgument("args", args); + // Split the arguments list on "--". // The arguments before the "--" (or all arguments if there is no "--") are // for ScriptCs.exe, and the arguments after that are for the csx script. From 3ac569deb962140576a20e43765191a06028ccec Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Mon, 24 Jun 2013 23:58:25 -0700 Subject: [PATCH 099/993] Adding ability to override any service, removing manually creating services by using a temp container --- src/ScriptCs/CompositionRoot.cs | 95 +++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 34 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 19862bd7..c4004713 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -18,68 +18,95 @@ public class CompositionRoot { private readonly bool _debug; private readonly LogLevel _logLevel; - private readonly bool _shouldInitDrirectoryCatalog; + private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; + private IDictionary _overrides; - public CompositionRoot(ScriptCsArgs args) + public CompositionRoot(ScriptCsArgs args) : this(args, new Dictionary()) { - Guard.AgainstNullArgument("args", args); + } + public CompositionRoot(ScriptCsArgs args, IDictionary overrides) + { + Guard.AgainstNullArgument("args", args); + _overrides = overrides; + _debug = args.Debug; _logLevel = args.LogLevel; - _shouldInitDrirectoryCatalog = ShouldInitDrirectoryCatalog(args); + _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(args); } - public void Initialize() + public void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) { + if (_overrides.ContainsKey(typeof (T))) + { + var reg = _overrides[typeof(T)]; + if (reg.GetType().IsSubclassOf(typeof (Type))) + { + builder.RegisterType((Type) reg).As(); + } + else + { + builder.RegisterInstance(reg).As(); + } + } + else + { + registrationAction(builder); + } + } + + public void Initialize() + { var builder = new ContainerBuilder(); builder.RegisterType().As().Exported(x => x.As()); var loggerConfigurator = new LoggerConfigurator(_logLevel); loggerConfigurator.Configure(new ReplConsole()); var logger = loggerConfigurator.GetLogger(); - + builder.RegisterInstance(logger).Exported(x => x.As()); - var types = new[] - { - typeof (ScriptHostFactory), - typeof (FilePreProcessor), - typeof (ScriptPackResolver), - typeof (NugetInstallationProvider), - typeof (PackageInstaller), - }; - - builder.RegisterTypes(types).AsImplementedInterfaces(); - + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + if (_debug) { - builder.RegisterType().As(); - builder.RegisterType().As(); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); } else { - builder.RegisterType().As(); - builder.RegisterType().As(); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); } - builder.RegisterType().As(); + RegisterOverrideOrDefault(builder, b => b.RegisterType()); + + // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container + var tempBuilder = new ContainerBuilder(); + + tempBuilder.RegisterInstance(logger); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - // Hack to resolve assemblies for MEF catalog before building Autofac container - var fileSystem = new FileSystem(); - var assemblyUtility = new AssemblyUtility(); - var packageContainer = new PackageContainer(fileSystem); - var packageAssemblyResolver = new PackageAssemblyResolver(fileSystem, packageContainer); - var assemblyResolver = new AssemblyResolver(fileSystem, packageAssemblyResolver, assemblyUtility, logger); + var tempContainer = tempBuilder.Build(); + var assemblyResolver = tempContainer.Resolve(); - builder.RegisterInstance(fileSystem).As(); - builder.RegisterInstance(assemblyUtility).As(); - builder.RegisterInstance(packageContainer).As(); - builder.RegisterInstance(packageAssemblyResolver).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); + builder.RegisterInstance(tempContainer.Resolve()).As(); builder.RegisterInstance(assemblyResolver).As(); - if (_shouldInitDrirectoryCatalog) + if (_shouldInitDirectoryCatalog) { var currentDirectory = Environment.CurrentDirectory; var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); @@ -107,7 +134,7 @@ public ILog GetLogger() return _container.Resolve(); } - private static bool ShouldInitDrirectoryCatalog(ScriptCsArgs args) + private static bool ShouldInitDirectoryCatalog(ScriptCsArgs args) { return args.Repl || !string.IsNullOrWhiteSpace(args.ScriptName); } From bb694a662fcd11311f16394afac4150c395a73b4 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 00:51:26 -0700 Subject: [PATCH 100/993] Extracting engine and executor to be passed in so CR can be moved to core --- src/ScriptCs/CompositionRoot.cs | 39 +++++++++++++++++++-------------- src/ScriptCs/Program.cs | 17 +++++++++++++- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index c4004713..26b481a9 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -16,23 +16,38 @@ namespace ScriptCs { public class CompositionRoot { - private readonly bool _debug; private readonly LogLevel _logLevel; private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; private IDictionary _overrides; + private Type _scriptExecutorType; + private Type _scriptEngineType; - public CompositionRoot(ScriptCsArgs args) : this(args, new Dictionary()) + public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType) : this(args, scriptExecutorType, scriptEngineType, new Dictionary()) { } - public CompositionRoot(ScriptCsArgs args, IDictionary overrides) + public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) { Guard.AgainstNullArgument("args", args); + Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); + Guard.AgainstNullArgument("scriptEngine", scriptEngineType); + + if (!typeof(IScriptExecutor).IsAssignableFrom(scriptExecutorType)) + { + throw new ArgumentException("scriptExecutor type must implement IScriptExecutor", "scriptExecutor"); + } + + if (!typeof (IScriptEngine).IsAssignableFrom(scriptEngineType)) + { + throw new ArgumentException("scriptEgnine type must implement IScriptEngine", "scriptEngine"); + } + + _scriptExecutorType = scriptExecutorType; + _scriptEngineType = scriptEngineType; + _overrides = overrides; - - _debug = args.Debug; _logLevel = args.LogLevel; _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(args); } @@ -67,24 +82,14 @@ public void Initialize() var logger = loggerConfigurator.GetLogger(); builder.RegisterInstance(logger).Exported(x => x.As()); + builder.RegisterType(_scriptEngineType).As(); + builder.RegisterType(_scriptExecutorType).As(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - - if (_debug) - { - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - } - else - { - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - } - RegisterOverrideOrDefault(builder, b => b.RegisterType()); // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index cdced5ae..ca6b339a 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -3,6 +3,7 @@ using PowerArgs; using ScriptCs.Command; using System.Linq; +using ScriptCs.Engine.Roslyn; namespace ScriptCs { @@ -12,10 +13,24 @@ private static int Main(string[] args) { string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); + Type scriptExecutorType; + Type scriptEngineType; var commandArgs = ParseArguments(args); + - var compositionRoot = new CompositionRoot(commandArgs); + if (commandArgs.Debug) + { + scriptExecutorType = typeof (DebugScriptExecutor); + scriptEngineType = typeof (RoslynScriptDebuggerEngine); + } + else + { + scriptExecutorType = typeof (ScriptExecutor); + scriptEngineType = typeof (RoslynScriptEngine); + } + + var compositionRoot = new CompositionRoot(commandArgs, scriptExecutorType, scriptEngineType); compositionRoot.Initialize(); var logger = compositionRoot.GetLogger(); From 83ee88cf565eb63d4195f6b18545e87128fa420c Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 00:53:44 -0700 Subject: [PATCH 101/993] fixing typo --- src/ScriptCs/CompositionRoot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs/CompositionRoot.cs index 26b481a9..e7b706ba 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs/CompositionRoot.cs @@ -41,7 +41,7 @@ public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEn if (!typeof (IScriptEngine).IsAssignableFrom(scriptEngineType)) { - throw new ArgumentException("scriptEgnine type must implement IScriptEngine", "scriptEngine"); + throw new ArgumentException("scriptEngine type must implement IScriptEngine", "scriptEngine"); } _scriptExecutorType = scriptExecutorType; From f76c6e22dd4437bd23443302b2133108bb2a8500 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 02:00:40 -0700 Subject: [PATCH 102/993] Moving CompositionRoot to core, renaming ReplConsole to IConsole and doing a bunch of necessary refactorings to cut the CR dependencies --- ScriptCs.sln.ide/graph/ScriptCs.sln.ide | 3 + scriptcs_debug.sln | 37 ++++++++++++ .../CompositionRoot.cs | 58 +++++++++++-------- src/ScriptCs.Core/ILoggerConfigurator.cs | 13 +++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 6 ++ .../ScriptServiceRoot.cs | 0 src/ScriptCs.Core/packages.config | 1 + src/ScriptCs/LoggerConfigurator.cs | 2 +- src/ScriptCs/Program.cs | 7 ++- .../{ReplConsole.cs => ScriptConsole.cs} | 4 +- src/ScriptCs/ScriptCs.csproj | 6 +- 11 files changed, 102 insertions(+), 35 deletions(-) create mode 100644 ScriptCs.sln.ide/graph/ScriptCs.sln.ide create mode 100644 scriptcs_debug.sln rename src/{ScriptCs => ScriptCs.Core}/CompositionRoot.cs (74%) create mode 100644 src/ScriptCs.Core/ILoggerConfigurator.cs rename src/{ScriptCs => ScriptCs.Core}/ScriptServiceRoot.cs (100%) rename src/ScriptCs/{ReplConsole.cs => ScriptConsole.cs} (93%) diff --git a/ScriptCs.sln.ide/graph/ScriptCs.sln.ide b/ScriptCs.sln.ide/graph/ScriptCs.sln.ide new file mode 100644 index 00000000..4b1badd9 --- /dev/null +++ b/ScriptCs.sln.ide/graph/ScriptCs.sln.ide @@ -0,0 +1,3 @@ + + 0001-01-01T00:00:00Z + \ No newline at end of file diff --git a/scriptcs_debug.sln b/scriptcs_debug.sln new file mode 100644 index 00000000..24e9cece --- /dev/null +++ b/scriptcs_debug.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "scriptcs", "src\ScriptCs\bin\Debug\scriptcs.exe", "{D797ABD7-8971-4227-B9C4-8ECC158FD12B}" + ProjectSection(DebuggerProjectSystem) = preProject + PortSupplier = 00000000-0000-0000-0000-000000000000 + Executable = C:\code\scriptcs\src\ScriptCs\bin\Debug\scriptcs.exe + RemoteMachine = GBLOCK-WIN8 + StartingDirectory = C:\code\scriptcs-samples\wpf + Arguments = start.csx -debug + Environment = Default + LaunchingEngine = 00000000-0000-0000-0000-000000000000 + LaunchSQLEngine = No + AttachLaunchAction = No + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39CDE834-543F-4352-AF43-F1CA3D6CCBFF}" + ProjectSection(SolutionItems) = preProject + ..\scriptcs-samples\wpf\CalculatorView.xaml = ..\scriptcs-samples\wpf\CalculatorView.xaml + ..\scriptcs-samples\wpf\mvvm.csx = ..\scriptcs-samples\wpf\mvvm.csx + ..\scriptcs-samples\wpf\start.csx = ..\scriptcs-samples\wpf\start.csx + ..\scriptcs-samples\wpf\utilities.csx = ..\scriptcs-samples\wpf\utilities.csx + ..\scriptcs-samples\wpf\viewmodels.csx = ..\scriptcs-samples\wpf\viewmodels.csx + ..\scriptcs-samples\wpf\views.csx = ..\scriptcs-samples\wpf\views.csx + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D797ABD7-8971-4227-B9C4-8ECC158FD12B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/ScriptCs/CompositionRoot.cs b/src/ScriptCs.Core/CompositionRoot.cs similarity index 74% rename from src/ScriptCs/CompositionRoot.cs rename to src/ScriptCs.Core/CompositionRoot.cs index e7b706ba..eaf14efe 100644 --- a/src/ScriptCs/CompositionRoot.cs +++ b/src/ScriptCs.Core/CompositionRoot.cs @@ -8,7 +8,6 @@ using Autofac.Integration.Mef; using Common.Logging; using ScriptCs.Contracts; -using ScriptCs.Engine.Roslyn; using ScriptCs.Package; using ScriptCs.Package.InstallationProvider; @@ -16,50 +15,59 @@ namespace ScriptCs { public class CompositionRoot { - private readonly LogLevel _logLevel; private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; private ScriptServiceRoot _scriptServiceRoot; private IDictionary _overrides; private Type _scriptExecutorType; private Type _scriptEngineType; + private IConsole _console; + private string _scriptName; + private bool _repl; + private ILoggerConfigurator _loggerConfigurator; - public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType) : this(args, scriptExecutorType, scriptEngineType, new Dictionary()) + public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) + : this(scriptName, repl, loggerConfigurator, console, scriptExecutorType, scriptEngineType, new Dictionary()) { } - public CompositionRoot(ScriptCsArgs args, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) + public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) { - Guard.AgainstNullArgument("args", args); Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); Guard.AgainstNullArgument("scriptEngine", scriptEngineType); + Guard.AgainstNullArgument("console", console); + Guard.AgainstNullArgument("loggerConfigurator", loggerConfigurator); + + _loggerConfigurator = loggerConfigurator; + _console = console; + _scriptName = scriptName; + _repl = repl; if (!typeof(IScriptExecutor).IsAssignableFrom(scriptExecutorType)) { throw new ArgumentException("scriptExecutor type must implement IScriptExecutor", "scriptExecutor"); } - - if (!typeof (IScriptEngine).IsAssignableFrom(scriptEngineType)) + + if (!typeof(IScriptEngine).IsAssignableFrom(scriptEngineType)) { throw new ArgumentException("scriptEngine type must implement IScriptEngine", "scriptEngine"); } _scriptExecutorType = scriptExecutorType; _scriptEngineType = scriptEngineType; - + _overrides = overrides; - _logLevel = args.LogLevel; - _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(args); + _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(_repl, _scriptName); } public void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) { - if (_overrides.ContainsKey(typeof (T))) + if (_overrides.ContainsKey(typeof(T))) { var reg = _overrides[typeof(T)]; - if (reg.GetType().IsSubclassOf(typeof (Type))) + if (reg.GetType().IsSubclassOf(typeof(Type))) { - builder.RegisterType((Type) reg).As(); + builder.RegisterType((Type)reg).As(); } else { @@ -73,17 +81,16 @@ public void RegisterOverrideOrDefault(ContainerBuilder builder, Action().As().Exported(x => x.As()); + + _loggerConfigurator.Configure(_console); + var logger = _loggerConfigurator.GetLogger(); - var loggerConfigurator = new LoggerConfigurator(_logLevel); - loggerConfigurator.Configure(new ReplConsole()); - var logger = loggerConfigurator.GetLogger(); - builder.RegisterInstance(logger).Exported(x => x.As()); builder.RegisterType(_scriptEngineType).As(); builder.RegisterType(_scriptExecutorType).As(); + builder.RegisterInstance(_console).As(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); @@ -97,9 +104,9 @@ public void Initialize() tempBuilder.RegisterInstance(logger); RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b=>b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); var tempContainer = tempBuilder.Build(); @@ -126,7 +133,7 @@ public void Initialize() _container = builder.Build(); - _scriptServiceRoot = _container.Resolve(); + _scriptServiceRoot = _container.Resolve(); } public ScriptServiceRoot GetServiceRoot() @@ -139,9 +146,10 @@ public ILog GetLogger() return _container.Resolve(); } - private static bool ShouldInitDirectoryCatalog(ScriptCsArgs args) + private static bool ShouldInitDirectoryCatalog(bool repl, string scriptName) { - return args.Repl || !string.IsNullOrWhiteSpace(args.ScriptName); + return repl || !string.IsNullOrWhiteSpace(scriptName); } } } + diff --git a/src/ScriptCs.Core/ILoggerConfigurator.cs b/src/ScriptCs.Core/ILoggerConfigurator.cs new file mode 100644 index 00000000..4494037e --- /dev/null +++ b/src/ScriptCs.Core/ILoggerConfigurator.cs @@ -0,0 +1,13 @@ +using Common.Logging; +using ScriptCs.Contracts; + +namespace ScriptCs +{ + public interface ILoggerConfigurator + { + void Configure(IConsole console); + ILog GetLogger(); + } +} + + diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 9c78920e..6a5e3db1 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -29,6 +29,9 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll + ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll @@ -44,6 +47,7 @@ + @@ -61,6 +65,7 @@ + @@ -89,6 +94,7 @@ + diff --git a/src/ScriptCs/ScriptServiceRoot.cs b/src/ScriptCs.Core/ScriptServiceRoot.cs similarity index 100% rename from src/ScriptCs/ScriptServiceRoot.cs rename to src/ScriptCs.Core/ScriptServiceRoot.cs diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 0d6dfbdf..761319e9 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -4,5 +4,6 @@ + \ No newline at end of file diff --git a/src/ScriptCs/LoggerConfigurator.cs b/src/ScriptCs/LoggerConfigurator.cs index bb2597a0..2b4e6d92 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/src/ScriptCs/LoggerConfigurator.cs @@ -10,7 +10,7 @@ namespace ScriptCs { - public class LoggerConfigurator + public class LoggerConfigurator : ILoggerConfigurator { private const string ThreadPattern = " Thread[%thread]"; private const string Pattern = "%-5level{threadLevel}: %message%newline"; diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index ca6b339a..76b2ccb3 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -17,8 +17,7 @@ private static int Main(string[] args) Type scriptEngineType; var commandArgs = ParseArguments(args); - - + if (commandArgs.Debug) { scriptExecutorType = typeof (DebugScriptExecutor); @@ -30,7 +29,9 @@ private static int Main(string[] args) scriptEngineType = typeof (RoslynScriptEngine); } - var compositionRoot = new CompositionRoot(commandArgs, scriptExecutorType, scriptEngineType); + var loggerConfigurator = new LoggerConfigurator(commandArgs.LogLevel); + + var compositionRoot = new CompositionRoot(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); compositionRoot.Initialize(); var logger = compositionRoot.GetLogger(); diff --git a/src/ScriptCs/ReplConsole.cs b/src/ScriptCs/ScriptConsole.cs similarity index 93% rename from src/ScriptCs/ReplConsole.cs rename to src/ScriptCs/ScriptConsole.cs index 1df082ef..2a40f14a 100644 --- a/src/ScriptCs/ReplConsole.cs +++ b/src/ScriptCs/ScriptConsole.cs @@ -3,9 +3,9 @@ namespace ScriptCs { - public class ReplConsole : IConsole + public class ScriptConsole : IConsole { - public ReplConsole() + public ScriptConsole() { Console.CancelKeyPress += HandleCancelKeyPress; } diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 8a4d8b25..fcdb9c82 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -73,15 +73,13 @@ - - + + - - From 7a8f3e17c8def7880cd9e725ce6d86c6f9e63d83 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 02:13:38 -0700 Subject: [PATCH 103/993] removing PowerArgs from core --- src/ScriptCs.Core/ScriptCs.Core.csproj | 3 --- src/ScriptCs.Core/packages.config | 1 - 2 files changed, 4 deletions(-) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 6a5e3db1..0a54e099 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -29,9 +29,6 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll - - ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll diff --git a/src/ScriptCs.Core/packages.config b/src/ScriptCs.Core/packages.config index 761319e9..0d6dfbdf 100644 --- a/src/ScriptCs.Core/packages.config +++ b/src/ScriptCs.Core/packages.config @@ -4,6 +4,5 @@ - \ No newline at end of file From dcfdfe4bdff98e6ba2a214bc29d98e23038cd205 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:38:18 -0700 Subject: [PATCH 104/993] Adding unit tests --- src/ScriptCs.Core/CompositionRoot.cs | 4 +- .../CompositionRootTests.cs | 318 ++++++++++++++++++ .../ScriptCs.Core.Tests.csproj | 8 + test/ScriptCs.Core.Tests/packages.config | 1 + 4 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 test/ScriptCs.Core.Tests/CompositionRootTests.cs diff --git a/src/ScriptCs.Core/CompositionRoot.cs b/src/ScriptCs.Core/CompositionRoot.cs index eaf14efe..0687a62f 100644 --- a/src/ScriptCs.Core/CompositionRoot.cs +++ b/src/ScriptCs.Core/CompositionRoot.cs @@ -80,7 +80,7 @@ public void RegisterOverrideOrDefault(ContainerBuilder builder, Action(); builder.RegisterType(_scriptExecutorType).As(); builder.RegisterInstance(_console).As(); + builder.RegisterType(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); @@ -134,6 +135,7 @@ public void Initialize() _container = builder.Build(); _scriptServiceRoot = _container.Resolve(); + return _container; } public ScriptServiceRoot GetServiceRoot() diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs new file mode 100644 index 00000000..d77829fd --- /dev/null +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Xunit; +using Should; + +namespace ScriptCs.Tests +{ + public class CompositionRootTests + { + public class TheInitializeMethod + { + private Mock _mockConsole = new Mock(); + private Type _scriptExecutorType = null; + private Type _scriptEngineType = null; + private Mock _mockLoggerConfigurator = new Mock(); + private Mock _mockLogger = new Mock(); + private IDictionary _overrides = new Dictionary(); + + public TheInitializeMethod() + { + var mockScriptExecutorType = new Mock(); + _scriptExecutorType = mockScriptExecutorType.Object.GetType(); + + var mockScriptEngineType = new Mock(); + _scriptEngineType = mockScriptEngineType.Object.GetType(); + + _mockLoggerConfigurator.Setup(l => l.GetLogger()).Returns(_mockLogger.Object); + } + + [Fact] + public void ShouldInvokeTheConfigureMethod() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + _mockLoggerConfigurator.Verify(l=>l.Configure(It.IsAny())); + + } + + [Fact] + public void ShouldGetTheLogger() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + _mockLoggerConfigurator.Verify(l=>l.GetLogger()); + } + + [Fact] + public void ShouldRegisterTheLoggerInstance() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + var logger = container.Resolve(); + logger.ShouldEqual(_mockLogger.Object); + } + + [Fact] + public void ShouldRegisterTheScriptEngine() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + var engine = container.Resolve(); + engine.GetType().ShouldEqual(_scriptEngineType); + } + + [Fact] + public void ShouldRegisterTheExecutor() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + var executor = container.Resolve(); + executor.GetType().ShouldEqual(_scriptExecutorType); + } + + [Fact] + public void ShouldRegisterTheConsoleInstance() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheServiceRoot() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + + [Fact] + public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFileSystemIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldReturnTheLoggerWhenGetLoggerIsInvoked() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + root.GetLogger().ShouldEqual(_mockLogger.Object); + } + + [Fact] + public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() + { + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + root.Initialize(); + root.GetServiceRoot().ShouldNotBeNull(); + + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptHostFactory() + { + var mock = new Mock(); + _overrides[typeof (IScriptHostFactory)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenFilePreProcessor() + { + var mock = new Mock(); + _overrides[typeof(IFilePreProcessor)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptPackResolver() + { + var mock = new Mock(); + _overrides[typeof(IScriptPackResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenInstallationProvider() + { + var mock = new Mock(); + _overrides[typeof(IInstallationProvider)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageInstaller() + { + var mock = new Mock(); + _overrides[typeof(IPackageInstaller)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + public class TestFileSystem : FileSystem + { + } + + [Fact] + public void ShouldRegisterTheOverriddenFileSystem() + { + _overrides[typeof(IFileSystem)] = new TestFileSystem(); + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(); + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyUtility() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyUtility)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageContainer() + { + var mock = new Mock(); + _overrides[typeof(IPackageContainer)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IPackageAssemblyResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + + + } + } +} diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index b2d1e374..f11fec92 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -9,6 +9,13 @@ ..\..\ + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll @@ -38,6 +45,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/packages.config b/test/ScriptCs.Core.Tests/packages.config index ae265215..2fc851e7 100644 --- a/test/ScriptCs.Core.Tests/packages.config +++ b/test/ScriptCs.Core.Tests/packages.config @@ -1,5 +1,6 @@  + From dcd8156eed1b33884d40afcafb3ed75fd4de2b7e Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:40:17 -0700 Subject: [PATCH 105/993] removing whitespace --- test/ScriptCs.Core.Tests/CompositionRootTests.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs index d77829fd..1b3c97eb 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -251,7 +251,6 @@ public void ShouldRegisterTheOverriddenPackageInstaller() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } public class TestFileSystem : FileSystem @@ -275,7 +274,6 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } [Fact] @@ -286,7 +284,6 @@ public void ShouldRegisterTheOverriddenPackageContainer() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } [Fact] @@ -297,7 +294,6 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } [Fact] @@ -308,7 +304,6 @@ public void ShouldRegisterTheOverriddenAssemblyResolver() var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); - } From ece779d6e90ee66057a817de1195e4f3213a3df9 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:44:30 -0700 Subject: [PATCH 106/993] fixing tests to register by type --- .../CompositionRootTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs index 1b3c97eb..154a11fc 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -206,7 +206,7 @@ public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() public void ShouldRegisterTheOverriddenScriptHostFactory() { var mock = new Mock(); - _overrides[typeof (IScriptHostFactory)] = mock.Object; + _overrides[typeof (IScriptHostFactory)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -216,7 +216,7 @@ public void ShouldRegisterTheOverriddenScriptHostFactory() public void ShouldRegisterTheOverriddenFilePreProcessor() { var mock = new Mock(); - _overrides[typeof(IFilePreProcessor)] = mock.Object; + _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -227,7 +227,7 @@ public void ShouldRegisterTheOverriddenFilePreProcessor() public void ShouldRegisterTheOverriddenScriptPackResolver() { var mock = new Mock(); - _overrides[typeof(IScriptPackResolver)] = mock.Object; + _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -237,7 +237,7 @@ public void ShouldRegisterTheOverriddenScriptPackResolver() public void ShouldRegisterTheOverriddenInstallationProvider() { var mock = new Mock(); - _overrides[typeof(IInstallationProvider)] = mock.Object; + _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -247,7 +247,7 @@ public void ShouldRegisterTheOverriddenInstallationProvider() public void ShouldRegisterTheOverriddenPackageInstaller() { var mock = new Mock(); - _overrides[typeof(IPackageInstaller)] = mock.Object; + _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -260,7 +260,7 @@ public class TestFileSystem : FileSystem [Fact] public void ShouldRegisterTheOverriddenFileSystem() { - _overrides[typeof(IFileSystem)] = new TestFileSystem(); + _overrides[typeof(IFileSystem)] = typeof(TestFileSystem); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(); @@ -270,7 +270,7 @@ public void ShouldRegisterTheOverriddenFileSystem() public void ShouldRegisterTheOverriddenAssemblyUtility() { var mock = new Mock(); - _overrides[typeof(IAssemblyUtility)] = mock.Object; + _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -280,7 +280,7 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() public void ShouldRegisterTheOverriddenPackageContainer() { var mock = new Mock(); - _overrides[typeof(IPackageContainer)] = mock.Object; + _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -290,7 +290,7 @@ public void ShouldRegisterTheOverriddenPackageContainer() public void ShouldRegisterTheOverriddenPackageAssemblyResolver() { var mock = new Mock(); - _overrides[typeof(IPackageAssemblyResolver)] = mock.Object; + _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); @@ -300,7 +300,7 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() public void ShouldRegisterTheOverriddenAssemblyResolver() { var mock = new Mock(); - _overrides[typeof(IAssemblyResolver)] = mock.Object; + _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); var container = root.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); From 7dd8e1d736ccae495d1d59c79a8cae68907f19f2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 03:50:17 -0700 Subject: [PATCH 107/993] Adding an instance override test --- test/ScriptCs.Core.Tests/CompositionRootTests.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/CompositionRootTests.cs index 154a11fc..034236cf 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/CompositionRootTests.cs @@ -306,6 +306,17 @@ public void ShouldRegisterTheOverriddenAssemblyResolver() container.Resolve().ShouldBeType(mock.Object.GetType()); } + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolverInstance() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object; + var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = root.Initialize(); + container.Resolve().ShouldEqual(mock.Object); + } + + } From 1d5069846420a36aa4509beb03d46d0acdf9dd45 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 09:28:53 -0700 Subject: [PATCH 108/993] Resetting CommonVersionInfo.cs content --- common/CommonVersionInfo.cs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 270505b9..590a13eb 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,18 +1,9 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18033 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -using System; using System.Reflection; -[assembly: System.Reflection.AssemblyVersionAttribute("0.5.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.5.0-alpha")] - -// Generated by the MSBuild WriteCodeFragment class on 16/05/2013 1:24:46 PM. +/** + * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the + * contents of 'build\ScriptCs.Version.props'. + **/ +[assembly: AssemblyVersion("0.0.0")] +[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file From 0098498cc72e86e1473eb6dab548eadd45072231 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 10:57:14 -0600 Subject: [PATCH 109/993] Ignore *.bak files --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 11b6d0f7..362c5a12 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ x64/ *.tlh *.tmp *.log +*.bak *.vspscc *.vssscc .builds @@ -107,4 +108,4 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML -artifacts \ No newline at end of file +artifacts From aba0d6aa1cd19224789f64c6044b05a4ed133a36 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 14:44:58 -0700 Subject: [PATCH 110/993] Renaming CompositionRoot and ServiceRoot, fix for #351 --- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +- .../{CompositionRoot.cs => ScriptRuntime.cs} | 18 +-- ...ScriptServiceRoot.cs => ScriptServices.cs} | 4 +- src/ScriptCs/Command/CommandFactory.cs | 64 ++++----- src/ScriptCs/Program.cs | 6 +- .../ScriptCs.Core.Tests.csproj | 2 +- ...tionRootTests.cs => ScriptRuntimeTests.cs} | 136 +++++++++--------- test/ScriptCs.Tests/CleanCommandTests.cs | 2 +- test/ScriptCs.Tests/CommandFactoryTests.cs | 4 +- .../ScriptCs.Tests/ExecuteReplCommandTests.cs | 2 +- .../ExecuteScriptCommandTests.cs | 8 +- test/ScriptCs.Tests/InstallCommandTests.cs | 4 +- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 13 files changed, 128 insertions(+), 128 deletions(-) rename src/ScriptCs.Core/{CompositionRoot.cs => ScriptRuntime.cs} (88%) rename src/ScriptCs.Core/{ScriptServiceRoot.cs => ScriptServices.cs} (95%) rename test/ScriptCs.Core.Tests/{CompositionRootTests.cs => ScriptRuntimeTests.cs} (56%) diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 0a54e099..361d92e7 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -44,7 +44,7 @@ - + @@ -91,7 +91,7 @@ - + diff --git a/src/ScriptCs.Core/CompositionRoot.cs b/src/ScriptCs.Core/ScriptRuntime.cs similarity index 88% rename from src/ScriptCs.Core/CompositionRoot.cs rename to src/ScriptCs.Core/ScriptRuntime.cs index 0687a62f..6d073ffd 100644 --- a/src/ScriptCs.Core/CompositionRoot.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -13,11 +13,11 @@ namespace ScriptCs { - public class CompositionRoot + public class ScriptRuntime { private readonly bool _shouldInitDirectoryCatalog; private IContainer _container; - private ScriptServiceRoot _scriptServiceRoot; + private ScriptServices _scriptServices; private IDictionary _overrides; private Type _scriptExecutorType; private Type _scriptEngineType; @@ -26,12 +26,12 @@ public class CompositionRoot private bool _repl; private ILoggerConfigurator _loggerConfigurator; - public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) + public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) : this(scriptName, repl, loggerConfigurator, console, scriptExecutorType, scriptEngineType, new Dictionary()) { } - public CompositionRoot(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) + public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) { Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); Guard.AgainstNullArgument("scriptEngine", scriptEngineType); @@ -91,14 +91,14 @@ public IContainer Initialize() builder.RegisterType(_scriptEngineType).As(); builder.RegisterType(_scriptExecutorType).As(); builder.RegisterInstance(_console).As(); - builder.RegisterType(); + builder.RegisterType(); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType()); + RegisterOverrideOrDefault(builder, b => b.RegisterType()); // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container var tempBuilder = new ContainerBuilder(); @@ -134,13 +134,13 @@ public IContainer Initialize() _container = builder.Build(); - _scriptServiceRoot = _container.Resolve(); + _scriptServices = _container.Resolve(); return _container; } - public ScriptServiceRoot GetServiceRoot() + public ScriptServices GetScriptServices() { - return _scriptServiceRoot; + return _scriptServices; } public ILog GetLogger() diff --git a/src/ScriptCs.Core/ScriptServiceRoot.cs b/src/ScriptCs.Core/ScriptServices.cs similarity index 95% rename from src/ScriptCs.Core/ScriptServiceRoot.cs rename to src/ScriptCs.Core/ScriptServices.cs index d8d665bb..a144d45e 100644 --- a/src/ScriptCs.Core/ScriptServiceRoot.cs +++ b/src/ScriptCs.Core/ScriptServices.cs @@ -4,9 +4,9 @@ namespace ScriptCs { - public class ScriptServiceRoot + public class ScriptServices { - public ScriptServiceRoot( + public ScriptServices( IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IScriptExecutor executor, diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index f322affb..fb077817 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -4,11 +4,11 @@ namespace ScriptCs.Command { public class CommandFactory { - private readonly ScriptServiceRoot _scriptServiceRoot; + private readonly ScriptServices _scriptServices; - public CommandFactory(ScriptServiceRoot scriptServiceRoot) + public CommandFactory(ScriptServices scriptServices) { - _scriptServiceRoot = scriptServiceRoot; + _scriptServices = scriptServices; } public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) @@ -17,19 +17,19 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Help) { - return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: true); + return new ShowUsageCommand(_scriptServices.Logger, isValid: true); } if (args.Repl) { var replCommand = new ExecuteReplCommand( - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Engine, - _scriptServiceRoot.FilePreProcessor, - _scriptServiceRoot.Logger, - _scriptServiceRoot.Console, - _scriptServiceRoot.AssemblyResolver); + _scriptServices.FileSystem, + _scriptServices.ScriptPackResolver, + _scriptServices.Engine, + _scriptServices.FilePreProcessor, + _scriptServices.Logger, + _scriptServices.Console, + _scriptServices.AssemblyResolver); return replCommand; } @@ -39,13 +39,13 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var executeCommand = new ExecuteScriptCommand( args.ScriptName, scriptArgs, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.Executor, - _scriptServiceRoot.ScriptPackResolver, - _scriptServiceRoot.Logger, - _scriptServiceRoot.AssemblyResolver); + _scriptServices.FileSystem, + _scriptServices.Executor, + _scriptServices.ScriptPackResolver, + _scriptServices.Logger, + _scriptServices.AssemblyResolver); - var fileSystem = _scriptServiceRoot.FileSystem; + var fileSystem = _scriptServices.FileSystem; var currentDirectory = fileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); var packagesFolder = Path.Combine(currentDirectory, Constants.PackagesFolder); @@ -56,9 +56,9 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) null, false, fileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.PackageInstaller, - _scriptServiceRoot.Logger); + _scriptServices.PackageAssemblyResolver, + _scriptServices.PackageInstaller, + _scriptServices.Logger); return new CompositeCommand(installCommand, executeCommand); } @@ -71,17 +71,17 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) var installCommand = new InstallCommand( args.Install, args.AllowPreRelease, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.PackageAssemblyResolver, - _scriptServiceRoot.PackageInstaller, - _scriptServiceRoot.Logger); + _scriptServices.FileSystem, + _scriptServices.PackageAssemblyResolver, + _scriptServices.PackageInstaller, + _scriptServices.Logger); - var currentDirectory = _scriptServiceRoot.FileSystem.CurrentDirectory; + var currentDirectory = _scriptServices.FileSystem.CurrentDirectory; var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); - if (!_scriptServiceRoot.FileSystem.FileExists(packageFile)) + if (!_scriptServices.FileSystem.FileExists(packageFile)) { - var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + var saveCommand = new SaveCommand(_scriptServices.PackageAssemblyResolver); return new CompositeCommand(installCommand, saveCommand); } @@ -90,19 +90,19 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Clean) { - var saveCommand = new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + var saveCommand = new SaveCommand(_scriptServices.PackageAssemblyResolver); var cleanCommand = new CleanCommand( args.ScriptName, - _scriptServiceRoot.FileSystem, - _scriptServiceRoot.Logger); + _scriptServices.FileSystem, + _scriptServices.Logger); return new CompositeCommand(saveCommand, cleanCommand); } if (args.Save) { - return new SaveCommand(_scriptServiceRoot.PackageAssemblyResolver); + return new SaveCommand(_scriptServices.PackageAssemblyResolver); } if (args.Version) @@ -110,7 +110,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) return new VersionCommand(); } - return new ShowUsageCommand(_scriptServiceRoot.Logger, isValid: false); + return new ShowUsageCommand(_scriptServices.Logger, isValid: false); } } } diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 76b2ccb3..ca1d0b28 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -31,13 +31,13 @@ private static int Main(string[] args) var loggerConfigurator = new LoggerConfigurator(commandArgs.LogLevel); - var compositionRoot = new CompositionRoot(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); + var compositionRoot = new ScriptRuntime(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); compositionRoot.Initialize(); var logger = compositionRoot.GetLogger(); - logger.Debug("Creating ScriptServiceRoot"); + logger.Debug("Creating ScriptServices"); - var scriptServiceRoot = compositionRoot.GetServiceRoot(); + var scriptServiceRoot = compositionRoot.GetScriptServices(); var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs, scriptArgs); diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index f11fec92..4052b23c 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -45,7 +45,7 @@ Properties\CommonVersionInfo.cs - + diff --git a/test/ScriptCs.Core.Tests/CompositionRootTests.cs b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs similarity index 56% rename from test/ScriptCs.Core.Tests/CompositionRootTests.cs rename to test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs index 034236cf..61c20a5b 100644 --- a/test/ScriptCs.Core.Tests/CompositionRootTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs @@ -14,7 +14,7 @@ namespace ScriptCs.Tests { - public class CompositionRootTests + public class ScriptRuntimeTests { public class TheInitializeMethod { @@ -39,8 +39,8 @@ public TheInitializeMethod() [Fact] public void ShouldInvokeTheConfigureMethod() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); _mockLoggerConfigurator.Verify(l=>l.Configure(It.IsAny())); } @@ -48,16 +48,16 @@ public void ShouldInvokeTheConfigureMethod() [Fact] public void ShouldGetTheLogger() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); _mockLoggerConfigurator.Verify(l=>l.GetLogger()); } [Fact] public void ShouldRegisterTheLoggerInstance() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); var logger = container.Resolve(); logger.ShouldEqual(_mockLogger.Object); } @@ -65,8 +65,8 @@ public void ShouldRegisterTheLoggerInstance() [Fact] public void ShouldRegisterTheScriptEngine() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); var engine = container.Resolve(); engine.GetType().ShouldEqual(_scriptEngineType); } @@ -74,8 +74,8 @@ public void ShouldRegisterTheScriptEngine() [Fact] public void ShouldRegisterTheExecutor() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); var executor = container.Resolve(); executor.GetType().ShouldEqual(_scriptExecutorType); } @@ -83,122 +83,122 @@ public void ShouldRegisterTheExecutor() [Fact] public void ShouldRegisterTheConsoleInstance() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] - public void ShouldRegisterTheServiceRoot() + public void ShouldRegisterTheScriptServices() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); - container.Resolve().ShouldNotBeNull(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); + container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); - container.Resolve().ShouldNotBeNull(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); + container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFileSystemIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldReturnTheLoggerWhenGetLoggerIsInvoked() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); - root.GetLogger().ShouldEqual(_mockLogger.Object); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); + runtime.GetLogger().ShouldEqual(_mockLogger.Object); } [Fact] public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() { - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - root.Initialize(); - root.GetServiceRoot().ShouldNotBeNull(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); + runtime.Initialize(); + runtime.GetScriptServices().ShouldNotBeNull(); } @@ -207,8 +207,8 @@ public void ShouldRegisterTheOverriddenScriptHostFactory() { var mock = new Mock(); _overrides[typeof (IScriptHostFactory)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -217,8 +217,8 @@ public void ShouldRegisterTheOverriddenFilePreProcessor() { var mock = new Mock(); _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -228,8 +228,8 @@ public void ShouldRegisterTheOverriddenScriptPackResolver() { var mock = new Mock(); _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -238,8 +238,8 @@ public void ShouldRegisterTheOverriddenInstallationProvider() { var mock = new Mock(); _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -248,8 +248,8 @@ public void ShouldRegisterTheOverriddenPackageInstaller() { var mock = new Mock(); _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -261,8 +261,8 @@ public class TestFileSystem : FileSystem public void ShouldRegisterTheOverriddenFileSystem() { _overrides[typeof(IFileSystem)] = typeof(TestFileSystem); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(); } @@ -271,8 +271,8 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() { var mock = new Mock(); _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -281,8 +281,8 @@ public void ShouldRegisterTheOverriddenPackageContainer() { var mock = new Mock(); _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -291,8 +291,8 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -301,8 +301,8 @@ public void ShouldRegisterTheOverriddenAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -311,8 +311,8 @@ public void ShouldRegisterTheOverriddenAssemblyResolverInstance() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object; - var root = new CompositionRoot(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = root.Initialize(); + var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); + var container = runtime.Initialize(); container.Resolve().ShouldEqual(mock.Object); } diff --git a/test/ScriptCs.Tests/CleanCommandTests.cs b/test/ScriptCs.Tests/CleanCommandTests.cs index 62553def..00ce9fa0 100644 --- a/test/ScriptCs.Tests/CleanCommandTests.cs +++ b/test/ScriptCs.Tests/CleanCommandTests.cs @@ -25,7 +25,7 @@ public void ShouldDeletePackagesFolder() var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); fs.Setup(i => i.DirectoryExists(It.Is(x => x.Contains(Constants.PackagesFolder)))).Returns(true); fs.Setup(i => i.GetWorkingDirectory(It.IsAny())).Returns("c:\\"); diff --git a/test/ScriptCs.Tests/CommandFactoryTests.cs b/test/ScriptCs.Tests/CommandFactoryTests.cs index 353d9030..4ad4bfd5 100644 --- a/test/ScriptCs.Tests/CommandFactoryTests.cs +++ b/test/ScriptCs.Tests/CommandFactoryTests.cs @@ -11,7 +11,7 @@ public class CommandFactoryTests { public class CreateCommandMethod { - private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool packagesFolderExists = true) + private static ScriptServices CreateRoot(bool packagesFileExists = true, bool packagesFolderExists = true) { const string CurrentDirectory = "C:\\"; const string PackagesFile = "C:\\packages.config"; @@ -31,7 +31,7 @@ private static ScriptServiceRoot CreateRoot(bool packagesFileExists = true, bool var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); return root; } diff --git a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs index d86e3ed0..17ecd72a 100644 --- a/test/ScriptCs.Tests/ExecuteReplCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteReplCommandTests.cs @@ -27,7 +27,7 @@ public void ShouldPromptForInput() var console = new FakeConsole(writer, reader); - var root = new ScriptServiceRoot( + var root = new ScriptServices( mockFileSystem.Object, Mock.Of(), Mock.Of(), diff --git a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs index c3363161..96c4f1b1 100644 --- a/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs +++ b/test/ScriptCs.Tests/ExecuteScriptCommandTests.cs @@ -36,7 +36,7 @@ public void ScriptExecCommandShouldInvokeWithScriptPassedFromArgs() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -76,7 +76,7 @@ public void NonManagedAssembliesAreExcluded() var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); @@ -113,7 +113,7 @@ public void ShouldReturnErrorIfThereIsCompileException() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -148,7 +148,7 @@ public void ShouldReturnErrorIfThereIsExecuteException() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); diff --git a/test/ScriptCs.Tests/InstallCommandTests.cs b/test/ScriptCs.Tests/InstallCommandTests.cs index c1e4efaa..505e6d22 100644 --- a/test/ScriptCs.Tests/InstallCommandTests.cs +++ b/test/ScriptCs.Tests/InstallCommandTests.cs @@ -38,7 +38,7 @@ public void InstallCommandShouldInstallSinglePackageIfNamePassed() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); @@ -72,7 +72,7 @@ public void InstallCommandShouldInstallFromPackagesConfigIfNoNamePassed() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); resolver.Setup(i => i.GetPackages(It.IsAny())).Returns(new List { diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 8546f5e8..462cbe5e 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -43,7 +43,7 @@ public void VersionCommandShouldOutputVersion() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServiceRoot(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); From dc298a6c8f7c63839f93412846a4a240aef53a79 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Tue, 25 Jun 2013 14:49:30 -0700 Subject: [PATCH 111/993] removing user files and adding to .gitignore --- .gitignore | 1 + ScriptCs.sln.ide/graph/ScriptCs.sln.ide | 3 -- scriptcs_debug.sln | 37 ------------------------- 3 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 ScriptCs.sln.ide/graph/ScriptCs.sln.ide delete mode 100644 scriptcs_debug.sln diff --git a/.gitignore b/.gitignore index 362c5a12..ffd6105f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ TestResults *.suo *.user *.sln.docstates +*.sln.ide # Build results [Dd]ebug/ diff --git a/ScriptCs.sln.ide/graph/ScriptCs.sln.ide b/ScriptCs.sln.ide/graph/ScriptCs.sln.ide deleted file mode 100644 index 4b1badd9..00000000 --- a/ScriptCs.sln.ide/graph/ScriptCs.sln.ide +++ /dev/null @@ -1,3 +0,0 @@ - - 0001-01-01T00:00:00Z - \ No newline at end of file diff --git a/scriptcs_debug.sln b/scriptcs_debug.sln deleted file mode 100644 index 24e9cece..00000000 --- a/scriptcs_debug.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "scriptcs", "src\ScriptCs\bin\Debug\scriptcs.exe", "{D797ABD7-8971-4227-B9C4-8ECC158FD12B}" - ProjectSection(DebuggerProjectSystem) = preProject - PortSupplier = 00000000-0000-0000-0000-000000000000 - Executable = C:\code\scriptcs\src\ScriptCs\bin\Debug\scriptcs.exe - RemoteMachine = GBLOCK-WIN8 - StartingDirectory = C:\code\scriptcs-samples\wpf - Arguments = start.csx -debug - Environment = Default - LaunchingEngine = 00000000-0000-0000-0000-000000000000 - LaunchSQLEngine = No - AttachLaunchAction = No - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{39CDE834-543F-4352-AF43-F1CA3D6CCBFF}" - ProjectSection(SolutionItems) = preProject - ..\scriptcs-samples\wpf\CalculatorView.xaml = ..\scriptcs-samples\wpf\CalculatorView.xaml - ..\scriptcs-samples\wpf\mvvm.csx = ..\scriptcs-samples\wpf\mvvm.csx - ..\scriptcs-samples\wpf\start.csx = ..\scriptcs-samples\wpf\start.csx - ..\scriptcs-samples\wpf\utilities.csx = ..\scriptcs-samples\wpf\utilities.csx - ..\scriptcs-samples\wpf\viewmodels.csx = ..\scriptcs-samples\wpf\viewmodels.csx - ..\scriptcs-samples\wpf\views.csx = ..\scriptcs-samples\wpf\views.csx - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D797ABD7-8971-4227-B9C4-8ECC158FD12B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal From 88f64542b71335e1f9604d824355e166ecc26a9d Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 26 Jun 2013 00:13:38 -0700 Subject: [PATCH 112/993] Adding the new Host project with a ScriptRuntimeBuilder. Bunch of refactoring to make ScriptCs project even lighter --- .../ScriptCs => ScriptCs.Hosting}/LogLevel.cs | 0 .../LoggerConfigurator.cs | 2 +- .../ScriptConsole.cs | 0 .../ScriptConsoleAppender.cs | 4 +- ScriptCs.Hosting/ScriptCs.Hosting.csproj | 91 +++++++++++++++++++ ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 63 +++++++++++++ ScriptCs.Hosting/packages.config | 6 ++ ScriptCs.sln | 6 ++ src/ScriptCs/Program.cs | 31 +++---- src/ScriptCs/ScriptCs.csproj | 8 +- 10 files changed, 184 insertions(+), 27 deletions(-) rename {src/ScriptCs => ScriptCs.Hosting}/LogLevel.cs (100%) rename {src/ScriptCs => ScriptCs.Hosting}/LoggerConfigurator.cs (96%) rename {src/ScriptCs => ScriptCs.Hosting}/ScriptConsole.cs (100%) rename src/ScriptCs/ScriptcsConsoleAppender.cs => ScriptCs.Hosting/ScriptConsoleAppender.cs (81%) create mode 100644 ScriptCs.Hosting/ScriptCs.Hosting.csproj create mode 100644 ScriptCs.Hosting/ScriptRuntimeBuilder.cs create mode 100644 ScriptCs.Hosting/packages.config diff --git a/src/ScriptCs/LogLevel.cs b/ScriptCs.Hosting/LogLevel.cs similarity index 100% rename from src/ScriptCs/LogLevel.cs rename to ScriptCs.Hosting/LogLevel.cs diff --git a/src/ScriptCs/LoggerConfigurator.cs b/ScriptCs.Hosting/LoggerConfigurator.cs similarity index 96% rename from src/ScriptCs/LoggerConfigurator.cs rename to ScriptCs.Hosting/LoggerConfigurator.cs index 2b4e6d92..06bab269 100644 --- a/src/ScriptCs/LoggerConfigurator.cs +++ b/ScriptCs.Hosting/LoggerConfigurator.cs @@ -29,7 +29,7 @@ public void Configure(IConsole console) { var hierarchy = (Hierarchy)LogManager.GetRepository(); var logger = LogManager.GetLogger(LoggerName); - var consoleAppender = new ScriptcsConsoleAppender(console) + var consoleAppender = new ScriptConsoleAppender(console) { Layout = new PatternLayout(GetLogPattern(_logLevel)), Threshold = hierarchy.LevelMap[_logLevel.ToString().ToUpper(CultureInfo.CurrentCulture)] diff --git a/src/ScriptCs/ScriptConsole.cs b/ScriptCs.Hosting/ScriptConsole.cs similarity index 100% rename from src/ScriptCs/ScriptConsole.cs rename to ScriptCs.Hosting/ScriptConsole.cs diff --git a/src/ScriptCs/ScriptcsConsoleAppender.cs b/ScriptCs.Hosting/ScriptConsoleAppender.cs similarity index 81% rename from src/ScriptCs/ScriptcsConsoleAppender.cs rename to ScriptCs.Hosting/ScriptConsoleAppender.cs index f250e7f5..b0867ea1 100644 --- a/src/ScriptCs/ScriptcsConsoleAppender.cs +++ b/ScriptCs.Hosting/ScriptConsoleAppender.cs @@ -5,11 +5,11 @@ namespace ScriptCs { - public class ScriptcsConsoleAppender : AppenderSkeleton + public class ScriptConsoleAppender : AppenderSkeleton { private readonly IConsole _console; - public ScriptcsConsoleAppender(IConsole console) + public ScriptConsoleAppender(IConsole console) { _console = console; } diff --git a/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/ScriptCs.Hosting/ScriptCs.Hosting.csproj new file mode 100644 index 00000000..969ac0cf --- /dev/null +++ b/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -0,0 +1,91 @@ + + + + + Debug + AnyCPU + {9AEF2D95-87FB-4829-B384-34BFE076D531} + Library + Properties + ScriptCs.Hosting + ScriptCs.Hosting + v4.5 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll + + + ..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll + + + ..\packages\log4net.1.2.10\lib\2.0\log4net.dll + + + + + + + + + + + + {6049e205-8b5f-4080-b023-70600e51fd64} + ScriptCs.Contracts + + + {e590e710-e159-48e6-a3e6-1a83d3fe732c} + ScriptCs.Core + + + {e79ec231-e27d-4057-91c9-2d001a3a8c3b} + ScriptCs.Engine.Roslyn + + + + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs new file mode 100644 index 00000000..27894868 --- /dev/null +++ b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Engine.Roslyn; + +namespace ScriptCs +{ + public class ScriptRuntimeBuilder + { + private bool _debug = false; + private bool _repl = false; + private string _scriptName; + private LogLevel _logLevel; + + public ScriptRuntime Build() + { + Type scriptExecutorType; + Type scriptEngineType; + + if (_debug) + { + scriptExecutorType = typeof(DebugScriptExecutor); + scriptEngineType = typeof(RoslynScriptDebuggerEngine); + } + else + { + scriptExecutorType = typeof(ScriptExecutor); + scriptEngineType = typeof(RoslynScriptEngine); + } + + var loggerConfigurator = new LoggerConfigurator(_logLevel); + + var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), scriptExecutorType, scriptEngineType); + return runtime; + } + + public ScriptRuntimeBuilder Debug(bool debug = true) + { + _debug = debug; + return this; + } + + public ScriptRuntimeBuilder ScriptName(string name) + { + _scriptName = name; + return this; + } + + public ScriptRuntimeBuilder Repl(bool repl = true) + { + _repl = repl; + return this; + } + + public ScriptRuntimeBuilder LogLevel(LogLevel level) + { + _logLevel = level; + return this; + } + } +} diff --git a/ScriptCs.Hosting/packages.config b/ScriptCs.Hosting/packages.config new file mode 100644 index 00000000..8ec4ed08 --- /dev/null +++ b/ScriptCs.Hosting/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ScriptCs.sln b/ScriptCs.sln index 79d00af5..22eac033 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -33,6 +33,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn", "s EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Tests", "test\ScriptCs.Engine.Roslyn.Tests\ScriptCs.Engine.Roslyn.Tests.csproj", "{28D11DE5-9F98-4E0A-8CCC-9CDC19110451}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Debug|Any CPU.Build.0 = Debug|Any CPU {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Release|Any CPU.ActiveCfg = Release|Any CPU {28D11DE5-9F98-4E0A-8CCC-9CDC19110451}.Release|Any CPU.Build.0 = Release|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index ca1d0b28..c635f873 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -13,31 +13,22 @@ private static int Main(string[] args) { string[] scriptArgs; ScriptCsArgs.SplitScriptArgs(ref args, out scriptArgs); - Type scriptExecutorType; - Type scriptEngineType; - + var commandArgs = ParseArguments(args); - - if (commandArgs.Debug) - { - scriptExecutorType = typeof (DebugScriptExecutor); - scriptEngineType = typeof (RoslynScriptDebuggerEngine); - } - else - { - scriptExecutorType = typeof (ScriptExecutor); - scriptEngineType = typeof (RoslynScriptEngine); - } - var loggerConfigurator = new LoggerConfigurator(commandArgs.LogLevel); - - var compositionRoot = new ScriptRuntime(commandArgs.ScriptName, commandArgs.Repl,loggerConfigurator,new ScriptConsole(), scriptExecutorType, scriptEngineType); - compositionRoot.Initialize(); + var runtime = new ScriptRuntimeBuilder(). + Debug(commandArgs.Debug). + LogLevel(commandArgs.LogLevel). + ScriptName(commandArgs.ScriptName). + Repl(commandArgs.Repl). + Build(); + + runtime.Initialize(); - var logger = compositionRoot.GetLogger(); + var logger = runtime.GetLogger(); logger.Debug("Creating ScriptServices"); - var scriptServiceRoot = compositionRoot.GetScriptServices(); + var scriptServiceRoot = runtime.GetScriptServices(); var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs, scriptArgs); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index fcdb9c82..08c6c705 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -73,11 +73,7 @@ - - - - @@ -89,6 +85,10 @@ + + {9aef2d95-87fb-4829-b384-34bfe076d531} + ScriptCs.Hosting + {6049e205-8b5f-4080-b023-70600e51fd64} ScriptCs.Contracts From b31cade3dbc72a4b0247dd4342054c6e4b846ad2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 26 Jun 2013 00:51:15 -0700 Subject: [PATCH 113/993] Adding override methods to builder --- ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 97 ++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 8 deletions(-) diff --git a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs index 27894868..89f4bf70 100644 --- a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs +++ b/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -4,6 +4,8 @@ using System.Text; using System.Threading.Tasks; using ScriptCs.Engine.Roslyn; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; namespace ScriptCs { @@ -13,26 +15,32 @@ public class ScriptRuntimeBuilder private bool _repl = false; private string _scriptName; private LogLevel _logLevel; + private IDictionary _overrides = new Dictionary(); + private Type _scriptExecutorType; + private Type _scriptEngineType; public ScriptRuntime Build() { - Type scriptExecutorType; - Type scriptEngineType; - if (_debug) { - scriptExecutorType = typeof(DebugScriptExecutor); - scriptEngineType = typeof(RoslynScriptDebuggerEngine); + if (_scriptExecutorType == null) + _scriptExecutorType = typeof(DebugScriptExecutor); + + if (_scriptEngineType == null) + _scriptEngineType = typeof(RoslynScriptDebuggerEngine); } else { - scriptExecutorType = typeof(ScriptExecutor); - scriptEngineType = typeof(RoslynScriptEngine); + if (_scriptExecutorType == null) + _scriptExecutorType = typeof(ScriptExecutor); + + if (_scriptEngineType == null) + _scriptEngineType = typeof(RoslynScriptEngine); } var loggerConfigurator = new LoggerConfigurator(_logLevel); - var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), scriptExecutorType, scriptEngineType); + var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), _scriptExecutorType, _scriptEngineType, _overrides); return runtime; } @@ -59,5 +67,78 @@ public ScriptRuntimeBuilder LogLevel(LogLevel level) _logLevel = level; return this; } + + public ScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor + { + _scriptExecutorType = typeof (T); + return this; + } + + public ScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine + { + _scriptEngineType = typeof(T); + return this; + } + + public ScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory + { + _overrides[typeof(IScriptHostFactory)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager + { + _overrides[typeof(IScriptPackManager)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver + { + _overrides[typeof(IScriptPackResolver)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider + { + _overrides[typeof(IInstallationProvider)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder FileSystem() where T : IFileSystem + { + _overrides[typeof(IFileSystem)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility + { + _overrides[typeof(IAssemblyUtility)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder PackageContainer() where T : IPackageContainer + { + _overrides[typeof(IPackageContainer)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor + { + _overrides[typeof(IFilePreProcessor)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver + { + _overrides[typeof(IPackageAssemblyResolver)] = typeof(T); + return this; + } + + public ScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor + { + _overrides[typeof(IAssemblyResolver)] = typeof(T); + return this; + } + } } From 38cf679afa58d050506c9d1c1f74288c9766a9fa Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 09:58:26 -0700 Subject: [PATCH 114/993] VersionCommand should depend on IConsole --- src/ScriptCs/Command/CommandFactory.cs | 2 +- src/ScriptCs/Command/VersionCommand.cs | 14 ++++++-- test/ScriptCs.Tests/VersionCommandTests.cs | 38 ++++++++-------------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index fb077817..082baea6 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -107,7 +107,7 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Version) { - return new VersionCommand(); + return new VersionCommand(_scriptServices.Console); } return new ShowUsageCommand(_scriptServices.Logger, isValid: false); diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index d51b4a0a..d8264c36 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -1,12 +1,22 @@ -using System; +using System.Diagnostics; +using ScriptCs.Contracts; namespace ScriptCs.Command { internal class VersionCommand : IVersionCommand { + private readonly IConsole _console; + + public VersionCommand(IConsole console) + { + _console = console; + } + public CommandResult Execute() { - Console.WriteLine("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + var message = string.Format("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + _console.WriteLine(message); + return CommandResult.Success; } } diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 462cbe5e..029d1eb2 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -1,6 +1,8 @@ -using Common.Logging; +using System.Diagnostics; +using Common.Logging; using Moq; using ScriptCs.Command; +using ScriptCs.Contracts; using ScriptCs.Package; using System.IO; using Xunit; @@ -11,28 +13,15 @@ public class VersionCommandTests { public class ExecuteMethod { - private readonly System.Version _currentVersion; - - System.Text.StringBuilder _outputText; - StringWriter _mockConsole; - TextWriter _actualConsole; - - public ExecuteMethod() - { - _currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; - _outputText = new System.Text.StringBuilder(); - _mockConsole = new StringWriter(_outputText); - _actualConsole = System.Console.Out; - System.Console.SetOut(_mockConsole); - } - [Fact] public void VersionCommandShouldOutputVersion() { - var args = new ScriptCsArgs - { - Version = true - }; + var assembly = typeof(ScriptCsArgs).Assembly; + var version = assembly.GetName().Version.ToString(); + + string actual = null; + + var args = new ScriptCsArgs { Version = true }; var fs = new Mock(); var resolver = new Mock(); @@ -43,17 +32,16 @@ public void VersionCommandShouldOutputVersion() var logger = new Mock(); var filePreProcessor = new Mock(); var assemblyName = new Mock(); - var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object); + var mockConsole = new Mock(); + mockConsole.Setup(x => x.WriteLine(It.IsAny())).Callback(text => actual = text); + var root = new ScriptServices(fs.Object, resolver.Object, executor.Object, engine.Object, filePreProcessor.Object, scriptpackResolver.Object, packageInstaller.Object, logger.Object, assemblyName.Object, mockConsole.Object); var factory = new CommandFactory(root); var result = factory.CreateCommand(args, new string[0]); - // clear the fake console output - _outputText.Clear(); - result.Execute(); - Assert.Contains("scriptcs version " + _currentVersion.ToString(), _outputText.ToString()); + Assert.Contains(version, actual); } } } From 90909caa49ff44ecbe2f02f873e0a2e9bc996b3d Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Tue, 25 Jun 2013 09:59:49 -0700 Subject: [PATCH 115/993] VersionCommand should write the product version --- src/ScriptCs/Command/VersionCommand.cs | 5 ++++- test/ScriptCs.Tests/VersionCommandTests.cs | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ScriptCs/Command/VersionCommand.cs b/src/ScriptCs/Command/VersionCommand.cs index d8264c36..1ed1e9b2 100644 --- a/src/ScriptCs/Command/VersionCommand.cs +++ b/src/ScriptCs/Command/VersionCommand.cs @@ -14,7 +14,10 @@ public VersionCommand(IConsole console) public CommandResult Execute() { - var message = string.Format("scriptcs version {0}", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version); + var assembly = typeof(Program).Assembly; + var productVersion = FileVersionInfo.GetVersionInfo(assembly.Location).ProductVersion; + var message = string.Format("scriptcs v{0}", productVersion); + _console.WriteLine(message); return CommandResult.Success; diff --git a/test/ScriptCs.Tests/VersionCommandTests.cs b/test/ScriptCs.Tests/VersionCommandTests.cs index 029d1eb2..70e4b967 100644 --- a/test/ScriptCs.Tests/VersionCommandTests.cs +++ b/test/ScriptCs.Tests/VersionCommandTests.cs @@ -17,7 +17,7 @@ public class ExecuteMethod public void VersionCommandShouldOutputVersion() { var assembly = typeof(ScriptCsArgs).Assembly; - var version = assembly.GetName().Version.ToString(); + var version = FileVersionInfo.GetVersionInfo(assembly.Location).ProductVersion; string actual = null; From b6c06ad11766630c93d130dd0f62f51e8bb1012f Mon Sep 17 00:00:00 2001 From: Filip W Date: Wed, 26 Jun 2013 20:44:12 +0200 Subject: [PATCH 116/993] updated to support Repl multi line --- src/ScriptCs.Core/Repl.cs | 25 ++++++++++++++++--- src/ScriptCs.Core/ScriptResult.cs | 22 ++++++++++++++++ .../RoslynScriptEngine.cs | 4 ++- src/ScriptCs/Command/ExecuteReplCommand.cs | 5 ++-- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 7beeb1a5..89960a1a 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -24,6 +24,8 @@ public override void Terminate() Console.Exit(); } + public string Buffer { get; set; } + public override ScriptResult Execute(string script) { try @@ -50,8 +52,17 @@ public override ScriptResult Execute(string script) return new ScriptResult(); } + //if (!script.EndsWith(";")) + //{ + // Buffer += script; + // return new ScriptResult(); + //} + Console.ForegroundColor = ConsoleColor.Cyan; - var result = ScriptEngine.Execute(script, new string[0], References, DefaultNamespaces, ScriptPackSession); + + Buffer += script; + + var result = ScriptEngine.Execute(Buffer, new string[0], References, DefaultNamespaces, ScriptPackSession); if (result != null) { if (result.CompileException != null) @@ -66,8 +77,16 @@ public override ScriptResult Execute(string script) Console.Write(result.ExecuteException.ToString()); } - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine(result.ReturnValue.ToJsv()); + if (result.IsPendingClosingChar) + { + return result; + } + else + { + Buffer = null; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(result.ReturnValue.ToJsv()); + } } return result; diff --git a/src/ScriptCs.Core/ScriptResult.cs b/src/ScriptCs.Core/ScriptResult.cs index 10933f69..c34c26c0 100644 --- a/src/ScriptCs.Core/ScriptResult.cs +++ b/src/ScriptCs.Core/ScriptResult.cs @@ -9,5 +9,27 @@ public class ScriptResult public Exception ExecuteException { get; set; } public Exception CompileException { get; set; } + + public bool ContinueBuffering { get; set; } + + public bool IsPendingClosingChar { get; set; } + + public char? ExpectingClosingChar { get; set; } + + public void UpdateClosingExpectation(Exception ex) + { + var message = ex.Message; + char? closingChar = null; + + if (message.Contains("CS1026: ) expected")) + closingChar = ')'; + else if (message.Contains("CS1513: } expected")) + closingChar = '}'; + else if (message.Contains("CS1003: Syntax error, ']' expected")) + closingChar = ']'; + + ExpectingClosingChar = closingChar; + IsPendingClosingChar = closingChar.HasValue; + } } } \ No newline at end of file diff --git a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs index 6ae75a46..f15341c3 100644 --- a/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs +++ b/src/ScriptCs.Engine.Roslyn/RoslynScriptEngine.cs @@ -102,7 +102,9 @@ protected virtual ScriptResult Execute(string code, Session session) } catch (Exception ex) { - result.CompileException = ex; + result.UpdateClosingExpectation(ex); + if (!result.IsPendingClosingChar) + result.CompileException = ex; } return result; } diff --git a/src/ScriptCs/Command/ExecuteReplCommand.cs b/src/ScriptCs/Command/ExecuteReplCommand.cs index 95d5d3ed..2d1adee4 100644 --- a/src/ScriptCs/Command/ExecuteReplCommand.cs +++ b/src/ScriptCs/Command/ExecuteReplCommand.cs @@ -68,10 +68,11 @@ public CommandResult Execute() private bool ExecuteLine(Repl repl) { - _console.Write("> "); + if (string.IsNullOrWhiteSpace(repl.Buffer)) + _console.Write("> "); var line = _console.ReadLine(); - if (line == string.Empty) return false; + if (line == string.Empty && string.IsNullOrWhiteSpace(repl.Buffer)) return false; repl.Execute(line); return true; From 33ae6840ce9ac9f72695a209ee1a8c017ddd7b39 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 12:00:17 -0700 Subject: [PATCH 117/993] Move ScriptCs.Hosting project into the src folder --- ScriptCs.sln | 2 +- .../ScriptCs.Hosting}/LogLevel.cs | 0 .../ScriptCs.Hosting}/LoggerConfigurator.cs | 0 .../ScriptCs.Hosting}/ScriptConsole.cs | 0 .../ScriptCs.Hosting}/ScriptConsoleAppender.cs | 0 .../ScriptCs.Hosting}/ScriptCs.Hosting.csproj | 16 ++++++++-------- .../ScriptCs.Hosting}/ScriptRuntimeBuilder.cs | 0 .../ScriptCs.Hosting}/packages.config | 0 src/ScriptCs/ScriptCs.csproj | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/LogLevel.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/LoggerConfigurator.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptConsole.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptConsoleAppender.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptCs.Hosting.csproj (84%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/ScriptRuntimeBuilder.cs (100%) rename {ScriptCs.Hosting => src/ScriptCs.Hosting}/packages.config (100%) diff --git a/ScriptCs.sln b/ScriptCs.sln index 22eac033..70adc0fa 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -33,7 +33,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn", "s EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Tests", "test\ScriptCs.Engine.Roslyn.Tests\ScriptCs.Engine.Roslyn.Tests.csproj", "{28D11DE5-9F98-4E0A-8CCC-9CDC19110451}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "src\ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/ScriptCs.Hosting/LogLevel.cs b/src/ScriptCs.Hosting/LogLevel.cs similarity index 100% rename from ScriptCs.Hosting/LogLevel.cs rename to src/ScriptCs.Hosting/LogLevel.cs diff --git a/ScriptCs.Hosting/LoggerConfigurator.cs b/src/ScriptCs.Hosting/LoggerConfigurator.cs similarity index 100% rename from ScriptCs.Hosting/LoggerConfigurator.cs rename to src/ScriptCs.Hosting/LoggerConfigurator.cs diff --git a/ScriptCs.Hosting/ScriptConsole.cs b/src/ScriptCs.Hosting/ScriptConsole.cs similarity index 100% rename from ScriptCs.Hosting/ScriptConsole.cs rename to src/ScriptCs.Hosting/ScriptConsole.cs diff --git a/ScriptCs.Hosting/ScriptConsoleAppender.cs b/src/ScriptCs.Hosting/ScriptConsoleAppender.cs similarity index 100% rename from ScriptCs.Hosting/ScriptConsoleAppender.cs rename to src/ScriptCs.Hosting/ScriptConsoleAppender.cs diff --git a/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj similarity index 84% rename from ScriptCs.Hosting/ScriptCs.Hosting.csproj rename to src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index 969ac0cf..c1cde3ee 100644 --- a/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -33,13 +33,13 @@ - ..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll - ..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll + ..\..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll - ..\packages\log4net.1.2.10\lib\2.0\log4net.dll + ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll @@ -50,24 +50,24 @@ - + {6049e205-8b5f-4080-b023-70600e51fd64} ScriptCs.Contracts - + {e590e710-e159-48e6-a3e6-1a83d3fe732c} ScriptCs.Core - + {e79ec231-e27d-4057-91c9-2d001a3a8c3b} ScriptCs.Engine.Roslyn - + Properties\CommonAssemblyInfo.cs - + Properties\CommonVersionInfo.cs diff --git a/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs similarity index 100% rename from ScriptCs.Hosting/ScriptRuntimeBuilder.cs rename to src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs diff --git a/ScriptCs.Hosting/packages.config b/src/ScriptCs.Hosting/packages.config similarity index 100% rename from ScriptCs.Hosting/packages.config rename to src/ScriptCs.Hosting/packages.config diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 08c6c705..ac3e3e66 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -85,7 +85,7 @@ - + {9aef2d95-87fb-4829-b384-34bfe076d531} ScriptCs.Hosting From d7525959ef3d65b0388fd13a566df19c51cd1230 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 12:09:24 -0700 Subject: [PATCH 118/993] Add AssemblyInfo.cs to the ScriptCs.Hosting project --- src/ScriptCs.Hosting/Properties/AssemblyInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/ScriptCs.Hosting/Properties/AssemblyInfo.cs diff --git a/src/ScriptCs.Hosting/Properties/AssemblyInfo.cs b/src/ScriptCs.Hosting/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..27c64e7e --- /dev/null +++ b/src/ScriptCs.Hosting/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; + +[assembly: AssemblyTitle("ScriptCs.Hosting")] +[assembly: AssemblyDescription("ScriptCs.Hosting provides common services necessary for hosting scriptcs in your application.")] From 8ed5ed2cf5c2aa22bb08f937162dbaafc1dac942 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 12:21:45 -0700 Subject: [PATCH 119/993] ScriptCs.Hosting should use the common build settings defined by the build script --- src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 26 ++------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index c1cde3ee..f6c02dd1 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -1,35 +1,12 @@  - + - Debug - AnyCPU {9AEF2D95-87FB-4829-B384-34BFE076D531} Library - Properties ScriptCs.Hosting ScriptCs.Hosting - v4.5 - 512 ..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 @@ -72,6 +49,7 @@ + From 30ff9d937087d41e3b8a4704cc8f1a724b023cc1 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 13:04:43 -0700 Subject: [PATCH 120/993] Create a nuspec file for ScriptCs.Hosting --- build/Build.proj | 1 + .../Properties/ScriptCs.Hosting.nuspec | 14 ++++++++++++++ src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 1 + 3 files changed, 16 insertions(+) create mode 100644 src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec diff --git a/build/Build.proj b/build/Build.proj index 1c340e06..679c3aee 100644 --- a/build/Build.proj +++ b/build/Build.proj @@ -79,6 +79,7 @@ + diff --git a/src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec b/src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec new file mode 100644 index 00000000..896e7dbb --- /dev/null +++ b/src/ScriptCs.Hosting/Properties/ScriptCs.Hosting.nuspec @@ -0,0 +1,14 @@ + + + + ScriptCs.Hosting + 0.0.0 + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + Glenn Block, Justin Rusbatch, Filip Wojcieszyn + https://github.com/scriptcs/scriptcs/blob/master/LICENSE.md + http://scriptcs.net + http://www.gravatar.com/avatar/5c754f646971d8bc800b9d4057931938.png?s=120 + ScriptCs.Hosting provides common services necessary for hosting scriptcs in your application. + roslyn csx script scriptcs + + \ No newline at end of file diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index f6c02dd1..7acdba64 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -56,6 +56,7 @@ + From 692bda054d350a8f835c39ded31b7d8c15fae14a Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Wed, 26 Jun 2013 14:26:16 -0700 Subject: [PATCH 121/993] Create a test project for ScriptCs.Hosting --- ScriptCs.sln | 7 ++++ .../Properties/AssemblyInfo.cs | 4 ++ .../ScriptCs.Hosting.Tests.csproj | 40 +++++++++++++++++++ test/ScriptCs.Hosting.Tests/packages.config | 4 ++ 4 files changed, 55 insertions(+) create mode 100644 test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs create mode 100644 test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj create mode 100644 test/ScriptCs.Hosting.Tests/packages.config diff --git a/ScriptCs.sln b/ScriptCs.sln index 70adc0fa..506cc3c3 100644 --- a/ScriptCs.sln +++ b/ScriptCs.sln @@ -35,6 +35,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Engine.Roslyn.Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting", "src\ScriptCs.Hosting\ScriptCs.Hosting.csproj", "{9AEF2D95-87FB-4829-B384-34BFE076D531}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScriptCs.Hosting.Tests", "test\ScriptCs.Hosting.Tests\ScriptCs.Hosting.Tests.csproj", "{EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,6 +75,10 @@ Global {9AEF2D95-87FB-4829-B384-34BFE076D531}.Debug|Any CPU.Build.0 = Debug|Any CPU {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AEF2D95-87FB-4829-B384-34BFE076D531}.Release|Any CPU.Build.0 = Release|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,5 +87,6 @@ Global {4D6A2A55-BB17-40CB-9567-EAFF80BEFDCE} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} {AC228213-7356-4F0D-BA48-EBA5FB8A7506} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} {28D11DE5-9F98-4E0A-8CCC-9CDC19110451} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A} = {A59C6538-62EA-4BF6-AA00-E0E9A2892D47} EndGlobalSection EndGlobal diff --git a/test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs b/test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d1a57655 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; + +[assembly: AssemblyTitle("ScriptCs.Hosting.Tests")] +[assembly: AssemblyDescription("")] diff --git a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj new file mode 100644 index 00000000..54bed027 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj @@ -0,0 +1,40 @@ + + + + + {EC03EAA0-94FD-4145-8F78-5F2E30E3FF9A} + Library + Properties + ScriptCs.Hosting.Tests + ScriptCs.Hosting.Tests + ..\..\ + + + + + + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + + + + Properties\CommonAssemblyInfo.cs + + + Properties\CommonVersionInfo.cs + + + + + + + + + {9aef2d95-87fb-4829-b384-34bfe076d531} + ScriptCs.Hosting + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Hosting.Tests/packages.config b/test/ScriptCs.Hosting.Tests/packages.config new file mode 100644 index 00000000..7c4280d1 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From 73283c53a7670ea2281a09e77012b811616094b7 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 28 Jun 2013 23:15:05 -0700 Subject: [PATCH 122/993] Settings services to be singletons, fix for #360 --- src/ScriptCs.Core/ScriptRuntime.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/ScriptRuntime.cs b/src/ScriptCs.Core/ScriptRuntime.cs index 6d073ffd..a88191c2 100644 --- a/src/ScriptCs.Core/ScriptRuntime.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -67,7 +67,7 @@ public void RegisterOverrideOrDefault(ContainerBuilder builder, Action(); + builder.RegisterType((Type)reg).As().SingleInstance(); } else { From eac02b2bbb94441ac286e66aa52df09db1fec17e Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 6 Jul 2013 08:32:25 +0200 Subject: [PATCH 123/993] Added tests for REPL multiline --- src/ScriptCs.Core/Repl.cs | 6 -- test/ScriptCs.Core.Tests/ReplTests.cs | 42 +++++++++++++ .../RoslynScriptEngineTests.cs | 63 +++++++++++++++++++ 3 files changed, 105 insertions(+), 6 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 89960a1a..076be474 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -52,12 +52,6 @@ public override ScriptResult Execute(string script) return new ScriptResult(); } - //if (!script.EndsWith(";")) - //{ - // Buffer += script; - // return new ScriptResult(); - //} - Console.ForegroundColor = ConsoleColor.Cyan; Buffer += script; diff --git a/test/ScriptCs.Core.Tests/ReplTests.cs b/test/ScriptCs.Core.Tests/ReplTests.cs index ac977553..ce8c4d5a 100644 --- a/test/ScriptCs.Core.Tests/ReplTests.cs +++ b/test/ScriptCs.Core.Tests/ReplTests.cs @@ -303,6 +303,48 @@ public void ShouldNotExecuteAnythingIfLineIsAReference() mocks.ScriptEngine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Never()); } + + [Fact] + public void ShouldSetBufferIFLineIsFirstOfMultilineConstruct() + { + var mocks = new Mocks(); + mocks.ScriptEngine.Setup( + x => + x.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(x => new ScriptResult() + { + ExpectingClosingChar = ')', + IsPendingClosingChar = true + }); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("var x = 1;"); + + _repl.Buffer.ShouldNotBeNull(); + } + + [Fact] + public void ShouldResetSetBufferIFLineIsBoLongerMultilineConstruct() + { + var mocks = new Mocks(); + mocks.ScriptEngine.Setup( + x => + x.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(new ScriptResult + { + IsPendingClosingChar = false + }); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Buffer = "class test {"; + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("}"); + + _repl.Buffer.ShouldBeNull(); + } } } } diff --git a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs index fc013f64..fc272900 100644 --- a/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs +++ b/test/ScriptCs.Engine.Roslyn.Tests/RoslynScriptEngineTests.cs @@ -245,6 +245,69 @@ public void ShouldNotReturnReturnValueIfCodeExecutionDoesNotReturnValue() result.ReturnValue.ShouldBeNull(); } + + [Fact] + public void ShouldSetIsPendingClosingCharToTrueIfCodeIsMissingCurlyBracket() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())) + .Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "class test {"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState {Session = roslynEngine.CreateSession()}; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] {"System"}, Enumerable.Empty(), + scriptPackSession); + + result.IsPendingClosingChar.ShouldBeTrue(); + result.ExpectingClosingChar.ShouldEqual('}'); + } + + [Fact] + public void ShouldSetIsPendingClosingCharToTrueIfCodeIsMissingSquareBracket() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())) + .Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "var x = new[1] { 1}; var y = x[0"; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), + scriptPackSession); + + result.IsPendingClosingChar.ShouldBeTrue(); + result.ExpectingClosingChar.ShouldEqual(']'); + } + + [Fact] + public void ShouldSetIsPendingClosingCharToTrueIfCodeIsMissingParenthesis() + { + var scriptHostFactory = new Mock(); + scriptHostFactory.Setup(f => f.CreateScriptHost(It.IsAny(), It.IsAny())) + .Returns((IScriptPackManager p, string[] q) => new ScriptHost(p, q)); + + var code = "System.Diagnostics.Debug.WriteLine(\"a\""; + + var engine = CreateScriptEngine(scriptHostFactory: scriptHostFactory); + var scriptPackSession = new ScriptPackSession(new List()); + var roslynEngine = new ScriptEngine(); + var session = new SessionState { Session = roslynEngine.CreateSession() }; + scriptPackSession.State[RoslynScriptEngine.SessionKey] = session; + var result = engine.Execute(code, new string[0], new[] { "System" }, Enumerable.Empty(), + scriptPackSession); + + result.IsPendingClosingChar.ShouldBeTrue(); + result.ExpectingClosingChar.ShouldEqual(')'); + } } } } \ No newline at end of file From 7319e26c557562c923686cc67a479380a910f6de Mon Sep 17 00:00:00 2001 From: Filip W Date: Sat, 6 Jul 2013 08:39:17 +0200 Subject: [PATCH 124/993] added test to verify the overall resubmission --- test/ScriptCs.Core.Tests/ReplTests.cs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/test/ScriptCs.Core.Tests/ReplTests.cs b/test/ScriptCs.Core.Tests/ReplTests.cs index ce8c4d5a..69635434 100644 --- a/test/ScriptCs.Core.Tests/ReplTests.cs +++ b/test/ScriptCs.Core.Tests/ReplTests.cs @@ -326,7 +326,7 @@ public void ShouldSetBufferIFLineIsFirstOfMultilineConstruct() } [Fact] - public void ShouldResetSetBufferIFLineIsBoLongerMultilineConstruct() + public void ShouldResetBufferIfLineIsNoLongerMultilineConstruct() { var mocks = new Mocks(); mocks.ScriptEngine.Setup( @@ -345,6 +345,27 @@ public void ShouldResetSetBufferIFLineIsBoLongerMultilineConstruct() _repl.Buffer.ShouldBeNull(); } + + [Fact] + public void ShouldResubmitEverytingIfLineIsNoLongerMultilineConstruct() + { + var mocks = new Mocks(); + mocks.ScriptEngine.Setup( + x => + x.Execute(It.Is(i => i == "class test {}"), It.IsAny(), It.IsAny>(), + It.IsAny>(), It.IsAny())) + .Returns(new ScriptResult + { + IsPendingClosingChar = false + }); + mocks.FileSystem.Setup(i => i.CurrentDirectory).Returns("C:/"); + _repl = GetRepl(mocks); + _repl.Buffer = "class test {"; + _repl.Initialize(Enumerable.Empty(), Enumerable.Empty()); + _repl.Execute("}"); + + mocks.ScriptEngine.Verify(); + } } } } From e4a8338ad8f5530273510aad7447e88efbef2ca0 Mon Sep 17 00:00:00 2001 From: lbargaoanu Date: Mon, 15 Jul 2013 15:38:07 +0300 Subject: [PATCH 125/993] Allow adding namespaces and refrences to script executor without having to create a script pack Issue #327 --- src/ScriptCs.Core/Repl.cs | 7 +- src/ScriptCs.Core/ScriptExecutor.cs | 81 ++++++++++++++++++- .../ScriptExecutorTests.cs | 47 ++++++++++- 3 files changed, 122 insertions(+), 13 deletions(-) diff --git a/src/ScriptCs.Core/Repl.cs b/src/ScriptCs.Core/Repl.cs index 076be474..fd5721ee 100644 --- a/src/ScriptCs.Core/Repl.cs +++ b/src/ScriptCs.Core/Repl.cs @@ -47,7 +47,7 @@ public override ScriptResult Execute(string script) { var assemblyName = PreProcessorUtil.GetPath(PreProcessorUtil.RString, script); var assemblyPath = FileSystem.GetFullPath(Path.Combine(Constants.BinFolder, assemblyName)); - References = References.Union(FileSystem.FileExists(assemblyPath) ? new[] { assemblyPath } : new[] { assemblyName }); + AddReference(FileSystem.FileExists(assemblyPath) ? assemblyPath : assemblyName); return new ScriptResult(); } @@ -87,10 +87,7 @@ public override ScriptResult Execute(string script) } catch (FileNotFoundException fileEx) { - if (References != null && References.Any(i => i == fileEx.FileName)) - { - References = References.Except(new[] {fileEx.FileName}); - } + RemoveReference(fileEx.FileName); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("\r\n" + fileEx + "\r\n"); return new ScriptResult { CompileException = fileEx }; diff --git a/src/ScriptCs.Core/ScriptExecutor.cs b/src/ScriptCs.Core/ScriptExecutor.cs index 46e02aa1..41063b97 100644 --- a/src/ScriptCs.Core/ScriptExecutor.cs +++ b/src/ScriptCs.Core/ScriptExecutor.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; using Common.Logging; @@ -15,20 +17,90 @@ public class ScriptExecutor : IScriptExecutor public IFilePreProcessor FilePreProcessor { get; private set; } public IScriptEngine ScriptEngine { get; private set; } public ILog Logger { get; private set; } - public IEnumerable References { get; protected set; } + public Collection References { get; private set; } + public Collection Namespaces { get; private set; } public ScriptPackSession ScriptPackSession { get; protected set; } public ScriptExecutor(IFileSystem fileSystem, IFilePreProcessor filePreProcessor, IScriptEngine scriptEngine, ILog logger) { + References = new Collection(); + AddReferences(DefaultReferences); + Namespaces = new Collection(); + AddNamespaces(DefaultNamespaces); FileSystem = fileSystem; FilePreProcessor = filePreProcessor; ScriptEngine = scriptEngine; Logger = logger; } + public void AddNamespaces(IEnumerable namespaces) + { + Guard.AgainstNullArgument("namespaces", namespaces); + + foreach(var @namespace in namespaces) + { + AddNamespace(@namespace); + } + } + + public void AddNamespace(string @namespace) + { + Guard.AgainstNullArgument("namespace", @namespace); + + Namespaces.Add(@namespace); + } + + public void AddNamespaceByType(Type typeFromReferencedAssembly) + { + Guard.AgainstNullArgument("typeFromReferencedAssembly", typeFromReferencedAssembly); + + AddNamespace(typeFromReferencedAssembly.Namespace); + } + + public void AddNamespaceByType() + { + AddNamespaceByType(typeof(T)); + } + + public void AddReferences(IEnumerable paths) + { + Guard.AgainstNullArgument("paths", paths); + + foreach(var path in paths) + { + AddReference(path); + } + } + + public void AddReferenceByType(Type typeFromReferencedAssembly) + { + Guard.AgainstNullArgument("typeFromReferencedAssembly", typeFromReferencedAssembly); + + AddReference(typeFromReferencedAssembly.Assembly.Location); + } + + public void AddReferenceByType() + { + AddReferenceByType(typeof(T)); + } + + public void AddReference(string path) + { + Guard.AgainstNullArgument("path", path); + + References.Add(path); + } + + public void RemoveReference(string path) + { + Guard.AgainstNullArgument("path", path); + + References.Remove(path); + } + public virtual void Initialize(IEnumerable paths, IEnumerable scriptPacks) { - References = DefaultReferences.Union(paths); + AddReferences(paths); var bin = Path.Combine(FileSystem.CurrentDirectory, "bin"); ScriptEngine.BaseDirectory = bin; @@ -56,9 +128,10 @@ public virtual ScriptResult Execute(string script, string[] scriptArgs) var path = Path.IsPathRooted(script) ? script : Path.Combine(FileSystem.CurrentDirectory, script); var result = FilePreProcessor.ProcessFile(path); var references = References.Union(result.References); + var namespaces = Namespaces.Union(result.UsingStatements); Logger.Debug("Starting execution in engine"); - return ScriptEngine.Execute(result.Code, scriptArgs, references, DefaultNamespaces, ScriptPackSession); + return ScriptEngine.Execute(result.Code, scriptArgs, references, namespaces, ScriptPackSession); } } } \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index a9eecca7..b5b7d9df 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -219,14 +219,53 @@ public void ShouldAddReferenceToEachDestinationFile() var destPaths = new string[] { "System", "System.Core", destinationFilePath1, destinationFilePath2, destinationFilePath3, destinationFilePath4 }; - scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny())); + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); + scriptExecutor.AddReference("a"); + scriptExecutor.AddReferences(new[]{"b", "c", "d"}); + scriptExecutor.AddReferenceByType(); + scriptExecutor.AddReferenceByType(typeof(TheInitializeMethod)); + var explicitReferences = new[] { "a", "b", "c", "d", typeof(FactAttribute).Assembly.Location, typeof(TheInitializeMethod).Assembly.Location }; // act - scriptExecutor.Initialize(paths, Enumerable.Empty()); + scriptExecutor.Initialize(destPaths, Enumerable.Empty()); scriptExecutor.Execute(scriptName); // assert - scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(destPaths))), It.IsAny>(), It.IsAny()), Times.Once()); + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(explicitReferences.Union(destPaths)))), It.IsAny>(), It.IsAny()), Times.Once()); + } + + [Fact] + public void ShouldAddNamespaces() + { + // arrange + var defaultReferences = ScriptExecutor.DefaultReferences; + var fileSystem = new Mock(); + var scriptEngine = new Mock(); + var preProcessor = new Mock(); + preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); + + var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); + + var currentDirectory = @"C:\"; + + var scriptName = "script.csx"; + + fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); + fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); + + scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); + + scriptExecutor.AddNamespace("a"); + scriptExecutor.AddNamespaces(new[] { "b", "c", "d" }); + scriptExecutor.AddNamespaceByType(); + scriptExecutor.AddNamespaceByType(typeof(TheInitializeMethod)); + var explicitNamespaces = new[] { "a", "b", "c", "d", typeof(FactAttribute).Namespace, typeof(TheInitializeMethod).Namespace }; + // act + scriptExecutor.Initialize(new string[0], Enumerable.Empty()); + scriptExecutor.Execute(scriptName); + + // assert + scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x=>x.SequenceEqual(ScriptExecutor.DefaultNamespaces.Union(explicitNamespaces))), It.IsAny()), Times.Once()); } [Fact] @@ -274,4 +313,4 @@ public void ExecutorShouldPassDefaultReferencesToEngine() } } } -} \ No newline at end of file +} From bb4f4d13d32722969b047c8cd23aca02b903eaa2 Mon Sep 17 00:00:00 2001 From: lbargaoanu Date: Tue, 23 Jul 2013 14:53:53 +0300 Subject: [PATCH 126/993] ScriptExecutor tests refactoring --- .../ScriptCs.Core.Tests.csproj | 22 ++- .../ScriptExecutorTests.cs | 138 +++++------------- test/ScriptCs.Core.Tests/app.config | 19 +++ test/ScriptCs.Core.Tests/packages.config | 6 +- 4 files changed, 78 insertions(+), 107 deletions(-) create mode 100644 test/ScriptCs.Core.Tests/app.config diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 4052b23c..24cc0d24 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -26,9 +26,19 @@ False ..\..\packages\Nuget.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + ..\..\packages\AutoFixture.3.6.5\lib\net40\Ploeh.AutoFixture.dll + + + ..\..\packages\AutoFixture.AutoMoq.3.6.5\lib\net40\Ploeh.AutoFixture.AutoMoq.dll + + + ..\..\packages\AutoFixture.Xunit.3.6.5\lib\net40\Ploeh.AutoFixture.Xunit.dll + - - ..\..\packages\Should.1.1.12.0\lib\Should.dll + + False + ..\..\packages\Should.1.1.20\lib\Should.dll @@ -36,6 +46,10 @@ ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + False + ..\..\packages\xunit.extensions.1.9.1\lib\net20\xunit.extensions.dll + @@ -44,6 +58,9 @@ Properties\CommonVersionInfo.cs + + ScriptCsAutoDataAttribute.cs + @@ -68,6 +85,7 @@ + diff --git a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs index b5b7d9df..45bd5ee5 100644 --- a/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptExecutorTests.cs @@ -2,49 +2,24 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Common.Logging; using Moq; +using Ploeh.AutoFixture.Xunit; using ScriptCs.Contracts; using Should; using Xunit; +using Xunit.Extensions; namespace ScriptCs.Tests { public class ScriptExecutorTests { - public static ScriptExecutor CreateScriptExecutor( - Mock fileSystem = null, - Mock fileProcessor = null, - Mock scriptEngine = null) - { - if (fileSystem == null) - { - fileSystem = new Mock(); - fileSystem.Setup(fs => fs.GetWorkingDirectory(It.IsAny())).Returns(@"C:\"); - } - - fileProcessor = fileProcessor ?? new Mock(); - - if (scriptEngine == null) - { - scriptEngine = new Mock(); - scriptEngine.SetupProperty(e => e.BaseDirectory); - } - - var logger = new Mock(); - - return new ScriptExecutor(fileSystem.Object, fileProcessor.Object, scriptEngine.Object, logger.Object); - } - public class TheInitializeMethod { - [Fact] - public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() + [Theory, ScriptCsAutoData] + public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { // arrange - var scriptEngine = new Mock(); - var fileSystem = new Mock(); - var preProcessor = new Mock(); preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); var currentDirectory = @"C:\"; @@ -53,8 +28,6 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() scriptEngine.SetupProperty(e => e.BaseDirectory); - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); - var paths = new string[0]; IEnumerable recipes = Enumerable.Empty(); @@ -66,24 +39,20 @@ public void ShouldSetEngineBaseDirectoryBasedOnCurrentDirectoryAndBinFolder() expectedBaseDirectory.ShouldEqual(scriptEngine.Object.BaseDirectory); } - [Fact] - public void ShouldInitializeScriptPacks() + [Theory, ScriptCsAutoData] + public void ShouldInitializeScriptPacks([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, + [Frozen] Mock scriptPack1, ScriptExecutor scriptExecutor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); // act - executor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); + scriptExecutor.Initialize(Enumerable.Empty(), new[] { scriptPack1.Object }); // assert scriptPack1.Verify(p => p.Initialize(It.IsAny())); @@ -92,19 +61,15 @@ public void ShouldInitializeScriptPacks() public class TheTerminateMethod { - [Fact] - public void ShouldTerminateScriptPacksWhenTerminateIsCalled() + [Theory, ScriptCsAutoData] + public void ShouldTerminateScriptPacksWhenTerminateIsCalled([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, + [Frozen] Mock scriptPack1, ScriptExecutor executor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - - var scriptPack1 = new Mock(); scriptPack1.Setup(p => p.Initialize(It.IsAny())); scriptPack1.Setup(p => p.GetContext()).Returns(Mock.Of()); scriptPack1.Setup(p => p.Terminate()); @@ -121,59 +86,43 @@ public void ShouldTerminateScriptPacksWhenTerminateIsCalled() public class TheExecuteMethod { - [Fact] - public void ConstructsAbsolutePathBeforePreProcessingFile() + [Theory, ScriptCsAutoData] + public void ConstructsAbsolutePathBeforePreProcessingFile([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, ScriptExecutor executor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void DoNotChangePathIfAbsolute() + [Theory, ScriptCsAutoData] + public void DoNotChangePathIfAbsolute([Frozen] Mock preProcessor, [Frozen] Mock fileSystem, ScriptExecutor executor) { - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor); executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); preProcessor.Verify(p => p.ProcessFile(@"c:\my_script\script.csx")); } - [Fact] - public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked() + [Theory, ScriptCsAutoData] + public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecuteIsInvoked([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { - // arrange - var scriptEngine = new Mock(); - var preProcessor = new Mock(); - var fileSystem = new Mock(); - string code = Guid.NewGuid().ToString(); var currentDirectory = @"C:\"; fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(currentDirectory); fileSystem.Setup(fs => fs.CurrentDirectory).Returns(currentDirectory); - var scriptExecutor = CreateScriptExecutor( - fileSystem: fileSystem, - fileProcessor: preProcessor, - scriptEngine: scriptEngine); - var scriptName = "script.csx"; var paths = new string[0]; var recipes = Enumerable.Empty(); @@ -189,21 +138,16 @@ public void ShouldExecuteScriptReturnedFromFileProcessorInScriptEngineWhenExecut preProcessor.Verify(fs => fs.ProcessFile(Path.Combine(currentDirectory, scriptName)), Times.Once()); scriptEngine.Verify(s => s.Execute(code, It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny()), Times.Once()); - } - [Fact] - public void ShouldAddReferenceToEachDestinationFile() + [Theory, ScriptCsAutoData] + public void ShouldAddReferenceToEachDestinationFile([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { // arrange var defaultReferences = ScriptExecutor.DefaultReferences; - var fileSystem = new Mock(); - var scriptEngine = new Mock(); - var preProcessor = new Mock(); preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); - var currentDirectory = @"C:\"; var destinationFilePath1 = Path.Combine(currentDirectory, @"bin\fileName1.cs"); var destinationFilePath2 = Path.Combine(currentDirectory, @"bin\fileName2.cs"); @@ -222,7 +166,7 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); scriptExecutor.AddReference("a"); - scriptExecutor.AddReferences(new[]{"b", "c", "d"}); + scriptExecutor.AddReferences(new[]{"a", "a", "b", "c", "d"}); scriptExecutor.AddReferenceByType(); scriptExecutor.AddReferenceByType(typeof(TheInitializeMethod)); var explicitReferences = new[] { "a", "b", "c", "d", typeof(FactAttribute).Assembly.Location, typeof(TheInitializeMethod).Assembly.Location }; @@ -234,18 +178,14 @@ public void ShouldAddReferenceToEachDestinationFile() scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.Is>(x => x.SequenceEqual(defaultReferences.Union(explicitReferences.Union(destPaths)))), It.IsAny>(), It.IsAny()), Times.Once()); } - [Fact] - public void ShouldAddNamespaces() + [Theory, ScriptCsAutoData] + public void ShouldAddNamespaces([Frozen] Mock scriptEngine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor scriptExecutor) { // arrange var defaultReferences = ScriptExecutor.DefaultReferences; - var fileSystem = new Mock(); - var scriptEngine = new Mock(); - var preProcessor = new Mock(); preProcessor.Setup(x => x.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult()); - var scriptExecutor = CreateScriptExecutor(fileSystem, preProcessor, scriptEngine); - var currentDirectory = @"C:\"; var scriptName = "script.csx"; @@ -256,7 +196,7 @@ public void ShouldAddNamespaces() scriptEngine.Setup(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), It.IsAny())); scriptExecutor.AddNamespace("a"); - scriptExecutor.AddNamespaces(new[] { "b", "c", "d" }); + scriptExecutor.AddNamespaces(new[] {"a", "a", "b", "c", "d" }); scriptExecutor.AddNamespaceByType(); scriptExecutor.AddNamespaceByType(typeof(TheInitializeMethod)); var explicitNamespaces = new[] { "a", "b", "c", "d", typeof(FactAttribute).Namespace, typeof(TheInitializeMethod).Namespace }; @@ -268,44 +208,34 @@ public void ShouldAddNamespaces() scriptEngine.Verify(e => e.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x=>x.SequenceEqual(ScriptExecutor.DefaultNamespaces.Union(explicitNamespaces))), It.IsAny()), Times.Once()); } - [Fact] - public void ExecutorShouldPassDefaultNamespacesToEngine() + [Theory, ScriptCsAutoData] + public void ExecutorShouldPassDefaultNamespacesToEngine([Frozen] Mock engine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor executor) { var expectedNamespaces = ScriptExecutor.DefaultNamespaces; - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var engine = new Mock(); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); engine.Verify(i => i.Execute(It.IsAny(), It.IsAny(), It.IsAny>(), It.Is>(x => !x.Except(expectedNamespaces).Any()), It.IsAny()), Times.Exactly(1)); } - [Fact] - public void ExecutorShouldPassDefaultReferencesToEngine() + [Theory, ScriptCsAutoData] + public void ExecutorShouldPassDefaultReferencesToEngine([Frozen] Mock engine, [Frozen] Mock fileSystem, + [Frozen] Mock preProcessor, ScriptExecutor executor) { var defaultReferences = ScriptExecutor.DefaultReferences; - var fileSystem = new Mock(); fileSystem.Setup(f => f.GetWorkingDirectory(It.IsAny())).Returns(@"c:\my_script"); fileSystem.Setup(f => f.CurrentDirectory).Returns(@"c:\my_script"); - var preProcessor = new Mock(); preProcessor.Setup(p => p.ProcessFile(It.IsAny())).Returns(new FilePreProcessorResult { Code = "var a = 0;" }); - var engine = new Mock(); - - var executor = CreateScriptExecutor(fileSystem: fileSystem, fileProcessor: preProcessor, scriptEngine: engine); - executor.Initialize(Enumerable.Empty(), Enumerable.Empty()); executor.Execute("script.csx"); @@ -313,4 +243,4 @@ public void ExecutorShouldPassDefaultReferencesToEngine() } } } -} +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/app.config b/test/ScriptCs.Core.Tests/app.config new file mode 100644 index 00000000..280e1ca4 --- /dev/null +++ b/test/ScriptCs.Core.Tests/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/packages.config b/test/ScriptCs.Core.Tests/packages.config index 2fc851e7..d7496cbb 100644 --- a/test/ScriptCs.Core.Tests/packages.config +++ b/test/ScriptCs.Core.Tests/packages.config @@ -1,9 +1,13 @@  + + + - + + \ No newline at end of file From cbb5e1be059f77613044be30af696fbab7b94c27 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 24 Jul 2013 13:44:24 -0700 Subject: [PATCH 127/993] Refactored runtime into a ScriptContainerFactory, this will enable reuse of the initialization container for loading modules. Also added module loader infra but not wired up yet --- .../FilePreProcessorResult.cs | 22 ++ src/ScriptCs.Contracts/IAssemblyResolver.cs | 9 + src/ScriptCs.Contracts/IAssemblyUtility.cs | 7 + src/ScriptCs.Contracts/IFilePreProcessor.cs | 11 + .../IFilePreProcessorResult.cs | 16 + src/ScriptCs.Contracts/IFileSystem.cs | 47 +++ .../IPackageAssemblyResolver.cs | 13 + src/ScriptCs.Contracts/IScriptCsModule.cs | 14 + src/ScriptCs.Contracts/IScriptEngine.cs | 10 + src/ScriptCs.Contracts/IScriptExecutor.cs | 13 + src/ScriptCs.Contracts/IScriptHostFactory.cs | 11 + src/ScriptCs.Contracts/IScriptPackManager.cs | 9 + src/ScriptCs.Contracts/IScriptPackResolver.cs | 10 + src/ScriptCs.Contracts/IScriptResult.cs | 19 ++ src/ScriptCs.Contracts/IScriptRuntime.cs | 12 + .../IScriptRuntimeBuilder.cs | 31 ++ src/ScriptCs.Contracts/LogLevel.cs | 10 + src/ScriptCs.Core/IScriptContainerFactory.cs | 10 + src/ScriptCs.Core/ScriptContainerFactory.cs | 143 +++++++++ src/ScriptCs.Core/ScriptCs.Core.csproj | 2 + src/ScriptCs.Core/ScriptRuntime.cs | 139 +------- src/ScriptCs.Hosting/IModule.cs | 13 + src/ScriptCs.Hosting/IModuleMetadata.cs | 8 + src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs | 26 ++ src/ScriptCs.Hosting/ModuleAttribute.cs | 15 + src/ScriptCs.Hosting/ModuleLoader.cs | 54 ++++ src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 6 + src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 39 +-- src/ScriptCs/ModuleAttribute.cs | 14 + src/ScriptCs/Program.cs | 17 +- src/ScriptCs/ScriptCs.csproj | 1 + .../ScriptContainerFactoryTests.cs | 235 ++++++++++++++ .../ScriptCs.Core.Tests.csproj | 1 + .../ScriptCs.Core.Tests/ScriptRuntimeTests.cs | 300 +----------------- 34 files changed, 845 insertions(+), 442 deletions(-) create mode 100644 src/ScriptCs.Contracts/FilePreProcessorResult.cs create mode 100644 src/ScriptCs.Contracts/IAssemblyResolver.cs create mode 100644 src/ScriptCs.Contracts/IAssemblyUtility.cs create mode 100644 src/ScriptCs.Contracts/IFilePreProcessor.cs create mode 100644 src/ScriptCs.Contracts/IFilePreProcessorResult.cs create mode 100644 src/ScriptCs.Contracts/IFileSystem.cs create mode 100644 src/ScriptCs.Contracts/IPackageAssemblyResolver.cs create mode 100644 src/ScriptCs.Contracts/IScriptCsModule.cs create mode 100644 src/ScriptCs.Contracts/IScriptEngine.cs create mode 100644 src/ScriptCs.Contracts/IScriptExecutor.cs create mode 100644 src/ScriptCs.Contracts/IScriptHostFactory.cs create mode 100644 src/ScriptCs.Contracts/IScriptPackManager.cs create mode 100644 src/ScriptCs.Contracts/IScriptPackResolver.cs create mode 100644 src/ScriptCs.Contracts/IScriptResult.cs create mode 100644 src/ScriptCs.Contracts/IScriptRuntime.cs create mode 100644 src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs create mode 100644 src/ScriptCs.Contracts/LogLevel.cs create mode 100644 src/ScriptCs.Core/IScriptContainerFactory.cs create mode 100644 src/ScriptCs.Core/ScriptContainerFactory.cs create mode 100644 src/ScriptCs.Hosting/IModule.cs create mode 100644 src/ScriptCs.Hosting/IModuleMetadata.cs create mode 100644 src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs create mode 100644 src/ScriptCs.Hosting/ModuleAttribute.cs create mode 100644 src/ScriptCs.Hosting/ModuleLoader.cs create mode 100644 src/ScriptCs/ModuleAttribute.cs create mode 100644 test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs diff --git a/src/ScriptCs.Contracts/FilePreProcessorResult.cs b/src/ScriptCs.Contracts/FilePreProcessorResult.cs new file mode 100644 index 00000000..f5731ebe --- /dev/null +++ b/src/ScriptCs.Contracts/FilePreProcessorResult.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public class FilePreProcessorResult + { + public FilePreProcessorResult() + { + UsingStatements = new List(); + LoadedScripts = new List(); + References = new List(); + } + + public List UsingStatements { get; set; } + + public List LoadedScripts { get; set; } + + public List References { get; set; } + + public string Code { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IAssemblyResolver.cs b/src/ScriptCs.Contracts/IAssemblyResolver.cs new file mode 100644 index 00000000..04bc3338 --- /dev/null +++ b/src/ScriptCs.Contracts/IAssemblyResolver.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace ScriptCs +{ + public interface IAssemblyResolver + { + IEnumerable GetAssemblyPaths(string path); + } +} diff --git a/src/ScriptCs.Contracts/IAssemblyUtility.cs b/src/ScriptCs.Contracts/IAssemblyUtility.cs new file mode 100644 index 00000000..805b4d5b --- /dev/null +++ b/src/ScriptCs.Contracts/IAssemblyUtility.cs @@ -0,0 +1,7 @@ +namespace ScriptCs +{ + public interface IAssemblyUtility + { + bool IsManagedAssembly(string assemblyPath); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessor.cs b/src/ScriptCs.Contracts/IFilePreProcessor.cs new file mode 100644 index 00000000..d4943eb2 --- /dev/null +++ b/src/ScriptCs.Contracts/IFilePreProcessor.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IFilePreProcessor + { + FilePreProcessorResult ProcessFile(string path); + + FilePreProcessorResult ProcessScript(string script); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessorResult.cs b/src/ScriptCs.Contracts/IFilePreProcessorResult.cs new file mode 100644 index 00000000..780d7559 --- /dev/null +++ b/src/ScriptCs.Contracts/IFilePreProcessorResult.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + public interface IFilePreProcessorResult + { + List UsingStatements { get; set; } + List LoadedScripts { get; set; } + List References { get; set; } + string Code { get; set; } + } +} diff --git a/src/ScriptCs.Contracts/IFileSystem.cs b/src/ScriptCs.Contracts/IFileSystem.cs new file mode 100644 index 00000000..f4c152ee --- /dev/null +++ b/src/ScriptCs.Contracts/IFileSystem.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace ScriptCs.Contracts +{ + public interface IFileSystem + { + IEnumerable EnumerateFiles(string dir, string search, SearchOption searchOption = SearchOption.AllDirectories); + + void Copy(string source, string dest, bool overwrite); + + bool DirectoryExists(string path); + + void CreateDirectory(string path); + + void DeleteDirectory(string path); + + string ReadFile(string path); + + string[] ReadFileLines(string path); + + DateTime GetLastWriteTime(string file); + + bool IsPathRooted(string path); + + string GetFullPath(string path); + + string CurrentDirectory { get; } + + string NewLine { get; } + + string GetWorkingDirectory(string path); + + void Move(string source, string dest); + + bool FileExists(string path); + + void FileDelete(string path); + + IEnumerable SplitLines(string value); + + void WriteToFile(string path, string text); + + Stream CreateFileStream(string filePath, FileMode mode); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs b/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs new file mode 100644 index 00000000..62fb4d83 --- /dev/null +++ b/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using ScriptCs.Package; + +namespace ScriptCs.Contracts +{ + public interface IPackageAssemblyResolver + { + void SavePackages(Action output); + IEnumerable GetPackages(string workingDirectory); + IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptCsModule.cs b/src/ScriptCs.Contracts/IScriptCsModule.cs new file mode 100644 index 00000000..3e6855e2 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptCsModule.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + public interface IScriptCsModule + { + void Initialize(IScriptRuntimeBuilder builder); + } +} diff --git a/src/ScriptCs.Contracts/IScriptEngine.cs b/src/ScriptCs.Contracts/IScriptEngine.cs new file mode 100644 index 00000000..b4081283 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptEngine.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IScriptEngine + { + string BaseDirectory { get; set; } + IScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptExecutor.cs b/src/ScriptCs.Contracts/IScriptExecutor.cs new file mode 100644 index 00000000..8b2c531f --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptExecutor.cs @@ -0,0 +1,13 @@ +using ScriptCs.Contracts; +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IScriptExecutor + { + void Initialize(IEnumerable paths, IEnumerable scriptPacks); + ScriptResult Execute(string script, string[] scriptArgs); + ScriptResult Execute(string script); + void Terminate(); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptHostFactory.cs b/src/ScriptCs.Contracts/IScriptHostFactory.cs new file mode 100644 index 00000000..153ca62c --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptHostFactory.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +using ScriptCs.Contracts; + +namespace ScriptCs.Contracts +{ + public interface IScriptHostFactory + { + ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs); + } +} diff --git a/src/ScriptCs.Contracts/IScriptPackManager.cs b/src/ScriptCs.Contracts/IScriptPackManager.cs new file mode 100644 index 00000000..2a51a49e --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptPackManager.cs @@ -0,0 +1,9 @@ +using ScriptCs.Contracts; + +namespace ScriptCs.Contracts +{ + public interface IScriptPackManager + { + TContext Get() where TContext : IScriptPackContext; + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptPackResolver.cs b/src/ScriptCs.Contracts/IScriptPackResolver.cs new file mode 100644 index 00000000..cf728f0e --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptPackResolver.cs @@ -0,0 +1,10 @@ +using ScriptCs.Contracts; +using System.Collections.Generic; + +namespace ScriptCs.Contracts +{ + public interface IScriptPackResolver + { + IEnumerable GetPacks(); + } +} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptResult.cs b/src/ScriptCs.Contracts/IScriptResult.cs new file mode 100644 index 00000000..e7b28885 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptResult.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + public interface IScriptResult + { + object ReturnValue { get; set; } + Exception ExecuteException { get; set; } + Exception CompileException { get; set; } + bool ContinueBuffering { get; set; } + bool IsPendingClosingChar { get; set; } + char? ExpectingClosingChar { get; set; } + void UpdateClosingExpectation(Exception ex); + } +} diff --git a/src/ScriptCs.Contracts/IScriptRuntime.cs b/src/ScriptCs.Contracts/IScriptRuntime.cs new file mode 100644 index 00000000..6717fa06 --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptRuntime.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs.Contracts +{ + class IScriptRuntime + { + } +} diff --git a/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs b/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs new file mode 100644 index 00000000..d89bfaef --- /dev/null +++ b/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs.Contracts +{ + public interface IScriptRuntimeBuilder + { + ScriptRuntime Build(); + IScriptRuntimeBuilder Debug(bool debug = true); + IScriptRuntimeBuilder ScriptName(string name); + IScriptRuntimeBuilder Repl(bool repl = true); + IScriptRuntimeBuilder LogLevel(LogLevel level); + IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor; + IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine; + IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory; + IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager; + IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver; + IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider; + IScriptRuntimeBuilder FileSystem() where T : IFileSystem; + IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility; + IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer; + IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor; + IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver; + IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor; + } +} diff --git a/src/ScriptCs.Contracts/LogLevel.cs b/src/ScriptCs.Contracts/LogLevel.cs new file mode 100644 index 00000000..bd15dd0e --- /dev/null +++ b/src/ScriptCs.Contracts/LogLevel.cs @@ -0,0 +1,10 @@ +namespace ScriptCs.Contracts +{ + public enum LogLevel + { + Error, + Info, + Debug, + Trace + } +} diff --git a/src/ScriptCs.Core/IScriptContainerFactory.cs b/src/ScriptCs.Core/IScriptContainerFactory.cs new file mode 100644 index 00000000..a9420f34 --- /dev/null +++ b/src/ScriptCs.Core/IScriptContainerFactory.cs @@ -0,0 +1,10 @@ +using Autofac; + +namespace ScriptCs +{ + public interface IScriptContainerFactory + { + IContainer InitializationContainer { get; } + IContainer RuntimeContainer { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/ScriptContainerFactory.cs b/src/ScriptCs.Core/ScriptContainerFactory.cs new file mode 100644 index 00000000..f232787b --- /dev/null +++ b/src/ScriptCs.Core/ScriptContainerFactory.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Autofac.Core; +using Autofac.Integration.Mef; +using Common.Logging; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs +{ + public class ScriptContainerFactory : IScriptContainerFactory + { + private readonly ILog _logger; + private readonly IConsole _console; + private readonly Type _scriptEngineType; + private readonly Type _scriptExecutorType; + private readonly bool _initDirectoryCatalog; + private IDictionary _overrides = null; + + public ScriptContainerFactory(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides ) + { + Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); + Guard.AgainstNullArgument("scriptEngine", scriptEngineType); + Guard.AgainstNullArgument("console", console); + Guard.AgainstNullArgument("logger", logger); + + if (overrides == null) + overrides = new Dictionary(); + + _logger = logger; + _console = console; + _scriptEngineType = scriptEngineType; + _scriptExecutorType = scriptExecutorType; + _initDirectoryCatalog = initDirectoryCatalog; + _overrides = overrides; + } + + private IContainer _initializationContainer; + public IContainer InitializationContainer + { + get + { + if (_initializationContainer == null) + { + _initializationContainer = CreateInitializationContainer(); + } + return _initializationContainer; + } + } + + private IContainer _runtimeContainer; + public IContainer RuntimeContainer + { + get + { + if (_runtimeContainer == null) + { + _runtimeContainer = CreateRuntimeContainer(); + } + return _runtimeContainer; + } + } + + private IContainer CreateInitializationContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + return builder.Build(); + } + + private IContainer CreateRuntimeContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger).Exported(x => x.As()); + builder.RegisterType(_scriptEngineType).As(); + builder.RegisterType(_scriptExecutorType).As(); + builder.RegisterInstance(_console).As(); + builder.RegisterType(); + + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType()); + + var initializationContainer = InitializationContainer; + var assemblyResolver = initializationContainer.Resolve(); + + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(assemblyResolver).As(); + + if (_initDirectoryCatalog) + { + var currentDirectory = Environment.CurrentDirectory; + var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); + + var aggregateCatalog = new AggregateCatalog(); + + assemblies.Select(x => new AssemblyCatalog(x)).ToList() + .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); + + builder.RegisterComposablePartCatalog(aggregateCatalog); + } + + return builder.Build(); + } + + private void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) + { + if (_overrides.ContainsKey(typeof(T))) + { + var reg = _overrides[typeof(T)]; + if (reg.GetType().IsSubclassOf(typeof(Type))) + { + builder.RegisterType((Type)reg).As().SingleInstance(); + } + else + { + builder.RegisterInstance(reg).As(); + } + } + else + { + registrationAction(builder); + } + } + } +} diff --git a/src/ScriptCs.Core/ScriptCs.Core.csproj b/src/ScriptCs.Core/ScriptCs.Core.csproj index 361d92e7..9a93ff5c 100644 --- a/src/ScriptCs.Core/ScriptCs.Core.csproj +++ b/src/ScriptCs.Core/ScriptCs.Core.csproj @@ -44,6 +44,8 @@ + + diff --git a/src/ScriptCs.Core/ScriptRuntime.cs b/src/ScriptCs.Core/ScriptRuntime.cs index a88191c2..ea8182f6 100644 --- a/src/ScriptCs.Core/ScriptRuntime.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -15,143 +15,22 @@ namespace ScriptCs { public class ScriptRuntime { - private readonly bool _shouldInitDirectoryCatalog; - private IContainer _container; - private ScriptServices _scriptServices; - private IDictionary _overrides; - private Type _scriptExecutorType; - private Type _scriptEngineType; - private IConsole _console; - private string _scriptName; - private bool _repl; - private ILoggerConfigurator _loggerConfigurator; - - public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType) - : this(scriptName, repl, loggerConfigurator, console, scriptExecutorType, scriptEngineType, new Dictionary()) - { - } - - public ScriptRuntime(string scriptName, bool repl, ILoggerConfigurator loggerConfigurator, IConsole console, Type scriptExecutorType, Type scriptEngineType, IDictionary overrides) + public ScriptRuntime(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides) + : this(new ScriptContainerFactory(logger, console, scriptEngineType, scriptExecutorType, initDirectoryCatalog, overrides)) { - Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); - Guard.AgainstNullArgument("scriptEngine", scriptEngineType); - Guard.AgainstNullArgument("console", console); - Guard.AgainstNullArgument("loggerConfigurator", loggerConfigurator); - - _loggerConfigurator = loggerConfigurator; - _console = console; - _scriptName = scriptName; - _repl = repl; - - if (!typeof(IScriptExecutor).IsAssignableFrom(scriptExecutorType)) - { - throw new ArgumentException("scriptExecutor type must implement IScriptExecutor", "scriptExecutor"); - } - - if (!typeof(IScriptEngine).IsAssignableFrom(scriptEngineType)) - { - throw new ArgumentException("scriptEngine type must implement IScriptEngine", "scriptEngine"); - } - - _scriptExecutorType = scriptExecutorType; - _scriptEngineType = scriptEngineType; - - _overrides = overrides; - _shouldInitDirectoryCatalog = ShouldInitDirectoryCatalog(_repl, _scriptName); + } - public void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) + public ScriptRuntime(IScriptContainerFactory containerFactory) { - if (_overrides.ContainsKey(typeof(T))) - { - var reg = _overrides[typeof(T)]; - if (reg.GetType().IsSubclassOf(typeof(Type))) - { - builder.RegisterType((Type)reg).As().SingleInstance(); - } - else - { - builder.RegisterInstance(reg).As(); - } - } - else - { - registrationAction(builder); - } + var container = containerFactory.RuntimeContainer; + ScriptServices = container.Resolve(); + Logger = container.Resolve(); } - public IContainer Initialize() - { - var builder = new ContainerBuilder(); - - _loggerConfigurator.Configure(_console); - var logger = _loggerConfigurator.GetLogger(); - - builder.RegisterInstance(logger).Exported(x => x.As()); - builder.RegisterType(_scriptEngineType).As(); - builder.RegisterType(_scriptExecutorType).As(); - builder.RegisterInstance(_console).As(); - builder.RegisterType(); - - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType()); - - // Hack using a second container to resolve assemblies for MEF catalog before building Autofac container - var tempBuilder = new ContainerBuilder(); - - tempBuilder.RegisterInstance(logger); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(tempBuilder, b => b.RegisterType().As()); - - var tempContainer = tempBuilder.Build(); - var assemblyResolver = tempContainer.Resolve(); - - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(tempContainer.Resolve()).As(); - builder.RegisterInstance(assemblyResolver).As(); + public ScriptServices ScriptServices { get; private set; } - if (_shouldInitDirectoryCatalog) - { - var currentDirectory = Environment.CurrentDirectory; - var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); - - var aggregateCatalog = new AggregateCatalog(); - - assemblies.Select(x => new AssemblyCatalog(x)).ToList() - .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); - - builder.RegisterComposablePartCatalog(aggregateCatalog); - } - - _container = builder.Build(); - - _scriptServices = _container.Resolve(); - return _container; - } - - public ScriptServices GetScriptServices() - { - return _scriptServices; - } - - public ILog GetLogger() - { - return _container.Resolve(); - } - - private static bool ShouldInitDirectoryCatalog(bool repl, string scriptName) - { - return repl || !string.IsNullOrWhiteSpace(scriptName); - } + public ILog Logger { get; private set; } } } diff --git a/src/ScriptCs.Hosting/IModule.cs b/src/ScriptCs.Hosting/IModule.cs new file mode 100644 index 00000000..f1c70eed --- /dev/null +++ b/src/ScriptCs.Hosting/IModule.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public interface IModule + { + void Initialize(IScriptRuntimeBuilder builder, bool repl, bool debug); + } +} diff --git a/src/ScriptCs.Hosting/IModuleMetadata.cs b/src/ScriptCs.Hosting/IModuleMetadata.cs new file mode 100644 index 00000000..74f09ea2 --- /dev/null +++ b/src/ScriptCs.Hosting/IModuleMetadata.cs @@ -0,0 +1,8 @@ +namespace ScriptCs +{ + public interface IModuleMetadata + { + string Name { get; } + string Extensions { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs new file mode 100644 index 00000000..bbc82d30 --- /dev/null +++ b/src/ScriptCs.Hosting/IScriptRuntimeBuilder.cs @@ -0,0 +1,26 @@ +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs +{ + public interface IScriptRuntimeBuilder + { + ScriptRuntime Build(); + IScriptRuntimeBuilder Debug(bool debug = true); + IScriptRuntimeBuilder ScriptName(string name); + IScriptRuntimeBuilder Repl(bool repl = true); + IScriptRuntimeBuilder LogLevel(LogLevel level); + IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor; + IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine; + IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory; + IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager; + IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver; + IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider; + IScriptRuntimeBuilder FileSystem() where T : IFileSystem; + IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility; + IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer; + IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor; + IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver; + IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor; + } +} \ No newline at end of file diff --git a/src/ScriptCs.Hosting/ModuleAttribute.cs b/src/ScriptCs.Hosting/ModuleAttribute.cs new file mode 100644 index 00000000..6f438db0 --- /dev/null +++ b/src/ScriptCs.Hosting/ModuleAttribute.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.Composition; + +namespace ScriptCs.Hosting +{ + public class ModuleAttribute : ExportAttribute, IModuleMetadata + { + public ModuleAttribute(string name) : base(typeof (IModule)) + { + Name = name; + } + + public string Name { get; private set; } + public string Extensions { get; set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Hosting/ModuleLoader.cs b/src/ScriptCs.Hosting/ModuleLoader.cs new file mode 100644 index 00000000..92e81eef --- /dev/null +++ b/src/ScriptCs.Hosting/ModuleLoader.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ScriptCs +{ + public class ModuleLoader + { + private readonly IAssemblyResolver _resolver; + private readonly Action _catalogAction; + + [ImportingConstructor] + public ModuleLoader(IAssemblyResolver resolver) : + this(resolver, null) + { + } + + public ModuleLoader(IAssemblyResolver resolver, Action catalogAction) + { + _resolver = resolver; + _catalogAction = catalogAction; + if (catalogAction == null) + catalogAction = (p, catalog) => catalog.Catalogs.Add(new AssemblyCatalog(p)); + + _catalogAction = catalogAction; + } + + public void Load(IScriptRuntimeBuilder builder, string modulePackagesPath, string extension, bool repl, bool debug, string[] moduleNames) + { + var paths = _resolver.GetAssemblyPaths(modulePackagesPath); + var catalog = new AggregateCatalog(); + foreach (var path in paths) + { + _catalogAction(path, catalog); + } + + var container = new CompositionContainer(catalog); + var modules = container.GetExports() + .Where(m => moduleNames.Contains(m.Metadata.Name) || + (extension != null && (m.Metadata.Extensions == extension || m.Metadata.Extensions.Split(',').Contains(extension)))) + .Select(m => m.Value); + + foreach (var module in modules) + { + module.Initialize(builder, repl, debug); + } + } + } +} diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index 7acdba64..179dd3c6 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -19,6 +19,7 @@ ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll + @@ -47,8 +48,13 @@ Properties\CommonVersionInfo.cs + + + + + diff --git a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs index 89f4bf70..3cf69f23 100644 --- a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs +++ b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -9,7 +9,7 @@ namespace ScriptCs { - public class ScriptRuntimeBuilder + public class ScriptRuntimeBuilder : IScriptRuntimeBuilder { private bool _debug = false; private bool _repl = false; @@ -39,102 +39,103 @@ public ScriptRuntime Build() } var loggerConfigurator = new LoggerConfigurator(_logLevel); - - var runtime = new ScriptRuntime(_scriptName, _repl, loggerConfigurator, new ScriptConsole(), _scriptExecutorType, _scriptEngineType, _overrides); + var initDirectoryCatalog = _scriptName.Length > 0 || _repl; + var factory = new ScriptContainerFactory(loggerConfigurator.GetLogger(), new ScriptConsole(), _scriptEngineType, _scriptExecutorType, initDirectoryCatalog, _overrides); + var runtime = new ScriptRuntime(factory); return runtime; } - public ScriptRuntimeBuilder Debug(bool debug = true) + public IScriptRuntimeBuilder Debug(bool debug = true) { _debug = debug; return this; } - public ScriptRuntimeBuilder ScriptName(string name) + public IScriptRuntimeBuilder ScriptName(string name) { _scriptName = name; return this; } - public ScriptRuntimeBuilder Repl(bool repl = true) + public IScriptRuntimeBuilder Repl(bool repl = true) { _repl = repl; return this; } - public ScriptRuntimeBuilder LogLevel(LogLevel level) + public IScriptRuntimeBuilder LogLevel(LogLevel level) { _logLevel = level; return this; } - public ScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor + public IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor { _scriptExecutorType = typeof (T); return this; } - public ScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine + public IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine { _scriptEngineType = typeof(T); return this; } - public ScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory + public IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory { _overrides[typeof(IScriptHostFactory)] = typeof(T); return this; } - public ScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager + public IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager { _overrides[typeof(IScriptPackManager)] = typeof(T); return this; } - public ScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver + public IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver { _overrides[typeof(IScriptPackResolver)] = typeof(T); return this; } - public ScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider + public IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider { _overrides[typeof(IInstallationProvider)] = typeof(T); return this; } - public ScriptRuntimeBuilder FileSystem() where T : IFileSystem + public IScriptRuntimeBuilder FileSystem() where T : IFileSystem { _overrides[typeof(IFileSystem)] = typeof(T); return this; } - public ScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility + public IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility { _overrides[typeof(IAssemblyUtility)] = typeof(T); return this; } - public ScriptRuntimeBuilder PackageContainer() where T : IPackageContainer + public IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer { _overrides[typeof(IPackageContainer)] = typeof(T); return this; } - public ScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor + public IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor { _overrides[typeof(IFilePreProcessor)] = typeof(T); return this; } - public ScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver + public IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver { _overrides[typeof(IPackageAssemblyResolver)] = typeof(T); return this; } - public ScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor + public IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor { _overrides[typeof(IAssemblyResolver)] = typeof(T); return this; diff --git a/src/ScriptCs/ModuleAttribute.cs b/src/ScriptCs/ModuleAttribute.cs new file mode 100644 index 00000000..c02bb5ec --- /dev/null +++ b/src/ScriptCs/ModuleAttribute.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.Composition; + +namespace ScriptCs.Hosting +{ + public class ModuleAttribute : ExportAttribute + { + public ModuleAttribute(string name) : base(typeof (IModule)) + { + Name = name; + } + + public string Name { get; private set; } + } +} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index c635f873..5039329c 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -1,5 +1,5 @@ using System; - +using Autofac; using PowerArgs; using ScriptCs.Command; using System.Linq; @@ -16,19 +16,22 @@ private static int Main(string[] args) var commandArgs = ParseArguments(args); - var runtime = new ScriptRuntimeBuilder(). + var runtimeBuilder = new ScriptRuntimeBuilder(). Debug(commandArgs.Debug). LogLevel(commandArgs.LogLevel). ScriptName(commandArgs.ScriptName). - Repl(commandArgs.Repl). - Build(); + Repl(commandArgs.Repl); + + var containerBuilder = new ContainerBuilder(); + + - runtime.Initialize(); + var runtime = runtimeBuilder.Build(); - var logger = runtime.GetLogger(); + var logger = runtime.Logger; logger.Debug("Creating ScriptServices"); - var scriptServiceRoot = runtime.GetScriptServices(); + var scriptServiceRoot = runtime.ScriptServices; var commandFactory = new CommandFactory(scriptServiceRoot); var command = commandFactory.CreateCommand(commandArgs, scriptArgs); diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ac3e3e66..83d09dc3 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -73,6 +73,7 @@ + diff --git a/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs b/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs new file mode 100644 index 00000000..fd0c385d --- /dev/null +++ b/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class ScriptContainerFactoryTests + { + public class TheCreateInitializationContainerMethod + { + + } + + public class TheCreateRuntimeContainerMethod + { + private Mock _mockConsole = new Mock(); + private Type _scriptExecutorType = null; + private Type _scriptEngineType = null; + private Mock _mockLogger = new Mock(); + private IDictionary _overrides = new Dictionary(); + private IScriptContainerFactory _factory = null; + + public TheCreateRuntimeContainerMethod() + { + var mockScriptExecutorType = new Mock(); + _scriptExecutorType = mockScriptExecutorType.Object.GetType(); + + var mockScriptEngineType = new Mock(); + _scriptEngineType = mockScriptEngineType.Object.GetType(); + + _factory = new ScriptContainerFactory(_mockLogger.Object, _mockConsole.Object, _scriptEngineType, _scriptExecutorType, false, _overrides); + } + + [Fact] + public void ShouldRegisterTheLoggerInstance() + { + var logger = _factory.RuntimeContainer.Resolve(); + logger.ShouldEqual(_mockLogger.Object); + } + + [Fact] + public void ShouldRegisterTheScriptEngine() + { + var engine = _factory.RuntimeContainer.Resolve(); + engine.GetType().ShouldEqual(_scriptEngineType); + } + + [Fact] + public void ShouldRegisterTheExecutor() + { + var executor = _factory.RuntimeContainer.Resolve(); + executor.GetType().ShouldEqual(_scriptExecutorType); + } + + [Fact] + public void ShouldRegisterTheConsoleInstance() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheScriptServices() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultFileSystemIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() + { + _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptHostFactory() + { + var mock = new Mock(); + _overrides[typeof(IScriptHostFactory)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenFilePreProcessor() + { + var mock = new Mock(); + _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + + } + + [Fact] + public void ShouldRegisterTheOverriddenScriptPackResolver() + { + var mock = new Mock(); + _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenInstallationProvider() + { + var mock = new Mock(); + _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageInstaller() + { + var mock = new Mock(); + _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenFileSystem() + { + var mock = new Mock(); + _overrides[typeof(IFileSystem)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyUtility() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageContainer() + { + var mock = new Mock(); + _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenPackageAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolver() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); + _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + } + + [Fact] + public void ShouldRegisterTheOverriddenAssemblyResolverInstance() + { + var mock = new Mock(); + _overrides[typeof(IAssemblyResolver)] = mock.Object; + _factory.RuntimeContainer.Resolve().ShouldEqual(mock.Object); + } + } + } +} diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index 4052b23c..c4ecdce7 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -45,6 +45,7 @@ Properties\CommonVersionInfo.cs + diff --git a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs index 61c20a5b..f5ede929 100644 --- a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading.Tasks; using Autofac; +using Autofac.Core.Registration; using Common.Logging; using Moq; using ScriptCs.Contracts; @@ -18,307 +19,34 @@ public class ScriptRuntimeTests { public class TheInitializeMethod { - private Mock _mockConsole = new Mock(); - private Type _scriptExecutorType = null; - private Type _scriptEngineType = null; - private Mock _mockLoggerConfigurator = new Mock(); private Mock _mockLogger = new Mock(); - private IDictionary _overrides = new Dictionary(); + private ScriptServices _scriptServices = new ScriptServices(null, null, null, null,null,null,null,null,null,null); + private Mock _mockFactory = new Mock(); + private ScriptRuntime _runtime = null; public TheInitializeMethod() { - var mockScriptExecutorType = new Mock(); - _scriptExecutorType = mockScriptExecutorType.Object.GetType(); - - var mockScriptEngineType = new Mock(); - _scriptEngineType = mockScriptEngineType.Object.GetType(); - - _mockLoggerConfigurator.Setup(l => l.GetLogger()).Returns(_mockLogger.Object); - } - - [Fact] - public void ShouldInvokeTheConfigureMethod() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - _mockLoggerConfigurator.Verify(l=>l.Configure(It.IsAny())); - - } - - [Fact] - public void ShouldGetTheLogger() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - _mockLoggerConfigurator.Verify(l=>l.GetLogger()); - } - - [Fact] - public void ShouldRegisterTheLoggerInstance() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - var logger = container.Resolve(); - logger.ShouldEqual(_mockLogger.Object); - } - - [Fact] - public void ShouldRegisterTheScriptEngine() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - var engine = container.Resolve(); - engine.GetType().ShouldEqual(_scriptEngineType); - } - - [Fact] - public void ShouldRegisterTheExecutor() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - var executor = container.Resolve(); - executor.GetType().ShouldEqual(_scriptExecutorType); - } - - [Fact] - public void ShouldRegisterTheConsoleInstance() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); + var builder = new ContainerBuilder(); + builder.RegisterInstance(_mockLogger.Object); + builder.RegisterInstance(_scriptServices); + var container = builder.Build(); + _mockFactory.SetupGet(f => f.RuntimeContainer).Returns(container); + _runtime = new ScriptRuntime(_mockFactory.Object); } [Fact] - public void ShouldRegisterTheScriptServices() + public void ShouldResolveLogger() { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); + _runtime.Logger.ShouldEqual(_mockLogger.Object); } - [Fact] - public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() + public void ShouldResolveScriptServices() { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } + _runtime.ScriptServices.ShouldEqual(_scriptServices); - [Fact] - public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); } - [Fact] - public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultFileSystemIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldNotBeNull(); - } - - [Fact] - public void ShouldReturnTheLoggerWhenGetLoggerIsInvoked() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - runtime.GetLogger().ShouldEqual(_mockLogger.Object); - } - - [Fact] - public void ShouldReturnTheScriptServiceRootWhenTheGetterIsInvoked() - { - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType); - runtime.Initialize(); - runtime.GetScriptServices().ShouldNotBeNull(); - - } - - [Fact] - public void ShouldRegisterTheOverriddenScriptHostFactory() - { - var mock = new Mock(); - _overrides[typeof (IScriptHostFactory)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenFilePreProcessor() - { - var mock = new Mock(); - _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - - } - - [Fact] - public void ShouldRegisterTheOverriddenScriptPackResolver() - { - var mock = new Mock(); - _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenInstallationProvider() - { - var mock = new Mock(); - _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenPackageInstaller() - { - var mock = new Mock(); - _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - public class TestFileSystem : FileSystem - { - } - - [Fact] - public void ShouldRegisterTheOverriddenFileSystem() - { - _overrides[typeof(IFileSystem)] = typeof(TestFileSystem); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(); - } - - [Fact] - public void ShouldRegisterTheOverriddenAssemblyUtility() - { - var mock = new Mock(); - _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenPackageContainer() - { - var mock = new Mock(); - _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenPackageAssemblyResolver() - { - var mock = new Mock(); - _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenAssemblyResolver() - { - var mock = new Mock(); - _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldBeType(mock.Object.GetType()); - } - - [Fact] - public void ShouldRegisterTheOverriddenAssemblyResolverInstance() - { - var mock = new Mock(); - _overrides[typeof(IAssemblyResolver)] = mock.Object; - var runtime = new ScriptRuntime(null, false, _mockLoggerConfigurator.Object, _mockConsole.Object, _scriptExecutorType, _scriptEngineType, _overrides); - var container = runtime.Initialize(); - container.Resolve().ShouldEqual(mock.Object); - } - - - - } } } From 36428f453792909801a1b165acca059b28fa9d64 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Wed, 24 Jul 2013 13:51:20 -0700 Subject: [PATCH 128/993] deleting files --- .../FilePreProcessorResult.cs | 22 --------- src/ScriptCs.Contracts/IAssemblyResolver.cs | 9 ---- src/ScriptCs.Contracts/IAssemblyUtility.cs | 7 --- src/ScriptCs.Contracts/IFilePreProcessor.cs | 11 ----- .../IFilePreProcessorResult.cs | 16 ------- src/ScriptCs.Contracts/IFileSystem.cs | 47 ------------------- .../IPackageAssemblyResolver.cs | 13 ----- src/ScriptCs.Contracts/IScriptCsModule.cs | 14 ------ src/ScriptCs.Contracts/IScriptEngine.cs | 10 ---- src/ScriptCs.Contracts/IScriptExecutor.cs | 13 ----- src/ScriptCs.Contracts/IScriptHostFactory.cs | 11 ----- src/ScriptCs.Contracts/IScriptPackManager.cs | 9 ---- src/ScriptCs.Contracts/IScriptPackResolver.cs | 10 ---- src/ScriptCs.Contracts/IScriptResult.cs | 19 -------- src/ScriptCs.Contracts/IScriptRuntime.cs | 12 ----- .../IScriptRuntimeBuilder.cs | 31 ------------ src/ScriptCs.Contracts/LogLevel.cs | 10 ---- 17 files changed, 264 deletions(-) delete mode 100644 src/ScriptCs.Contracts/FilePreProcessorResult.cs delete mode 100644 src/ScriptCs.Contracts/IAssemblyResolver.cs delete mode 100644 src/ScriptCs.Contracts/IAssemblyUtility.cs delete mode 100644 src/ScriptCs.Contracts/IFilePreProcessor.cs delete mode 100644 src/ScriptCs.Contracts/IFilePreProcessorResult.cs delete mode 100644 src/ScriptCs.Contracts/IFileSystem.cs delete mode 100644 src/ScriptCs.Contracts/IPackageAssemblyResolver.cs delete mode 100644 src/ScriptCs.Contracts/IScriptCsModule.cs delete mode 100644 src/ScriptCs.Contracts/IScriptEngine.cs delete mode 100644 src/ScriptCs.Contracts/IScriptExecutor.cs delete mode 100644 src/ScriptCs.Contracts/IScriptHostFactory.cs delete mode 100644 src/ScriptCs.Contracts/IScriptPackManager.cs delete mode 100644 src/ScriptCs.Contracts/IScriptPackResolver.cs delete mode 100644 src/ScriptCs.Contracts/IScriptResult.cs delete mode 100644 src/ScriptCs.Contracts/IScriptRuntime.cs delete mode 100644 src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs delete mode 100644 src/ScriptCs.Contracts/LogLevel.cs diff --git a/src/ScriptCs.Contracts/FilePreProcessorResult.cs b/src/ScriptCs.Contracts/FilePreProcessorResult.cs deleted file mode 100644 index f5731ebe..00000000 --- a/src/ScriptCs.Contracts/FilePreProcessorResult.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs -{ - public class FilePreProcessorResult - { - public FilePreProcessorResult() - { - UsingStatements = new List(); - LoadedScripts = new List(); - References = new List(); - } - - public List UsingStatements { get; set; } - - public List LoadedScripts { get; set; } - - public List References { get; set; } - - public string Code { get; set; } - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IAssemblyResolver.cs b/src/ScriptCs.Contracts/IAssemblyResolver.cs deleted file mode 100644 index 04bc3338..00000000 --- a/src/ScriptCs.Contracts/IAssemblyResolver.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs -{ - public interface IAssemblyResolver - { - IEnumerable GetAssemblyPaths(string path); - } -} diff --git a/src/ScriptCs.Contracts/IAssemblyUtility.cs b/src/ScriptCs.Contracts/IAssemblyUtility.cs deleted file mode 100644 index 805b4d5b..00000000 --- a/src/ScriptCs.Contracts/IAssemblyUtility.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ScriptCs -{ - public interface IAssemblyUtility - { - bool IsManagedAssembly(string assemblyPath); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessor.cs b/src/ScriptCs.Contracts/IFilePreProcessor.cs deleted file mode 100644 index d4943eb2..00000000 --- a/src/ScriptCs.Contracts/IFilePreProcessor.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IFilePreProcessor - { - FilePreProcessorResult ProcessFile(string path); - - FilePreProcessorResult ProcessScript(string script); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IFilePreProcessorResult.cs b/src/ScriptCs.Contracts/IFilePreProcessorResult.cs deleted file mode 100644 index 780d7559..00000000 --- a/src/ScriptCs.Contracts/IFilePreProcessorResult.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - public interface IFilePreProcessorResult - { - List UsingStatements { get; set; } - List LoadedScripts { get; set; } - List References { get; set; } - string Code { get; set; } - } -} diff --git a/src/ScriptCs.Contracts/IFileSystem.cs b/src/ScriptCs.Contracts/IFileSystem.cs deleted file mode 100644 index f4c152ee..00000000 --- a/src/ScriptCs.Contracts/IFileSystem.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace ScriptCs.Contracts -{ - public interface IFileSystem - { - IEnumerable EnumerateFiles(string dir, string search, SearchOption searchOption = SearchOption.AllDirectories); - - void Copy(string source, string dest, bool overwrite); - - bool DirectoryExists(string path); - - void CreateDirectory(string path); - - void DeleteDirectory(string path); - - string ReadFile(string path); - - string[] ReadFileLines(string path); - - DateTime GetLastWriteTime(string file); - - bool IsPathRooted(string path); - - string GetFullPath(string path); - - string CurrentDirectory { get; } - - string NewLine { get; } - - string GetWorkingDirectory(string path); - - void Move(string source, string dest); - - bool FileExists(string path); - - void FileDelete(string path); - - IEnumerable SplitLines(string value); - - void WriteToFile(string path, string text); - - Stream CreateFileStream(string filePath, FileMode mode); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs b/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs deleted file mode 100644 index 62fb4d83..00000000 --- a/src/ScriptCs.Contracts/IPackageAssemblyResolver.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using ScriptCs.Package; - -namespace ScriptCs.Contracts -{ - public interface IPackageAssemblyResolver - { - void SavePackages(Action output); - IEnumerable GetPackages(string workingDirectory); - IEnumerable GetAssemblyNames(string workingDirectory, Action outputCallback = null); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptCsModule.cs b/src/ScriptCs.Contracts/IScriptCsModule.cs deleted file mode 100644 index 3e6855e2..00000000 --- a/src/ScriptCs.Contracts/IScriptCsModule.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - public interface IScriptCsModule - { - void Initialize(IScriptRuntimeBuilder builder); - } -} diff --git a/src/ScriptCs.Contracts/IScriptEngine.cs b/src/ScriptCs.Contracts/IScriptEngine.cs deleted file mode 100644 index b4081283..00000000 --- a/src/ScriptCs.Contracts/IScriptEngine.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IScriptEngine - { - string BaseDirectory { get; set; } - IScriptResult Execute(string code, string[] scriptArgs, IEnumerable references, IEnumerable namespaces, ScriptPackSession scriptPackSession); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptExecutor.cs b/src/ScriptCs.Contracts/IScriptExecutor.cs deleted file mode 100644 index 8b2c531f..00000000 --- a/src/ScriptCs.Contracts/IScriptExecutor.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ScriptCs.Contracts; -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IScriptExecutor - { - void Initialize(IEnumerable paths, IEnumerable scriptPacks); - ScriptResult Execute(string script, string[] scriptArgs); - ScriptResult Execute(string script); - void Terminate(); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptHostFactory.cs b/src/ScriptCs.Contracts/IScriptHostFactory.cs deleted file mode 100644 index 153ca62c..00000000 --- a/src/ScriptCs.Contracts/IScriptHostFactory.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -using ScriptCs.Contracts; - -namespace ScriptCs.Contracts -{ - public interface IScriptHostFactory - { - ScriptHost CreateScriptHost(IScriptPackManager scriptPackManager, string[] scriptArgs); - } -} diff --git a/src/ScriptCs.Contracts/IScriptPackManager.cs b/src/ScriptCs.Contracts/IScriptPackManager.cs deleted file mode 100644 index 2a51a49e..00000000 --- a/src/ScriptCs.Contracts/IScriptPackManager.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ScriptCs.Contracts; - -namespace ScriptCs.Contracts -{ - public interface IScriptPackManager - { - TContext Get() where TContext : IScriptPackContext; - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptPackResolver.cs b/src/ScriptCs.Contracts/IScriptPackResolver.cs deleted file mode 100644 index cf728f0e..00000000 --- a/src/ScriptCs.Contracts/IScriptPackResolver.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ScriptCs.Contracts; -using System.Collections.Generic; - -namespace ScriptCs.Contracts -{ - public interface IScriptPackResolver - { - IEnumerable GetPacks(); - } -} \ No newline at end of file diff --git a/src/ScriptCs.Contracts/IScriptResult.cs b/src/ScriptCs.Contracts/IScriptResult.cs deleted file mode 100644 index e7b28885..00000000 --- a/src/ScriptCs.Contracts/IScriptResult.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - public interface IScriptResult - { - object ReturnValue { get; set; } - Exception ExecuteException { get; set; } - Exception CompileException { get; set; } - bool ContinueBuffering { get; set; } - bool IsPendingClosingChar { get; set; } - char? ExpectingClosingChar { get; set; } - void UpdateClosingExpectation(Exception ex); - } -} diff --git a/src/ScriptCs.Contracts/IScriptRuntime.cs b/src/ScriptCs.Contracts/IScriptRuntime.cs deleted file mode 100644 index 6717fa06..00000000 --- a/src/ScriptCs.Contracts/IScriptRuntime.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ScriptCs.Contracts -{ - class IScriptRuntime - { - } -} diff --git a/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs b/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs deleted file mode 100644 index d89bfaef..00000000 --- a/src/ScriptCs.Contracts/IScriptRuntimeBuilder.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ScriptCs.Package; -using ScriptCs.Package.InstallationProvider; - -namespace ScriptCs.Contracts -{ - public interface IScriptRuntimeBuilder - { - ScriptRuntime Build(); - IScriptRuntimeBuilder Debug(bool debug = true); - IScriptRuntimeBuilder ScriptName(string name); - IScriptRuntimeBuilder Repl(bool repl = true); - IScriptRuntimeBuilder LogLevel(LogLevel level); - IScriptRuntimeBuilder ScriptExecutor() where T : IScriptExecutor; - IScriptRuntimeBuilder ScriptEngine() where T : IScriptEngine; - IScriptRuntimeBuilder ScriptHostFactory() where T : IScriptHostFactory; - IScriptRuntimeBuilder ScriptPackManager() where T : IScriptPackManager; - IScriptRuntimeBuilder ScriptPackResolver() where T : IScriptPackResolver; - IScriptRuntimeBuilder InstallationProvider() where T : IInstallationProvider; - IScriptRuntimeBuilder FileSystem() where T : IFileSystem; - IScriptRuntimeBuilder AssemblyUtility() where T : IAssemblyUtility; - IScriptRuntimeBuilder PackageContainer() where T : IPackageContainer; - IScriptRuntimeBuilder FilePreProcessor() where T : IFilePreProcessor; - IScriptRuntimeBuilder PackageAssemblyResolver() where T : IPackageAssemblyResolver; - IScriptRuntimeBuilder AssemblyResolver() where T : IFilePreProcessor; - } -} diff --git a/src/ScriptCs.Contracts/LogLevel.cs b/src/ScriptCs.Contracts/LogLevel.cs deleted file mode 100644 index bd15dd0e..00000000 --- a/src/ScriptCs.Contracts/LogLevel.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ScriptCs.Contracts -{ - public enum LogLevel - { - Error, - Info, - Debug, - Trace - } -} From b0f9fa4c8bf22a1f7c27dbe534ab67fb69738930 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 02:35:30 -0500 Subject: [PATCH 129/993] adding module loader tests --- src/ScriptCs.Hosting/ModuleAttribute.cs | 1 + src/ScriptCs.Hosting/ModuleLoader.cs | 29 ++++--- .../ModuleLoaderTests.cs | 86 +++++++++++++++++++ .../ScriptCs.Hosting.Tests.csproj | 15 ++++ test/ScriptCs.Hosting.Tests/packages.config | 1 + 5 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs diff --git a/src/ScriptCs.Hosting/ModuleAttribute.cs b/src/ScriptCs.Hosting/ModuleAttribute.cs index 6f438db0..095169fb 100644 --- a/src/ScriptCs.Hosting/ModuleAttribute.cs +++ b/src/ScriptCs.Hosting/ModuleAttribute.cs @@ -2,6 +2,7 @@ namespace ScriptCs.Hosting { + [MetadataAttribute] public class ModuleAttribute : ExportAttribute, IModuleMetadata { public ModuleAttribute(string name) : base(typeof (IModule)) diff --git a/src/ScriptCs.Hosting/ModuleLoader.cs b/src/ScriptCs.Hosting/ModuleLoader.cs index 92e81eef..34e441bc 100644 --- a/src/ScriptCs.Hosting/ModuleLoader.cs +++ b/src/ScriptCs.Hosting/ModuleLoader.cs @@ -12,37 +12,44 @@ namespace ScriptCs public class ModuleLoader { private readonly IAssemblyResolver _resolver; - private readonly Action _catalogAction; + private readonly Action _addToCatalog; + private readonly Func>> _getModules; [ImportingConstructor] public ModuleLoader(IAssemblyResolver resolver) : - this(resolver, null) + this(resolver, null, null) { } - public ModuleLoader(IAssemblyResolver resolver, Action catalogAction) + public ModuleLoader(IAssemblyResolver resolver, Action addToCatalog, Func>> getModules) { _resolver = resolver; - _catalogAction = catalogAction; - if (catalogAction == null) - catalogAction = (p, catalog) => catalog.Catalogs.Add(new AssemblyCatalog(p)); + if (addToCatalog == null) + addToCatalog = (p, catalog) => catalog.Catalogs.Add(new AssemblyCatalog(p)); + + _addToCatalog = addToCatalog; + + if (getModules == null) + getModules = (container) => container.GetExports(); + + _getModules = getModules; - _catalogAction = catalogAction; } - public void Load(IScriptRuntimeBuilder builder, string modulePackagesPath, string extension, bool repl, bool debug, string[] moduleNames) + public void Load(IScriptRuntimeBuilder builder, string modulePackagesPath, string extension, bool repl, bool debug, params string[] moduleNames) { var paths = _resolver.GetAssemblyPaths(modulePackagesPath); var catalog = new AggregateCatalog(); foreach (var path in paths) { - _catalogAction(path, catalog); + _addToCatalog(path, catalog); } var container = new CompositionContainer(catalog); - var modules = container.GetExports() + var lazyModules = _getModules(container); + var modules = lazyModules .Where(m => moduleNames.Contains(m.Metadata.Name) || - (extension != null && (m.Metadata.Extensions == extension || m.Metadata.Extensions.Split(',').Contains(extension)))) + (extension != null && m.Metadata.Extensions != null && (m.Metadata.Extensions.Equals(extension) || m.Metadata.Extensions.Split(',').Contains(extension)))) .Select(m => m.Value); foreach (var module in modules) diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs new file mode 100644 index 00000000..83cfbdf3 --- /dev/null +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Moq; +using Xunit; +using Should; + +namespace ScriptCs.Hosting.Tests +{ + public class ModuleLoaderTests + { + public class TheLoadMethod + { + private Mock _mockAssemblyResolver = new Mock(); + private IList _paths = new List(); + private IList> _modules = new List>(); + private Func>> _getModules; + private Mock _mockModule1 = new Mock(); + private Mock _mockModule2 = new Mock(); + private Mock _mockModule3 = new Mock(); + + public TheLoadMethod() + { + var paths = new [] {"path1", "path2"}; + _mockAssemblyResolver.Setup(r => r.GetAssemblyPaths(It.IsAny())).Returns(paths); + _modules.Add(new Lazy(()=>_mockModule1.Object, new ModuleMetadata {Extensions="ext1,ext2", Name="module1"})); + _modules.Add(new Lazy(() => _mockModule2.Object, new ModuleMetadata { Extensions = "ext3,ext4", Name = "module2" })); + _modules.Add(new Lazy(() => _mockModule3.Object, new ModuleMetadata { Name = "module3" })); + _getModules = c => _modules; + + } + + [Fact] + public void ShouldResolvePathsFromTheAssemblyResolver() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p,c) => { }, c => Enumerable.Empty>()); + loader.Load(null, "c:\test", null, false, false); + _mockAssemblyResolver.Verify(r=>r.GetAssemblyPaths("c:\test")); + } + + [Fact] + public void ShouldInvokeTheCatalogActionForEachFile() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), c => Enumerable.Empty>()); + loader.Load(null, "c:\test", null, false, false); + _paths.Count.ShouldEqual(2); + } + + [Fact] + public void ShouldInitializeModulesThatMatchOnExtension() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); + loader.Load(null, null, "ext1", false, false); + _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); + _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + + loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); + loader.Load(null, null, "ext3", false, false); + _mockModule1.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Once()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + + } + + [Fact] + public void ShouldInitializeModulesTheMatchBasedOnName() + { + var loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); + loader.Load(null, null, null, false, false, "module3"); + _mockModule1.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Once()); + } + + public class ModuleMetadata : IModuleMetadata + { + public string Name { get; set; } + public string Extensions { get; set; } + } + } + } +} diff --git a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj index 54bed027..6e3a28b3 100644 --- a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj +++ b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj @@ -10,12 +10,22 @@ ..\..\ + + ..\ScriptCs.Tests\bin\Debug\Moq.dll + + + ..\..\packages\Should.1.1.12.0\lib\Should.dll + + ..\..\packages\xunit.1.9.1\lib\net20\xunit.dll + + ..\ScriptCs.Tests\bin\Debug\xunit.extensions.dll + @@ -24,12 +34,17 @@ Properties\CommonVersionInfo.cs + + + {E590E710-E159-48E6-A3E6-1A83D3FE732C} + ScriptCs.Core + {9aef2d95-87fb-4829-b384-34bfe076d531} ScriptCs.Hosting diff --git a/test/ScriptCs.Hosting.Tests/packages.config b/test/ScriptCs.Hosting.Tests/packages.config index 7c4280d1..5aa03453 100644 --- a/test/ScriptCs.Hosting.Tests/packages.config +++ b/test/ScriptCs.Hosting.Tests/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file From 6e81cc863ae89d8e52964b42ffbab9c74be0e4b2 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 03:48:56 -0500 Subject: [PATCH 130/993] Fixing registering all services as singletons, adding -install -g and -clean -g support --- src/ScriptCs.Core/FileSystem.cs | 6 ++++ src/ScriptCs.Core/IFileSystem.cs | 4 ++- .../IInstallationProvider.cs | 1 + .../NugetInstallationProvider.cs | 12 +++++--- src/ScriptCs.Core/ScriptContainerFactory.cs | 30 +++++++++---------- src/ScriptCs.Core/ScriptServices.cs | 7 ++++- src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs | 6 ++-- src/ScriptCs/Command/CommandFactory.cs | 25 ++++++++++++++-- src/ScriptCs/Command/InstallCommand.cs | 10 +++++-- src/ScriptCs/ScriptCsArgs.cs | 5 ++++ 10 files changed, 78 insertions(+), 28 deletions(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index 41e9c6c3..ab04a878 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -49,6 +49,7 @@ public bool IsPathRooted(string path) public string CurrentDirectory { get { return Environment.CurrentDirectory; } + set { Environment.CurrentDirectory = value; } } public string NewLine @@ -93,6 +94,11 @@ public Stream CreateFileStream(string filePath, FileMode mode) return new FileStream(filePath, mode); } + public string LocalApplicationData + { + get { return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); } + } + public string GetWorkingDirectory(string path) { if (string.IsNullOrWhiteSpace(path)) diff --git a/src/ScriptCs.Core/IFileSystem.cs b/src/ScriptCs.Core/IFileSystem.cs index fdb62ce3..37ec5696 100644 --- a/src/ScriptCs.Core/IFileSystem.cs +++ b/src/ScriptCs.Core/IFileSystem.cs @@ -26,7 +26,7 @@ public interface IFileSystem string GetFullPath(string path); - string CurrentDirectory { get; } + string CurrentDirectory { get; set; } string NewLine { get; } @@ -43,5 +43,7 @@ public interface IFileSystem void WriteToFile(string path, string text); Stream CreateFileStream(string filePath, FileMode mode); + + string LocalApplicationData { get; } } } \ No newline at end of file diff --git a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs index 5d8fe5c9..299b5e43 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/IInstallationProvider.cs @@ -6,6 +6,7 @@ namespace ScriptCs.Package.InstallationProvider public interface IInstallationProvider { IEnumerable GetRepositorySources(string path); + void Initialize(); bool IsInstalled(IPackageReference packageId, bool allowPreRelease = false); bool InstallPackage(IPackageReference packageId, bool allowPreRelease = false, Action packageInstalled = null); } diff --git a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs index 1edb0dc8..6eab329c 100644 --- a/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs +++ b/src/ScriptCs.Core/Package/InstallationProvider/NugetInstallationProvider.cs @@ -8,9 +8,9 @@ namespace ScriptCs.Package.InstallationProvider { public class NugetInstallationProvider : IInstallationProvider { - private readonly IFileSystem _fileSystem; - private readonly PackageManager _manager; - private readonly IEnumerable _repositoryUrls; + private IFileSystem _fileSystem; + private PackageManager _manager; + private IEnumerable _repositoryUrls; private static readonly Version EmptyVersion = new Version(); @@ -19,7 +19,11 @@ public NugetInstallationProvider(IFileSystem fileSystem) Guard.AgainstNullArgument("fileSystem", fileSystem); _fileSystem = fileSystem; - var path = Path.Combine(fileSystem.CurrentDirectory, Constants.PackagesFolder); + } + + public void Initialize() + { + var path = Path.Combine(_fileSystem.CurrentDirectory, Constants.PackagesFolder); _repositoryUrls = GetRepositorySources(path); var remoteRepository = new AggregateRepository(PackageRepositoryFactory.Default, _repositoryUrls, true); _manager = new PackageManager(remoteRepository, path); diff --git a/src/ScriptCs.Core/ScriptContainerFactory.cs b/src/ScriptCs.Core/ScriptContainerFactory.cs index f232787b..844a0f49 100644 --- a/src/ScriptCs.Core/ScriptContainerFactory.cs +++ b/src/ScriptCs.Core/ScriptContainerFactory.cs @@ -71,11 +71,11 @@ private IContainer CreateInitializationContainer() { var builder = new ContainerBuilder(); builder.RegisterInstance(_logger); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); return builder.Build(); } @@ -83,17 +83,17 @@ private IContainer CreateRuntimeContainer() { var builder = new ContainerBuilder(); builder.RegisterInstance(_logger).Exported(x => x.As()); - builder.RegisterType(_scriptEngineType).As(); - builder.RegisterType(_scriptExecutorType).As(); + builder.RegisterType(_scriptEngineType).As().SingleInstance(); + builder.RegisterType(_scriptExecutorType).As().SingleInstance(); builder.RegisterInstance(_console).As(); - builder.RegisterType(); - - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As()); - RegisterOverrideOrDefault(builder, b => b.RegisterType()); + builder.RegisterType().SingleInstance(); + + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); var initializationContainer = InitializationContainer; var assemblyResolver = initializationContainer.Resolve(); diff --git a/src/ScriptCs.Core/ScriptServices.cs b/src/ScriptCs.Core/ScriptServices.cs index a144d45e..315fcd4c 100644 --- a/src/ScriptCs.Core/ScriptServices.cs +++ b/src/ScriptCs.Core/ScriptServices.cs @@ -1,6 +1,7 @@ using Common.Logging; using ScriptCs.Contracts; using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; namespace ScriptCs { @@ -16,7 +17,9 @@ public ScriptServices( IPackageInstaller packageInstaller, ILog logger, IAssemblyResolver assemblyResolver, - IConsole console = null) + IConsole console = null, + IInstallationProvider installationProvider = null + ) { FileSystem = fileSystem; PackageAssemblyResolver = packageAssemblyResolver; @@ -28,6 +31,7 @@ public ScriptServices( Logger = logger; Console = console; AssemblyResolver = assemblyResolver; + InstallationProvider = installationProvider; } public IFileSystem FileSystem { get; private set; } @@ -40,5 +44,6 @@ public ScriptServices( public IFilePreProcessor FilePreProcessor { get; private set; } public IConsole Console { get; private set; } public IAssemblyResolver AssemblyResolver { get; private set; } + public IInstallationProvider InstallationProvider { get; private set; } } } diff --git a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs index 3cf69f23..9487efd8 100644 --- a/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs +++ b/src/ScriptCs.Hosting/ScriptRuntimeBuilder.cs @@ -39,8 +39,10 @@ public ScriptRuntime Build() } var loggerConfigurator = new LoggerConfigurator(_logLevel); - var initDirectoryCatalog = _scriptName.Length > 0 || _repl; - var factory = new ScriptContainerFactory(loggerConfigurator.GetLogger(), new ScriptConsole(), _scriptEngineType, _scriptExecutorType, initDirectoryCatalog, _overrides); + var console = new ScriptConsole(); + loggerConfigurator.Configure(console); + var initDirectoryCatalog = _scriptName != null || _repl; + var factory = new ScriptContainerFactory(loggerConfigurator.GetLogger(), console, _scriptEngineType, _scriptExecutorType, initDirectoryCatalog, _overrides); var runtime = new ScriptRuntime(factory); return runtime; } diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index 082baea6..ff448ec1 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -74,9 +74,22 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) _scriptServices.FileSystem, _scriptServices.PackageAssemblyResolver, _scriptServices.PackageInstaller, - _scriptServices.Logger); + _scriptServices.Logger + ); + + string currentDirectory = null; + + if (args.Global) + { + currentDirectory = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); + _scriptServices.FileSystem.CurrentDirectory = currentDirectory; + if (!_scriptServices.FileSystem.DirectoryExists(currentDirectory)) + _scriptServices.FileSystem.CreateDirectory(currentDirectory); + } + else + currentDirectory = _scriptServices.FileSystem.CurrentDirectory; - var currentDirectory = _scriptServices.FileSystem.CurrentDirectory; + _scriptServices.InstallationProvider.Initialize(); var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); if (!_scriptServices.FileSystem.FileExists(packageFile)) @@ -92,6 +105,14 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) { var saveCommand = new SaveCommand(_scriptServices.PackageAssemblyResolver); + if (args.Global) + { + var currentDirectory = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); + _scriptServices.FileSystem.CurrentDirectory = currentDirectory; + if (!_scriptServices.FileSystem.DirectoryExists(currentDirectory)) + _scriptServices.FileSystem.CreateDirectory(currentDirectory); + } + var cleanCommand = new CleanCommand( args.ScriptName, _scriptServices.FileSystem, diff --git a/src/ScriptCs/Command/InstallCommand.cs b/src/ScriptCs/Command/InstallCommand.cs index 319d79bf..293094f8 100644 --- a/src/ScriptCs/Command/InstallCommand.cs +++ b/src/ScriptCs/Command/InstallCommand.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.Versioning; using Common.Logging; using ScriptCs.Package; @@ -26,7 +27,8 @@ public InstallCommand( IFileSystem fileSystem, IPackageAssemblyResolver packageAssemblyResolver, IPackageInstaller packageInstaller, - ILog logger) + ILog logger + ) { _name = name; _allowPre = allowPre; @@ -38,11 +40,13 @@ public InstallCommand( public CommandResult Execute() { - _logger.Info("Installing packages..."); var workingDirectory = _fileSystem.CurrentDirectory; + _logger.Info("Installing packages..."); + _logger.TraceFormat("Packages folder: {0}", Path.Combine(workingDirectory, "Packages")); + var packages = GetPackages(workingDirectory); - + try { _packageInstaller.InstallPackages(packages, _allowPre, _logger.Info); diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index a8009099..0dcba45e 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -34,6 +34,11 @@ public class ScriptCsArgs [ArgDescription("Installs and restores packages which are specified in packages.config")] public string Install { get; set; } + [ArgShortcut("g")] + [ArgDescription("Installs and restores global packages which are specified in packages.config")] + public bool Global { get; set; } + + [ArgShortcut("save")] [ArgDescription("Creates a packages.config file based on the packages directory")] public bool Save { get; set; } From 5b25a70c7d22060eb5629a6d5c3cf001dca51091 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 04:10:59 -0500 Subject: [PATCH 131/993] cleanup / bug fixing --- common/CommonVersionInfo.cs | 21 ++++++++++++----- src/ScriptCs/Command/CommandFactory.cs | 23 +++++++++++-------- .../ModuleLoaderTests.cs | 7 ------ .../ScriptCs.Hosting.Tests.csproj | 3 ++- test/ScriptCs.Hosting.Tests/packages.config | 1 + 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/common/CommonVersionInfo.cs b/common/CommonVersionInfo.cs index 590a13eb..e8a62e22 100644 --- a/common/CommonVersionInfo.cs +++ b/common/CommonVersionInfo.cs @@ -1,9 +1,18 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; using System.Reflection; -/** - * Do not manually edit this file. The build script will generate and insert the proper version numbers based on the - * contents of 'build\ScriptCs.Version.props'. - **/ +[assembly: System.Reflection.AssemblyVersionAttribute("0.6.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("0.6.0-alpha")] + +// Generated by the MSBuild WriteCodeFragment class on 7/25/2013 4:08:10 AM. -[assembly: AssemblyVersion("0.0.0")] -[assembly: AssemblyInformationalVersion("0.0.0")] \ No newline at end of file diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index ff448ec1..e78dcb86 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -20,6 +20,18 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) return new ShowUsageCommand(_scriptServices.Logger, isValid: true); } + if (args.Global) + { + var currentDir = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); + _scriptServices.FileSystem.CurrentDirectory = currentDir; + + if (!_scriptServices.FileSystem.DirectoryExists(currentDir)) + _scriptServices.FileSystem.CreateDirectory(currentDir); + + } + + _scriptServices.InstallationProvider.Initialize(); + if (args.Repl) { var replCommand = new ExecuteReplCommand( @@ -79,17 +91,8 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) string currentDirectory = null; - if (args.Global) - { - currentDirectory = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); - _scriptServices.FileSystem.CurrentDirectory = currentDirectory; - if (!_scriptServices.FileSystem.DirectoryExists(currentDirectory)) - _scriptServices.FileSystem.CreateDirectory(currentDirectory); - } - else - currentDirectory = _scriptServices.FileSystem.CurrentDirectory; + currentDirectory = _scriptServices.FileSystem.CurrentDirectory; - _scriptServices.InstallationProvider.Initialize(); var packageFile = Path.Combine(currentDirectory, Constants.PackagesFile); if (!_scriptServices.FileSystem.FileExists(packageFile)) diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs index 83cfbdf3..e1552d5a 100644 --- a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -57,13 +57,6 @@ public void ShouldInitializeModulesThatMatchOnExtension() _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - - loader = new ModuleLoader(_mockAssemblyResolver.Object, (p, c) => _paths.Add(p), _getModules); - loader.Load(null, null, "ext3", false, false); - _mockModule1.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Once()); - _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - } [Fact] diff --git a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj index 6e3a28b3..3d3a01e9 100644 --- a/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj +++ b/test/ScriptCs.Hosting.Tests/ScriptCs.Hosting.Tests.csproj @@ -11,7 +11,8 @@ - ..\ScriptCs.Tests\bin\Debug\Moq.dll + ..\..\packages\Moq.4.0.10827\lib\NET40\Moq.dll + True ..\..\packages\Should.1.1.12.0\lib\Should.dll diff --git a/test/ScriptCs.Hosting.Tests/packages.config b/test/ScriptCs.Hosting.Tests/packages.config index 5aa03453..08b40aa8 100644 --- a/test/ScriptCs.Hosting.Tests/packages.config +++ b/test/ScriptCs.Hosting.Tests/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file From 20b973703efb337a1f7c9887aed8fdb5632d713b Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 04:18:45 -0500 Subject: [PATCH 132/993] fix order of creation for module folder --- src/ScriptCs/Command/CommandFactory.cs | 5 ++--- test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ScriptCs/Command/CommandFactory.cs b/src/ScriptCs/Command/CommandFactory.cs index e78dcb86..5b47726e 100644 --- a/src/ScriptCs/Command/CommandFactory.cs +++ b/src/ScriptCs/Command/CommandFactory.cs @@ -23,11 +23,10 @@ public ICommand CreateCommand(ScriptCsArgs args, string[] scriptArgs) if (args.Global) { var currentDir = Path.Combine(_scriptServices.FileSystem.LocalApplicationData, "scriptcs"); - _scriptServices.FileSystem.CurrentDirectory = currentDir; - if (!_scriptServices.FileSystem.DirectoryExists(currentDir)) _scriptServices.FileSystem.CreateDirectory(currentDir); - + + _scriptServices.FileSystem.CurrentDirectory = currentDir; } _scriptServices.InstallationProvider.Initialize(); diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs index e1552d5a..3426f0eb 100644 --- a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -56,7 +56,7 @@ public void ShouldInitializeModulesThatMatchOnExtension() loader.Load(null, null, "ext1", false, false); _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never());g } [Fact] From 7c369e88cf147be7f17bef6f6e8015df25e699fa Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Thu, 25 Jul 2013 04:21:25 -0500 Subject: [PATCH 133/993] fix typo in test --- test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs index 3426f0eb..e1552d5a 100644 --- a/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs +++ b/test/ScriptCs.Hosting.Tests/ModuleLoaderTests.cs @@ -56,7 +56,7 @@ public void ShouldInitializeModulesThatMatchOnExtension() loader.Load(null, null, "ext1", false, false); _mockModule1.Verify(m=>m.Initialize(It.IsAny(), false, false), Times.Once()); _mockModule2.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); - _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never());g + _mockModule3.Verify(m => m.Initialize(It.IsAny(), false, false), Times.Never()); } [Fact] From be2786e0e51d3190f598a52d5b707c1843ad9b3b Mon Sep 17 00:00:00 2001 From: Brandon Stirnaman Date: Thu, 25 Jul 2013 09:58:27 -0500 Subject: [PATCH 134/993] Fixes scriptcs/scriptcs#375 - line splitting when linebreaks differ between Host and file --- src/ScriptCs.Core/FileSystem.cs | 2 +- test/ScriptCs.Core.Tests/FileSystemTests.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ScriptCs.Core/FileSystem.cs b/src/ScriptCs.Core/FileSystem.cs index ab04a878..c481e082 100644 --- a/src/ScriptCs.Core/FileSystem.cs +++ b/src/ScriptCs.Core/FileSystem.cs @@ -81,7 +81,7 @@ public IEnumerable SplitLines(string value) { Guard.AgainstNullArgument("value", value); - return value.Split(new[] { NewLine }, StringSplitOptions.None); + return value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); } public void WriteToFile(string path, string text) diff --git a/test/ScriptCs.Core.Tests/FileSystemTests.cs b/test/ScriptCs.Core.Tests/FileSystemTests.cs index f683eedf..7c8b1ee7 100644 --- a/test/ScriptCs.Core.Tests/FileSystemTests.cs +++ b/test/ScriptCs.Core.Tests/FileSystemTests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.IO; using Should; using Xunit; @@ -80,5 +81,20 @@ public void ReturnsCorrectWorkingDirectoryIfPathDoesNotExist() _fileSystem.GetWorkingDirectory(nonExistantFilePath).ShouldEqual(@"C:\working_dir"); } } + + public class SplitLinesMethod + { + private readonly FileSystem _fileSystem = new FileSystem(); + + [Fact] + public void ReturnsCorrectLines() + { + var fileContentsLin = "using System;\nusing System.IO;"; + var fileContentsWin = "using System;\r\nusing System.IO;"; + + _fileSystem.SplitLines(fileContentsLin).Count().ShouldEqual(2); + _fileSystem.SplitLines(fileContentsWin).Count().ShouldEqual(2); + } + } } } \ No newline at end of file From 32ec49137dbe874c85751c07a7d8fc1c11861f48 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 26 Jul 2013 01:55:24 -0500 Subject: [PATCH 135/993] Refactored into separate container factories, necessary for wiring up modules --- src/ScriptCs.Core/IRuntimeContainerFactory.cs | 9 ++ src/ScriptCs.Core/IScriptContainerFactory.cs | 10 -- .../InitializationContainerFactory.cs | 36 ++++++ src/ScriptCs.Core/RuntimeContainerFactory.cs | 74 +++++++++++ src/ScriptCs.Core/ScriptContainerFactory.cs | 122 +++--------------- src/ScriptCs.Core/ScriptCs.Core.csproj | 4 +- src/ScriptCs.Core/ScriptRuntime.cs | 10 +- src/ScriptCs.Hosting/ModuleAttribute.cs | 2 +- src/ScriptCs.Hosting/ScriptCs.Hosting.csproj | 53 ++++++-- src/ScriptCs.Hosting/packages.config | 9 ++ src/ScriptCs/ModuleAttribute.cs | 14 -- src/ScriptCs/Program.cs | 4 - src/ScriptCs/Properties/Settings.Designer.cs | 26 ++++ src/ScriptCs/Properties/Settings.settings | 6 + src/ScriptCs/ScriptCs.csproj | 42 +++++- src/ScriptCs/ScriptCsArgs.cs | 4 + .../InitializationContainerFactoryTests.cs | 21 +++ ...sts.cs => RuntimeContainerFactoryTests.cs} | 63 +++++---- .../ScriptCs.Core.Tests.csproj | 3 +- .../ScriptCs.Core.Tests/ScriptRuntimeTests.cs | 4 +- 20 files changed, 331 insertions(+), 185 deletions(-) create mode 100644 src/ScriptCs.Core/IRuntimeContainerFactory.cs delete mode 100644 src/ScriptCs.Core/IScriptContainerFactory.cs create mode 100644 src/ScriptCs.Core/InitializationContainerFactory.cs create mode 100644 src/ScriptCs.Core/RuntimeContainerFactory.cs delete mode 100644 src/ScriptCs/ModuleAttribute.cs create mode 100644 src/ScriptCs/Properties/Settings.Designer.cs create mode 100644 src/ScriptCs/Properties/Settings.settings create mode 100644 test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs rename test/ScriptCs.Core.Tests/{ScriptContainerFactoryTests.cs => RuntimeContainerFactoryTests.cs} (65%) diff --git a/src/ScriptCs.Core/IRuntimeContainerFactory.cs b/src/ScriptCs.Core/IRuntimeContainerFactory.cs new file mode 100644 index 00000000..12523461 --- /dev/null +++ b/src/ScriptCs.Core/IRuntimeContainerFactory.cs @@ -0,0 +1,9 @@ +using Autofac; + +namespace ScriptCs +{ + public interface IRuntimeContainerFactory + { + IContainer Container { get; } + } +} \ No newline at end of file diff --git a/src/ScriptCs.Core/IScriptContainerFactory.cs b/src/ScriptCs.Core/IScriptContainerFactory.cs deleted file mode 100644 index a9420f34..00000000 --- a/src/ScriptCs.Core/IScriptContainerFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Autofac; - -namespace ScriptCs -{ - public interface IScriptContainerFactory - { - IContainer InitializationContainer { get; } - IContainer RuntimeContainer { get; } - } -} \ No newline at end of file diff --git a/src/ScriptCs.Core/InitializationContainerFactory.cs b/src/ScriptCs.Core/InitializationContainerFactory.cs new file mode 100644 index 00000000..5991e486 --- /dev/null +++ b/src/ScriptCs.Core/InitializationContainerFactory.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Common.Logging; +using ScriptCs.Package; + +namespace ScriptCs +{ + public interface IInitializationContainerFactory + { + IContainer Container { get; } + } + + public class InitializationContainerFactory : ScriptContainerFactory, IInitializationContainerFactory + { + public InitializationContainerFactory(ILog logger, IDictionary overrides) + : base(logger, overrides) + { + } + + protected override IContainer CreateContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + return builder.Build(); + } + } +} diff --git a/src/ScriptCs.Core/RuntimeContainerFactory.cs b/src/ScriptCs.Core/RuntimeContainerFactory.cs new file mode 100644 index 00000000..81d6d961 --- /dev/null +++ b/src/ScriptCs.Core/RuntimeContainerFactory.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition.Hosting; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autofac; +using Autofac.Integration.Mef; +using Common.Logging; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; + +namespace ScriptCs +{ + public class RuntimeContainerFactory : ScriptContainerFactory, IRuntimeContainerFactory + { + private readonly IConsole _console; + private readonly Type _scriptEngineType; + private readonly Type _scriptExecutorType; + private readonly bool _initDirectoryCatalog; + private readonly IInitializationContainerFactory _initializationContainerFactory; + + public RuntimeContainerFactory(ILog logger, IDictionary overrides, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IInitializationContainerFactory initializationContainerFactory) : + base(logger, overrides) + { + _console = console; + _scriptEngineType = scriptEngineType; + _scriptExecutorType = scriptExecutorType; + _initDirectoryCatalog = initDirectoryCatalog; + _initializationContainerFactory = initializationContainerFactory; + } + + protected override IContainer CreateContainer() + { + var builder = new ContainerBuilder(); + builder.RegisterInstance(_logger).Exported(x => x.As()); + builder.RegisterType(_scriptEngineType).As().SingleInstance(); + builder.RegisterType(_scriptExecutorType).As().SingleInstance(); + builder.RegisterInstance(_console).As(); + builder.RegisterType().SingleInstance(); + + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); + RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); + var initializationContainer = _initializationContainerFactory.Container; + var assemblyResolver = initializationContainer.Resolve(); + + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(assemblyResolver).As(); + + if (_initDirectoryCatalog) + { + var currentDirectory = Environment.CurrentDirectory; + var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); + + var aggregateCatalog = new AggregateCatalog(); + + assemblies.Select(x => new AssemblyCatalog(x)).ToList() + .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); + + builder.RegisterComposablePartCatalog(aggregateCatalog); + } + + return builder.Build(); + } + } +} diff --git a/src/ScriptCs.Core/ScriptContainerFactory.cs b/src/ScriptCs.Core/ScriptContainerFactory.cs index 844a0f49..6326b594 100644 --- a/src/ScriptCs.Core/ScriptContainerFactory.cs +++ b/src/ScriptCs.Core/ScriptContainerFactory.cs @@ -14,113 +14,18 @@ namespace ScriptCs { - public class ScriptContainerFactory : IScriptContainerFactory + public abstract class ScriptContainerFactory { - private readonly ILog _logger; - private readonly IConsole _console; - private readonly Type _scriptEngineType; - private readonly Type _scriptExecutorType; - private readonly bool _initDirectoryCatalog; - private IDictionary _overrides = null; + private readonly IDictionary _overrides = null; + protected readonly ILog _logger; - public ScriptContainerFactory(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides ) + public ScriptContainerFactory(ILog logger, IDictionary overrides) { - Guard.AgainstNullArgument("scriptExecutor", scriptExecutorType); - Guard.AgainstNullArgument("scriptEngine", scriptEngineType); - Guard.AgainstNullArgument("console", console); - Guard.AgainstNullArgument("logger", logger); - - if (overrides == null) - overrides = new Dictionary(); - - _logger = logger; - _console = console; - _scriptEngineType = scriptEngineType; - _scriptExecutorType = scriptExecutorType; - _initDirectoryCatalog = initDirectoryCatalog; _overrides = overrides; + _logger = logger; } - private IContainer _initializationContainer; - public IContainer InitializationContainer - { - get - { - if (_initializationContainer == null) - { - _initializationContainer = CreateInitializationContainer(); - } - return _initializationContainer; - } - } - - private IContainer _runtimeContainer; - public IContainer RuntimeContainer - { - get - { - if (_runtimeContainer == null) - { - _runtimeContainer = CreateRuntimeContainer(); - } - return _runtimeContainer; - } - } - - private IContainer CreateInitializationContainer() - { - var builder = new ContainerBuilder(); - builder.RegisterInstance(_logger); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - return builder.Build(); - } - - private IContainer CreateRuntimeContainer() - { - var builder = new ContainerBuilder(); - builder.RegisterInstance(_logger).Exported(x => x.As()); - builder.RegisterType(_scriptEngineType).As().SingleInstance(); - builder.RegisterType(_scriptExecutorType).As().SingleInstance(); - builder.RegisterInstance(_console).As(); - builder.RegisterType().SingleInstance(); - - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); - RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); - - var initializationContainer = InitializationContainer; - var assemblyResolver = initializationContainer.Resolve(); - - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(assemblyResolver).As(); - - if (_initDirectoryCatalog) - { - var currentDirectory = Environment.CurrentDirectory; - var assemblies = assemblyResolver.GetAssemblyPaths(currentDirectory); - - var aggregateCatalog = new AggregateCatalog(); - - assemblies.Select(x => new AssemblyCatalog(x)).ToList() - .ForEach(catalog => aggregateCatalog.Catalogs.Add(catalog)); - - builder.RegisterComposablePartCatalog(aggregateCatalog); - } - - return builder.Build(); - } - - private void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) + protected void RegisterOverrideOrDefault(ContainerBuilder builder, Action registrationAction) { if (_overrides.ContainsKey(typeof(T))) { @@ -139,5 +44,20 @@ private void RegisterOverrideOrDefault(ContainerBuilder builder, Action - + + + diff --git a/src/ScriptCs.Core/ScriptRuntime.cs b/src/ScriptCs.Core/ScriptRuntime.cs index ea8182f6..d84f5151 100644 --- a/src/ScriptCs.Core/ScriptRuntime.cs +++ b/src/ScriptCs.Core/ScriptRuntime.cs @@ -15,15 +15,17 @@ namespace ScriptCs { public class ScriptRuntime { + /* public ScriptRuntime(ILog logger, IConsole console, Type scriptEngineType, Type scriptExecutorType, bool initDirectoryCatalog, IDictionary overrides) - : this(new ScriptContainerFactory(logger, console, scriptEngineType, scriptExecutorType, initDirectoryCatalog, overrides)) + : this(new RuntimeContainerFactory(logger, console, scriptEngineType, scriptExecutorType, initDirectoryCatalog)) { } - - public ScriptRuntime(IScriptContainerFactory containerFactory) + */ + + public ScriptRuntime(IRuntimeContainerFactory containerFactory) { - var container = containerFactory.RuntimeContainer; + var container = containerFactory.Container; ScriptServices = container.Resolve(); Logger = container.Resolve(); } diff --git a/src/ScriptCs.Hosting/ModuleAttribute.cs b/src/ScriptCs.Hosting/ModuleAttribute.cs index 095169fb..d940f524 100644 --- a/src/ScriptCs.Hosting/ModuleAttribute.cs +++ b/src/ScriptCs.Hosting/ModuleAttribute.cs @@ -1,6 +1,6 @@ using System.ComponentModel.Composition; -namespace ScriptCs.Hosting +namespace ScriptCs { [MetadataAttribute] public class ModuleAttribute : ExportAttribute, IModuleMetadata diff --git a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj index 179dd3c6..b81aef24 100644 --- a/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj +++ b/src/ScriptCs.Hosting/ScriptCs.Hosting.csproj @@ -9,6 +9,17 @@ ..\ + + False + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.dll + + + ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll + + + False + ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll + ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll @@ -18,6 +29,34 @@ ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll + + False + ..\..\packages\NuGet.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + + + True + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + True + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + False + ..\..\packages\ScriptCs.Contracts.0.6.0-alpha\lib\net45\ScriptCs.Contracts.dll + + + False + ..\..\packages\ScriptCs.Core.0.6.0-alpha\lib\net45\ScriptCs.Core.dll + + + False + ..\..\packages\ScriptCs.Engine.Roslyn.0.6.0-alpha\lib\net45\ScriptCs.Engine.Roslyn.dll + + + False + ..\..\packages\ServiceStack.Text.3.9.56\lib\net35\ServiceStack.Text.dll + @@ -27,20 +66,6 @@ - - - {6049e205-8b5f-4080-b023-70600e51fd64} - ScriptCs.Contracts - - - {e590e710-e159-48e6-a3e6-1a83d3fe732c} - ScriptCs.Core - - - {e79ec231-e27d-4057-91c9-2d001a3a8c3b} - ScriptCs.Engine.Roslyn - - Properties\CommonAssemblyInfo.cs diff --git a/src/ScriptCs.Hosting/packages.config b/src/ScriptCs.Hosting/packages.config index 8ec4ed08..5a7fb1a4 100644 --- a/src/ScriptCs.Hosting/packages.config +++ b/src/ScriptCs.Hosting/packages.config @@ -1,6 +1,15 @@  + + + + + + + + + \ No newline at end of file diff --git a/src/ScriptCs/ModuleAttribute.cs b/src/ScriptCs/ModuleAttribute.cs deleted file mode 100644 index c02bb5ec..00000000 --- a/src/ScriptCs/ModuleAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.ComponentModel.Composition; - -namespace ScriptCs.Hosting -{ - public class ModuleAttribute : ExportAttribute - { - public ModuleAttribute(string name) : base(typeof (IModule)) - { - Name = name; - } - - public string Name { get; private set; } - } -} \ No newline at end of file diff --git a/src/ScriptCs/Program.cs b/src/ScriptCs/Program.cs index 5039329c..c55f3719 100644 --- a/src/ScriptCs/Program.cs +++ b/src/ScriptCs/Program.cs @@ -22,10 +22,6 @@ private static int Main(string[] args) ScriptName(commandArgs.ScriptName). Repl(commandArgs.Repl); - var containerBuilder = new ContainerBuilder(); - - - var runtime = runtimeBuilder.Build(); var logger = runtime.Logger; diff --git a/src/ScriptCs/Properties/Settings.Designer.cs b/src/ScriptCs/Properties/Settings.Designer.cs new file mode 100644 index 00000000..0f094d02 --- /dev/null +++ b/src/ScriptCs/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.18051 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ScriptCs.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/src/ScriptCs/Properties/Settings.settings b/src/ScriptCs/Properties/Settings.settings new file mode 100644 index 00000000..049245f4 --- /dev/null +++ b/src/ScriptCs/Properties/Settings.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index 83d09dc3..ccf0792c 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -8,6 +8,21 @@ scriptcs ..\..\ ..\..\build\ScriptCs.ruleset + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true ..\..\common\Icon.ico @@ -73,7 +88,11 @@ - + + True + True + Settings.settings + @@ -84,6 +103,10 @@ + + SettingsSingleFileGenerator + Settings.Designer.cs + @@ -108,6 +131,23 @@ Properties\Icon.ico + + + False + Microsoft .NET Framework 4.5 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + \ No newline at end of file diff --git a/src/ScriptCs/ScriptCsArgs.cs b/src/ScriptCs/ScriptCsArgs.cs index 0dcba45e..1c9f3662 100644 --- a/src/ScriptCs/ScriptCsArgs.cs +++ b/src/ScriptCs/ScriptCsArgs.cs @@ -55,6 +55,10 @@ public class ScriptCsArgs [ArgDescription("Outputs version information")] public bool Version { get; set; } + [ArgShortcut("modules")] + [ArgDescription("Specify modules to load")] + public string Modules { get; set; } + public static void SplitScriptArgs(ref string[] args, out string[] scriptArgs) { Guard.AgainstNullArgument("args", args); diff --git a/test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs b/test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs new file mode 100644 index 00000000..1d55d586 --- /dev/null +++ b/test/ScriptCs.Core.Tests/InitializationContainerFactoryTests.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using Autofac; +using Common.Logging; +using Moq; +using ScriptCs.Contracts; +using ScriptCs.Package; +using ScriptCs.Package.InstallationProvider; +using Should; +using Xunit; + +namespace ScriptCs.Tests +{ + public class InitializationContainerFactoryTests + { + public class TheCreateInitializationContainerMethod + { + + } + } +} \ No newline at end of file diff --git a/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs b/test/ScriptCs.Core.Tests/RuntimeContainerFactoryTests.cs similarity index 65% rename from test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs rename to test/ScriptCs.Core.Tests/RuntimeContainerFactoryTests.cs index fd0c385d..24718000 100644 --- a/test/ScriptCs.Core.Tests/ScriptContainerFactoryTests.cs +++ b/test/ScriptCs.Core.Tests/RuntimeContainerFactoryTests.cs @@ -14,7 +14,7 @@ namespace ScriptCs.Tests { - public class ScriptContainerFactoryTests + public class RuntimeContainerFactoryTests { public class TheCreateInitializationContainerMethod { @@ -28,7 +28,7 @@ public class TheCreateRuntimeContainerMethod private Type _scriptEngineType = null; private Mock _mockLogger = new Mock(); private IDictionary _overrides = new Dictionary(); - private IScriptContainerFactory _factory = null; + private IRuntimeContainerFactory _runtimeContainerFactory = null; public TheCreateRuntimeContainerMethod() { @@ -38,106 +38,107 @@ public TheCreateRuntimeContainerMethod() var mockScriptEngineType = new Mock(); _scriptEngineType = mockScriptEngineType.Object.GetType(); - _factory = new ScriptContainerFactory(_mockLogger.Object, _mockConsole.Object, _scriptEngineType, _scriptExecutorType, false, _overrides); + var initializationContainerFactory = new InitializationContainerFactory(_mockLogger.Object, _overrides); + _runtimeContainerFactory = new RuntimeContainerFactory(_mockLogger.Object, _overrides, _mockConsole.Object, _scriptEngineType, _scriptExecutorType, false, initializationContainerFactory); } [Fact] public void ShouldRegisterTheLoggerInstance() { - var logger = _factory.RuntimeContainer.Resolve(); + var logger = _runtimeContainerFactory.Container.Resolve(); logger.ShouldEqual(_mockLogger.Object); } [Fact] public void ShouldRegisterTheScriptEngine() { - var engine = _factory.RuntimeContainer.Resolve(); + var engine = _runtimeContainerFactory.Container.Resolve(); engine.GetType().ShouldEqual(_scriptEngineType); } [Fact] public void ShouldRegisterTheExecutor() { - var executor = _factory.RuntimeContainer.Resolve(); + var executor = _runtimeContainerFactory.Container.Resolve(); executor.GetType().ShouldEqual(_scriptExecutorType); } [Fact] public void ShouldRegisterTheConsoleInstance() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheScriptServices() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptHostFactoryIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFilePreProcessorIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptPackResolverIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultInstallationProviderIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageInstallerIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultScriptServiceRootIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultFileSystemIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyUtilityIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageContainerIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultPackageAssemblyResolverIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] public void ShouldRegisterTheDefaultAssemblyResolverIfNoOverride() { - _factory.RuntimeContainer.Resolve().ShouldNotBeNull(); + _runtimeContainerFactory.Container.Resolve().ShouldNotBeNull(); } [Fact] @@ -145,7 +146,7 @@ public void ShouldRegisterTheOverriddenScriptHostFactory() { var mock = new Mock(); _overrides[typeof(IScriptHostFactory)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -153,7 +154,7 @@ public void ShouldRegisterTheOverriddenFilePreProcessor() { var mock = new Mock(); _overrides[typeof(IFilePreProcessor)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } @@ -162,7 +163,7 @@ public void ShouldRegisterTheOverriddenScriptPackResolver() { var mock = new Mock(); _overrides[typeof(IScriptPackResolver)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -170,7 +171,7 @@ public void ShouldRegisterTheOverriddenInstallationProvider() { var mock = new Mock(); _overrides[typeof(IInstallationProvider)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -178,7 +179,7 @@ public void ShouldRegisterTheOverriddenPackageInstaller() { var mock = new Mock(); _overrides[typeof(IPackageInstaller)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -186,7 +187,7 @@ public void ShouldRegisterTheOverriddenFileSystem() { var mock = new Mock(); _overrides[typeof(IFileSystem)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -194,7 +195,7 @@ public void ShouldRegisterTheOverriddenAssemblyUtility() { var mock = new Mock(); _overrides[typeof(IAssemblyUtility)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -202,7 +203,7 @@ public void ShouldRegisterTheOverriddenPackageContainer() { var mock = new Mock(); _overrides[typeof(IPackageContainer)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -210,17 +211,15 @@ public void ShouldRegisterTheOverriddenPackageAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IPackageAssemblyResolver)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } - - [Fact] public void ShouldRegisterTheOverriddenAssemblyResolver() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object.GetType(); - _factory.RuntimeContainer.Resolve().ShouldBeType(mock.Object.GetType()); + _runtimeContainerFactory.Container.Resolve().ShouldBeType(mock.Object.GetType()); } [Fact] @@ -228,7 +227,7 @@ public void ShouldRegisterTheOverriddenAssemblyResolverInstance() { var mock = new Mock(); _overrides[typeof(IAssemblyResolver)] = mock.Object; - _factory.RuntimeContainer.Resolve().ShouldEqual(mock.Object); + _runtimeContainerFactory.Container.Resolve().ShouldEqual(mock.Object); } } } diff --git a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj index c4ecdce7..cbf3b688 100644 --- a/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj +++ b/test/ScriptCs.Core.Tests/ScriptCs.Core.Tests.csproj @@ -45,7 +45,8 @@ Properties\CommonVersionInfo.cs - + + diff --git a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs index f5ede929..949ebb78 100644 --- a/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs +++ b/test/ScriptCs.Core.Tests/ScriptRuntimeTests.cs @@ -21,7 +21,7 @@ public class TheInitializeMethod { private Mock _mockLogger = new Mock(); private ScriptServices _scriptServices = new ScriptServices(null, null, null, null,null,null,null,null,null,null); - private Mock _mockFactory = new Mock(); + private Mock _mockFactory = new Mock(); private ScriptRuntime _runtime = null; public TheInitializeMethod() @@ -30,7 +30,7 @@ public TheInitializeMethod() builder.RegisterInstance(_mockLogger.Object); builder.RegisterInstance(_scriptServices); var container = builder.Build(); - _mockFactory.SetupGet(f => f.RuntimeContainer).Returns(container); + _mockFactory.SetupGet(f => f.Container).Returns(container); _runtime = new ScriptRuntime(_mockFactory.Object); } From bd75859f12ed696069f427a56533e4474c373986 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 26 Jul 2013 02:12:38 -0500 Subject: [PATCH 136/993] fixing references in scriptcs proj to be nuget references --- src/ScriptCs/ScriptCs.csproj | 59 ++++++++++++++++++++++-------------- src/ScriptCs/packages.config | 9 +++++- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/ScriptCs/ScriptCs.csproj b/src/ScriptCs/ScriptCs.csproj index ccf0792c..6bd5f068 100644 --- a/src/ScriptCs/ScriptCs.csproj +++ b/src/ScriptCs/ScriptCs.csproj @@ -36,26 +36,57 @@ False ..\..\packages\Autofac.3.0.2\lib\net40\Autofac.Configuration.dll - + + False ..\..\packages\Autofac.Mef.3.0.1\lib\net40\Autofac.Integration.Mef.dll - + + False ..\..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll - + + False ..\..\packages\Common.Logging.Log4Net.2.0.1\lib\net20\Common.Logging.Log4Net.dll False ..\..\packages\log4net.1.2.10\lib\2.0\log4net.dll + + False + ..\..\packages\NuGet.Core.2.2.0\lib\net40-Client\NuGet.Core.dll + False ..\..\packages\PowerArgs.1.6.0.0\lib\net40\PowerArgs.dll - + + True + ..\..\packages\Roslyn.Compilers.Common.1.2.20906.2\lib\net45\Roslyn.Compilers.dll + + + True + ..\..\packages\Roslyn.Compilers.CSharp.1.2.20906.2\lib\net45\Roslyn.Compilers.CSharp.dll + + + False + ..\..\packages\ScriptCs.Contracts.0.6.0-alpha\lib\net45\ScriptCs.Contracts.dll + + False - ..\..\packages\ServiceStack.Text.3.9.47\lib\net35\ServiceStack.Text.dll + ..\..\packages\ScriptCs.Core.0.6.0-alpha\lib\net45\ScriptCs.Core.dll + + + False + ..\..\packages\ScriptCs.Engine.Roslyn.0.6.0-alpha\lib\net45\ScriptCs.Engine.Roslyn.dll + + + False + ..\..\packages\ScriptCs.Hosting.0.6.0-alpha\lib\net45\ScriptCs.Hosting.dll + + + False + ..\..\packages\ServiceStack.Text.3.9.56\lib\net35\ServiceStack.Text.dll @@ -108,24 +139,6 @@ Settings.Designer.cs - - - {9aef2d95-87fb-4829-b384-34bfe076d531} - ScriptCs.Hosting - - - {6049e205-8b5f-4080-b023-70600e51fd64} - ScriptCs.Contracts - - - {e590e710-e159-48e6-a3e6-1a83d3fe732c} - ScriptCs.Core - - - {e79ec231-e27d-4057-91c9-2d001a3a8c3b} - ScriptCs.Engine.Roslyn - - Properties\Icon.ico diff --git a/src/ScriptCs/packages.config b/src/ScriptCs/packages.config index 9531ddb6..5bf002f1 100644 --- a/src/ScriptCs/packages.config +++ b/src/ScriptCs/packages.config @@ -5,6 +5,13 @@ + - + + + + + + + \ No newline at end of file From 4d6ffb9633e6e6e897c293046f00071800b28c38 Mon Sep 17 00:00:00 2001 From: Glenn Block Date: Fri, 26 Jul 2013 15:13:13 -0500 Subject: [PATCH 137/993] Refactor IInitializationContainerFactory TODO: Better name --- .../InitializationContainerFactory.cs | 22 ++++++++++++++++++- src/ScriptCs.Core/RuntimeContainerFactory.cs | 10 +++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/ScriptCs.Core/InitializationContainerFactory.cs b/src/ScriptCs.Core/InitializationContainerFactory.cs index 5991e486..d3dbbc4e 100644 --- a/src/ScriptCs.Core/InitializationContainerFactory.cs +++ b/src/ScriptCs.Core/InitializationContainerFactory.cs @@ -11,7 +11,8 @@ namespace ScriptCs { public interface IInitializationContainerFactory { - IContainer Container { get; } + IAssemblyResolver GetAssemblyResolver(); + void RegisterServices(ContainerBuilder builder); } public class InitializationContainerFactory : ScriptContainerFactory, IInitializationContainerFactory @@ -21,6 +22,8 @@ public InitializationContainerFactory(ILog logger, IDictionary ove { } + + protected override IContainer CreateContainer() { var builder = new ContainerBuilder(); @@ -32,5 +35,22 @@ protected override IContainer CreateContainer() RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); return builder.Build(); } + + public IAssemblyResolver GetAssemblyResolver() + { + return Container.Resolve(); + } + + public void RegisterServices(ContainerBuilder builder) + { + var initializationContainer = Container; + + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + builder.RegisterInstance(initializationContainer.Resolve()).As(); + + } } } diff --git a/src/ScriptCs.Core/RuntimeContainerFactory.cs b/src/ScriptCs.Core/RuntimeContainerFactory.cs index 81d6d961..eaa5cc26 100644 --- a/src/ScriptCs.Core/RuntimeContainerFactory.cs +++ b/src/ScriptCs.Core/RuntimeContainerFactory.cs @@ -46,14 +46,10 @@ protected override IContainer CreateContainer() RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); RegisterOverrideOrDefault(builder, b => b.RegisterType().As().SingleInstance()); RegisterOverrideOrDefault(builder, b => b.RegisterType().SingleInstance()); - var initializationContainer = _initializationContainerFactory.Container; - var assemblyResolver = initializationContainer.Resolve(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(initializationContainer.Resolve()).As(); - builder.RegisterInstance(assemblyResolver).As(); + _initializationContainerFactory.RegisterServices(builder); + + var assemblyResolver = _initializationContainerFactory.GetAssemblyResolver(); if (_initDirectoryCatalog) { From 9b2256c12bf5572504cacb8d6733057a326c0378 Mon Sep 17 00:00:00 2001 From: Justin Rusbatch Date: Sat, 27 Jul 2013 18:06:25 -0400 Subject: [PATCH 138/993] Update NuGet from v2.2.1 to v2.6.1 --- .nuget/NuGet.exe | Bin 651264 -> 777728 bytes .nuget/NuGet.targets | 30 ++++++------------------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe index 4645f4b35e8ebd8508fe5691df73ce88a4a8028a..c296edf177fc5c0373b2c705a006b8c686098e37 100644 GIT binary patch literal 777728 zcmb@v37lL-)%SnrcF*nZJ2Oc-JxnJVAPJJ8m?0tTGXsPGitMW(n;@Gk0ylOOmJHJl zARf^5A|NWi1x4S1y`+wf|^Uf!^eeS8M zQ>RXyI(2HjhaCUbAQuEdp8qer5Cos*SAQ$*`JW$C1kYOd*;&CSN>42Qbl1U8EPlmV zXV(|4swHREPC0MUX{VfjesaO0Q_ombTYdhbv(I1j(!-8gbY61$8O!?m;;mEChrcWc z4(`eY*FOD)BeL9n5`2?g zgJ6#RYyGCLK1xu8?!gB42DK{vRb`%8VJuDWfReF5x4DcB?4JiJLBAhh>}hK&qnL%7scDBEt!Gh zDGa)U)33+}>&`2fE<7Fv(Xp53g5IvKO`~^w-!h!&rWS^`3UiYN5EC2{^*94Ou8`pj z@Hk54;~C&_r3`0)$Ds{Ao&g?5AwA9jk3#?+XMo4`WjF)C{W^50e$?+MW<0hPn9#v{ zduXji~8VA)+UCGU2q!;Hx-J$gd{ef=2#EpRksk23%q_4g9!Osl_zAlmCs5khC! zw4Ae=<@AuzMi8F10ni?A7I-Tt3M)>J1j*SqZSmUv3FhLmcnCx7mLd@|6K*btq)1YzmKZuG6%_ScB zT(O$aM&iEyO1_jvB0L`3l1QcMTHvlqce#6D;nG{m-3e6Vz8c6?m3*N=rRB#dVbH%Z zS_;iNEhe54)`A+FwS`lGX}GW!R4l2bj8vkzkwcT?N}*gx5MsQZY`Pp(6+7xC9wS9i z&Mz6KV8Kw0H*z0^>%bSkk}vyGx|3;A)wOWZRVkK>1I2aaV*TE(AX<|v7mDS)+ZHB9 zAKCcA3%O)ZK&#o2Vd>c5^8R2Sl!<@koO>8LV;8|(_i7mHigRIqg4E+4s7oTf#es#p z--756aNIWlH@g$LRL;L&(JS3K_XSb7PkeXR&=y3GSmH`ljy79SA}$gwM+rqysk_Tj z^;oNhO0n_PJVHHzl#5j9H56`D|9UtKO(65vBA~8HsazTu=ywC8zg>uOsal=(I&b=` zs}j@A<1r=rmdV6?UJXL-C1Ho5(lkz9{)!AkZ|zp^mYv>qw=i+|!`kO~u<@ zinU0&2x~zNO4|%y-V7Jkg7V$TV$nmYBXe@O{z`AyUG7b2neiwx3c&P*-D%Dbz)88! z0yj_@!O+G9L+*Hx^Sq+XD$g3ouPe{0cJuJsHXHMf2_pupV>D_-aON&|&;CC@@w zjGQA@5niO<=Y(Tq5roOskj)dr)OsYFo)M5@KA z!(@zDqOmCw6@3*z_@^0RssQs#WGw5eMAzzIq*Vv%5*_02EBW=b z6mJ&G`Q)WUs&o%jqS1tCvZ?R7K;e}_DR~)T;|G8)nQ0$i0qBc#dP`B&W271GNBkOw zWmU=a!M&V!`V!Cc{=BS-%8-R(EYmHsUhcm3>>aNzR*&s17BFQ;P))mmCP4H12_6{UF{Zr7YeR7!Gy}Em4Bnh-7eJ>LZvx;1CX2^o#oU zK8FFs1Bdo{oB#gP z+>#7ufX5AGI0HNmOXSlU;BlBGk23%q4TPqgA2-p433?k%3gOZ6rM3uuKs*dkIdt@I z(U>e~=%{X-y5o78jFSaeiQ&*;eZ22CMrnhvKMox=74?K}B|lNYEy)w%Xy8#y1#~O{ zbYpi2kKPno{)4rPw&FTh6Vj%gwCVo+|y zHofmD)G(*`E{B1^=h+KtL1Cb1ehc=M__0a5;C6-gI>L^I`^}$1_uwRty_~>4`+70} z3WLiR27@SbY`m%HF5$86_x~+vScB ze{)UVu{WUV#=TfUA4RY`6X6YwE(Kqs$*fAzg9-V^ebb_*gi7u;B!N0L9520j!)qyE)h+^6T?_wRJ%xew+wyA)bh|KxU8tdHy)T?FA`E_KA|LIxad5d)e}sIT|}x}mPV5b=68%|>GP5MVqh{xiEr zxu`C$I|e`&+_DU30Jvpl%9B@Hg8c5Ygfa+WfRt}Yl5LWkBmciHc#K) zPa&l{Q^?wFZP6?OIvAy4_qT;@O5)TOiIKKwMgsRBBhg~WXOI0!l?Wpiv@@LYrwG}= z=l3G)+5AH@4@b2{nyHE7(L1Q=C^;RtC#=1sD=mBD3EYZt+EuV9Btq>70{Yie@!lGE zcb?YWK4K_V+ea5g@5-M6;VBU_iW5{{Y*5(vx^mcs90qEyf_jU1)y4`qrtRcPDn#tg z5;>)`u?; z8;rE_t-m4d9%|fVvI%63ZukE!52oa(+cy!tT2&x!w+Y?v!Rd7qOnL%Z&kwD z6Ir}e3FZ^#jqO213v16b!`maAD?aq7l|!l?4ULoYh4U)YQoUBQ7!LNvS)ers|IPo; zq8%URMI7nxz%W5jv=mtm@BY&MR8+G$JE$Gf9_b={8#RD*;C9Y%26!C$;o}+LaX9B5 zXMo4;mf;NWIBLYlGr;4{i0N1V@ICuvNWFjhhGvO`Ov4n32Yoj$y@owCD@0bBthKXS+MtkWR>K9D38W7 zxghU5o3R6-5mwzLq-al97P>9nXg3H;CtoG*Efn4LN>T`m$yESF_hz2Hzm9xX^kWx* zvx$=aQJOdeg{WWEZJkqrDGGNj2M$CG9`GODd^LdR(25{MQ|G#z4JP@baoG zpC4=>?JSc+4RT&N3r0`xF!c(4;?Omkp|7)0z56*7dXxsZ_?CjrDm5OKs7Z|9R5YP# zO3J%Rm2UXP?UBEQ$p3eak~v9{J5{|f-K=Mko*^iUy%t|y?0Ro}C1YXO)nP=s;r;j7 z0Y){LZRMr+ZF*(!AGy1bQye89L8Z`xHK4|~Blf(t*C1Z(YUnNpce~z-)%3T1H?jLl zh2*3BmSPC18j=t3=4D=4UJCYu${g~n#`*5ZJwP@+VXolbLQDq#BZL+leapz$BEYmF zU*4=pjIJrqx{|L+UzS1YZkTpXsmt}BG2Dxz+~l_~R8ctjl>J!E)gMJ{?lB&d-vBEm zihJ_OYJLhU=91mQ*uSY&#qJ^=_@l?bS^YimXEmWEi)Js2-d=zOg$DWiyy>6ZhyrJSD6JX~t}1xQZfZz90-P z4OV>Cn@7!=oB$1Efm<_0Dw|Xp7!Gp@u117-FdKNN*jIU|s6gBsRcW9I1wXNfMkkNZ zDha!Su%$oTKyxDI#sMle^)JcT=ev2Z{XuGO@||Y~xATizQqHo%2;C2*T)x}g2=TFy za2T1DcQ^1FC7&a(v9>G7=iQPXl*nU<-PbEkaygJ=J1bFNV|$9eq>`VTb8mpFS>441 zD;XPar7<;d49FY7JYB7HZ&2AVL$^`mdR4zsu$n3Onkjb=cUk{(RIqvC`45B9;Ka9O zGMp29h&27}Wsx+Z@gqdpN|krR;<+%k0#tXudpCs{qx3-`d08%qy4`z)@I`JGjCql0 zOzcDhz16-#v6MVPtW*-$G$m2VM+24av`V5pHW9P;C^4&*!UkG9g-y$xmZvc6>*Jze z;X7mwG-nY9d-6*=q)(uamC;iXdUA#Ovn9zlSN}R1-4_*erTPO5+~lOB?fomfmh&>k znXOsjZS9<{oDCT9XY;`z^igWn_fb%aU+gkudQuF!`@C%59J)*4VvKY_ZXD$eYJ>6$ z<~7Gy8UsYZ%L$>az`M!4sOa5p8{{`UE1ybxiIA)Bp#j8E_pE&KG)(jq@=G=r4gspu z7sYPA8p;5CEAkC}QnmBgYNF0s}h)wM+hLca53ICW$@J^lsj;Vsyq;u%rt+ux7d4XZ zqabL#{w?Res@KTBC4VHLd1KWTvK4JuM%QnJ`j95F|D-br`Ck-phZ37Am$|d{p?pvSiRZ8H;7F9uMtV3psB}wHH1*Nf$oGI4xMoU3ytd}bm zsxgu^`*JH|$-u|Ue6c9NXvq$z<;=|ulA9=$Ep~WokW1bPf__R?uaID+b_&gWBXapfU?J`D7hXX*~)3 z1VIAFae~tkCs2=ZTCt^Z@x}Sba!hHk%la(jnl`*=%AeRlKvK$jIuJRd%#KD7uf6qOIoBIQ(E};{>x5 z4?*QW&ILPJT{AHbZ)j#eMd~xtUuOV-vI#GYuux#&WAF5NkR%>J2UgUIgu2F8K{6Yl%76LuuLeB_Au> z67#cDbRvD0MU0c*%F6k^SjNHk#gO`)k)n?eh9dV4oU$c0O*vG16%=hioBWVLuNGNzi`K+nVQ=12T!i11e#<4-DMYJQ|a#WsEarzleWzX+NV)`GO; z?DqzoA37RGG**N@J650&4d=q-(?rKV>sFotenGkZ88B?!h#ZunnY=W3odXS4xcVxY z54?5o7t+5(^7AxPVVohseHMzz{USRGO%(M3V5a4-Qs9HYxbO7X@i@i@&HNNm#@7Po zi^=CeYop4@*rg!)HJZlL)VPDS*v}KFQE^=kmG)hD*C6>Yue?}Smb@>0k;PK`w-8A} z7Q$Yv?Z~rInp+ftq2VQwuTU=J@`)so&UWp^lGuzw@iN&Wc}WZjxZSVI(~m*8{6O> z{z|D>!9bRa zChvpGHw&bJL*$k-tiL#z@|0D+z8zvxl@^EN2x;*HtYgkHI^TE!C>}O7;5~p02Td z5EwH=9+dY8`mp4bE(j(jg0X{uH7}w)Jljw{ugZ+$#ClIlyLyYYo7L`2af-F~x50O{ z!Jlfu4EN0`>?NmC?aR%8f;r1YrS>GGE2UA4p*)Hwi0tt{^!T~pYl0)U5?R_bTcuRr5hn=UjA^jD0s@p! zOVlE^7|Ez1E6h5fmtTi89GT{w+SI(r50KNT>#YB}BKXiqm#Ng?^38)okgKCO^}m^2 zu0tuF{INy_80Eib9ki_Gim!A=QlL2fa1>9*p*P&?cheL+#a zDc-TABkmzdqBmD`WyZ3NquXeGTM?fUEnzLl>ex}Vk-o6tXvk4QtQcdkuj(P6d`EB0 zLUwzH_Pe}VFX#Eq(BA`{d|y$c5~8y9%Y*`mw8<|0#7ylq?OtRRSQVpNVVN#w2$KAO zlpgFaB|qe){wHcAc^XJH?d|4$!7-&w)>U>o2f?||bx2u5>y{Ag0ojZhUbqGS6Im_tG~I`|1G#+QRZW{y5h{gDqU7p&=5idkHl(fUu7 z>Cbp%LcMw>p&}qJpVtMK{V|)XnH4B!g4l=A9D|sRLC#{vqw5FaZuEqOxnc5*m=aIm^qw+`uAWv)73ALZrVW1dXw7UWwC6)X6q39 zr5*Zp%HUqKm<;3}Uk;t6Ejpn_RDR;Wr@uEHSMExj$YHseb@y#T13tfn!KN&0<$SOz z4I3{icFBsDI#@QtSjfCB+0&x?Eqs{yW0R?tM*87LzUUxjJC_*C#8d4h&^1b_|1!3p zh`ZmBm`Q=znB(O4z_mRU@4tbPKk#6%(W^|7Kl0MIVIi1T)LFp-x=OBP#_bk=y9(%EFF z*SkG~qi^tKIW=_HQR&!6pzP-yv2&(l@)uQ`*pTwVjdhHndH>JI`OIUkt20G}BN{Vyb;GHFR8jT76Lp__>6e-$&rT9Biej5J==7769?z2=m#7UcU+l$XxX zJm`FD7*gpT-Ga7JnB@ zY!4ngPEmUxkH>&7UG5!gWijB+Ze`I|?z1fVd=>{c85wYAwPI<9uNawSvAowbyF43T z%)F-A<-&xx@$S;>3R+&CNBkE2jP` zwAuIZyCVtf5ygz7{N!`wlrxKt^HfmTe?zey?RsQe0|wu#k1WNHh?eh=VEv@Y8NNWax#XQ1Eh5D#ENaY0ijR~pg4@5=X9 zdq&kmXL~0t%H0rVN2X{t9wid{<4;aR<(9{=|q&*(10$BJLY1;P_jlHYC;G=Q^}2K~Dg6j?5KNKM<(Z+lV3txV5= z_ugF(@!Szuw^{P&!78^tEiVMRgs$@(7$@Xwz-ru7FOg~smx7iGt3Xe+zPXZkC3PC}~;JohZ`#%JOZ3edz13`?UZ6P;VA=F~nRqIoS-nYw()Y z>(9x!t;*lBY0we)4&Jm}-WK#nQq8Cn*rZf0^kV3Q&+wXNQt8d#ro~B@1sn^>)0pz5 zsy9%JKDK-_I*XEvr6cS<6THU5^tn-TsbF>^U_T;CIfFQ_f_l24mPxHlpe^O_GF=wD z8kz2iOto44KS)*8)oKkrnm@sNihPw8V4=6T*~-nOpRJbAR*(KHPobC;iK<;%%~}{= zO(KesP$G}^=D|*pr155|l7jbX;e)=}*8mnsb)d%JYhhCflg)W#VI z+<6(!0C0oLUm48F1;I+{wZ1=c;yhhHeg|Hr*NAZ_2DZI0Mb_wmn0FY#?ZpDvcp9bL zlGo%S9!<<5VHOiPxuhLEB=lrEW@}-t<}rFFS+OknajIq*?W&1?ue71=aSV zo<@6t+IOF}WnMds2$t*UD~aVNt$RJO+6fA4FI7hVS@P=Zu?5K&%GH*Un<8*~y(InD1L+_Wh-e05lD_iep z>ix#%d+k#c-OW{Ag}DV+0kAgb`hk+`n(-QEDcxG$i+(W-U1KdE9X*e2XBEd#A{s|K zGK29}>OAc)v?yNYD0JHU);Cj*>?~lY9J8Wy7%IU?`<#JffPkSg$6^_DFlsKAdma6J za*6pLE1G0pYtHFaX~shyCvND8%%%L-#fyj zI~Vt0Xbxo8JK|`}C+d910W4;?GdrMhB|dSmH*Knxi-J{Cl6>t1L6UjxK0%Upt-Amu zIoIY3lH_Vv3zC-9&q9WrYPknQ!m?i!*;;aProbuHb!LAi&ew~^D+Z7^?LWzI26)`6 z3}*ni%JRj*X_#01X#5&_((H_xjI6s8Q6=Ay(XMKjLE044(Ts0>RogSpz(#!nH$|ud zGGV|TA{b07?bWSH zGjlH+Z-)Adh=`CqWN|WktN_dn=*%_(4WZn}X&0t?-F24r{ zAhopxD}~;Ny>x9)*t``QDtg2`6L&h;u`Q#15SVkHA(eLUWMf$0CsmeL?A{fslloPq zCJz&F-pXB#q!0_^+EZwl@A+tF`Q%o7&}4I}haEiW+ZOhgJR#P+?^d$;38EP)S*XV%9-F*2zD#O| zsYu6JH#84M&|l@l{N(HO(>-~CemEOm=U1|-Ebk4DvK&+n3~5>uCh-)J9{)pWm%xFKJ;1`tWa~zw=}qkHukb+9n_v_7kD@!u57my(u@86B`YW^+SEb2 zkJ4S#2{&0FCd>$O?>Uvj%r5GNYF>{x|>$N9IrI)SBYzS*&Z|@fh9DesBsZc zw%Z)(r{|-EwIH`MU2@~%wn#7?)j7x&PYG*5ZWki;l^U0{MWgz^k*mF&jQyleTkTd0MsrQ>FD!dj3;#YxI1>}AA*8GT$DR!FwfTQTM0 z?Ql`!av+c)dV zG$UoJt#z;<(QF+(n<`Rzp5TnGpS|4sM7oFO0Z7tTQoZ%2xAf%GGFNc}cTe!Z!4uRAw|8$Ikl|zUr6W z_~Ip3^9RhfjRqIpoz25_YyDYww_w|36l~_tw0GFVUHbwuY}&SPU1ScE(aN*Fv&sDq z%;oO^Cw9(Z3+U?4n>kxcXtQw$6uMreFEe29O@yy@# zWm`^W_<;!95U!%dBZ}eu+8*s0)ZSd$#<9pP8`*55n!1a}CZ`{Ly20h!1!d~~5KD(^ zFl`)lng#$ij+*BVGnyEMi1nao>`^ka^)7sJoMGa9n+DlCN;GWTcYsqHH&F81kG@Yz zZvmK`YHkW@>v2IJf}*rx%+gnTQuBA`hNDH>+I)H>vAKOrO$NiFY_plR0S>axMM6fe z+C!)r(bVnQWGAPc-16MH6I-JmWVAWO3|<|YZhjJ54%3Y z8Q^g@WHWUCUp35ze6x?}Fe3d=;j%$a%~_Zm_*2O-T( zH;)s8gAcp#W1WhvV)%DE+8x=cY}=0Ic2!(=P&4Xc%UbW@rEj4ujw#>RFN2)ZVv}>a z#9#qquIH2&e`v4hP6E!_u=?)r5rZZ~8y+LX^HT=L_BSC~`|-mG<<~E4x~%Ro$vozn zID1wi(NLHhaL15rPRN-?ZF+OB;4SYyg4)J;H%?kMbtdx(d2tuKftgG85t|$9lUUQs zr_)SX(uRLr%em~r;=saKz`m$BpN+|)Ti?}ffS1;J^-k~akls9E+-y)WpAdZ<-n?S1=+ z?ES7tW!gBRwgrJ+VfowpS~WmXLh3Y&AMcemP^J zQ(B4CW%+2?Jb#q@Mf@R}czoMdMpv}b*j$mtN@yrJ?|y8}y({!!yk|ys4E? z-B~IFMQywbrOE~_%&&3%8RVvfwIEH-j5OZe7U^_FdJ4{_gtZ{IQazbTlf63NZ?6)?mW>}3>(A&8ueOUDX}!o5%NV+E~0sq4W9VXPptTeag}44-R1 zr8KSC;@kUBRQyIf-n05sQdst6sFrC8lt;o80nH|%{Lz>$O9Wze;7a3Q3*;ga` z&eaa=6$Kc|`jUIY#w{?KHRab3=3A4n7Swp7Y9rG>;@{d9|IB85VJ)a}ReSu(@;Sjd zlHhg+A{qu?;k5rm5 zo+ATx-FidVHjUxVY#A%BxIE^^=o|dYkdv-W4tg=qU-Lj?(l~M?t z>Vr1<`ZxS@X!>s@}r7nL*;=D`CV#`q}!kFnGIO z3i6~zV$R<6;oCOe+om&TL8y++i>HLOAh$2C?q#IV-GAJmnY;|dz>3vSf3Xx+HC3LD z*+=z@*qsMYJ>CVtoyaBs;(cAQFJk}yx5zAwSIN8A5>V+*odv7J zWTWDiwQZMUNA$=_kW09BHkI)XO(_giitbzy;LNZ*A={JdqcV#|XQo4KJw_mH1L~8O zlKuqan^qk8ljyU-nfY{Rd2D;a{aBu*ms7}}Y&IGW0~(tJ>A|qk98H?f{|;M~&Os$ekl{ILPsouojdY%&XR) z`KhjyxlB{K*C7LMRAo1BP4AU>nChH-6RF$onV7uV-f>5CM^^G@gsNYfu7g?Et>Gul_Z^KNoiR%Zi?}dxMP6%loXzlarTi=yV?O+K(SgotqD(=MaBZhb%}_@ z3U!FtdCSX)m%-P!!MC-+_q5kj3~#W{I*7{I`u z%n|BPum1X1y2C9nWP1|xNf(l+U^`V)Cjq~RizNuTfDm6+)$tjiPd0wf1)r@^RutJb zs@5JtOalXU(PSE$er13joy*O&Y#dwfkuw)(Fd?JZ_Iz0GHnZONJfdo?bIKLnHvP@{+3ahSM zPMOodmo`g46STA0BS|mgfn**#q0)vpidUM&$Hi!wIZrQh2yM=y(D-;8tM3-8$B9*8 zEl7TJIuqe{wlD;|foNKbQpII+r8EM7ImtI`!=$U+s-D|XTciN14$3R+z8O8AL)bo zNM^BnIf%L?fchSKuHbCb4YhW&-D59RENlH~pY4y6at+3B&Gyj#{l>J&T}Rf#h1$P2 z#iJE*^L*wxVY_~NtCL00xs>;j-#PHWY^4H+a#o@_VfPaI$iPsDYp>(X*OS?tT(?~T z7Dx4;VQ%TGqWXOt)9cL_>(9lEfM-Evo~U%F**WR*qg&ThLYwx;d*x%)@Hp9orHC&u zlnQzGcHZ(yj>zd4-rwQ&T9eu93CwKcQZn^^g580cp$9E1ABo^B+4 zW~1{utEh9V*v)pjRU<&};jc=|HNJvY`va~`3Yjlo)cA!H3-To_g{rc7!<|1st6Xek z0Eg5kmi!Mqv)=Kfrc~54)3%r!b~l0d#wyDzuXA$2`NpqIPpqpI?;)Ca$VOIGUB8#l3)bZQtbc9Hi6xtU|8-N2}{u-N`=yI2O!V zyg4MOGrtojzX4aARS1{#CHtW#rDP)rTKGGVZg#K0x8Rk!{SJ)sxfu4|*jl9S-5dK1 zL9_CWw{T5ihS#-?Y};{HLBV=inz`0+vhPfAUt#DjBXCT$PAZL>-JaUVSu9rBXi;F~ z=JW9PkR)@_&CxB0%mpPqRd#z8Dt%duo^mfcI4i{P24j{tlbnB?ZZP~ncKQtv=_q$x z-*B37pi7orjt8T>i+Z}|GoHtmye)Y9wtk;bi1+#H16q5AuzUPkb#;Yw?SJ$2j|F-$69L-eH+ZE2*o)Skiqv_Lp`r>QKCP*!5E$UxeB(Y^8#pA`fihCsI7T+spj;sWDCNyS2%E z@)MFavi_ugH78&I=_|{NcAj`O{H{ks+pe*rkGT_RrFW4UDlzup@@%LdnzJ0ouL0*|=F~Y1~il*_P4?v1FL!{rCVlC@07m=>l6WY{t|D z?$%~vOppa<4s%NVJ$nYOG=)bThvq^6T2zmwiW@|9-k~*=3@s0 zZKd&F@R@nic;o&I`IN90q^V{;%T`Vg&b=3kzOT*IUatbtq09H=qiV@VNDUAr9~R(Q zdS8>JOn-90R&acg$?!-SoG5vngsyAJdo~ma%Wkn~`GuTQnnx%k2ANYFC(gyB&u8bu z$4QSSCN+L%SR?Ku{s#XWrW1BW|ai`5sbXLUftmcmG7NeWkShR@j$C zjoM%B7I>SI($>Bq=mA07_W?a9i0QvoQ=b!rYrkshAwf$8eO}Pjg1#W=y@DPF%IwYu zYIh0sMFl=3=u3j=$5%~#S&(j5nUbeS0>Mq)yfqQyUA1SMm24{J=u5IvvJp2BL%!TsxYBWwDJE7mwaC3PQ!5IV?3 zY#NC8c3uu%4UGxu=!EFD&l4Ep|8!r!%}%+UWC;AG|3bgpg*US+%e=h4ssf0A4TUaM z-gY>h?GdM`Ps?mj-u6&UD!j_ol1x;_e(Zfhv$1RY`nrO5Es&8fQ)IdaX{<$vT>Xf+ zed>|PvB13wDz!_fD+{T;9>`5d)?wrGFqqC#T2xKt`KStMi(0#aRG~d>aW&;Z_oSl= zK|{RT29(-WL`*x+d@>7x=%|ZK0`qsQz|vB5Xbs1YL#TG~fw6AW8h-6_zh zzvhWw7O%;V$xsySrUY(Qr4@{A3&N*6pqb80t0#_qZA(wajCJDi3AwKt-0DL1YnsDg z>Vt|3@q(`V1RWNC%WBtCoT*2%dfXWtb8Yk$dE{NMTJP?rpgH*mb?x%fSoZGf`)qo*w~xLf!N0AzMq$}@Ylm9fzj8lEpr;}YtMU^?g;UsD;>j~YNia5(%PX8<_v;rR(IsJeT^i+huj zHt^`I4euJdX9>$CZ}y1hJ3|>oxHoU^Lf*bRWkcyKfkjAP^2s$Ry&XL!VH#*UeWtF2 zXwqlYuXpT%<)2TOsRFSp&e>vFli$LXh3EXeXYO}~SfLSoys#H5^FKo9oS9^Qx$3VP z=X!kXUZ$+wA3X_cSGtcpC1hx&Qw66Yg%;1h|s?HI{&8rbtv9VGT`si1kr;40ON`x%LC ztWh1_A{EfWSyp0S506f-2ka@^DtvFmoJ*|HI|ixt=Pa7P?xn9?a&)-fKFkgdJITwg zvOH%Cx^FTb{sj+J`t+Ni<@+6UTu7siiqigLJ128>Gk(tflL#A@6UZFW-+|fZI$Gfs z@8_Lj3PIh>Z=rfD0|S%Dj?bF4$R$jZX1+=k^pu0;gVc=HmflQy{+CD32B1rMHxaj7 zxj!#q@*d#oUWWsl1*#tBZUN(N<*{&)d#~U(C`ubXOj8|~ypNF4e$j#IZM+z73x_S8 zuKQ5gm)O_Zl;^^}oi1~XY1DpIXSKAV)ShZf=cG-;-v}f5$hY5>-?zYfE{<@CNyq*TcK-mAl7g6QOo92(wG0l5Op~*(-A} z^ng)o!)h*JSQIxmJ1VeNE~kl;uS$-VBKa;Ln~^NS?$aXFKL7<9xPnT__lQ^jph`$l ziwR>f?sF(54BYtDgi6Kl3Y~Vr3Saf{ZSSqY^3Qvp{x#I!A*hDarx$@YgSsp5K#^j0 zKO>(fGWi%lITdE#+y=hZbmKe{`#YW}c|>ZvY&P<#MzVxVo+8Gq8SY5k0V#YJM zPQSHFz!mC@j^fMoUebt(5AaFX>A#dLmrxnffAO?mTOM}DBKUE5pF_lKazcA7prt#^ zwRcQG+_BXM#wU&v#&l^O*}Ye9C2oDtypjCm|Da-7-k&93T#?PCUU!j9vtZ2lh(Gmf zdqeelrQO2P<|h9v*Cm?JkMU=S(2Aa7XTuK^w`@{8)+lD}F4Ed>kaJZ_V3) zZkzX4o3Cev$q(4w$HdOvJf;-UVo!XWSA#G6xnXJN4ehnbG_=uV^H9q_27@;G@wj|X}1g+N+txbS3K zW9Adr3iuq4^zsNFY#6V@joNJpdi_wQRCXA+{tzjqLxi0_>rTVA)Dd!RUCd$M8 zl-rp`gp+Ji(v06mDTdhtwd?JPhi_GOA4IYJu;mV*=3(-jjy0$Lq5A+K^}q4(Wo29~ zZMQP*1)ZCrQ(tPixf`%XI-;UvgUX!m7Al!n+ zw=6Wvqfz^@>T5e#vrmn-)t5z7|9=7L-VF~n(^j8kS~E7#oho_g!ljVWSVn3Is{G%Q4&v(G*HlLaPP95-vb-?ps`WfpHKY2#{mpkD9+yP(SVrDu!bikj{ z0e@2m{1YAU|L%Z4Xv>-T`Cte9KRe)$UN|$I+dANX+yP%*G&7w8I^eJCfZxyozj*P? z^v~{qe|rb~gB|dH?SS8QtC{mXp#%Q94)_N<;Q!tMKlYND^F5^l{^kz&pLW16-g;*G zXLP{d*a81g2mD_<;Fm6$Ip2#q;6K;_|6B+BPD3-(zp?}V+a2&rwwamE$sO?5cffzO z1HRkMOn`|Emu8*~2sQvr7m3>JIoX zbin_$1Ac5|=6o;ffPb(9{!bn7mF;Gxzjp`xRUPo3>45)d2mEeJXU_NR4*2(Wz(3gm zKYQ8C^bhEOU%M%Ojo+k~PN6Wf^lwHze2LaEVvjV3l3rV>O?4W(Y3!`ofLj><9i9ro!Sz|e+SQo9wNZ(ARrVRY_ro650owfi}X z(9T%is&S_-d2shZ)!5|XXq)2mli!1TXgWAr`lEgur|lQk9-@ryG4im@Sunj{vLh_fl*pyyIObnpfy7ur`@SJ#?q}1S z9%Ei1+^cOwExDBg=4pcWNp61DO4Hr$2O9M~2FLY15ZIcq-+@l2XP*)M`A1db*jBTWx0&rd2u^B9FH%c|>n>(>lT+_pZt zhWwkSH^OzLs?o^SS6Lf~*A$Xj{H%XNHe1L1%QO;~G)dUdI>+iN(-qkgt0%#yqS?#1tJ^QnRws^shmGYY?nkW-2D~~Nq+;LD>2trj;^8@y1VlInl-HS z>LY2I17ZhbpBJaJ(@&nX%2d&39N=YEwcN|oFZvos?1cU%$p=;xMYpK4eB6UsWDn$V zurgHc;rd+8ZI|O~&))G(gf9lG9Hg5oLia7Ar(XpMnR}UK_Z;1(x^1t(#Z*T+-)G;B z%((|MCFbiZInV94AvMhL5JKj3g~>i-#QZK#Q}&Rc?+}CSViu$c_1L~j2!cs-*6R&# zk(kv>zOQhtsj*il`GF$%Y_4zC5}Rs$8jhUg(o-;gu_Z0vg}!|LE6t{LVe&&Lsd1v( z%vZ19s;La0hpxvVNk5(IQk>e@A<$fhTM zl(?CN{1(jAS)7cggtZ{hOPrC_=Bc=o7$vV(7((zrg&6lTOYH|oUBb}g$ddIpP0t6fS1v|NlL3;jT(gRo21D;{;`;V#?RVH|7`+&>4mi*_97=M zNWbA?B5OaY+mTHoz6Gvy;A|0@OB9}=@I`l;RAFC0ce)@9d0gooolU%Anl$;jq-177 zI{~Vdz74AG%B-k}9T0Jgkz|2bmB6-qxh*i~PY(>2`-b<1cnJO|{%_0wOZl%nvOkvc z?VE{vAStHjHUAI9d}oSh)l=V_)m>IB&UyS*;M5OjD~0|BmzV79>+Q(By7pRPvKhb* zKKMH<>ns<>w+kQDp9Ac1UsFA)@;Df<9=I^Dmc^Q``Y#FX<(%CaNTit8vILjR2+p}P z_2a9MH7cyUmN@+mx@lJ!y?9SudPmB>!44N>`{$Mfr@S%SKUdT}=)oQEzJ6y_JJLz7 z-lRNnYvUjrb?xww|BytK9L)M!+Xg#o#_v&C7|h#^nOt6V519Jr4?x>rjmF~3p2#gp zpv)Z|fO}PmFbzw}Xk#clrH{|cMhtQX<$9uh(B!MWLmN1sM(_M-*q+)5Mp~=K2+uka z+p}3fTx8LOxaf#VRo&be`%5$YQ9+vHQpnQqSi7UR4OU+3)p8J-okjj1f`yzNXpDWUG#-1x zI6eIx_fhwJykG8KRth#D|XVP-zD15$2<+-n037&Rwf4I)A-bzqN&%+qy;VDKf78 zSh=%dAfA#&n1Nue0izv!7(N@%fK2E2#k;>Qm+e1s~eWR0F%) z*wykc@C)PPYt;blmwGvyC>M2YqAIr?I=`3hG3&Q#p1CDXuC5zf0VAeufYXgSg zY5C0fGdkek+X4Um4)`TI%uN5d4*2(Oir+P?{T!S>Uy6{kwXu&NW7fvl?qIv&V_X2% z#)|rxw&rq-UwFdDW-~|3J;Z?JqS`BESd96{=vh{l-Vh*1CB%DW6)gm#dmg}9WUDU=%eq5j&Gxx{F5ZdHUnA| zlYd!&lwZ29^)l)3-Oy_M5>=X6hks2-ro(?}>aeg4Jv!>}=!`n7d@Qp}hkpgabl8An z-1AKx7NVuYhBqCa0dG1y1KxCa2E6I;40zMw8StjVGvG~!+wq&~@G|ztbq~0|Qz-oZ z*v`Bma#}YPfCEo|ACKY12kv(&_tB`5AK|6fvbTaxX$EQZP2@1|UeFK6y;!B?qHXt2 z<>KoWU4LGJ)t*fQ$O7DNGMoV(_uC9-fXDqV!x>;WXZKJnX#8G5HonJQ2tJPPY+*~s zn6Y{(wT_pgz9|57rA!c=P(^O}PGVRCdbe>2=nxm)}Fa z*o1vjn=seggxO7-Al+ULfAl+NBK1+_KKZM*{DrITLW2B)d3(R0I|ZJE z&VA6Szcd}2Y^H3&$$oxXa{@ilgz$EV!Y=&k9X*kRMZ4~c@8RlN4-I_Nu`A=;f%N*S zZa;iw3HjQy=kK)*iMUV4#;=VZwQh@=4W99E)dKt_8R;dH@3H=Nnun%CKrhpXNd1jX zs<6Gi2M+2Rk*7PGZin`Va)n6g{97|W&7X7l1Pp|Z>#jJd+e@xPjX%Ifx=+|(eML3f zJBVx08}u$h?Jf_K!^y(yv>e$1?nE+Fdf)++?AHjtpH#hE(5#nQd%dua!SAhPbKT5) z7`zVr7c|g;LsA{sQniwsT%e!ko(bjkDdqLLW?o5qUd{aytET6b@%d?`J-?au+!@oJ zH$83UQ)KvKM@v(mh{ZbW(Q*34^D-X8MtSEcb+ z`uKY`<7e&t^WyD|P2S!xjkjs-{mLeT?d@IjmdBtoUx3c$&AW0g!S-f1FvD%9{2AIXMo}SJ|OKSK7{v&DQEo!Yyz9IFa~jgHy$S;kEo}%7}hm*C2qK$_esgGL1`oxW^`pHJW>^ zS~}GeEF_}-GMCY=DRlZ~E2D(nL~oRb_feXAXD2sGoT{fT4q#i~Y5;V=y`Vtt`(cQy zb1j?|5-K;SeWmH=wsVt0g+7E$(0gNKCm9W~HOlR-3{zbc2l7|LEFS}WK8j90{=3Fs zCLe6zm25`pS2pUK$(@&ebL;S4aGZ##rVS(pJnej&pdFg<=T3p2pSFJ(9brpNEi z!VK{7`!bvX9ycq)82~QRi$}a(ygAj2!`t;DYX=XzUdlh;CNP$)&#~9g^?`7&rG0B2 zZDcBjykpO9Jk_I&e4cXz%1%npA0?mu)Q`2hEOKZyBk%M=;X65PS8wpT20v5@(eu?* zQmW?@Wzmw4YJjIdH^Uj=ag_{bfXDS`I0HOxvkYedxFf@f+2FEWxb9MA4qkaGAT85C zmd*fAtD4~q@VI#y&H#^_pWzJfIA%J1xeV~Q!3<}B$8DbB4Dh%uGMoV(w`GPiz~dHX zI0L}x><0GE{z9kEmf6U{g9%%~<8gUq`k=c48!v%C)|x&7qFz=_3u{3-$~$6LUHbSK zVD#dA9vOkH+X#GA1m=o>unj$2q6Do}YR?Pm72>Q>`&vX4t9t`r4BX-jX8^eAWqMDm zOahbs_A&|6SOS5pOm~STHulF;!dj49)hd(Xw{aIbBQVrP;A0{%AOgZR^l-2Hk7e45 zC{`u|;QuwDyBI1>!Ry72Hluiiy`eo!FZC+f`LL<>Fuk;eUEUt1mn+>n8y8t}P!rQb-{cZ&=kko~>Ah()mJ%t8Kip|>nxT0;YXu?{M4w8+y zi+J!Av~Ans-lMqeYmTRcwV-56Ub$s>#eBHs;MhW5`6^l|Sp>l667tDn0kRLiALjP_#r(Z&*raL2TS>C5Cw}Ql!unj%j#lEoHwMF}cqP;}Xgl*{IF7bt3 z+7|7Ting_)3ER-atx;hod|{Wh#r-eEU81 zPccjWyC|+<+0CF`XpKgs^%1gkueXeRy%g;H`g+kxj)y64^9-~xES(WHk5z#aRfHYd zitrf~VLKH;SPODfQ0D4@`kx5Pc+L7t?g3E-*-;zpmC+mq|D8?n-&1nJ|3|-H3zMbf z5;lh0GQXD)e^I%x7GxKdr#VAYY5N@t=jSl9`$Fq~OKJZjrM=8(Z{J4yQ=+}S3MOnr z4|f>_tN&F=bf1aRw$uK*0!|8(llcvkQ+T=$@u+vR0Aur3OA(^}!sK*|@)|`^wfV15 zB=){L739TTUjmrPPrfA$IQWLu(eFv*M;5Opj=LPbxH5bR;eLwdUR(yh2BoV;H3Z3S zt~NiyKAg&>O74C*NDgE?Pz)2JdA6LqCQbLS!Vgw>i;v!badPlY_^5xFU~aR)Z%RM* zS;wP}lUqPXVQn?E`rSz|nAE}4cOZ;~ksbNz9o-xn#nng9So%tSiM>>C4-l=G?4$_A zr9W-#h|DYb0lu!bFR^v^n%|HRF@#B<3XRT0wjVLoNHv&ylH9ys&ykPmf5%EFb&&A=r+V_Iz7SZU;SvIhwU z3+L8%CE1eNO_Y8>H**3%A8Uom!?%E+m%?`e&rjj|ffuCkH-HCI_&MOsQ~0mITcoh2 zGPg|OZFgoX3di&B~`i=}BMC)Jt#rqFK^~ed)_33SrBJ5x7Dxv(uMb^fD)X z`LbTh_Oh`ur81{Q=fWB{O5!nu7!+SNm!~9I;yeG2 zIEnwS;Xi(n4RSGHI)G}2pobaSUW8ug_mcEipR?8b>(k%M(qDZmR`@IZuRf|7Cs(CN zeG^xKZ%Kdk!B@TOL$Lb2KK-3YfAt|*Z5;VLzxF9xy*#9so70d7^&(}bad>?y2F!H@ z-=frEg1Zv?{;j?{;BZ*`A>#9m>k1m|*dn5awdbZIdqBF6H$8raev$heS+JFB52y^R zkR0nj1f%POzRz#5&sv?PMN7$^#9;!VEiY+(W2ZL5_C?avQTupGSPOD*fFE}yk95v2 zZ+BjPTjgjm*x0#^%9liCFHsTJg4`P+(AcFd(w7x!r6LJyL5|7Pk;blVk-nlxdn=N# z7UbR}ey-*b=j<~ud{mGKc683&(-cli?s+?Nhh(s=ZF1j-M9AWwnTQ*^wdMO&<;yAI zcuH6ca&H!MSl_0D^oSz8RFQX^)^Eg_>MPcEk<3XSCx?Po`x!$ywawr#-hIccDYsIw zwkJ`2S7v>{SJr7;P+k+$gkL{8&Fh#}UIJ&ztIy`e7)O-rr=@wdqFP?BR$gK9N(j721gEy~ zks(?0(_?WSGH*}k9+&|1)(YZqtPT)R?xcwSA;hll6aEJpfCq4UXE+0luP9i_?~mb&v(~r3m(E(B0AHcg=)rff1~#w$x>Zf> z1jNc@{o7?p+&eORlJTN>xdG_@1iAx_{mC|THxWtqIFYQX4?_C>zT55+`6= z1tll*3M=fn_B_54Tjt)W(#ST>3O+*E&){wS@30lE{bKCYcss2xIfdl)Q+eQ9oW@VD zPFly)_pUL##4^6v0CAf4bdprM>u2aEs=r1*`WjVoCQ!N1pPXgCe4m6(S>4=*c{cCK zIXs5=G)Bp9%j&jGY8c03$mi*@?ss8e5aKK@+0WaxkS|s2d9&YhrFuDoGCf0?TI))W zQI<^C_u4gs=hg0O!t-m}?3Upd)ZX2M2WzuOGyIf9=og}23y)K(0m)YN%-RJLa53)R zv($pkbswZ)wGjh|cVOtABQSKo;Ax7Y_5D7r?FY|FKN8Juj4kKYgN-90k=5>R2=lXS z!dj5cve`gzfE_Q4GJ?V3FwtaCNe{4Ep-ukGc*GLS_p`lSh+)eKzlb{dx`YP9Bre#ilDv_TErgKl40%)6aZ3mBuO3 zxQvhK`Dj4e%;%LppZ%3jUHKfF=A%7B7a$M)rF(|_EgVX*re!^& zy{ycAsk7Aj;*R>o-ng9vz@XrrQ~1q%Z41zI-)n`m_d{t&!~QGDy5lDAKA<&UhV4-J z$239Q)f7ZpfloCN*tp|in4N$p=%;(~M6qvc3P+IDZ{dGdeq1B^?&``NmAO{0A~Nyc zMx0Rm0ryC=7i2~%N-jh=+-P(M3^B-_P!8!1}%h-<>)3&zW<1U;d~*vh{>x$atY7+MdW#e&Qyr@g2tiu;#87`XwKT3nr>j_#dt^VzmAu<6B=t>s^fuMr2AIgBU!eXrjwQ;phuI0t_$)lf z1T`=BMUbK~U?Y;!2%^KYlfI|b_!_&n@IXYXR%L9j-qkc4` z%L9jLq2L@mws@lCmJ>2vBhA^FjDK4C@}pZrVde}|>&Dg`BS~dc*;q6kZ&MGzXs+ym zSxLJ^MC>gg(*4+nH)qc<{{iCiap>H@mm%^paag8Rs^6mkJ2ATnP8Zf8mF?YOx%x|$ z>p?Uy)41nczy<_k!c7ZA7Ddh+a61yCEXnvqWv1AQ2b2v#nfLITP6K!&hh|5qWZHz$ z2MJ=r>~_d~L4R*iSAQoa6i;G8PXC$e=PX!~%BCH5A=)eO6ZThfSR&n6neO|sf-P?O(MbK5u(V9fL6rGP}x8*)J zLVie)~Gcv1Cp;ahjH<@~PqyB9RfX#&Xy0bKxzdY4Ho)UbYMC4j& z`d{*Nt2aqhhZmUNC{Yx)GP|?G5|`}oS>n3GV*7=vmbgUm+9$3}@j6YMPg^~he_gu9 zS(1&n0R6ILVwchSZ*`Uluj=0t;hsYo>VcR?Pa}B2x;_&RIwGb=l_b7gbrNM}@aE0G zRgpDNKE4E0E&|SkPC)TT@Nw@$x=8!DqV1oc^On}@|Dj$jc#|S{gW;jAhGjb6ep;YU zdNQBxA1b;CK7EQ)Sy=10?^njO_*J+5hV3xg=1tgr1D;l4q1hJCBvSPL*o*xr8OqLv zU%F=+lP=wtT6?eEWh<`4c6u*3`LNXCMqw-Z7{P}J0F|o)6lsE^DSJM;6u+cheRcJ9 ztz=z&VsO++zRscl*^(fAn#KzsherGf9?|}OZ+~LI>^dlk_g0OuZH0;-XsrqvptF$d zXtg#O#8`234o^RWc%(Ul(D88_h|{CvwwYbDCFSn?$fg7-Ph$u=136%1eZDfoHu8|M zj+s4^pKRdnE?C&I8B9(4!9#MoP^ZF)_?+jH$%Phcw2q(!tFqFy1{8*P<+~3Qe+m-X ztyDYka?c=l=bZ;ah46XSSyZY?nX=xu<}%HcR}q}P%J5uXZDlSgQueS`+xh4P+L(muuO0C&P8YYunVEHkWgMxnLlkgiK~d7OI_98O-eaOQ;E zDInRCd>bU+)X{W<&lD%tY$q`@-8`mtEDE`f8=WfU+2bo(5>BRCoy^hBF`bZA0>=x-u&pTW6EMTZ91 zvN2*v1jleFz8tU4#=Bv=tH0aYbE)h#K=Q?04+6?(LGUvdv^t)VxSPl(IXf4Qt}N?c z-A1#&x&b{wx=y@l(><-qjRxsHh@ygsmrb<0hA;&U?RgNBR_3nY%^8c&>y@v6K`-Cu z53*KqF!)ozkH0AFF!~a&&VjCBsXh2Ehg)ho_*khb%(BFC5TYx2Bo((%yvli9Zv4>*()5W;2Anv%-qCq#KO>@|BmPtbTgmME29b+^r{>h?;)Y- z9P==$Qp}oQWlT`>a#upA@!ky5;X=AbNP?P|yGlsMXONB%(zQYo)Vvz+%lN-d{$G*5 zpyuVSh6q`89nj9<9hC0qdfc3lI23H=IMEG!np}wcM%-rjB)SO~LclcyA1x6K&zk|w zNxJsi*N}&e6EeKKUA){vh%rIU%P|L?>#o(~t@u)|)>nKwINpWymeoK{4G5Q9dSciF-9wb`8(BX1)^|l7jEaNsj!BNV%W}BQ)$Ap-2vzzj^rCxiEf^?1LP3e=H~6A#kd1)=R$!zgjOot5%736z-It!DiePziAu5Rl-*0pT zM}gB1&Kt~8-bk3!97pt$ju2zpw$5Vt`(Sjv1^`28zA!&($d(~F&pg^D%AQ<@U9>Y4T-f0+u=CKoTOxu9PClW= zxnBztO_ryh2TLxUM%q|gyOUzj{_b78i{T~jt=}z2`~#l#dw7HzCFXB0PJ1>>!Cp=VVl(wgnOLg8xVv?PPMm5t)PK4F? zJ_3vhYF-XmP}QArJhby+)8Rk<88{k2e$JZ_Y%k-TsU(ZhJ9SM_oiXX|TPA$qj+ zHN6o1vh_8inApJbmp_=-C~Nsa62}e1F~j1pzCRlaM}f1^^yJ&(>B&zorpB=n+G1i< zi%bdapF(@Or>)b(ZL~YuX?IM6ScfT<8nLEMEPaK#xuFX8ZzFpxCD%*byjMaLJ+_tF~lHtjeHHCs-%$~Z@YZZ`k@+V zSYS8>uiTUg(XW*0nksk@7sncCL}Fjjt_@CPu2Qf&pmo$<9;5e_jCB!GcFu`lXF{-0 z6D;~QMCW)=(Sv9szadoo7(UT&Cxi={0Wb}!gwVgb+PC3UVE8m62+J$ zX1CDq;2lQZyYm2(*5gt^yk1wR_z4kUHYRy-G^`286_B4Igz}N^@^T^l#LyOo6TiRqrMQXx-muUkR~e?w$pwKO6Qab)uRPeyK_$g zv3ml$a@BVME!ju(G~k%=iPduBDcT=o*2#|`TbU;wpsx z28DAPPAzQWv>M-Av`Z~n21fwId|bJQHSy9V?~R@zMkv1(+<8~{)z18QKil-lYNrLO zUO;!^LzaDxM86|kZ)Ny%VyxnRudhze*!1n1&AqFqON@05^mInQC9`l&YdNRme8NLL zkKLZfZXeUcG6v~-CMGDo^_e}C?D3iPziW%N2r%9{0XW?!1 zu;ztjmGOQA=`?lL3H}U@6RTa5dnSuxG^Ul+J)WT+&(M@|&y@b2DGB9r^qdmiYm#c) zRV%rk-b>zleDnvrbJ6oc>g(z2>FpQT^4srX^m(rPk{iT>U`G~E)T9>kr_(k)eGSa| z3C==>39?AMe$yg>Kgau4{+|J!#orOwjlllGUsDqOL}wBYwdUEpm4EupXq;t@A)Oz3 z{eTPArp)7fm0KJxYREhKlnHO|8o{Ruqw)yjc{-I;1b?xWCQ^-go3 zuqG0P=+9u$kG#Mu=|{9E{BaOR#Unc$?ovLwJbuaJ=UVt>ltIAreO{O5ZNV&SuVSkD zI3?QO@7`tcTE{$kDA2YPy%Iq9}ulCG@AX z9Uc9JN0GfmWr0N+?Ujl0EJdkCY3n-@g?c(>Zl82z;)IQ^j_9vAd^~JSf?xkP_;X_9@4V8r(oVA@v;jEoALcua7Dy#};s zyUE;@{aM2MJI{+9Da}(wbKKK>T_k>HGzX#}hoGphS!h9wC8VzLu(v!Bp8I>sZeLLs4_Pk#+8ENG9pf2(o5fLK+^{%4){KL8(28Sg zu*#!aBkke9kRs_+B#b3Kl1vhs^il4lO%)@hOP976-R1C8_C0OUUBQQL<;@WbL_Hoa z<+WR!$(K9`z1=DX<$81uUTOYeO!XA|?2bA_#((y7_fA~7D+$rq6czArp9ZU!@x)Gt z0W1QXS=m;#e0)apdy#4xTtVb6lwBN)m(snN}>`K(tMFE+=^XV_HkkMQ7u#{u`>%Wa!l|6|^QlKfbAs7ixmqchcb(YNGAL zYNxR}&?VDNe*#7d#kxJ*2~k5ZTw z&>E{}5VWsV6f=BLV1T-R=K9&p?;L1jv~$|@Hs9%OCDrNJZ>+eP$}h!dk=AA@zx3IP zuBTAF6b3M_yS_X>E#B01_E)cI=WD?8r72JwA6-7C_YmEfLK}%1x^tcws!qq_?(J@T zMx^&J(ki7)l9SpegWYYUC$^_}qK|2|(j;O=v9^KO)@M&Q+Ep9!)jO$ix#E&onZ0SS zS=%!=4GPh){Y``R`B?=XHb(D;(N^{7Qk?_p5=$KMFOxgp#?7H zpR!@`S%ltHH2)6q#K^srF;MezU(*PrVZi-_uDNOywiAUyGz4ab?p!|63w5_bCB#Gl zpYH3pVOsghnjF(zzfNZkOH1wY6lM-!vYj%Qw|=3!1p>K9&t%Wp#&7pE1M3;hBOV=W z@@1S|OH-(}wKT&oBObQS6P0bf*y5^vT3NBJqOHD1MQyP(J|}1oP;5DT7mD$GA{-Oc zymV!#x6xf!_|T}RoW##HiCL!;n)#lK!~|vyzb8`4YxfNZBz0y-!p&Em`Hxi%wmoSJ zg_@q;?t#DA_OvEB&m&{+e>L_RITctMzt%iyxWT4YM-TwARy!{e6)VcHdJS%W{j-U7 zp}Q0IP)TG~QlLeZNsg?p%uTJXtY+7OBaZRS3S;SJZ#^{uq58^n#NS0OIS+BKCw?_a z-xZ{+nTCI_F%4VzwL!P3%9-%%`RXwAY$9`6-DGNBsNU90kh@En95Iuu*t{zF-drR! zzdpWkg-W#oIrjrl$Mk71ttZ;4=2}##M^<)bxQ;T{&pJDZ25$A+Lg~ItElw&NIRopirUsVJqX|Me$H@ z_Y$(xa;wc?x9Q(neiehR-ZZ}^+uqC87Jd>{kzW5V#(qn;sd_ma&xj5NJn|}$6{|M_ z@Y*h@5EKFRb+7!F`P|d=(dJ0%_c(q%c~*{?Z+j~Q1i04%sBw8xQj@j-RTwx~U)ATi zd1ZzSzE?(07KuVXWBh;lL|J?)FGG5oD3ktAGyCc|-@OIfy)RYQ*|F)ViU7^6S`Za( zPsfb@c!4UzHatw3b-D-ic9b|NScr##cdwidZcr)F(Jubkk9xqI!}?-7fk_i|V5pLA;;LP3Pqt837`xRk zk8Z}NE|?!x5h+g#W~x7&8QB{BlnJu5SQ*i-U{TxW{V?9NU6{%QjIq}!A9POA9AE?c zatbqthh3Y(%;8~QNnz&ju&<^tb9mTwDa;%mc6|ynhlkye!ps3oYt)sgwr9sOx98Iw z9{;8kW)2U#Ifa?S!w?94SaW#TttreL9`>~qW)2VgdI~cKunHA`{F{JuGvwX1Z=^Wp z@ZoMtVdn6#Z>BJFc-Xg6m^px<&v-R3>+?cZ5VY(2Z92KSpx#gC@orDUnS*dY;tVXf zjc=!c=}RXAh&dur857jJ+;^bmzN_wBWgT^bLOVFf)?Y@bUmT4nxC1zjg^0W-udc9U z>LTtp)KuKsNOdc{dpEhC^zPl|e#*P|koy_$-c#=1d-q;)Kj+nA#%T} zuRvvwy^elF zBO471-bm*{HBFi^XHCQEvve5#HUL}3YW$u9SpIr0+vN1;#rqRoLN`VAj&duZ7DKre zgL5IXt@R7PhS}9LTJk%kQd`blr;cL|_9|n+`>KCA zOGo`Kxf|c*S-(?GH-ijKW$JwEK5=I}`Cj;R9hONZ6Y9b;6ORp>OwtiqJo&Xnk>q_o z(3+=y;hN(}lxDUQ<^Rh_J6226USZ9+swv%ecZ>B&f(^C%9i(E>S@S{Fu-f;8zXPSM zJ?A1P<^69p@5T>6OvM~bd}EYHtyWO;a^IuDHtxwF%@op(LK4)x9GeTN-d8dB7*TC! z^}@4qhXS9j3~O=K_+f_PEK%G^6a_Ue$6f)-e~w!y3I%tkc=%B!#QF+h@|d9JW%8JH zFEV0sDp!%GOy9;8-R-J@# z-=XUIRlZ^=q8F+}bU)bsTh+H5(G{`I$K~d(8*bNhx@>i^FuCXF=%D)~zZ@L~Q-YJv zN#(=!0+Jgngl|s6TV~p(O<22|SgEU0gnd3s++)`J zJkB%T3kKP_R8VVLixQkOO>>3B`5l#Tm}+Y*7e zx9HP~0XNC@vLNB}8Px%C&m~v~l4!qKnc2m!_jrH1>9M02MI@amO6m;5_;NASgbx}BA3&B z`B@axM8YtqZrg|G;d^u7JMk9Rdou*6`xbmV-uq_o1y`aZ%U`t${ENV*0b{Ih?$^(7 zj860qY7dv-zXSEEzhb4nQ6~c42gqUj(ujslg|~s@zZuEWS>tSg$*j?;4%?1p3UUu} zEHjHsrj3uTo(G;F!>7Lo%TJPuvKLl)oc!_k8f_O$Js>Ffv~Lz{wZtbOWVYED^KSG# z?OgjrYL_bSdSU!J#ia2HDMY%OEg2q|sw;l(tP1Z-V@Bi3m}{GFvw4Y2L7L`C$I;EF?8Sh=1=}c1l zcv@kyN%l9pjc!5!FJ#@+6tc8Im6X1EvbMdd)I-$*f!mK&-4JP8+`*#0uRRBY7Qa(D zGS0vO|C6bG7-;OO`gVxDk)!Z!Ha6OtzD;N6El}N6bxr*%`+i0;XJ?PBbLDCPr;2AC zY$DT*<`Q6hw8%)W`xwQZw)1oib~n)-Z=-uGcp2h33z(&SWa!F_DgI_nSHbD6meDVq zLeR7Kx8c;+orx%P+&vh>wHmGq4Np-=vM!RT)}L zU-lGpEZ?KK!xanZIG8v3qHohH=dd-S&XjaMtaNIwZVq?{_DBjd2Qbz@k06BEL{R!P zN0sb(0&e}hw=F2yVp6N)vvd26MxyHp8&>H!#0 zz{r#UKLeoU+*B6r2sR|%-KiUt-V)HHpze;vF`_E&87joqo%_8E>6TrO*B+`*uP1B2 zU)0)fv_HXCoTE?-?v?5TWd@1O$=uH33M57@K*GJ0bWdiLj>hGV;c=BbO9O)!J;Zy39u|jtH;M9oZV6}u7axrm%GAZH1tIxSURK)XVY(TB6UoC+g_*yP=#{Ynz|qiwRcdFJvuc8<`^QBi{8t( z58Mv(8A=^V_kZ$shvZ)H)%YdFncRami+rv+dg&FPOmj85Qt>dmLC72vs^KeB;cZ6a zS3qpt+Z>0u_rgZ?1SptK>n<~cU%M9g6KjD_+-1#lc3TVlw6(ymS_}N~wZJFty5@LC z*8)FnE%2My0)Kif@HxA!Io>5}fq!l-@D*!;kFNzjXZJP7d(2wkpI!_6$7_M-_gFK1 z_Pf_uPmW&;{Bvu8|9DmSfpnE9o)p~0Jm@1Iw_2+Enayrde7w4*3-O~K8!Ubw5bl%v zu!pgxY{w_kZ`r=-a~GMX?8Mb+C;BBz&3%4xyc39-fAotC@PINw!F_~B$bB3(#qnfO zlF_-)kfvqe4m)+|n|PuvBkaCm^@%g***a3*7LvSFnx@CgKHZr;PYosPP-|4PRO7y+ z$plBW*E%LjmL^s&-u9U$=y{nn>|fE-ed{We@`8<H=ZFN~ z4wvFa4a7EQ8fyug?}5bIVa6G$23j~l zpU_*NRL%2;fW#;A#4;7D>ZtPNAn{xK9pt%8t(bGC;JNfj=1pDUnSz$M${pFLQYdcu zWLg)}um`Ua_O$;gY~JRbM9t#Z?};ImR=-8A#Di3^F+t6%E)J3&+iN6}>g4oR_g>8w zldC^1ynOu`y_j;|CQ_%vO?(EA`cr^Y-l-=-CjA|@|MynX5C@Yrm&(^EQkD*wsWT(< z_jYx-8=*yDU&f_CbJjzYZg-s`8K5(u3#$>0KV}@Asc5z0o_9AXDC5vZ3Q*j=lKiigm6$knfe2UxjEua5fFdWH4nV$2KugQUB<0T1^z$eSt9oVZoaMTenC z%3T3oeZAzq(c)eD4O#;`OuWZWGi#A9)pOb?!tx^Ab%m_O?g!tiFE3f%*&MY$=-$B3 zQKgTx74!~Yb6!Xdwvfq-4tHyk86EBxxzhA&UUP)fpHI^NWuM|}cvUALMNcyW1I)ht zCFjL~4l^=PbagVC$#(Uv%8+Bz4CyXYd>w5WQl66c8Nw>E<%o~F!`k=TviXs>TaTjW zl`EVS--p~t>y6U87+&8l{F-W1)PMmp(S6;@AwGhiw!*l zXNlDSTXN7hdOIlEX!raS%@*T3L|+##B(}_@hqLJwXzbJ6eG^b?538q=;F+76n31zt zYCJ}m&SC4Ea{eQ=Pd2#OG@X|Yj)b-@nRyTKF1?$0=_=j>HMXlm0$T;feKzhwbPmr& z>$H4F7vlEdSs#Vi4)gi;izMG?1Z!IKDMaTI5<5O7H?=L3tQ;c<$MXvy*m#cqynT3P zau`ohti5@x8BM^^lV7Bsj4!dr$buliD9QyKtH*4rzDe9@`TBd{)8nM2_yZ6)L+iSJ zu{yC{r;9953)C8^blLS&Z+RB~v-ywlzmsedO#eL57x;@Q{nVy*<^4{TS*t&YtK=^^ z_zqs3E7u1hNwX!BT@KM2pHa5s37y7N(S6f5)uug=b=M8nzmvGNPB#~PCcM;(t7+tz zmxhOQ&#?@X3yq_O}*#Swu!!# z1k*&L?J{axDk9haOpR_z$L;|}hx!Wwb<|(vMVy11^#`n!1jj8L(JDxxy6C$j~|!oys)REj;N#$QNiI=a0?#>N*yaZFJ2a=!r8eHd6w z4XV@`Q1Xx;FHBVTbrEp)urNsC++I2k<*rF^A*$DZh9363!QeTenXy97rr_tjHt zMt_IvB`RCbYHn|>Np!(0`*V*#bQJQa9Q-xI=HJBT#bQ%X^Ky@Z%Hdc$uF9SiwYM^Q zxrKZw6Y}rPkb*Y!u#nv}-vbGvttlT?V*{tEIHPA~7J543E)qOcX#6ch?jKEZf|{3+ z>n%(vczR@&r#BIL1HC27b5E)-mEpPr?YF#(Jm{B|5SDs^Trnz<+iW~3KTA^(ph>PB zeaschx~-;?pp>Fz3_-#p#Y2vAAE@aEX5?Dpi@8p(lSRvSyuX|!Io zL0|7=gN59*_!lQ`%d=!U(}XEutHP8-uLe0Z#8t^8Pt!NnA&t*4LQ&D@`VhO{)*8%z zH}7xhNE83T&`d%57O4R;$u4oKKvG`Qyg_5pd#ybpXuJPVem))dGr=3@tMRW)J$haB z=wqt+f|{56HI+Ue-z?EgGW?y;J05!2FPTIyBHO@7?AWiWBYo$K#hP9S;8!AW#mgwD z`V9c`BQpq>Y|GQ*PF9aA-%7#!JAm~Fb}5m&$J8QU&G5x8av}b>_!88-+;4>R?+nre zA$>wff|{3m93;nxk0wNX6aL-hd~`kUav~4s?W(T#k)C)8(aVs@&9LjU2En#hJgL9% zjrKp8=t4zjc_nB=56de@cZ<>Ps$N8=FeL_CwMv26Lxk(pUS^v*O8q-`r2l78$sNQlG5z=HO zTbI}@Pww*g6fvBU*#2xCY#@dr9JAe0=9Q$2Io@k9Z);@cFy3q9Da;(e)CbU=*w6C= zxh_v`qFxzNW_VP^C8+5vR%lH2H(kbBK8?>D#3R4K%@zc=Fdm&moH@6yQsbuc z%tgmR){7B2x1Ol8EHf+Pe=PoCGyr6j$z4FZ?8EJP5b~o>!)j%CBfxe`TcxwV%ag^B z)-4AduSeNQ~*0-8x`% zd<(D9730YrQ*GMoX?ZNM#92{L66+I8ZEZ&?CVgkHAOBJE=>q;XaPh5nv@h?7vTZyo zeZvUli-P+syp3q_%O~j$lH?7L(3V0|JzQQG@VLth(=24#x)#vWo}qaCyr9?aXg*o> z)yijt*ck$HRzQs6J1JY20>jR@+y+PEbRlkUuY99u5$=LLkBWB0T{QRfMH&Izx$u@~ zfEjq&qB(#)`bCs*IABj*SzEDXM0a5`gtbTQiz=hizs3U1NZ&7>Yidnglc383E2Gl^ z=iElH5O2=|H3Rc5M4!i3;g#lU=q3|Gs@Cb|fN3B7L(`NmlBbX5tsiT^2pf$;rfxV< z|1*U>Ca8HihV{9lNORz$np0>LGx!@DHw-vqf|{4ztm>X5kOoWN=XiZl#^d=AsGe^_ zII;($J$>vyfl2>n3bbsWJ?U1OeS`8y`zoqaVU100+SM0GvrkXnY)3GcWa%#jCP=AMa(wnHzcTI zrV6*T3tJ6j-XBe1Yi}LKFMQa%W`|(bJAL(U>It}Ql&ZW#dtQ9fKXwzT_4(!?E?^T= zm^pySuBO`5QqtpXURmRinL0D_SiO$ac>(YiTxu|`X>*TOV>=4V3)2%Qs*MHO&=)ON z)3);t=p#(9ZhQ@e&mzlW0BB^0VW;P!?G4bRn~5S(VbHMTO&FTSb|yBz;x2Kj*;W_f zK85(=-6#ljLRt(*y8=l8;xz?`i;J#S)ijJ~XYj0Dweoidv72*hx;}sV(!4YWagx7N zQ7Gd)0j;&>7X&3_2J(bvAAJ zo$im%Xt3^qU;|In()i6myy@K|O2-VT`=9}pzAL#QOJ6#s3disoowklLqxt@lmGO*5 z`&+p4<3nL<%ow<)O|a3t!5bUv-6ykLJ>6IpujX1D)@A@nR}gfIjMZZSAs;jnweTYD z(49zJZ1L!oGuxuzCA<+u=R7sMbAc-y(J*!K{ zC#Z8XsQJWS_E)zfj?;;QTEXyx@e@KaWSz_lp@vba(#ef5%gLwJCt!qGs)&4h9t^tP zlCC3nnqKu8(Dh`K>CNa{EVU;QXqv0jCpA|Xy%IYsj3{B*4L9V5M>`WVKZvsnn4pzB zirS{`Y`X-iHA_R(fV75I8`wU;N0OGw6LM}EiD_qNZibz)H)LlR`GRutESAS(M`*fU@Nrx2%3BX(f#n4|F)@VC( ziMxs~Y_E`}7bv+AGJ_+wTRfX`d3KXa7TR-3wze^t@^{ct>=3{o!a!d>I^B3u-H?pc z@cgJgxEG)}c|x)?u8M1FeUqsMV!$hUt0h)esxM@Z-*(j#Go_9tfeQOL=Rm2YLAi!= zjnBeg<_+M$_zi)ycUpxX z(@T*RFmr{Oh76Nvp#4& zx9C4s9jHiiQIN*E8EPLEwOd3@Q1f!kiu`OsI)8cF4?35$#r?@z0DEYNRU$E6|ElY3&m{!P6*>fbW2uqLp(ok#uKJd*gZm!phbg%E*_NQa?@6APZ!L{CiR zlj@~@K;`ScBhtSo6_RkitB>#T=qyBc@G3^n;uGD8)7KZ|g1huFf5mxNdoWEv>6$7= zvm<(BxZ;x3Bj@f0yp-wappB*b5I3Pxc{gg7?24nvK%lxb!cf4R0V@lu z&lv<%dDGWzBB%5O&EaA5QkXeBY-7Q;2x~*UqnC(I;WZAN!~0{(i}-Iq>#XgwL@Dj| zc%BVNVf`lzNXe?ewy>4XFWk2oR_daQIg!rBd>rW@dWVLlze8?JQ1dFff0DfVk2ScF z>iHViSlg(?FDq7Y1w+2wRqUMerSQah|E3_aCs+Te053mzv}P<@PqEs3b92=ZY{R{1KB?JUn7>#dX109mYMi}p!mtE%9x<$<;Fp3##J!8 zd7o5V3zE1V^l?3u#I=p$QoZW8tU*uT^UYR<$Rv4Dw!6DND_OdkJGd0fJ8Oi=T3sPbs6>JGjRzn>AmixPgH z6o)nIyT%JUib1qHDl&*W*P;BwR+_6*Q&+OB#ukTVtabR~Gnf{$POA0Ku3~pTM!^r_ zn{%93-p&}O{f6iQ{6^LT%1xS41+q&o@@}+XD(*J;9G;FZo@i-Q?05+lTkJ#o#VAB! zJ{5@oDehs&u@MHKjriPX}zf3&)B=8{yW~y z)b9L$omwk{7!`#7Ka%W?_Zkz_yj&Tip_1!U!}58$N6>kY&(m~{`B~-ZE=ivLUb&aAKda2Meulcdt1@r0 z%CQ1DHy7z5?RS`GEo9WxzA4%nZTqJB*1oCv^VVv4+kC8jZkD&U`8jwAm)%6wVQsmK z%qT?aZfs+DXy9ViDV3h?byxH*6y7lsHFPZK=uhd=iu zE*okguKl{%;CxZ(%SF%NMVG9o3c0Lqush1S_M|VJ9GpU!FRdQNy#q9MY>Yza9)wOV zTFHic(Y+lX5BH~5j^Nv&>M(aya&6Y<@TQMCGHv6E9}877GVty5za!WK4E`%XF+J;{7}5}K zfI2n2e;QlnLX|YOji`udohvz#bEp(b)g_gfen3c17Sad9|aSS;SAtIc)N@dDUS zfEfaGsrO$9{dD&6EJ5Nyyv77IFW0T^dLoZR{wV}wM0b_av44_|zghz7=x{1If8hl; z`pO)^RnA$anM(cvt1@+9J5xJkn0l_sl%NegjH!elKPSCf{2Y|w6|CF{Htli@ziC8p8WL%|{0lAqySqLY3$1D9_dB7e@}`$wvL2kaFt^OscpY zFjtD!;|tyTcsIOQp|SE)9G*<67|jI17iQT;nzD^ER_6I=7M{gucfz*#^6NxjhA-BM z-j0{1zvw4or@D>;Ay+?&f9=_Plz6Uf@}Gfa0b*R&;K3qWW*4hY4 zF83_P>%+zwNe7v;Y_Mbak&fYWyG4U_puD?_g6#H`%RZ_pN~iUYWq*b@J?m`pS5Giy zgJ1*J=vZ5-WbXE9^~-4={Um*k-?2-}rZboYZT%9QeDnlJ%@6fbK7=nzzX$gf@*;1X zpo+nqqY~P4p~e^#Yy=tb77)@iKw4SiaF4oZlnX=)d0;lVA=$&;l5={%LYL9@o9u`P zqjx$+E6n`HPE;A)#9gs<9(w-ZI^jnf0!sGnytc++6jA4JQ4HB(n9h|N;O97lo1k2b z{{T)RZ($#N4cEts9Kr!ft;Tx1^3}wHA zNGb?eO`~z7Pp+ewmml5;?@}S+RjKCz6i2%S880kJ6U>}P3HItt^M0|qwgzK>rIodY zef_?!bpMpYW^jyjVfQ8Pl;8w#1~a=qk(ai;hx-R|zePp&cO}QxpOE%~o0SLEa}hKm zHWAWFW-~5Y?96qdje)`+ORj!jEv$YiMNYx^abHcb`io6DDfAtD-Alyg$1T|#orb@D zsI>z3H8s2WIbj{|-$}1hqlom?*%R149e;6tY7F}gUPJP4fi?#FD|mCA`AfxLzCB_U*?*Vb}%s@zk^$?9khZa zMvFyw2vd&4>@^H6DpSz$G`;nXrpAe91&y9Whi96{LYb#}`Xs6P%<#mP7Y3_m8K6zC zr($ciu#==I7m0yHU&jv-Vlfx#nRd07j$g{sN&TAgc7VQnqG!nW zKfXp zD;pL~P$sYqH=0K@VNIpUskZ1cp=$^zRi8?uF1HYK5!+0ak`I(~Q`^!~4A|lfzD-)< zldME?^?nsazK*Ug60|;iH|YDj(1^8?7|n;3#y)V8_EyuNA8)GeNl^3Bjd*h#`(}`) z3yDd6WlT`>a=k)YoI#o)q|JpSsCmiufu!+BgNVEg(AX~%YEYrJP$)so%Q4TI>(0@{ zBJBev>wfg$J1WC9rfB~R#dSn+OHmZGp@-`ivj=35))mrLLK4)x+<=e{%pk2Nq^*S{ zsCh{#Xl~=64AM*?EfA8R=H;df>EH~~EFoc;_^56nG6?rs_zjtEd9(U+E z2^QAWjC13Kk24oEZLMg3b$ZkT-wwKh<8Xhsy?#s8rC{~To1spIK^xVRs#uJ6WTf+r zfIdSNEn$R_HMvSM!-1WI^#+I)uVnJ;h~#_3n`P8X%i7s$gB}FSG*a2(?p(P{%q30m z5K{hlZbb4&Q&_LEBIcWsU3kB|6r-$E=`<~&zRr~k!0q-j{)d_}zTYIx@@p2lkde0` zhO$5W$wHXM@sOJ%ySDN&3bcYa4i?-@b|O1j)Av~xj}qz7DcEG(7Ka(X@E-0{h|uwN z@C0Yy9D^y>%=hV1*9zi6n;R*7Sgz{e2BjyN)L#5*PUmxs~LICa`F zxqxmGR8ZMWzmtPC#M8u6Jn6US>YFkDt<)ov1I*!Jhomrb0Ml5c≷IF>|OB^!m|k z-c*ha^@5nnKb2LE2v_`;rELdS702c1g{$@H*AO*2eP8v%bk}wh$BdDFjy;+RF!i^I z1>*I0!QZKPPfkXgY3kI*3-4F=A)!0omA6e5SqJ ze6Wndn4somw8oB5L4|@m)1V6;E`f9y3Wnv_6lDzX@~$F#TGR){DJH zj9Bi$2Bzg)I@q|?zov__kZ^PRz|#QVcmysKT; z6*c1xmoabDk#>m<)YyH=B2zi{muby(xo9z<eXwP42ZwgV$bVZv$^#{_2D(e++kuh z8L#re&OVB@#$i>x`baaI;JBrZSn{>_IDVXxz9Hd+K zSEG0KY>Jd~M}g9=clKk|DW3`dU-iyJJZVS8V0+^KNiz>}+2rS<)lxo7-79i3`_Ps{ zoJ#^i6->&})4T6~rZ-#ktp88xebiUagkITf!2T3^EAC3Wtp7!ys^ohw4h#D-<90Y7 z!SeDnT?o}ufzr5j8hV|h@FOZ3Xu-=%EDwrb75HG|d! zjE^%P8z0{-C*zWQBa4K*)B4XYynm*AvucYWB^H|f38(5)nMxnOhk$5oNAKlbsGmr4 z#eAq<(eXg)C#n4^O~hf)_W@P;Eb!mC=mZaFexJC?_eraKNB%pdce4L%(R;rK+-f%f zV%(GRLqqyZUU3yKR+jXe?=J!Dk2Xl^i)6(^@%Xvb6|ssefnOybEhSjzuqIE%Xc_LV z!W8J@;B_jm=rkTI8*fM%&3k+eM+&g<0|tEy!bTYM1@m|EavgG(Wr~j}K0`=an_Wm$ z_rpiy1lU-udeuPV_^^d+ilh1HOu)-acD2}2_8|~&k~-TFYyrIon&}$2_yrq((EpR8 z5Y-9kHX^Mo`^@1LpC!Ose8#Bknq@PF2Xq^#<2U;tb4F(&{^X*2RZIJa*5H43*8hm= zt5l(|rpjTaLd+zH&Vm*LE#$8duStzd=7?ss#@}epN%rUjj-C|zkMEC|G*#vl-D$AX zwR+AY1o=E44Avd?c|N$Azt{6Y#bLq=E0remd*!}42=BHW>`sT~P)0Yi6m<0krB1R; zHrLLZ5Cjj2hOT9+G$N9c3UUqAwR3=u32I(i;nB5bCuh*k656>!6V$xi#-KIcpFtWE z(g%bjsCl^|AyqR-XA9{(Aqi?;Zmy8x4AMD5`k;^mH7~abNNygF)^(=Q`Ji-RT!dG3 zgZ+{@PQ-M%(%px>6I(|sM@)pVlo6jxu}Wj46nzvxV`(P7a}}TEf}rMQxzJdaLHdA@ zE)Y|KnwOg|rf7=Z+DJ4;6g?dwlcY01&Ul<-9@-bo_V-1~#mV<&e^spQpO3sg|{Yqw% z4Yh|=UuVvbK1f-iFuHI6Sh5eZ9rc>!(PTSjav+i2`Vab9HB)yg@d$=Yw*{eg(+NN!gjr60jB0cfXe`i8Y?=K9QUJqdAZ1()x+T`u_V!N{i?cf{le&DphlPSNSul?{x}aCtJ>1` zzE;|f2-n1gYy@WV;({!G25xQ1=h2bO;oFlFe?oDy$Ms3Q+vr`9rMF5j%LTs&p$(=- zDBl$?QEn#MRc|6>bM#p8_7r{byyjm!Zn4$`K*Xw zYEkYhcr4X8Mdj08&F2OD0uR15w|xug{-xUc7lEn0e~CAXz{`0_xARKg@l`zBR;sqi znCQd(O5v`-PvO4In{e0iQn;`1j=##oZJh~MHk*yVw)7Z(=$*HC&P5BrUHVVBMPgTu z6k1stU&ptPpLK!j`G{^Xh|&?-p5|lFWgYuQz+&Yl-p#&^F<5z%bFZ+RMA~VWmRG6F zrn7BYQ2Pxua?#Bqu~K6x>jAg$k=jGjE=Z~9SDO6t)JL1kQzo5?>*z4rE0-5Tz`&C#>za5loeLPb zSAmsPD}IsYiu*Az)`@>2V(fRzH@=S#w+#(Mc5*o<#0h?VjPg)cZL7D>U-cV15*Mp< zX@X((Y!h?8r4r?oSx_z@Zsv ztSQOm=e*C^xu7W%#{1W&(EOHsVW_9W__q1NhQUdf z2GT4FF7-t^YSlIV6~XH&VrCJlOjZVS6i#KesRHl|SIka3b-%XuYfv+=-Bb-819r9W zeE;;Asn>CJ*G)P^(88oE!yewHej;r@G}WQyN`h=||8|Lc^)HS$!z@%&Vyt)P{ z=sQ!%_jSJ`IGwQ15VlWh310w*HdP-cAleC7c*wKIW?Ffww|U2;Hc?7LJ>iR@xKyi| z1-oIz>n$)TeSjFP7ow9^Kh#||)d|+&N;Q#gQzC?}=cOy)+;zYTj&w7e)C{R^nkE&7 zQYN668+0WLv2t#UKP`;@FWVArR=>3$NBv9TLqT2sB-l9jAZP(1D88Wi!KmL z$FASQ4`bK0ma}1fJJ|PQhV>miwl2$plH>sC_vTFN%H0ns#QvV9{z{KK+^h zqiLNK;xAQ!jFAz|-+}y`fXN+LD*7x@&#BL=>A_>*Key(1eU0>2srb&@s%XLVR^d}> zA?>-R65o7P`1Z8&ooD6LcMzja9 zi?I~<^Mt20gT_>rGl}_RjJE1#baU}%sQ{fT_W-+VRTVeni(DdAloAy;(`3tx^q#v! z3n9^7D<-;E(}F2OUVrVl(EX5?XIW)D@E5w4Z^id9LkSkGAwaIrLyk ze%*xC35Xw&H=~TK=)Kv-{Xi!ae+$KVSNncGH{QQVv!5^eO%m>xg?w|ZVqWmBq`%j^ zNHQJzN3VO#BZC_xFllQ1fz&G{T*e^mj^! z##f}>;6?Frz44N(?<^*2dRn}Vi!xMyA*#=cs-WiOc2v|CXOJEi(sM!*)V$nILb@b_ z^oWrDAS6M}%k3fuI~hA<_h=De^hl`o0B|U>yCmX*g*h2aU-qz77 zRpQ9QkXeB?D7<54q&~T&5|B; z@Hgs4H6|AK7b5X0Wja89Sqf@ydsi25NxTgqp?eJ6M6Yb1db?2ns$6zYwBVS3z6!N z`1o;K`B$#KGo@cWs})>Gs}7Rx*=9&-K9;K=PDA=EGj*Qo6)hsd_dIZ@#uQ}|rvH%f zFt%(IE;l|)38f?7KZNrVReMZO^K!?t){&fBLGJ!D7*=bQj^52?2m4c&e^)#A>v1Yk zKWmDA1uD17Gz(NV57;!amF7aRRjRhGZ>xxrnh9PiKri$}Y7anE)Cok*2Z#zYfjk8y zY!#WsgFM1~5Q(N$Zkc#~FB+v*(Pg}>F}8Bqh%qNJV&zswXF@zDV&zs=XS|*_&YFd7 z#8hH7GcWYyTcw`~^e53v_A9GjR>}TNosH$UmyvMN1*$FNB0b$pJVvx*=UYN9QhV@F z4KJZnJIFK2Px<9i7``ep3_ zS;O-Ale0A&yh*eA-#6C>ex3|&>ScVMTF*+}7u0DbaSU$O7qDs@ysR|(I^KO?TE}y4 zSELzMkC1%Pn1)N1m9>so-4q;acuB1v)mlsoYGMTDc!XPY@1u!f-JD+06c^n!gwR0UiSIaft0scxD*mpxVBNUs)=;R{?aFiB|33_=Pi38a<+U z`EcH562OfZRp8&?CihF<5Nxo*+u9F<6N8)AoiGXJm?urLb8xTxuX$^E#4K@-X0H3( z>ayeGCCjUB4AWaqEg}Zo$|#>Dd7mX*W2-FDOvsgw zaRmr&AM>kLzci8#!kLu1UMsi!_YuI2&HgK|Jx& zNN!%%4=)JaivYOc8Dt_t?h86_@t&Y}qq>8dy9Ajrm0C-#858%&k1kL@l_%BW^NwV& zw6h2-XjjfidX{%Kdlq`mlH|dHf~5E-Hoez`UvApj~3Rj~`#^qKKy|mC?F{3fSO%7)I;@2tYoT4(Jns<#{wWhm9;H3i6=zG-R zXoYDC>lhsON!F`NjVsCOw3=3kG42F?Oi=T3`}z7sM;x+xdEB?t_BtFae=M-IZEOci zS`R&cNH)~RXG3p<(N=E`5Gbr3x+$goQ__=j%Ji`M1r>h_;10B))JK0dyazL#EBzqmX6*VG;9!Cj;JB3auUq!QSdQ!*{z#AiYD@KN^WO^joCbxVnvgb)xCsao`|!{dz7LcK1!w=8@d^! zeNHLjKxxHHcqF?ISH6SMzPBS@2XBr?*Th0k2em}_Q7_n8I~DiSAX3?2G4Z`F9>WNw zx=PeT0Nhf-je5=PZdSvbiaU(@pk$(`3@2D+vi{WDBi7s~8c>)feQytf!Y2>Z95FYe zHHA9oqrkW6Cei4VLT-7n67PJ*NRr z?Ke-y%^F!WgLiTwa1HjG)hDE90%s+*UbWu2C-4xObOs%a^6p?`H5wGrVU3_g-7C-a zETw2&-gA<{{rT0EkkHQrp%qVGu>RKR7?rm%Cr3Q-H%`H3jjEh^4bpo8itY{Ow8j{S*+(Df{a^Uifwzl64<}IGBEzWx0~pKk}Lbvf|?;_Fk&j(W+ZFX3DJW;jq`)U==Apx&=J<&pc?w zqY^bK3$7re57C9o{e7;V@2m7#a_bX=o6TcP!7OZT13t~w;BX~f2iSeV{xlGq`KeIbHC0YTECLsaEbbp z>u{S;duj1fC+NtVfWkR!NnCV@3gDJdBj_oct%SH3SM+oLQC^HY0k&O+!se$$MR}x!*SHZ6d&FA`?`8!e^7)M$a79}IV_YrT zIoD3onD3aFkH4>S3TvWCZ?QEvoyCsmE}+HePM%jE(%j$H++b7abt!**2$TvI5X3H9 z%@=%tLkV!U9s@&M%qU0m+;Be70M^|WejCEiN&3~U;NAF7Z2CuxjBJ`k$5PIn!&~83 zjF#ZW(54vH?OqoB41CJb-LPwSqqcmFcrwP^v-%iAxmq3Q4R$-+_si&zE8EP@0<`wS&Z0uGMM>gEGxo2!w z^Lm{(t-DVmkKHS@l1jd_gQKq9T-Q`AmEFF^C2fOVMEf?nJK4o&PzeS)bJVMe9YwbZeIA>L3jkt(2q4gsn`h9GSwiim%4u7hl@gv4JIWR& zQC(12X_GXmEB$_R^dV?u785&Ujc1~)rDpn6kNIG$-_^(gW=96ckLRZ(6Anv~&21XD zk$+~jOPQ`cv|Wk2NA=RoZ_He>uv5%j3-$O@j9O=eZZSDGx_*#eT6=H&|e9x81X;{{6G=%t6c}lsfjJ8e^f97X76Da08@+?lt?Po=?5XnV^}OP zJ?HmU)V+j_Z$dO$gxA#Ma?SokTbnlsl4sN)`HhZx9c|fCe+%EeqVM*ht;lXsA8u z?(p{k;&r@#DUkZSZj-f%p2?F!hIV;tbUMyxoVu4Yq6zdPg8s*#S2SsBoo0;iGvFT7mEdkB1QcaI`H^?zS{4`J+GMLL3 zAbOgpIa{}?p8(MwgiFTCNx`)Q8dP4{jlT?&d*b_EmT33l-Bs-0t`7uM7^_r|kV_&? zgo3GS^motFKzwn20<+${U7Lxh)L$$gZg6)B%|6;2B9gYPr_SNc>d7;(#**q`80nt5 zke*zzWSrX z=&L$S44sppM>~T%KEvkg)(01Z`CA8*v~PYybwBz{A7S>KkNQT9-RmiCW5*xwVNLZ6 zMXYqC>6ZOY2q+?gC@z4aqN3uCihvs; zT6ea(0ivQJZiq^GzrS{HUA{PZKZIhPEtqh7ap5+mk9-QQAHSQ7IL zbN?Ze{D)5Rzh;tu`6T~}N&dqo`46AuKVp*qNcU%SX5XB?qdXkjpGJQegPFr&-_Bs>aM*nr%pAaE7qSmo@rE`AuO*+9{gkpv9IgXkuM5QCT^1&@ zXs+}a-VI<_lWiQ7&SY^MgB5TbWPzU0G*h*+^B9iL4PkE4&PqIAY?#gT%gF5-yoPe* z4xGAs)EHXtri@`qo^@uO#vP$q5ind}%YWs32TT zP6RTQ&|J#kmnj_rnIX+sB(v>2Z+3I+cT%2g;z{6Cdwg4i>Sm3k?niv9_W)sU%_qT! znFP&N6vF)bsr;}vKk2rj-XpEco_c>dnaA9O%eDb$R@ z@V+ai-uzruj<3Ba*tn+XA(~3yOrlF0gUnu z_fLp3tG&*$GZ0S4&(`i6cqF^K9%b|JT}vfeq{BT5-mSsQq`AGMJC$%4Lv~1_vr2Ls zi+QKnOsOUx!!2`}50E?+ko|u3u0)&gu6kOSu$ZZGXd^;B^S*Fn&Ok~%-5;N=r|-Ml z_f!FH76yGqMN58`*NOBS&jLI?h}g5Fl?zx zsJ2$qK{GMH6GUx3&cZYIaZ2lR%7L4Q zzLsJ?kg(nkPsd8Ds~4PjT1q?dRN4u9x6{bxQIiwJSnRtYUCXkuv%Shw7&||L0*x&n z8$P~XqB!OD_?jxt4j!i?8-o+$R3n%p_;Ix%Oq0LG<;D@)a>z2ZVV$cImQV=p=C`GB zZ84x;j!X>(`&K8eYJC250^J=ECt=Y}qRGZQBP5OB&C3l$&2=4AW-y=6(5K_B_1bvYndTZ*QP*ev~wIzkQUki9>XtR{U6fV*622}h zCqMUjzpof1>n|rc^O4@4634-KKArAI1orXCC%_WEZ=_+5e^kqR8duJCT*9;jr(tro z!*Va(&zBLW zd9Ti0P^mad$7AKOqxIpm>==FHu_O6#gVqAqRK8B!<{4B(M`ctI!efRt8)L$`R5-tp z;yg}B%45gt1I`oljmM7V15OKEQ~72Ary@+iIXk)&oV$SYMaEm&p~3)-il~07!KR6O zf?UCe!o1MRJD!h6n=rBPMj6pu6)Haxa4X|}MX(cSTxYO`$5s4n?tOQT$`p%X+A)q& zsGr_w7ZUEOc4?2ra#u$>7JX5jJR!Acanw>$-ie|3w>!sOJ{xb(6;dh34ca*Vlh+8up z&buJgCa>Le|h-sNm2I9dR>}v(ubs%Q?%O=g8S( zPL@opH7jGg`W61(c2T$YADh z*l#kJIUM$61~Z4lew)F};jrIjFmpKU_ZiF_4tpwtnZsd!$YADh*dH^PIUL53n3v5Q z4tqL-nZsd!&S2(n*fSZ-91i!eqUX^YTM zWAUBo-_gHic+3Hw1=}o*j++rhd#EpkKY%K{N^KpwgoxQ?$?$nS3)u$zl;(vI zx+()JC39VcY^11_urZ%X(jMR83YR$+-YMC=P3YCMyd76+Jnx01$yDQAy4( zK+B*{UfTvF%NVQ41#Lk1v(jA%V5;Gso;iOqy5-;*D0`q|jlD}y!Y&}sW?oy6dDi8? z514e;m-BtO+Nbr8Lj5lxX7dkX4h6NKzzIFdVTO$Jh}g^O=wF3wx6X?pXiGmK zP)DtQ7a~!jl*<;>f{e><+f8beTK_2|*j5SHXf?(KwV?1iu$l?}&OuI4P*vEJmg#~G z`WD~e;{kDj<6R|0f@cD7=>879c_I|eAjRdK)MDHXfqJFfmRAaVTP?jD+_d^g_i~q5 z&zrE9OL_Q9qBk|X-$|CMbM3vUGoEtlsDxKjD(U{cl5beVPkBg(!PR76+{4-j$K{b< zVJ>^_+^`8C-f8i$u%Uc}`}(s_#3h6172qu~LhXn@{E;z%TL=B&X?O1>_cL2Ld`9EED+h48CHJ$Qav!;$bN9Y-|J&XB$^E>$_m}$xcOM}43}}RcSIJ#+_knVE zxck*|*WJy-Qo?* zgF1sk~R(xw=v2xIMZLveb>xso{eVSS)WD0^e z5VYmzTopT7(|0C2aF+|05_(Rf#aVE^wrwvOE+xUZpcWL4r8QbF6e7Juk>03Cf?7~u zDP59W2CREf2e9?zO}I@T{mnSS<^0sWMIJXICkUu*3~BQiZ5qwlDVhn>J0r%u=|0{* zR8Ms9iIK`1#nFAy;-@niOEr2gu>FVtpBRsd-wQ8=yl_19a7ZbDjpj-#!UjRMgzumd zyak%Z1+}2$3cQOeC0N)^2`z`+`5o4rR1SN{sl$&-I03u`uK!Eq&}Be+(-nP%n8 zn)B#@!2n4zS~Ciz*%4UtDwRf13+lhpl1RO?r^DV7MwOETz9sek<#bV=TKq`9hSZ|n z$>jjmVW>-HVlWRQ*VpcC!pXUA(H^9tqGHtwWDgIn?@D1 z9o6qh>-wDLpiid@{_qACU+cXo|M}AI%29LI#7bnmOLpH_a^^PwH3^Bng3iS&;GSFC%RPbBZi)|8U@s9V@ks!k9mTjb0Ds%oO zK-JUhs?9t`=OIk;d5Muru6^8vX=kx^_qAAn(Bil2F zE=VY0!!^IGSR?!A(7YU3eZJi@GG42g1oI*wQvJAo755EQjoC9j><1EFC)R#IPZ{f* zum&~;U^`D{O!Ui$)`!seA}l?n?=vcQ%8*Q|0MhS};*l~MykR*SB*ilNWs}~)nP+M2 zYQB{+eBRFL)NjWpYw1hIuE8avaqr;UyjI{2);#NHI+NN6Jg-*&#$L~<#BW|l6iaZu z61+$A>s=)_sf?UX9gm#P zPjVKOHZnHRdzrjf=Aj>u7Y5rSHwKM+L%jy*t$C!6E7FT&yfcqH3FE?}teaOBZsOft zXUDD}n2-B%v@?Vstor?KD(^W>0-o~N=`P@rucLC&sS@fer8exrx(6igd5>!BbZX4^ z?$V*rQgaBnu;Nv!U|dTHxENPrC}b2-&jpp=y`db(-vD!?B*T$j`n>kIzo|ao-r|GR zeLvlG_6$r2<&E7zYwrS)%cOlU0`8!GHiki-az9IjVOx-}7E2A1nW?wKMK=ov!kLtV zgXWIm288xhhD&^S+PCAtkwtq%XS2wlgs!LBzpv`MOsHYNmbA)+>e)-x^FCFNpcWL) z6549n(DhUY+UVX-JkYJ0h_0i6ZtonOpe_A4x>{{W1FPe}@N%LIX#(%5^+O4#3AmN@4Lv@{9#j$wp zun(}x>>AukFl&oS@&O9aU0-L{DzLa~P->>7zIuWx7A%ge&8q%+MZx>VtmvaeSgt&* zsZq2OFM&Q#zY?z1GJ{%g`?_joc&IX@J0RuQyOL>ipp%R8K_fw%h|4Ql5a==9tLoOP z&}Q3=L{+zPXEv8Q>^C)*#NHz67%1CxNHZ7hDWtUL(5eJKNkm5q=X5WQ(t_drRYRGZ1?uR*UjRv!d`VItRr>uE2(a?+V(dpLx}K zOqh6!Q&q(a5!N3|&ILxW0(bF@lVH94R;zzeLF!OUTK`q|0h;Kd{p%Hr5m zInYp~dq)pH!o$l`g?EAHNDtS$QIjO1PP;=U48`>vCE(z)A0k)#j z*}R3S>8g!9%>-UeK8R=4pQvcN8&z$72!D6I#4+BjxYByzUhSVrTC%M&Fxfx9l{}9o z&yof0s%^5WGt7o7>$D5pajD-ght_4N8qW3FF~(ec~xD=>a+8uOQRi{uCF5A zOug+G$}n<2&s?FqN0l@@|Bo8MbHiq4j&@{kVGJdr8ybYE{EDq7J;A*~t z4AFsAH_`n>Y5Ip6m6Du~3&5TN93*wy3mjkq0gEx}022rt4w_`l0VWU-U{h1$LOH!1 z%#qnQZd5TSmZ15A!!fY&>~1P%tc)B%z%B$v6{qzgvs zn;l@{0|UI(0VZ=Wz*`((f(HX!=>Rydv_h^nKv*tvu5(zpU;{rn`R}bq|}qGt-3ISaKy&r-Q-he0qMy?`bi-bw56ZW6w&dMS^g0#8|2u~HlJA_bB3kv56;gvZ(t=O*?`K#S( zhPeZ&keZ!{_-EIFKi=jOb|g|DY0WHTa+)&vj4~0_g2HE2xcuzrDzKiQJ`j#3F8ji9 z0K6Ecb?VO=*KBZ^gKUPZCZ8j1B^*V}uF1pR2RfUp%J9oT;j+i8*yp>FoXZ~j+jC}e zv#>9u-`NG|OfJc8E|=5lUbiF(Cqkb+$Q37_hk(L-^98&%-BIw=5{YTeSChY}g63xB z?6y0=CkfAn?8&C4U1n&~+02pAb@O`qHtv&2-~1w35=)B&;u3zDRwVJvJqk&<=Tq@F ztu3bcTeAu+b2_n_bEw;KK`kgGwERRg5(cJ_N;qHrNo-v>gThr>vkU0X5V|ix+PI(= z6ke;|q>j>AZQe=Hg-&%imbfC6uwH^BO^8L;jz_X^s6g3H5R(4A&bG`c668FWcpm2?S=v?e|upd zPaBxKK-l~mKeis!jfXg0;|U=I(@vcHi?54$(sv2$2;abA7j>?mX)N$8D)c1}$(`~L zCClgx;rg-Ta=u|zAx^{WCLzM@X&&WqlE3ktB0qsWzr&T@E#QR}%JfJ9+H*oZlKU*- zJcSUIL4&|EKhYDbpE=WVa+=uJt}fe`CrW#KnzkZcv||)&q#yBDoYVjy22t6Yh-Dgj zm^pxHJrlo9w-mo$!tTYzRD9ab9!58{ zFnIYwSj7hUh{AYd5Q#<@S3+=keK#TvQ2kBNQ*A%*lbnoLA^{W30Z-G(!XP)hXMpB&88MKWhF3x9#-};%#RKv?zyTv z!{@2uu#%{8IEUY+DpU6n&R6Q!@`L*Vxi570sN5I1yD9g%a$CF6zt+pz*&O5rZ2b&o z4u@@!!OY>Xg&E8o4qKGL%;B&NGnhFXwowK%hr>3`VCHbxCK=2e4%;+?nFAPmxvx>E zI5|O!OY>XZ8DfS9JXx+Gl#>r%V6ek*!CIB91eR)1~Z4lko!6<=5W}K8O$6G z+bM&Y0~qpy-$|MGN2>hM1qxRG8O-9D!_y9BFmnJyw{JeMZ1)%L07vuRtiQCM?iVRg zV+MVfcM}9ZU5g|=S!rVdp{j3yY{iq%W(lKP(Drf67TIx3I!Af>^DO;UQ>GVmy7ZUF z;r5A%nx3gae@u|wJ-iEtZNfzRNpW}+{?xX*oK21sZM%le({LvM-^FQSb$|2gS`6Tg zw?m&zxOh&%=E}@}kQNQ1XMP@0nBbQdaxwhD)K5K1=bC$ui=uJ%_2;V|I89Wm4V|p~ z&AIXoxQ4`axc^-FW$wt?5|k$)Dh{9GH?@i(MY(u%U7^t_75bHLBrw$v2xN)0YEa^Z zKHIkUvtQBqO{o%Jq`bpViS69D5x_eH0KzO1rrG#JZ6rA)e3ck|oje7iT&qK@z0q7W z?+X?PlHH*gJDgUr9&b==X>%Q>;x69zP|7&m1EM(Gpx;`uKMI1YCFidBF_D)^Y-}z0 z2CedFTFUi-AY(7&W@^e~DviC8SIZw}i)+m$SS`qrz?G@)tO%(d#{q9kS zTOPfZwrPHoEF0X2i1rf z7?141NC$ZgI(-i*8(8Xw`jgtP{~@NN?IN{rnny3~-&#i3`6_Z2~`5 z36EQV@S%5VaZ#`}*bS+iw>-8BB&1gc+qZm}ZI=SKw=(50Bi>ZwZ%AzNaLp&Yk5#DG zH2OD3f)=KJ5$zTVRAF=f7jzF59*n3T4d@APSB+q)%~DsA(J3aQG47m66gR1nb9wo13*mbR=&l@E-DkJY;NdXrHj>`0sb)I+ep=OcEDP zc{lE#3<35d|Iw!${-zJxl7HwMhrjc&YxHA?$Hm;JFT*b(3U~g?9E=@cugqZPaM(T> z%p5i*NB0Dl-HVeIAlp9*s4)wkeX}&?@H9-1d7At#oq$S{-3NN3>b`IvXa@DIa36nu zALug0DclE|7^l<5_L~$ZJgXY83NVFyyHvM74S{G-mv&-D?zq>p^UOCZ9n6F(t(ZQY zhQb21zwX?`;W>-)Z+^}EKv0?Vs$NG^I{$i{_e*?H739}=LEYg(Tpe9b9{=S=AfvT)BY>1j+Af7c;*0;yCi%G9=+k@aA%zbH@r^ZOZeesBa0oXlAhCi8)i`@^d1 z^Ku)!l{J0u$`wDW$s?kzF}R&5#ZIVvX&d)+CMLmCeyKq&6*L2{E9{N1niN}p!*xm< zYx-`;QP-273t88oM*W5fUMGOSG+b}1j0So+tX;Eu;* zd=}fhjhx3OL7Qcnm?V=_S>CF#pWW~5w5cJTvpoE53fDTN`<)ZQt9B>yYQkUiew^p} zf4U#XJ+Y+ANl9txF?rY@ksE`5D9kMhXgEmKOSZ%oLTU3iN_-jJskI+NCEEcn zQqYqGjSFf)t^Et(8!G&_3K!IZ!ka+C>?X_`Dfow!vvoir(Z+)QUWo*?pzvlAkzf-A zJta~u7b&kQq}o(Le^4qxEhxN2S=G43Y1K1}7(Lb2S!%s26jDz^T*%;&Y@NE2(4JZ$ zCLELn7h~FLqL}#v*q~58tFNX%^wg83v;{NTB1TV7SF#Jfa}TF!HLcmy*zGg4reeZ3 zp(3{YnJcPv*&!}K<9nDx4b{xS9fWG8q3WIGlVeJmEe*2@Gvw?vliA6J!avjT-{bga zI{ulC-^WIZXg7Lb)~`R1_v_xCo*sI3PtSy|-P7ZJyB_9Kx$Lv;{Bh5C``5-2KQQ;b zEq=v=?$$gaKIa`8SC6LSYJ|q{I!m6W?NIhxtx4(6YT~P?TlI7J54{15_%XVcw9Irr zCk_`l(yg+Dcj2u>Hb#VJRE>vV=8S3s)jZb08ar=OESnUYWLzE9uT6@zd{X>{@-I$` zW{=uvaDM!qnp@_giUsKb2l;$` zDaqgcZK5A*ugl-#+eZ{&SzZ3a5K58>y*Hp%|C zThKRyc;}_>VPn%pyQoN2iU4Y(0%G4H<3}%yZ;syb(&u@8W{nXcN_#nx(Y|RcvpNAs{ zv%OumXXG3~;+pi{znqM#)9HPTPr@WpNyFrv5GL_M8Ybt2Fo{IcFge>{x-+>W6{EkD zIa`=J8TU+4`I&}hQrnVJw{3S;&a%D7`yQ3E7+h3>`WF?!!keUKf>p;qut(c4H1kJw^V_Z-RO8$n| z_sqk*XBV_iHUDmvdqAB014kx%fF)cq(BQ#?Tqfvy9IZll~2DY0}f< zy>r10;?6_Vq@()nPqx?gv^;jGf%NP1Elc`Raxs&vvdF0%RrlEDQ>0R|x6_dOU*UfG zoQErg=Ye4yKbOqI_9=w1+^KBpS8z7=7mvP%EQW!iENo;ZNVqG>zo-{ea5ockron6z z)|jGuBBK$xk7yX!tC;wMtnpynD-PR{`^f3kM{-0v@8j~kS&qtnPrQ)4c@j~_6cmrz z@0!XEplSYFO?f0?Irt?4|3~1Xb8vrhSnh@f)uYb%gh+){**E3;KH9OIJWtwl|4h+! zsx4ZRyTurLnUZ^PD~)jM;{=wIHOg)Ws%RiD-wHjU{Q__z%jWApNb`P;H81|VRs6#t z${!O?4pi3(@1VDKgmsv)!ZC1}1Lf8VRff(br0t=SEs|DK4-lEt4Amtu5o#lc?~sO9rws2#{}meTXsSMPFUUH= z%Tzf^T_{vNxt2o6E{&=VyEJ9O(>m9iSD&IRA86OZlOXbX(9Vk?zAc4stk&XWgm+d= zxo>*Hs|ZZ2LkUyOGKYs0q;6R^R__L`OfGR*dod7apLVcqX}MJO?0z`SOhTcRh620+ z$^3=h<`S0hch*_aZu`;&dbe2+eV29qrgnMihi2u`#!!|vWWqdP<-0Oqtx{?oR%p^) zp|g1d8H@{RLE-1xWH7}yyctWa!wU&^%M%D{LG1*c$a>#N?GJB6-j*9C&nI^dLv3T% z)YZG7?mDH>qT*>fT1OOe++8_#(1_!LT2Q#21e5S|TXTsC7+FXiSc6UOWQ6UIg;ghY zK*H3icx{;ctWyEmo7jbJ2IR~veQl~y|pm5 zebhI7!q?f-Ak}m;?cIFbc*l5b%$UW|`s*;_YQEEZb$B04AD`Ns*k5$WXK;S{VnQymiy3q zh0dJP599FG-F4ht6kt(r42$}7BHNdGcHqVUs|Bd*Aeq)!W#nEcF*5@^FY#V20y80^ z#io;28fM{SUQ|IX$24Id_==I)kaD|Uk<)pAJA+q2jdahnZ`T{M92ulWR7re5Yr~fhS zhb`?f6Z1XF&jtl0-|sO=G%8crtpCWQw3hFGNy~bDENJcQ#vGJgGBq*a9|d1&YU}UL z9Kp{$qCR4_%8#Ij$nXOOh7PbQwslf>^1lkM+rZWQO*(EaW~`*l(ley@L#@;T5gcurNQT6VLviw>^-Tmhbl&+t5i#NWcZa}s}3a0 z*eYX-N*&3L5WSkN77=NuwIYc>;u3@~BF;?DNY0NoeNUt$oOO??E5J4GXNx_4H4%jD zZ+`V9ZJ6{Iw~iwyTh3oCIz-&KpcXV{s9MJtVjYxGJ1(dNjade+Dq!`i#Yz8%rswRX zv6F}kQ+YBU;Ls!huYYvf=z(WcNGa*^!KAbNYn{ZXbqXOFiH9rmZX%5fYC)}23*kp7 ze5S$$wV>u}fQ_FZ?`egYN9LFWwV>ANh47%HpMX++}e)N)*PM8ntobQVAX?UK%{OMY z!Oiq<#-nFIVlsq?W|A$%T^+*@L}xb3v#-X1){Re#2E$Y0U7~p+ zSX<)CKzPm)dOcT6o_adP!J%E(W;#89Lg~|K%d(nEQT+IytjVUygyb-to!8$ln~c$0YYJm2l-O^KooCoDvSfzuNXY#h z_>e>XmYKJ+S{i%3CS}7`9hKWSj>79dn`@?L-^m4(vLnyMjla|6-Oz$PDJ$#epPoSD z&iR6op(#xy4}HZ^(VNsjsQxNDPfzpxyw$ymHN^R6WN$pgVT?l26z`^c`*3KTPmF9@ ze4TpJhScV`pcWL~L)6Z}(?C(ksH^#V3ejB)Odobm;nrbTlXF~`2p2~Hjd4L+`U&^Y z%j#Hy2VtEhv1ENa4%gf7!>x(P7cD z+p_yF^+@7#{l%kJ7vc%ix@dunA#|Z|ZVWZ8bHUk{yjMd%4g$Bw|BK;Koq}gncs6O{ zd7tAExQ(YHI@G9vo=~TZtqTjKdxJ3ifj%=Xs0FzpuF*oIOBHETwUMAL{e<_El}WWi6-$g%2p} zt*HHJp2A4^imvFmv%F0fu-07;ZC{**HaDFF|I-L}3vJC!-`xqL@T zBUj_QslqYI!^|!>NoxD3Im{w{+9s042*;h%;JERB!qE|FFn<{w%|9@TbpHmSVk2y? zc?&6VxwVp}fkXVG#u$1fjWC~DG|Oa_QAIGbJ?Sdr^L;&{{i3g^Jy!mUj>$^72!M@} zN}^Gc>;Wg4`qkUbpO%aH7fw+3ZNkL_!E5^kBZ8TmQfZ|475wav-k~^IT>NjAU%ccH z;a`OY4N(5JN*{;Qn4D(@id4~eP)TN?sM0_3gZ(r2xXLX2D$jXvta+7`tT))K9^Rsy zqUbonw=zZuEq`>EsJJYMxxN+&&t0ku<3m{zt|T3kZ;L!)ma(v#s`_I2ID&GV%9p*y zxX6(F%^ctX_PPva4u>f*WhN8+U*p3&!hiSH9D6fOWOXH+%8lHt+pm#K?$zME8@&FeMjYNogw&dl%t{~?5G45r%$`}qOjgiQ76ZOkV0lIm4RX~+ zn3K&I@r(0Ktms;bEMTq+fUYM7WvSby;U23usmnDwkl7%D>7I$|j4Z;NX7Rfe83Keu zJnyBr^_MQ~;wr{2rNGkdgH5ZXBIdUCV7hX*&E|8$(+Pr+yXY9%8#v)cvWXG@yj$OL z_<(sUW0weXN4Qzu=JV9|*c&Xb>e%b~W^~bJZ7#@0+qX z=I}Ug&S2&MMw=?zKim)WRnKUzifCEpSSmoWYLhv`g}x^A}kV+{m}|*}RObZfLd@pD%RyWK{2EJ~AE@ zOO7f&LLB>LM_38BLIVw>KDuC=dC@n>@f&KJQT5DHvP7f7TcVU4mleYswbY;dn@US7 zQoOnjVK{5+fLCOP;p!)qs;Qr#Hj?~=^fgRqB)`C6uMc3KMKdAddNxsJ=EAK1`|CVL z0)e8Ec9g7*{T}^i1}zLL z-+D`-X+H^RF3J_uf{Zf{AEIH$uA*->w}g~Vl<~;8%igfAB|pX8U9Hbewj!+NH2E9W z6HE@q;r*bG!%h5FMujZdngqx)Rb8?6D3!1SP2IYpK+>mjk_5G&a4Xc%M`QI-j;|Ww z!vI=W7E*m$skS9(Tu=)NoMt1_r_#0q-rF&#J1ErT_VQKGSV>-ji_Z>xtSAIp{XXpV z+u=$T9j;U{vs`UmRmkxUS#s#&Y@KKTV)B5~t;05=9VQrPzC$9+`&4K1uKXA?s#!epB)7=VLp?pU)YZI9wQBRA z%_|+r38LY(G+A$>s{V$C-yjF^(VWgOBwtsILLCA}WThG@mMqXBiOK8{1*K!RuSp|UY!D6P!}(tfschu?{#N$VjsefNY`(q$RDI!{`CJ5(Qo6~{>7^}_ z=H>0cyAv!{70kD*LF)sU-tz8`qMDl4dpj3!6ibQ%Cby9ujClEPTYidHa=QakCuo?! zhIcUriQ)6&c_enuREFdIs(r1$;u-}tSW}^Jg@T&Rl%1aL`=qOyKs=vSu{2hgOUc34 z?e6^kuUAv@4^@)&q~sKp!=|a^Wi&W^iuy$yZUL@$wfvkwYrp2A`)pp-a@e2z6C_BC z)V)f+CNcCX6r3*E9&Le)rGP9If~_Tqo5YlKD8=pw7C2MUU@0C zlAjM`=LC}Boj@7xr%cU~&B5{5TbT?iqxwyDAyMkwRn9e)vZlFQ?$df(fu_%jCTgcK zE~o|RW%MOsFN)XPP5G-Gx8mGI0~akLvw5Y_tu}!sEtffsqD?X`{rR!q+?gFSD>JJ> zmjK!_NM=R*BaTi66@$S%vlhhk#T{dBhnRSN_>vMSfB2<29!{a2rOU8NG=+N!muzl#T5c`boQJYg zBQTTA(KG?^nb*JGLOK^*Kge+nAAq+YWeZ;?11H0DRBe54*y~6YTi;~>Ps7`7lx+F? zwfEIdWNA)pMB2PpONEVoCu56f(SAOU7xonQsS34^kzTd_Qlef?S;pQ;#TEV6$=^}j zE~2wEyTDfCewDKn9?+*8ex}b%E??{0AH<@?%{|FF{J=sw#;#Y}rG5Ba zSv#5oT4`I(y}e(X0~qUx(rDM6^@(?9am?ZA=!c%p91goNgPFr&@6BN50H$%X8{Z$Q zElc5-(21&+*Z)NPw(SD2B-J&?<&fqKHg(8 zvY%MK-yys|Jj4iaRkz}-p3cYbBlBz<@@t~|d@N{7KZW_&*X4X2>5kq7^*<$_Y#n(C zeqRc{JY|l)e58v>dudFUkFVruipxhz<@*a%K9*A{XiGl@Dhn2E+HFxc`xZYd)X4+n z<|}o9=Sa)8V4JOMPxzq4S2HB9p#F<%bho-nO*(tiIK+zL9MS`~UQ=kZLUOJMg`K7lRNfWG%dnb0z1^#C}dOIgUE8m;( zo}Z5{+}7U;!0y0L$*ZItgT%qVQO5ZStv9x-(XN!~A!`%g=O0HLn-qD6qL4ZpyIKx} z>Q_0cPl^w6yOqd-%sMklu(n7#+_tB`g6HfIy1KKDz7DKiA$}=sH|p#W8$%! zaixHSDzA*)A^;EgkU`q#*0t#Q{Psa2*xGIm@?~CBBFRgHjkCw_G^xWeCb{?dW_J1H2`z50N?>?`ssKN*))~g6tqHALI2%N*fQW&RN5aeeg5X zO894+cJZTsGyS)~!4SxMLaqMC9-(y2RSVeaPa7hmpYV z5tY9b{zZI*yRsQkNoFX<+>C##*t-djdOVTY`f!0NF2q-w2Qb*j1+}2?X|a@d@B@dY zQ%|e_^bN2Gyg>I@maYMkZ7m{9e;N55$sBU_%1LX|h}D{r(YtyIdP@a*(Oq1{$Md%S1n*oC?|dMo37^q$BAw^$x{{)`6rQIFTtein zm^@FhN>(^;PioH7wPFji^FJ5ISS(kpXRIO*H=D|eUv$G~tE$i?HGaEoPTtB>HC^am zs2-9Zv27Zb+D@GO7-ysPIE~PWBzhTTu+G*ufR87D8`ZErGE_54=4I-OZYJR`4G&WB zR59vmL-um~3%A0y3!7z$%qywwcmR!|vxw5H`c}k-4F=bg!0hdMbaSrgUtzY5$KI}b zb_bsc-tM$ndi>`fcmp{8~iMNcGrR_y@4ESj8n zb1sk0a4PkZjuZ6-t>eE^U#NRuXq(BlB92{Sw929jWHdyEPTlOR&G@?QVlzq~DmHQ@ zvo!PTNh6)hQ?0VGcUbqcIKD>k|F?=S3pP~B0@^u1!xPXDC$h%F9xXXo zQ{ri)^i$;t))INc$z-3^XwLlXT(2By)1$xGuQA)*V(qbFzwK;yi&=MAH|?I-9y(2f z4Zv@WVg4@j=XZ?@zQ!dl~JX? zC#j{hA8=>=~=NLEsllR}i-_e3OdBrY z|BOmFoXYHMLq|?0cIyNYrjRa}y%X{99!xliZ*RFi*RG+4lkxSGq5C+{7+YRSPEj&l zQoTh$t}~sWv3x2}uS3?pzq6JM?3g_?qLD$vPg)->4so^a4179neX7udHdGHXDVLxY z6uwCQLP!Ea`AEW7eGVI5X~&{_QNsl)mC;WE<5{BW7Og{ga<)v+HskE>TgXVwoi z4?G2qc;#DZdRQy%qq;Dw#6=$yu$QiIhHK$ag8mEhYHk{45OyQl?^4JZm2eF^gw#8)W z%3v=OAErTE9aX&47;TAy_RsE!SE}IH8q+nf2@z%jsFfU)9O~r`u<(f1!$#U7+)?N# zdjt25BB%vfN9pG1SR1T5gD_ScO-D8fbx+7_k>cdKTkB|LQcUIvL@P_W2X%(ufryUZ zx*mku)9IM0Zs_&dVRvwzQCqrfG;B|tMw-Z8ky0WsS|Tth-8<7t(xrp!WE)cV5UHnW ze0|$Hx_D;wmA?qTRT=$|K`(aoHPnsO$UwaEZ&W5iQ-xHyIHh$`bw!u4t0^h1jc9;2 z{42PceYUQb#@?+KT=^DHt{%@ponY1ErJzsFfEJ50sGU|CWNt zOrdALLS4b8KtV0YdUgXTr+T&w=}zp~jq*@U0p-x44(H>#)M0%#qf293!&-eb>yYYW z*OKrb>KBXBe(_P-pwcmRn?Bqv{+N9`#y-xM#bRrcv)*l(jTaj&05%d}glY))(SHGK zEI?C$?>Jx+0nQcRegLh{7E1g|m3SpVSsmgrr=T4f5Hjsae@{L zyKOoiAYu5PrS@@J<^{bd`X_14?j=uDGb>laAPMt1zY^_Aoacy>3QTlwCmo(E-{uo_ zgBUCV9m!rcHCf+Z`wCn(H)#I&7x?^1Y~|?3gk+hnGZmXZ{!N^C<@-GgF_Fpw6Hh(b zM5b-Fvy+;pt3?+Q?LSI4P5)ZBLr%P(6j~> z%-lA@Qsfej%GfPg1}q|Kz-n?Hz4FS3$)sygLyTO0NKDMfE1;H~&o8Y*GVXd;nh4=h z46c^LZuqQbTc0nKdSAscE?iIxaxVNw;OzE;`f?xY3de!586Z?w`YL0egwh_=7CMp( z$ZzaZ=B?qqP~K1Dt@l($1@^uCDBvE(;N}_>`TB>Yjxv|WyWwGxtS%Q%=f&9W9Ua3e z96U5f?3IC@HZN2%9i|slZv$3urLjB6CiZK4nvL{~*%IX=_1$oXS_dgnR_`T~(?uoq z@yorByO?Tc8$)^fxc=-6#VgSVcUMJSL@C0LshLK3cr!3oT3;yC<$j7{TMa=i$mXKP z6w_nY58ySwSU|DAP>hkwxS$pkenNghi?Pa}`4KLe9!B}Mu<}pd417klK^1JNDrkw~ zpMrrRyvPPXY0?bQMrl=5~fMV}>I zhw?FADYnz8bcYzX?ku2tmC%i=wgt7I@H6VF_2ojO0~P6YiX^B7g$EVsD}_kQ@<@VO zPb8`~ZajozK%E`{eQE6jAnTW@jOM`CxQr&J zce&Fm8-u8JMRn2Cx~tHHClR6fI8=-aYC+)+VAMDGGnH z!UeUU@Tj`WJ%vc8D$?bOB&Y?2)rxd)A<}7z^cF=D)Plm#iG%|F#*o=H_)XPqvMFxt z2Pan$bGQM>1aW5C8R(Tjd&}jz8I0wUFS9w4_{z}bL_}}Rj09Ee1v=E!WN(OP^_ac4 zqRKrm;)6+Lo;pPMZ}Ph)$~H8eMrbl}G|c_@oI z83}m$tI7R@_OWh8Gwif(HGz?_XajU$$@KKs-5qVPFHz_(_B3HQ9J1(83pj(2Jh;>F zm%~AT|1TM2_-D>^{F>{fZPf+7=2kY>$77#mriRu0oId5T&+D_MvbCoAlWCF4sKTu@ z;RI2ou_Zj)if-ZI-D-H%cBk-TvwqC*gOEaRzgO ze6`XE6I+Fo^BWoytZS}41Z%cKV7qao2u+(H{0vV~EiAPxJHg?Xm7OHa9g%| z2(-*H+6Gn9Nx>85E-=`bpQjn7A=Y}kgqOQ3H#Fzn7iRH8(Z9E za|QLN`%dC5XBX;V1EKQX6MmYLUOXrF8nPF`Uqyyi4-;x8l@)IrbuZ1z(`o&*=l_%s z^J&6SllrN(ISdlC%>f5{M2_vO)xWCd&dQ^E0rQB{>v48Z<9x$=#`5G?^kV9=n68#No+{MY6^x4(Ygk4R(+vY(C_Oa0sb@�U$(s8uK5CNLY|i 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 `zWs> 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