public async Task ReloadScript_WithInvalidCompilationAndMissingMethod_ReportsResults() { // Create the compilation exception we expect to throw during the reload var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny <IFunctionEntryPointResolver>())) .Throws(exception); dependencies.Compilation.Setup(c => c.Emit(It.IsAny <CancellationToken>())) .Returns(typeof(object).Assembly); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, Name = Guid.NewGuid().ToString(), ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <Script.Binding.FunctionBinding>(), new Collection <FunctionBinding>(), dependencies.EntrypointResolver.Object, new FunctionAssemblyLoader(string.Empty), dependencies.CompilationServiceFactory.Object, dependencies.TraceWriterFactory.Object); // Update the file to trigger a reload File.WriteAllText(filePath, string.Empty); await TestHelpers.Await(() => { return(dependencies.TraceWriter.Traces.Any(t => t.Message.Contains("Compilation failed.")) && dependencies.TraceWriter.Traces.Any(t => t.Message.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); dependencies.TraceWriter.Traces.Clear(); CompilationErrorException resultException = await Assert.ThrowsAsync <CompilationErrorException>(() => invoker.GetFunctionTargetAsync()); await TestHelpers.Await(() => { return(dependencies.TraceWriter.Traces.Any(t => t.Message.Contains("Function compilation error")) && dependencies.TraceWriter.Traces.Any(t => t.Message.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); }
private string Format(object?result) { return(result switch { string value => value, CompilationErrorException value => string.Join("\n", value.Diagnostics.Select(x => x.ToString())), Exception value => $"{value.GetType().Name}: {value.InnerException?.Message ?? value.Message}", _ => new InspectionFormatter(result).ToString() });
public async Task <CompilationErrorException> EvaluateCore(string code) { CompilationErrorException error = null; try { this.State = await this.State.ContinueWithAsync(code); } catch (CompilationErrorException cex) { error = cex; } catch (Exception ex) { this.OnError?.Invoke(ex.Message, ex); } return(error); }
private static ScriptResult FromCompilationException(CompilationErrorException ex) { return(new ScriptResult { CompilerErrors = ex.Diagnostics.Select( e => new CompilerError { Text = e.ToString(), SourceSpan = new TextSpan(e.Location.SourceSpan.Start, e.Location.SourceSpan.Length) }).ToArray() }); }
public void GetFunctionEntryPoint_WithNoPublicMethods_ThrowsCompilationException() { var resolver = new FunctionEntryPointResolver(); CompilationErrorException exc = Assert.Throws(typeof(CompilationErrorException), () => resolver.GetFunctionEntryPoint(new[] { new TestMethodReference("Run", false), new TestMethodReference("PrivateMethodName", false) })) as CompilationErrorException; var diagnostic = exc.Diagnostics.First(); Assert.Equal(DotNetConstants.MissingFunctionEntryPointCompilationCode, diagnostic.Id); }
// Evaluate without telling the delegates public async Task <CompilationErrorException> EvaluateSilently(string code) { CompilationErrorException error = null; try { ScriptState = await ScriptState.ContinueWithAsync(code); } catch (CompilationErrorException e) { error = e; } return(error); }
public void GetFunctionEntryPoint_WithMultiplePublicRunMethods_ThrowsCompilationException() { var resolver = new FunctionEntryPointResolver(); CompilationErrorException exc = Assert.Throws(typeof(CompilationErrorException), () => resolver.GetFunctionEntryPoint(new[] { new TestMethodReference("Run", true), new TestMethodReference("Run", true), new TestMethodReference("Run", true) })) as CompilationErrorException; var diagnostic = exc.Diagnostics.First(); Assert.Equal(DotNetConstants.AmbiguousFunctionEntryPointsCompilationCode, diagnostic.Id); }
public void GetFunctionEntryPoint_WithMissingNamedMethod_ThrowsCompilationException() { var resolver = new FunctionEntryPointResolver("NamedMethod"); CompilationErrorException exc = Assert.Throws(typeof(CompilationErrorException), () => resolver.GetFunctionEntryPoint(new[] { new TestMethodReference("Method1", true), new TestMethodReference("Method2", true), new TestMethodReference("NamedMethod", false) })) as CompilationErrorException; var diagnostic = exc.Diagnostics.First(); Assert.Equal(DotNetConstants.InvalidEntryPointNameCompilationCode, diagnostic.Id); }
private Exception CompileException(CompilationErrorException ex, string code) { Exception result = ex; var match = System.Text.RegularExpressions.Regex.Match(ex.Message, @"\(\s*(?<line>\d+)\s*,\s*(?<column>\d+)\s*\)\s*:\s*(?<message>.*)"); if (match.Success) { var lineNumber = int.Parse(match.Groups["line"].Value) - 1; var column = int.Parse(match.Groups["column"].Value) - 1; var line = code.Split('\n')[lineNumber]; var minCol = Math.Max(0, column - 20); var maxCol = Math.Min(line.Length, column + 20); var msg = line.Substring(minCol, column - minCol) + "^" + line.Substring(column, maxCol - column); result = new ArgumentException(match.Groups["message"].Value + ": " + msg); } return(result); }
public static EvalResult CreateErrorResult(string code, string consoleOut, TimeSpan compileTime, ImmutableArray <Diagnostic> compileErrors) { var ex = new CompilationErrorException(string.Join("\n", compileErrors.Select(a => a.GetMessage())), compileErrors); var errorResult = new EvalResult { Code = code, CompileTime = compileTime, ConsoleOut = consoleOut, Exception = ex.Message, ExceptionType = ex.GetType().Name, ExecutionTime = TimeSpan.FromMilliseconds(0), ReturnValue = null, ReturnTypeName = null }; return(errorResult); }
public async Task GetFunctionTargetAsync_CompilationError_ReportsResults() { // Create the compilation exception we expect to throw var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny <IFunctionEntryPointResolver>(), It.IsAny <Assembly>())) .Throws(exception); dependencies.Compilation.Setup(c => c.EmitAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(DotNetCompilationResult.FromPath(typeof(DotNetFunctionInvokerTests).Assembly.Location)); string functionName = Guid.NewGuid().ToString(); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), functionName); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = functionName, Language = DotNetScriptTypes.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host, metadata, new Collection <FunctionBinding>(), new Collection <FunctionBinding>(), dependencies.EntrypointResolver.Object, dependencies.CompilationServiceFactory.Object, dependencies.LoggerFactory, dependencies.MetricsLogger, new Collection <IScriptBindingProvider>()); // Send file change notification to trigger a reload var fileEventArgs = new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.GetTempPath(), Path.Combine(Path.GetFileName(rootFunctionsFolder), Path.GetFileName(filePath))); dependencies.Host.EventManager.Publish(new FileEvent(EventSources.ScriptFiles, fileEventArgs)); LogMessage[] logMessages = null; var loggerProvider = dependencies.LoggerProvider; await TestHelpers.Await(() => { logMessages = loggerProvider.GetAllLogMessages().ToArray(); return(logMessages.Any(t => t.FormattedMessage.Contains("Compilation failed.")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); // verify expected logs when the function target is retrieved // NOT on the invocation path dependencies.LoggerProvider.ClearAllLogMessages(); await Assert.ThrowsAsync <CompilationErrorException>(async() => { await invoker.GetFunctionTargetAsync(); }); Assert.Equal(3, logMessages.Length); Assert.Equal($"Script for function '{functionName}' changed. Reloading.", logMessages[0].FormattedMessage); Assert.Equal(LogLevel.Information, logMessages[0].Level); Assert.Equal("error AF001: Test compilation error", logMessages[1].FormattedMessage); Assert.Equal(LogLevel.Error, logMessages[1].Level); Assert.True(logMessages[1].State.Any(q => q.Key == ScriptConstants.LogPropertyIsUserLogKey)); Assert.Equal("Compilation failed.", logMessages[2].FormattedMessage); Assert.Equal(LogLevel.Information, logMessages[2].Level); Assert.True(logMessages.All(p => p.State.Any(q => q.Key == ScriptConstants.LogPropertyPrimaryHostKey))); await TestHelpers.Await(() => { logMessages = loggerProvider.GetAllLogMessages().ToArray(); return(logMessages.Any(t => t.FormattedMessage.Contains("Function compilation error")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); // now test the invoke path and verify that the compilation error // details are written loggerProvider.ClearAllLogMessages(); await Assert.ThrowsAsync <CompilationErrorException>(async() => { await invoker.GetFunctionTargetAsync(isInvocation: true); }); logMessages = loggerProvider.GetAllLogMessages().ToArray(); Assert.Equal(2, logMessages.Length); Assert.Equal("Function compilation error", logMessages[0].FormattedMessage); Assert.Equal(LogLevel.Error, logMessages[0].Level); Assert.Same("Test compilation exception", logMessages[0].Exception.Message); Assert.Equal("error AF001: Test compilation error", logMessages[1].FormattedMessage); Assert.Equal(LogLevel.Error, logMessages[1].Level); Assert.True(logMessages[1].State.Any(q => q.Key == ScriptConstants.LogPropertyIsUserLogKey)); Assert.True(logMessages.All(p => !(p.State != null && p.State.Any(q => q.Key == ScriptConstants.LogPropertyPrimaryHostKey)))); }
public ErrorLine(Exception ex, bool isWarning = false) { InitializeComponent(); this.FindControl <MyExpandable>("expander").ExpandedChanged += ExpandedChanged; InputTextBox headerBox; this.FindControl <MyExpandable>("expander").Header = headerBox = new InputTextBox() { FontSize = 12, Background = null, BorderThickness = new Thickness(0, 0, 0, 0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, Margin = new Thickness(-5, 0, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)) }; if (isWarning) { this.FindControl <Canvas>("errorIcon").IsVisible = false; this.FindControl <Canvas>("warningIcon").IsVisible = true; this.FindControl <Canvas>("background").Background = new SolidColorBrush(Color.FromRgb(255, 251, 230)); this.FindControl <Canvas>("border1").Background = new SolidColorBrush(Color.FromRgb(255, 245, 194)); this.FindControl <Canvas>("border2").Background = new SolidColorBrush(Color.FromRgb(255, 245, 194)); headerBox.Foreground = new SolidColorBrush(Color.FromRgb(149, 127, 81)); } headerBox.Text = ex.Message; if (ex is CompilationErrorException) { CompilationErrorException err = ((CompilationErrorException)ex); if (err.Diagnostics.Length == 1) { headerBox.Text = err.GetType().Name + ": " + err.Diagnostics[0].GetMessage(); FileLinePositionSpan lineSpan = err.Diagnostics[0].Location.GetMappedLineSpan(); this.FindControl <InputTextBox>("locationBox").Text = " " + err.Diagnostics[0].Id + " at " + lineSpan.Path + (!string.IsNullOrEmpty(lineSpan.Path) ? ":" : "") + (lineSpan.StartLinePosition.Line + 1).ToString() + ":" + (lineSpan.StartLinePosition.Character + 1).ToString(); this.FindControl <InputTextBox>("lineBox").Text = " " + err.Diagnostics[0].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().Replace("\t", " "); this.FindControl <InputTextBox>("positionBox").Text = " " + new string(' ', err.Diagnostics[0].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().CountCharsUpToPosition(lineSpan.StartLinePosition.Character)) + "^"; } else { this.FindControl <Grid>("detailsGrid").Children.Clear(); this.FindControl <Grid>("detailsGrid").RowDefinitions.Clear(); headerBox.Text = err.GetType().Name + "[" + err.Diagnostics.Length.ToString() + "]"; for (int i = 0; i < err.Diagnostics.Length; i++) { this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); InputTextBox message = new InputTextBox() { Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)) }; Grid.SetRow(message, i * 4); Grid.SetColumn(message, 1); message.Text = "• " + err.Diagnostics[i].GetMessage(); InputTextBox location = new InputTextBox() { Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), MyReadOnly = true }; Grid.SetRow(location, i * 4 + 1); Grid.SetColumn(location, 1); FileLinePositionSpan lineSpan = err.Diagnostics[i].Location.GetMappedLineSpan(); location.Text = " " + err.Diagnostics[i].Id + " at " + lineSpan.Path + (!string.IsNullOrEmpty(lineSpan.Path) ? ":" : "") + (lineSpan.StartLinePosition.Line + 1).ToString() + ":" + (lineSpan.StartLinePosition.Character + 1).ToString(); InputTextBox line = new InputTextBox() { Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), Margin = new Thickness(8, 4, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(0x3F, 0x48, 0xCC)) }; Grid.SetRow(line, i * 4 + 2); Grid.SetColumn(line, 1); line.Text = " " + err.Diagnostics[i].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().Replace("\t", " "); InputTextBox position = new InputTextBox() { Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), Margin = new Thickness(8, -5, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0)) }; Grid.SetRow(position, i * 4 + 3); Grid.SetColumn(position, 1); position.Text = " " + new string(' ', err.Diagnostics[i].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().CountCharsUpToPosition(lineSpan.StartLinePosition.Character)) + "^"; this.FindControl <Grid>("detailsGrid").Children.Add(message); this.FindControl <Grid>("detailsGrid").Children.Add(location); this.FindControl <Grid>("detailsGrid").Children.Add(line); this.FindControl <Grid>("detailsGrid").Children.Add(position); } } } else { headerBox.Text = ex.GetType().Name + ": " + ex.Message; this.FindControl <Grid>("detailsGrid").Children.Clear(); this.FindControl <Grid>("detailsGrid").RowDefinitions.Clear(); this.FindControl <Grid>("detailsGrid").ColumnDefinitions.Clear(); this.FindControl <Grid>("detailsGrid").Margin = new Thickness(20, 0, 0, 0); this.FindControl <Grid>("detailsGrid").Children.Add(CSharpOutputLine.contentElement(ex)); } }
private void OnEvaluationError(string output, CompilationErrorException error) { Content.Add(new OutputItem(output)); ScrollToEnd(); }
private void AddCompileErrorMessage(CompilationErrorException exp) { AddMessage(ScriptMessageType.Error, exp.Message); }
public async Task ReloadScript_WithInvalidCompilationAndMissingMethod_ReportsResults() { // Create the compilation exception we expect to throw during the reload var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny <IFunctionEntryPointResolver>(), It.IsAny <Assembly>())) .Throws(exception); dependencies.Compilation.Setup(c => c.EmitAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(DotNetCompilationResult.FromPath(typeof(DotNetFunctionInvokerTests).Assembly.Location)); string functionName = Guid.NewGuid().ToString(); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), functionName); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = functionName, ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <Script.Binding.FunctionBinding>(), new Collection <FunctionBinding>(), dependencies.EntrypointResolver.Object, dependencies.CompilationServiceFactory.Object); // Send file change notification to trigger a reload var fileEventArgs = new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.GetTempPath(), Path.Combine(Path.GetFileName(rootFunctionsFolder), Path.GetFileName(filePath))); dependencies.Host.Object.EventManager.Publish(new FileEvent(EventSources.ScriptFiles, fileEventArgs)); await TestHelpers.Await(() => { IEnumerable <LogMessage> logMessages = dependencies.LoggerProvider.GetAllLogMessages(); return(logMessages.Any(t => t.FormattedMessage.Contains("Compilation failed.")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); dependencies.LoggerProvider.ClearAllLogMessages(); CompilationErrorException resultException = await Assert.ThrowsAsync <CompilationErrorException>(() => invoker.GetFunctionTargetAsync()); await TestHelpers.Await(() => { IEnumerable <LogMessage> logMessages = dependencies.LoggerProvider.GetAllLogMessages(); return(logMessages.Any(t => t.FormattedMessage.Contains("Function compilation error")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); }
public static CompilerError[] ArrayFromException(CompilationErrorException exception) { return(ArrayFromDiagnostics(exception.Diagnostics)); }