Skip to content

Commit

Permalink
Adding Roslyn support for unit testing
Browse files Browse the repository at this point in the history
  • Loading branch information
fearthecowboy committed Jul 8, 2016
1 parent 19f629b commit f4d008a
Show file tree
Hide file tree
Showing 14 changed files with 647 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.25123" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25123</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="Exists('$(VSToolsPath)\DotNet\Microsoft.DotNet.Props')" />
<PropertyGroup Label="Globals">
<ProjectGuid>42dc6c97-6e79-4d0a-9a1d-dd34c99248e2</ProjectGuid>
<RootNamespace>Microsoft.Rest.CSharp.Compiler</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="..\..\..\tools\Autorest.xproj.targets"/>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="Exists('$(VSToolsPath)\DotNet\Microsoft.DotNet.targets')" />
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Microsoft.Rest.CSharp.Compiler.Compilation
{
public class CSharpCompiler : ManagedCompiler
{
private static readonly CSharpParseOptions parseOptions = new CSharpParseOptions(
LanguageVersion.CSharp6,
DocumentationMode.None);

public CSharpCompiler(IEnumerable<KeyValuePair<string, string>> sources,
IEnumerable<string> referencesAsFilenames)
: base(
Language.CSharp, sources,
referencesAsFilenames.Select(
each => MetadataReference.CreateFromFile(each, MetadataReferenceProperties.Assembly)))
{
}

protected sealed override CodeAnalysis.Compilation CreateCompilation(IEnumerable<SyntaxTree> syntaxTrees,
OutputKind outputKind, string outputName)
{
var compilation = CSharpCompilation.Create(
outputName,
syntaxTrees,
References,
GetCompilationOptions(outputKind));

return compilation;
}

protected sealed override IEnumerable<SyntaxTree> ParseSources()
{
var syntaxTrees =
from source in Sources
where !string.IsNullOrWhiteSpace(source.Value)
// ParseText throws a NullRefEx on empty files
select CSharpSyntaxTree.ParseText(source.Value, parseOptions, source.Key);

return syntaxTrees.ToList();
}

#region Helpers

public static CSharpCompilationOptions GetCompilationOptions(OutputKind outputKind)
{
switch (outputKind)
{
case OutputKind.ConsoleApplication:
return new CSharpCompilationOptions(
CodeAnalysis.OutputKind.ConsoleApplication,
allowUnsafe: false,
concurrentBuild: false,
optimizationLevel: OptimizationLevel.Debug);

case OutputKind.DynamicallyLinkedLibrary:
return new CSharpCompilationOptions(
CodeAnalysis.OutputKind.DynamicallyLinkedLibrary,
allowUnsafe: false,
concurrentBuild: false,
optimizationLevel: OptimizationLevel.Debug);

default:
throw new NotSupportedException();
}
}

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//

using System.Collections.Generic;
using System.IO;
using Microsoft.CodeAnalysis;

namespace Microsoft.Rest.CSharp.Compiler.Compilation
{
public struct CompilationResult
{
public bool Succeeded;

public string Reason;

public IEnumerable<Diagnostic> Messages;

public MemoryStream Output;

public OutputKind OutputKind;
}
}
108 changes: 108 additions & 0 deletions src/dev/AutoRest.Tooling.CSharp.Compiler/Compilation/Compiler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Rest.CSharp.Compiler.Compilation
{
public abstract class Compiler
{
/// <summary>
/// Default maximum compilation time
/// </summary>
public const int DefaultTimeout = 5000; //5s

protected Compiler(Language language, IEnumerable<KeyValuePair<string, string>> sources)
{
Language = language;
Parameters = new Dictionary<string, string>(StringComparer.Ordinal);
Sources = sources ?? new Dictionary<string, string>();
Timeout = DefaultTimeout;
}

/// <summary>
/// Supported language
/// </summary>
public Language Language { get; }

/// <summary>
/// Named parameters used by compiler, as appropriate
/// </summary>
public IDictionary<string, string> Parameters { get; }

/// <summary>
/// Source code
/// </summary>
public IEnumerable<KeyValuePair<string, string>> Sources { get; }

/// <summary>
/// Compilation timeout (in ms)
/// </summary>
/// <remarks>
/// This value represents the maximum time a compilation session can take
/// before being terminated.
/// </remarks>
public int Timeout { get; set; }

public async Task<CompilationResult> Compile(OutputKind outputKind, string outputName = null)
{
var cancellationTokenSource = new CancellationTokenSource();

try
{
var task = InnerCompile(outputKind, outputName, cancellationTokenSource.Token);
cancellationTokenSource.CancelAfter(Timeout);
return await task.ConfigureAwait(false);
}
catch (OperationCanceledException ocex)
{
if (cancellationTokenSource.IsCancellationRequested)
{
// Trace.TraceInformation("{0}:InnerCompile timed-out.", GetType().Name);
return new CompilationResult
{
Succeeded = false,
Reason = ResultReasons.TimedOutError,
// Messages = new[] {"Maximum compilation time reached"},
OutputKind = outputKind
};
}
else
{
// Trace.TraceWarning("{0}:InnerCompile was unexpectedly canceled. Exception: {1}", GetType().Name, ocex);
return new CompilationResult
{
Succeeded = false,
Reason = ResultReasons.CanceledError,
// Messages = new[] {"Compilation was canceled"},
OutputKind = outputKind
};
}
}
catch (Exception ex)
{
// Trace.TraceError("{0}:InnerCompile failed. Exception: {1}", GetType().Name, ex);
return new CompilationResult
{
Succeeded = false,
Reason = ResultReasons.UnknownError,
// Errors = new[] {"Unknown error"},
OutputKind = outputKind
};
}
finally
{
cancellationTokenSource.Dispose();
}
}

protected abstract Task<CompilationResult> InnerCompile(OutputKind outputKind, string outputName,
CancellationToken cancellationToken);
}
}
12 changes: 12 additions & 0 deletions src/dev/AutoRest.Tooling.CSharp.Compiler/Compilation/Language.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//

namespace Microsoft.Rest.CSharp.Compiler.Compilation
{
public enum Language
{
Unknown = 0,
CSharp = 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
//

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;

namespace Microsoft.Rest.CSharp.Compiler.Compilation
{
public static class ManagedAssets
{
public static string RuntimeDirectory => RuntimeEnvironment.GetRuntimeDirectory();

public static IEnumerable<string> FrameworkAssemblies => new[]
{
"mscorlib.dll",
"System.dll",
"System.Core.dll",
"System.Linq.Expressions.dll",
"System.Net.dll",
"System.Net.Http.dll",
"System.Runtime.dll",
"System.Threading.Tasks.dll",
"System.Xml.dll",
"System.Xml.Linq.dll",
"Microsoft.CSharp.dll"
}.Select(each => Path.Combine(RuntimeDirectory, each));

// Framework assemblies
private static readonly IEnumerable<MetadataReference> frameworkAssemblies =
LoadReferences(
RuntimeEnvironment.GetRuntimeDirectory(),
"mscorlib.dll",
"System.dll",
"System.Core.dll",
"System.Linq.Expressions.dll",
"System.Net.dll",
"System.Net.Http.dll",
"System.Runtime.dll",
"System.Threading.Tasks.dll",
"System.Xml.dll",
"System.Xml.Linq.dll",
"Microsoft.CSharp.dll");


public static IEnumerable<MetadataReference> All { get; } = frameworkAssemblies
.ToArray();

public static string ReferencesPath { get; } = "";

#region Helpers

private static string GetManifestResource(string name)
{
using (var reader = new StreamReader(
typeof(ManagedAssets).GetTypeInfo().Assembly.GetManifestResourceStream(name)))
{
return reader.ReadToEnd();
}
}

private static IEnumerable<MetadataReference> LoadReferences(string baseDirectory, params string[] assemblyNames)
{
var references =
from assemblyName in assemblyNames
let path = Path.Combine(baseDirectory, assemblyName)
select MetadataReference.CreateFromFile(path, MetadataReferenceProperties.Assembly);

return references.ToArray();
}

#endregion
}
}
Loading

0 comments on commit f4d008a

Please sign in to comment.