Add first unit tests
Refactor code to be more easy to test
This commit is contained in:
Родитель
a86bcbcc85
Коммит
aaca2c1893
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
@ -20,32 +21,48 @@ namespace XAMLator.Client
|
|||
string text,
|
||||
SyntaxTree syntaxTree,
|
||||
SemanticModel semanticModel)
|
||||
{
|
||||
{
|
||||
XAMLDocument xamlDocument = null;
|
||||
FormsViewClassDeclaration xamlClass = null;
|
||||
bool created;
|
||||
|
||||
// FIXME: Support any kind of types, not just Xamarin.Forms views
|
||||
if (!fileName.EndsWith(".xaml") && !fileName.EndsWith(".xaml.cs"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!GetOrCreate(fileName, text, syntaxTree, semanticModel,
|
||||
out FormsViewClassDeclaration xamlClass,
|
||||
out XAMLDocument xamlDocument))
|
||||
// Check if we have already an instance of the class declaration for that file
|
||||
if (!FormsViewClassDeclaration.TryGetByFileName(fileName, out xamlClass))
|
||||
{
|
||||
if (fileName.EndsWith(".xaml"))
|
||||
{
|
||||
xamlDocument = XAMLDocument.Parse(fileName, text);
|
||||
// Check if we have an instance of class by namespace
|
||||
if (!FormsViewClassDeclaration.TryGetByFullNamespace(xamlDocument.Type, out xamlClass))
|
||||
{
|
||||
xamlClass = await CreateFromXaml(xamlDocument);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xamlClass = await CreateFromCodeBehind(fileName, syntaxTree, semanticModel);
|
||||
}
|
||||
}
|
||||
|
||||
if (xamlClass == null)
|
||||
{
|
||||
Log.Error("Could not handle document update");
|
||||
return null;
|
||||
}
|
||||
|
||||
// The document is a XAML file
|
||||
if (fileName.EndsWith(".xaml"))
|
||||
if (fileName.EndsWith(".xaml") && xamlDocument == null)
|
||||
{
|
||||
if (xamlDocument == null)
|
||||
{
|
||||
xamlDocument = XAMLDocument.Parse(fileName, text);
|
||||
}
|
||||
xamlDocument = XAMLDocument.Parse(fileName, text);
|
||||
await xamlClass.UpdateXaml(xamlDocument);
|
||||
}
|
||||
// The document is code behind
|
||||
else if (fileName.EndsWith(".xaml.cs"))
|
||||
if (fileName.EndsWith(".xaml.cs"))
|
||||
{
|
||||
var classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, xamlClass.ClassName);
|
||||
if (xamlClass.NeedsClassInitialization)
|
||||
|
@ -55,78 +72,48 @@ namespace XAMLator.Client
|
|||
xamlClass.UpdateCode(classDeclaration);
|
||||
}
|
||||
return xamlClass;
|
||||
}
|
||||
|
||||
static async Task<FormsViewClassDeclaration> CreateFromXaml(XAMLDocument xamlDocument)
|
||||
|
||||
{
|
||||
string codeBehindFilePath = xamlDocument.FilePath + ".cs";
|
||||
if (!File.Exists(codeBehindFilePath))
|
||||
{
|
||||
Log.Error("XAML file without code behind");
|
||||
return null;
|
||||
}
|
||||
var xamlClass = new FormsViewClassDeclaration(codeBehindFilePath, xamlDocument);
|
||||
await xamlClass.UpdateXaml(xamlDocument);
|
||||
return xamlClass;
|
||||
}
|
||||
|
||||
static async Task<FormsViewClassDeclaration> CreateFromCodeBehind(string fileName,
|
||||
SyntaxTree syntaxTree, SemanticModel semanticModel)
|
||||
|
||||
static bool GetOrCreate(string fileName,
|
||||
string text,
|
||||
SyntaxTree syntaxTree,
|
||||
SemanticModel semanticModel,
|
||||
out FormsViewClassDeclaration xamlClass,
|
||||
out XAMLDocument xamlDocument)
|
||||
{
|
||||
string xaml = null, xamlFilePath = null, codeBehindFilePath = null;
|
||||
xamlDocument = null;
|
||||
string xaml = null, xamlFilePath = null, codeBehindFilePath = null;
|
||||
XAMLDocument xamlDocument;
|
||||
|
||||
// Check if we have already an instance of the class declaration for that file
|
||||
if (FormsViewClassDeclaration.TryGetByFileName(fileName, out xamlClass))
|
||||
codeBehindFilePath = fileName;
|
||||
var xamlCandidate = fileName.Substring(0, fileName.Length - 3);
|
||||
if (File.Exists(xamlCandidate))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fileName.EndsWith(".xaml"))
|
||||
{
|
||||
xaml = text;
|
||||
xamlFilePath = fileName;
|
||||
var candidate = xamlFilePath + ".cs";
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
codeBehindFilePath = candidate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
codeBehindFilePath = fileName;
|
||||
var candidate = fileName.Substring(0, fileName.Length - 3);
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
xamlFilePath = candidate;
|
||||
xaml = File.ReadAllText(xamlFilePath);
|
||||
}
|
||||
xamlFilePath = xamlCandidate;
|
||||
xaml = File.ReadAllText(xamlFilePath);
|
||||
}
|
||||
|
||||
// FIXME: Handle XF views without XAML
|
||||
// Parse the XAML file
|
||||
xamlDocument = XAMLDocument.Parse(xamlFilePath, xaml);
|
||||
if (xamlDocument == null)
|
||||
{
|
||||
Log.Error("Error parsing XAML");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we have an instance of class by namespace
|
||||
if (FormsViewClassDeclaration.TryGetByFullNamespace(xamlDocument.Type, out xamlClass))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
var className = xamlDocument.Type.Split('.').Last();
|
||||
var classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, className);
|
||||
var xamlClass = new FormsViewClassDeclaration(classDeclaration, semanticModel,
|
||||
codeBehindFilePath, xamlDocument);
|
||||
|
||||
// This is the first time we have an update for this type
|
||||
|
||||
// Create a new class declaration instance from the syntax tree
|
||||
if (syntaxTree != null)
|
||||
{
|
||||
var className = xamlDocument.Type.Split('.').Last();
|
||||
var classDeclaration = FormsViewClassDeclaration.FindClass(syntaxTree, className);
|
||||
xamlClass = new FormsViewClassDeclaration(classDeclaration, semanticModel,
|
||||
codeBehindFilePath, xamlDocument);
|
||||
}
|
||||
// Create a new class declaration instance from the XAML
|
||||
else
|
||||
{
|
||||
xamlClass = new FormsViewClassDeclaration(codeBehindFilePath, xamlDocument);
|
||||
|
||||
}
|
||||
return true;
|
||||
await xamlClass.UpdateXaml(xamlDocument);
|
||||
return xamlClass;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,15 @@ namespace XAMLator.Client
|
|||
/// <summary>
|
||||
/// The xaml classes.
|
||||
/// </summary>
|
||||
static readonly List<FormsViewClassDeclaration> classesCache = new List<FormsViewClassDeclaration>();
|
||||
internal static readonly List<FormsViewClassDeclaration> classesCache = new List<FormsViewClassDeclaration>();
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cache.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
{
|
||||
classesCache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a cached class declaration with the same full namespace.
|
||||
|
@ -91,7 +99,6 @@ namespace XAMLator.Client
|
|||
this.xamlFilePath = xaml.FilePath;
|
||||
StyleSheets = new Dictionary<string, string>();
|
||||
FillClassInfo(classDeclarationSyntax, model);
|
||||
UpdateXaml(xaml);
|
||||
UpdateCode(classDeclarationSyntax);
|
||||
classesCache.Add(this);
|
||||
}
|
||||
|
@ -110,7 +117,6 @@ namespace XAMLator.Client
|
|||
Namespace = xaml.Type.Substring(0, xaml.Type.LastIndexOf('.'));
|
||||
ClassName = xaml.Type.Split('.').Last();
|
||||
classesCache.Add(this);
|
||||
UpdateXaml(xaml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -203,6 +209,10 @@ namespace XAMLator.Client
|
|||
/// <param name="xaml">Xaml.</param>
|
||||
internal async Task UpdateXaml(XAMLDocument xaml)
|
||||
{
|
||||
if (Xaml == xaml.XAML)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Xaml = xaml.XAML;
|
||||
LoadStyleSheets(xaml);
|
||||
await UpdateAutoGeneratedCodeBehind();
|
||||
|
@ -324,9 +334,7 @@ namespace XAMLator.Client
|
|||
void FillPartials()
|
||||
{
|
||||
partials = symbol.Locations
|
||||
.Where(l =>
|
||||
l.SourceTree.FilePath != codeBehindFilePath &&
|
||||
l.SourceTree.FilePath != autoGenCodeBehindFilePath)
|
||||
.Where(FileIsPartial)
|
||||
.SelectMany(l => FindClass(l.SourceTree, classDeclarationSyntax.Identifier.Text).Members)
|
||||
.ToList();
|
||||
}
|
||||
|
@ -432,7 +440,7 @@ namespace XAMLator.Client
|
|||
/// Rewrites the autogenerated code constructor replace the LoadFromXaml
|
||||
/// call that reads the XAML fro the assembly resources for a call to
|
||||
/// <see cref="XAMLator.Server.VM.LoadXaml"/> that loads the XAML from
|
||||
/// the <see cref="EvalRequest"/>
|
||||
/// the <see cref="EvalRequestMessage"/>
|
||||
/// </summary>
|
||||
/// <returns>The autogenerated code constructor.</returns>
|
||||
/// <param name="classDeclaration">Class declaration.</param>
|
||||
|
@ -453,6 +461,13 @@ namespace XAMLator.Client
|
|||
return classDeclaration.ReplaceNode(loadFromXaml, newLoadXaml);
|
||||
}
|
||||
|
||||
bool FileIsPartial(Location location)
|
||||
{
|
||||
|
||||
return location.SourceTree.FilePath != codeBehindFilePath &&
|
||||
location.SourceTree.FilePath != autoGenCodeBehindFilePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a class for the given name in a syntax tree.
|
||||
/// </summary>
|
||||
|
|
|
@ -27,33 +27,25 @@ namespace XAMLator
|
|||
|
||||
public static XAMLDocument Parse(string filePath, string xaml)
|
||||
{
|
||||
try
|
||||
using (var stream = new StringReader(xaml))
|
||||
{
|
||||
using (var stream = new StringReader(xaml))
|
||||
{
|
||||
var reader = XmlReader.Create(stream);
|
||||
var xdoc = XDocument.Load(reader);
|
||||
XNamespace x = "http://schemas.microsoft.com/winfx/2009/xaml";
|
||||
XNamespace xm = "http://xamarin.com/schemas/2014/forms";
|
||||
var classAttribute = xdoc.Root.Attribute(x + "Class");
|
||||
CleanAutomationIds(xdoc.Root);
|
||||
var styleSheetElements = xdoc.Root
|
||||
.Descendants()
|
||||
.Where(e => e.Name.ToString().EndsWith("StyleSheet"));
|
||||
CleanStyleSheets(styleSheetElements);
|
||||
var styleSheets = styleSheetElements
|
||||
.Select(e => e.Attribute("Source"))
|
||||
.Where(e => e != null)
|
||||
.Select(e => e.Value)
|
||||
.ToList();
|
||||
xaml = xdoc.ToString();
|
||||
return new XAMLDocument(filePath, xaml, classAttribute.Value, styleSheets);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception(ex);
|
||||
return null;
|
||||
var reader = XmlReader.Create(stream);
|
||||
var xdoc = XDocument.Load(reader);
|
||||
XNamespace x = "http://schemas.microsoft.com/winfx/2009/xaml";
|
||||
XNamespace xm = "http://xamarin.com/schemas/2014/forms";
|
||||
var classAttribute = xdoc.Root.Attribute(x + "Class");
|
||||
CleanAutomationIds(xdoc.Root);
|
||||
var styleSheetElements = xdoc.Root
|
||||
.Descendants()
|
||||
.Where(e => e.Name.ToString().EndsWith("StyleSheet"));
|
||||
CleanStyleSheets(styleSheetElements);
|
||||
var styleSheets = styleSheetElements
|
||||
.Select(e => e.Attribute("Source"))
|
||||
.Where(e => e != null)
|
||||
.Select(e => e.Value)
|
||||
.ToList();
|
||||
xaml = xdoc.ToString();
|
||||
return new XAMLDocument(filePath, xaml, classAttribute.Value, styleSheets);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace XAMLator.Client
|
|||
{
|
||||
public class XAMLatorMonitor
|
||||
{
|
||||
TcpCommunicatorServer server;
|
||||
ITcpCommunicatorServer server;
|
||||
|
||||
public static XAMLatorMonitor Init(IIDE ide)
|
||||
{
|
||||
|
@ -14,19 +14,28 @@ namespace XAMLator.Client
|
|||
|
||||
public static XAMLatorMonitor Instance { get; private set; }
|
||||
|
||||
XAMLatorMonitor(IIDE ide)
|
||||
internal XAMLatorMonitor(IIDE ide, ITcpCommunicatorServer server = null)
|
||||
{
|
||||
IDE = ide;
|
||||
server = new TcpCommunicatorServer(Constants.DEFAULT_PORT);
|
||||
if (server == null)
|
||||
{
|
||||
server = new TcpCommunicatorServer();
|
||||
}
|
||||
this.server = server;
|
||||
ide.DocumentChanged += HandleDocumentChanged;
|
||||
}
|
||||
|
||||
public IIDE IDE { get; private set; }
|
||||
|
||||
public void StartMonitoring()
|
||||
{
|
||||
StartMonitoring(Constants.DEFAULT_PORT);
|
||||
}
|
||||
|
||||
internal void StartMonitoring(int port)
|
||||
{
|
||||
IDE.MonitorEditorChanges();
|
||||
server.StartListening();
|
||||
server.StartListening(port);
|
||||
}
|
||||
|
||||
async void HandleDocumentChanged(object sender, DocumentChangedEventArgs e)
|
||||
|
@ -36,25 +45,33 @@ namespace XAMLator.Client
|
|||
return;
|
||||
}
|
||||
|
||||
var classDecl = await DocumentParser.ParseDocument(e.Filename, e.Text, e.SyntaxTree, e.SemanticModel);
|
||||
|
||||
if (classDecl == null)
|
||||
try
|
||||
{
|
||||
return;
|
||||
var classDecl = await DocumentParser.ParseDocument(e.Filename, e.Text, e.SyntaxTree, e.SemanticModel);
|
||||
|
||||
if (classDecl == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EvalRequestMessage request = new EvalRequestMessage
|
||||
{
|
||||
Declarations = classDecl.Code,
|
||||
NeedsRebuild = classDecl.NeedsRebuild,
|
||||
OriginalTypeName = classDecl.FullNamespace,
|
||||
NewTypeName = classDecl.CurrentFullNamespace,
|
||||
Xaml = classDecl.Xaml,
|
||||
XamlResourceName = classDecl.XamlResourceId,
|
||||
StyleSheets = classDecl.StyleSheets
|
||||
};
|
||||
await server.Send(request);
|
||||
}
|
||||
|
||||
EvalRequest request = new EvalRequest
|
||||
catch (Exception ex)
|
||||
{
|
||||
Declarations = classDecl.Code,
|
||||
NeedsRebuild = classDecl.NeedsRebuild,
|
||||
OriginalTypeName = classDecl.FullNamespace,
|
||||
NewTypeName = classDecl.CurrentFullNamespace,
|
||||
Xaml = classDecl.Xaml,
|
||||
XamlResourceName = classDecl.XamlResourceId,
|
||||
StyleSheets = classDecl.StyleSheets
|
||||
};
|
||||
|
||||
await server.Send(request);
|
||||
Log.Exception(ex);
|
||||
await server.Send(new ErrorMessage($"Error parsing {e.Filename}",
|
||||
ex.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,25 @@ using System.ComponentModel;
|
|||
|
||||
namespace XAMLator
|
||||
{
|
||||
public class EvalRequest
|
||||
public class Message
|
||||
{
|
||||
public string Type => GetType().Name;
|
||||
}
|
||||
|
||||
public class ErrorMessage : Message
|
||||
{
|
||||
public ErrorMessage(string title, string exception)
|
||||
{
|
||||
Title = title;
|
||||
Exception = exception;
|
||||
}
|
||||
|
||||
public string Title { get; }
|
||||
|
||||
public string Exception { get; }
|
||||
}
|
||||
|
||||
public class EvalRequestMessage : Message
|
||||
{
|
||||
public string Declarations;
|
||||
public string NewTypeName;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator
|
||||
{
|
||||
public interface ITcpCommunicator
|
||||
{
|
||||
event EventHandler<object> DataReceived;
|
||||
|
||||
Task<bool> Send<T>(T obj);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator
|
||||
{
|
||||
public interface ITcpCommunicatorClient : ITcpCommunicator
|
||||
{
|
||||
Task<bool> Connect(string ip, int port);
|
||||
|
||||
void Disconnect();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator
|
||||
{
|
||||
public interface ITcpCommunicatorServer : ITcpCommunicator
|
||||
{
|
||||
event EventHandler ClientConnected;
|
||||
|
||||
int ClientsCount { get; }
|
||||
|
||||
Task<bool> StartListening(int serverPort);
|
||||
|
||||
void StopListening();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator
|
||||
{
|
||||
public interface IUIToolkit
|
||||
{
|
||||
Task RunInUIThreadAsync(Func<Task> action);
|
||||
|
||||
void RunInUIThread(Action action);
|
||||
}
|
||||
}
|
|
@ -8,22 +8,18 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace XAMLator
|
||||
{
|
||||
public class TcpCommunicatorServer : TcpCommunicator
|
||||
public class TcpCommunicatorServer : TcpCommunicator, ITcpCommunicatorServer
|
||||
{
|
||||
int serverPort;
|
||||
TcpListener listener;
|
||||
|
||||
public event EventHandler ClientConnected;
|
||||
|
||||
public TcpCommunicatorServer(int serverPort)
|
||||
{
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public int ClientsCount => clients.Count;
|
||||
|
||||
public Task<bool> StartListening()
|
||||
public Task<bool> StartListening(int serverPort)
|
||||
{
|
||||
this.serverPort = serverPort;
|
||||
var taskCompletion = new TaskCompletionSource<bool>();
|
||||
Task.Factory.StartNew(() => Run(taskCompletion), TaskCreationOptions.LongRunning);
|
||||
return taskCompletion.Task;
|
||||
|
@ -68,7 +64,7 @@ namespace XAMLator
|
|||
}
|
||||
}
|
||||
|
||||
public class TcpCommunicatorClient : TcpCommunicator
|
||||
public class TcpCommunicatorClient : TcpCommunicator, ITcpCommunicatorClient
|
||||
{
|
||||
TcpClient client;
|
||||
|
||||
|
@ -89,7 +85,7 @@ namespace XAMLator
|
|||
}
|
||||
}
|
||||
|
||||
public abstract class TcpCommunicator
|
||||
public abstract class TcpCommunicator : ITcpCommunicator
|
||||
{
|
||||
string pendingmsg;
|
||||
protected ConcurrentDictionary<Guid, Tuple<TcpClient, CancellationTokenSource>> clients = new ConcurrentDictionary<Guid, Tuple<TcpClient, CancellationTokenSource>>();
|
||||
|
|
|
@ -17,5 +17,9 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)ExtensionMethods.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)NetworkUtils.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)TcpCommunicator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ITcpCommunicatorServer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ITcpCommunicator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ITcpCommunicatorClient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IUIToolkit.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,4 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("XAMLator.Server.Tests")]
|
||||
|
|
@ -44,10 +44,15 @@ namespace XAMLator.Server
|
|||
}
|
||||
}
|
||||
|
||||
public void SetError(string title, string ex)
|
||||
{
|
||||
Error = ex;
|
||||
Title = title;
|
||||
}
|
||||
|
||||
public void SetError(string title, Exception ex)
|
||||
{
|
||||
Error = ex.ToString();
|
||||
Title = title;
|
||||
SetError(title, ex.ToString());
|
||||
}
|
||||
|
||||
public void SetError(string title, EvalResult result)
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace XAMLator.Server
|
|||
/// <returns>True if succeeded.</returns>
|
||||
/// <param name="code">The class code.</param>
|
||||
/// <param name="result">Eval result.</param>
|
||||
Task<bool> EvaluateCode(string code, EvalResult result);
|
||||
Task<bool> EvaluateCode(string code, EvalResult result, string extraCode = null);
|
||||
|
||||
/// <summary>
|
||||
/// Check if evaluation is supported. This can fail in iOS real devices
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace XAMLator.Server
|
|||
|
||||
public bool IsEvaluationSupported => isEvaluationSupported;
|
||||
|
||||
public Task<bool> EvaluateCode(string code, EvalResult result)
|
||||
public Task<bool> EvaluateCode(string code, EvalResult result, string initCode = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(code))
|
||||
{
|
||||
|
@ -42,8 +42,11 @@ namespace XAMLator.Server
|
|||
try
|
||||
{
|
||||
printer.Reset();
|
||||
eval.Evaluate(code, out object retResult, out bool result_set);
|
||||
result.Result = retResult;
|
||||
if (initCode != null)
|
||||
{
|
||||
eval.Evaluate(initCode, out object retResult, out bool result_set);
|
||||
}
|
||||
result.Result = eval.Evaluate(code);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
@ -22,32 +19,41 @@ namespace XAMLator.Server
|
|||
TaskScheduler mainScheduler;
|
||||
IPreviewer previewer;
|
||||
bool isRunning;
|
||||
TcpCommunicatorClient client;
|
||||
ITcpCommunicatorClient client;
|
||||
ErrorViewModel errorViewModel;
|
||||
IUIToolkit uiToolkit;
|
||||
|
||||
internal static PreviewServer Instance => serverInstance;
|
||||
|
||||
PreviewServer()
|
||||
internal PreviewServer()
|
||||
{
|
||||
client = new TcpCommunicatorClient();
|
||||
client.DataReceived += HandleDataReceived;
|
||||
errorViewModel = new ErrorViewModel();
|
||||
}
|
||||
|
||||
public static Task<bool> Run(Dictionary<Type, object> viewModelsMapping = null,
|
||||
IPreviewer previewer = null, string ideIP = null, int idePort = Constants.DEFAULT_PORT)
|
||||
{
|
||||
return Instance.RunInternal(viewModelsMapping, previewer, ideIP, idePort);
|
||||
return Instance.RunInternal(viewModelsMapping, previewer, ideIP, idePort,
|
||||
new UIToolkit(), new TcpCommunicatorClient());
|
||||
}
|
||||
|
||||
internal async Task<bool> RunInternal(Dictionary<Type, object> viewModelsMapping,
|
||||
IPreviewer previewer, string ideIP, int idePort)
|
||||
IPreviewer previewer, string ideIP, int idePort, IUIToolkit uiToolkit, ITcpCommunicatorClient client)
|
||||
{
|
||||
if (isRunning)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
this.uiToolkit = uiToolkit;
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
client = new TcpCommunicatorClient();
|
||||
}
|
||||
this.client = client;
|
||||
client.DataReceived += HandleDataReceived;
|
||||
|
||||
mainScheduler = TaskScheduler.FromCurrentSynchronizationContext();
|
||||
await RegisterDevice(ideIP, idePort);
|
||||
if (viewModelsMapping == null)
|
||||
|
@ -98,38 +104,49 @@ namespace XAMLator.Server
|
|||
|
||||
async void HandleDataReceived(object sender, object e)
|
||||
{
|
||||
await HandleEvalRequest((e as JContainer).ToObject<EvalRequest>());
|
||||
var container = e as JContainer;
|
||||
string type = (string)container["Type"];
|
||||
|
||||
if (type == typeof(EvalRequestMessage).Name)
|
||||
{
|
||||
await HandleEvalRequest(container.ToObject<EvalRequestMessage>());
|
||||
}
|
||||
else if (type == typeof(ErrorMessage).Name)
|
||||
{
|
||||
var errorMessage = container.ToObject<ErrorMessage>();
|
||||
await uiToolkit.RunInUIThreadAsync(async () =>
|
||||
{
|
||||
errorViewModel.SetError("Oh no! An exception!", errorMessage.Exception);
|
||||
await previewer.NotifyError(errorViewModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async Task HandleEvalRequest(EvalRequest request)
|
||||
async Task HandleEvalRequest(EvalRequestMessage request)
|
||||
{
|
||||
EvalResponse evalResponse = new EvalResponse();
|
||||
EvalResult result;
|
||||
try
|
||||
{
|
||||
result = await vm.Eval(request, mainScheduler, CancellationToken.None);
|
||||
if (result.ResultType != null)
|
||||
if (result.HasResult || result.ResultType != null)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await previewer.Preview(result);
|
||||
tcs.SetResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorViewModel.SetError("Oh no! An exception!", ex);
|
||||
await previewer.NotifyError(errorViewModel);
|
||||
tcs.SetException(ex);
|
||||
}
|
||||
});
|
||||
await tcs.Task;
|
||||
await uiToolkit.RunInUIThreadAsync(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await previewer.Preview(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorViewModel.SetError("Oh no! An exception!", ex);
|
||||
await previewer.NotifyError(errorViewModel);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
|
||||
await uiToolkit.RunInUIThreadAsync(async () =>
|
||||
{
|
||||
errorViewModel.SetError("Oh no! An evaluation error!", result);
|
||||
await previewer.NotifyError(errorViewModel);
|
||||
|
|
|
@ -44,6 +44,34 @@ namespace XAMLator.Server
|
|||
{
|
||||
Log.Information($"Visualizing result {res.ResultType}");
|
||||
|
||||
Page page = CreateViewFromResult(res);
|
||||
if (page != null)
|
||||
{
|
||||
await PreviewPage(page);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task NotifyError(ErrorViewModel errorViewModel)
|
||||
{
|
||||
await EnsurePresented();
|
||||
errorViewModel.CloseCommand = closeCommand;
|
||||
errorPage.BindingContext = errorViewModel;
|
||||
previewPage.ChangePage(errorPage);
|
||||
}
|
||||
|
||||
protected virtual async Task PreviewPage(Page page)
|
||||
{
|
||||
await EnsurePresented();
|
||||
NavigationPage.SetHasNavigationBar(previewPage, true);
|
||||
previewPage.ChangePage(page);
|
||||
}
|
||||
|
||||
protected virtual Page CreateViewFromResult(EvalResult res)
|
||||
{
|
||||
if (res.HasResult)
|
||||
{
|
||||
return res.Result as Page;
|
||||
}
|
||||
var result = TypeActivator(res.ResultType);
|
||||
Page page = result as Page;
|
||||
if (page == null && result is View view)
|
||||
|
@ -56,18 +84,8 @@ namespace XAMLator.Server
|
|||
{
|
||||
page.BindingContext = viewModel;
|
||||
}
|
||||
await EnsurePresented();
|
||||
NavigationPage.SetHasNavigationBar(previewPage, true);
|
||||
previewPage.ChangePage(page);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task NotifyError(ErrorViewModel errorViewModel)
|
||||
{
|
||||
await EnsurePresented();
|
||||
errorViewModel.CloseCommand = closeCommand;
|
||||
errorPage.BindingContext = errorViewModel;
|
||||
previewPage.ChangePage(errorPage);
|
||||
return page;
|
||||
}
|
||||
|
||||
protected virtual Task ShowPreviewPage(Page previewPage)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator.Server
|
||||
{
|
||||
public class UIToolkit : IUIToolkit
|
||||
{
|
||||
public void RunInUIThread(Action action)
|
||||
{
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(action);
|
||||
}
|
||||
|
||||
public Task RunInUIThreadAsync(Func<Task> action)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
Action asyncAction = () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
action().ContinueWith((r) => tcs.SetResult(true));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.SetException(ex);
|
||||
}
|
||||
};
|
||||
Xamarin.Forms.Device.BeginInvokeOnMainThread(asyncAction);
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@ namespace XAMLator.Server
|
|||
public class VM
|
||||
{
|
||||
static MethodInfo loadXAML;
|
||||
static EvalRequest currentEvalRequest;
|
||||
static EvalRequestMessage currentEvalRequest;
|
||||
readonly object mutex = new object();
|
||||
IEvaluator evaluator;
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace XAMLator.Server
|
|||
loadXAML.Invoke(null, new object[] { view, currentEvalRequest.Xaml });
|
||||
}
|
||||
|
||||
public Task<EvalResult> Eval(EvalRequest code, TaskScheduler mainScheduler, CancellationToken token)
|
||||
public Task<EvalResult> Eval(EvalRequestMessage code, TaskScheduler mainScheduler, CancellationToken token)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<EvalResult>();
|
||||
var r = new EvalResult();
|
||||
|
@ -60,7 +60,7 @@ namespace XAMLator.Server
|
|||
}
|
||||
}
|
||||
|
||||
async Task<EvalResult> EvalOnMainThread(EvalRequest code, CancellationToken token)
|
||||
async Task<EvalResult> EvalOnMainThread(EvalRequestMessage code, CancellationToken token)
|
||||
{
|
||||
EvalResult evalResult = new EvalResult();
|
||||
|
||||
|
@ -71,15 +71,17 @@ namespace XAMLator.Server
|
|||
sw.Start();
|
||||
|
||||
currentEvalRequest = code;
|
||||
object newType;
|
||||
|
||||
if (evaluator.IsEvaluationSupported)
|
||||
{
|
||||
if (code.NeedsRebuild)
|
||||
{
|
||||
await evaluator.EvaluateCode(code.Declarations, evalResult);
|
||||
await evaluator.EvaluateCode($"new {code.NewTypeName} ()", evalResult, code.Declarations);
|
||||
if (!evalResult.HasErrors && evalResult.HasResult)
|
||||
{
|
||||
evalResult.ResultType = evalResult.Result.GetType();
|
||||
}
|
||||
}
|
||||
if (!evalResult.HasErrors)
|
||||
else
|
||||
{
|
||||
evalResult.ResultType = GetTypeByName(code.NewTypeName);
|
||||
}
|
||||
|
@ -135,6 +137,10 @@ namespace XAMLator.Server
|
|||
static string LoadResource(AssemblyName assemblyName, string name)
|
||||
{
|
||||
Log.Information($"Resolving resource {name}");
|
||||
if (currentEvalRequest == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (name == currentEvalRequest.XamlResourceName)
|
||||
{
|
||||
return currentEvalRequest.Xaml;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)ErrorPage.xaml.cs">
|
||||
<DependentUpon>ErrorPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)AssemblyInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UIToolkit.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="$(MSBuildThisFileDirectory)ErrorPage.xaml">
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class CSSUpdateFeature : XAMLatorFeatureBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void When_the_css_is_updated_previewing_a_view_uses_the_new_version()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public class NonFormsTypesPreviewFeature
|
||||
{
|
||||
public NonFormsTypesPreviewFeature()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<configuration>
|
||||
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
|
||||
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
|
||||
<dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
|
||||
<dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
|
||||
<dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
|
||||
<dllmap os="linux" dll="libX11" target="libX11.so.6"/>
|
||||
<dllmap os="linux" dll="libXi" target="libXi.so.6"/>
|
||||
<dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0"/>
|
||||
<dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
|
||||
<dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
|
||||
<dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
|
||||
<dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
|
||||
<dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
|
||||
<!-- XQuartz compatibility (X11 on Mac) -->
|
||||
<dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
|
||||
<dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
|
||||
<dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
|
||||
<dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
|
||||
<dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
|
||||
<dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
|
||||
</configuration>
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
[SetUpFixture]
|
||||
public class SetupClass
|
||||
{
|
||||
[OneTimeSetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Forms.Init();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="XAMLator.Server.Tests.TestPage">
|
||||
<ContentPage.Content>
|
||||
<Label x:Name="label" Text="Sample"/>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
|
@ -0,0 +1,12 @@
|
|||
using Xamarin.Forms;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public partial class TestPage : ContentPage
|
||||
{
|
||||
public TestPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public enum PreviewState
|
||||
{
|
||||
None,
|
||||
Error,
|
||||
Preview
|
||||
}
|
||||
|
||||
public class TestPreviewer : Previewer
|
||||
{
|
||||
public TestPreviewer(Dictionary<Type, object> viewModelsMapping) : base(viewModelsMapping) { }
|
||||
|
||||
public PreviewState State { get; private set; }
|
||||
|
||||
public ErrorViewModel ErrorViewModel { get; private set; }
|
||||
|
||||
public EvalResult EvalResult { get; private set; }
|
||||
|
||||
public Page PreviewedPage { get; private set; }
|
||||
|
||||
public override Task NotifyError(ErrorViewModel errorViewModel)
|
||||
{
|
||||
State = PreviewState.Error;
|
||||
ErrorViewModel = errorViewModel;
|
||||
EvalResult = null;
|
||||
return base.NotifyError(errorViewModel);
|
||||
}
|
||||
|
||||
public override Task Preview(EvalResult res)
|
||||
{
|
||||
State = PreviewState.Preview;
|
||||
ErrorViewModel = null;
|
||||
EvalResult = res;
|
||||
return base.Preview(res);
|
||||
}
|
||||
|
||||
protected override Task PreviewPage(Page page)
|
||||
{
|
||||
PreviewedPage = page;
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
protected override Task HidePreviewPage(Page previewPage)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
protected override Task ShowPreviewPage(Page previewPage)
|
||||
{
|
||||
PreviewedPage = previewPage;
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public class TestTCPCommunicator : ITcpCommunicatorClient, ITcpCommunicatorServer
|
||||
{
|
||||
public event EventHandler<object> DataReceived;
|
||||
public event EventHandler ClientConnected;
|
||||
|
||||
public int ClientsCount { get; private set; }
|
||||
|
||||
public Task<bool> Connect(string ip, int port)
|
||||
{
|
||||
ClientsCount++;
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
ClientsCount--;
|
||||
}
|
||||
|
||||
public Task<bool> Send<T>(T obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
DataReceived?.Invoke(this, Serializer.DeserializeJson(Serializer.SerializeJson(obj)));
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception(ex);
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Task<bool> StartListening(int serverPort)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public void StopListening()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public class TestUIToolkit : IUIToolkit
|
||||
{
|
||||
public void RunInUIThread(Action action)
|
||||
{
|
||||
action();
|
||||
}
|
||||
|
||||
public Task RunInUIThreadAsync(Func<Task> action)
|
||||
{
|
||||
return action();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public class TestWorkspace : IDisposable
|
||||
{
|
||||
AdhocWorkspace workspace;
|
||||
|
||||
public TestWorkspace(string tempDir)
|
||||
{
|
||||
CopyFile(TestProjectDir, "TestPage.xaml", tempDir);
|
||||
CopyFile(TestProjectDir, "TestPage.xaml.cs", tempDir);
|
||||
CopyFile(TestAutogenDir, "TestPage.xaml.g.cs", tempDir);
|
||||
workspace = new AdhocWorkspace();
|
||||
var solution = SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default);
|
||||
workspace.AddSolution(solution);
|
||||
var projectId = ProjectId.CreateNewId();
|
||||
var versionStamp = VersionStamp.Create();
|
||||
var projectInfo = ProjectInfo.Create(projectId, versionStamp, "TestProject", "TestProject", LanguageNames.CSharp);
|
||||
var testProject = workspace.AddProject(projectInfo);
|
||||
AddReferences(testProject);
|
||||
AddDocument(testProject, tempDir, "TestPage.xaml.cs");
|
||||
AddDocument(testProject, tempDir, "TestPage.xaml");
|
||||
AddDocument(testProject, tempDir, "TestPage.xaml.g.cs");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
workspace.Dispose();
|
||||
}
|
||||
|
||||
public Document TestPageDoc => FindDocument("TestPage.xaml.cs");
|
||||
|
||||
string TestProjectDir => Path.Combine(TestContext.CurrentContext.TestDirectory, "..", "..");
|
||||
|
||||
string TestAutogenDir => Path.Combine(TestProjectDir, "obj", "Debug");
|
||||
|
||||
public Document FindDocument(string docName)
|
||||
{
|
||||
return workspace.CurrentSolution.Projects.Single().Documents.Single(d => d.Name == docName);
|
||||
}
|
||||
|
||||
public void UpdateDocument(ref Document document, string code)
|
||||
{
|
||||
var newSolution = workspace.CurrentSolution.WithDocumentText(
|
||||
document.Id, SourceText.From(code), PreservationMode.PreserveIdentity);
|
||||
workspace.TryApplyChanges(newSolution);
|
||||
document = workspace.CurrentSolution.GetDocument(document.Id);
|
||||
}
|
||||
|
||||
void CopyFile(string dir, string fileName, string outDir)
|
||||
{
|
||||
File.Copy(Path.Combine(dir, fileName), Path.Combine(outDir, fileName), true);
|
||||
}
|
||||
|
||||
Document AddDocument(Project testProject, string dir, string fileName)
|
||||
{
|
||||
DocumentInfo documentInfo = DocumentInfo.Create(
|
||||
DocumentId.CreateNewId(testProject.Id),
|
||||
fileName,
|
||||
new List<string> { dir },
|
||||
SourceCodeKind.Regular,
|
||||
TextLoader.From(TextAndVersion.Create(ReadFile(dir, fileName), VersionStamp.Create())),
|
||||
Path.Combine(dir, fileName));
|
||||
return workspace.AddDocument(documentInfo);
|
||||
}
|
||||
|
||||
SourceText ReadFile(string dir, string fileName)
|
||||
{
|
||||
return SourceText.From(File.ReadAllText(Path.Combine(dir, fileName)));
|
||||
}
|
||||
|
||||
void AddReferences(Project project)
|
||||
{
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
if (!assembly.IsDynamic)
|
||||
{
|
||||
project.AddMetadataReference(MetadataReference.CreateFromFile(assembly.Location));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UsageFeature : XAMLatorFeatureBase
|
||||
{
|
||||
[Test]
|
||||
public async Task A_xaml_changes_after_a_code_behind_and_the_view_is_previewed()
|
||||
{
|
||||
await When_a_csharp_document_changes("TestPage.xaml.cs");
|
||||
When_a_xaml_document_changes("TestPage.xaml");
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("XAMLator.Server.Tests.TestPage1", previewer.EvalResult.ResultType.FullName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task A_code_behind_changes_after_xaml_and_the_view_is_previewed()
|
||||
{
|
||||
When_a_xaml_document_changes("TestPage.xaml");
|
||||
await When_a_csharp_document_changes("TestPage.xaml.cs");
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("XAMLator.Server.Tests.TestPage1", previewer.EvalResult.ResultType.FullName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public class ViewWithoutXAMLPreviewFeature
|
||||
{
|
||||
public ViewWithoutXAMLPreviewFeature()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class XAMLAndCodeBehindPreviewFeature : XAMLatorFeatureBase
|
||||
{
|
||||
[Test]
|
||||
public async Task A_code_behind_changes_the_first_time_and_the_view_is_previewed_with_a_new_type()
|
||||
{
|
||||
await When_a_csharp_document_changes("TestPage.xaml.cs");
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("XAMLator.Server.Tests.TestPage1", previewer.EvalResult.ResultType.FullName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task When_the_code_changes_the_text_of_a_label_the_view_is_updated()
|
||||
{
|
||||
await When_the_code_changes("TestPage.xaml.cs", @"
|
||||
using Xamarin.Forms;
|
||||
namespace XAMLator.Server.Tests{
|
||||
public partial class TestPage : ContentPage {
|
||||
public TestPage() {
|
||||
InitializeComponent();
|
||||
label.Text = ""NEW TEXT"";
|
||||
}}}");
|
||||
var label = (previewer.PreviewedPage as ContentPage).Content as Label;
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("NEW TEXT", label.Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task When_the_code_contains_errors_the_error_page_is_shown()
|
||||
{
|
||||
await When_the_code_changes("TestPage.xaml.cs", @"
|
||||
using Xamarin.Forms;
|
||||
namespace XAMLator.Server.Tests{
|
||||
public partial class TestPage : ContentPage {
|
||||
public TestPage() {
|
||||
InvalidMethod();
|
||||
}}}");
|
||||
Assert.AreEqual(PreviewState.Error, previewer.State);
|
||||
Assert.AreEqual("Oh no! An evaluation error!", previewer.ErrorViewModel.Title);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task When_the_code_is_not_parsable_the_error_page_is_shown()
|
||||
{
|
||||
await When_the_code_changes("TestPage.xaml.cs", @"public new {}");
|
||||
Assert.AreEqual(PreviewState.Error, previewer.State);
|
||||
Assert.AreEqual("Oh no! An exception!", previewer.ErrorViewModel.Title);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
using NUnit.Framework;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class XAMLEvaluationFeature : XAMLatorFeatureBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void A_xaml_changes_and_the_view_is_previewed()
|
||||
{
|
||||
When_a_xaml_document_changes("TestPage.xaml");
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("XAMLator.Server.Tests.TestPage", previewer.EvalResult.ResultType.FullName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void When_a_xaml_element_name_is_changed_the_code_behind_is_autogenerated()
|
||||
{
|
||||
When_a_xaml_document_changes("TestPage.xaml",
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<ContentPage xmlns=""http://xamarin.com/schemas/2014/forms""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
|
||||
x:Class=""XAMLator.Server.Tests.TestPage"">
|
||||
<ContentPage.Content>
|
||||
<Label x:Name=""newLabel"" Text=""Sample""/>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
".Trim());
|
||||
|
||||
var contentPage = previewer.PreviewedPage as ContentPage;
|
||||
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("Sample", contentPage.FindByName<Label>("newLabel").Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void When_a_xaml_changes_the_previwed_view_has_the_new_changes()
|
||||
{
|
||||
When_a_xaml_document_changes("TestPage.xaml",
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<ContentPage xmlns=""http://xamarin.com/schemas/2014/forms""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
|
||||
x:Class=""XAMLator.Server.Tests.TestPage"">
|
||||
<ContentPage.Content>
|
||||
<Label x:Name=""newLabel"" Text=""New text""/>
|
||||
</ContentPage.Content>
|
||||
</ContentPage>
|
||||
".Trim());
|
||||
var contentPage = previewer.PreviewedPage as ContentPage;
|
||||
|
||||
Assert.AreEqual(PreviewState.Preview, previewer.State);
|
||||
Assert.AreEqual("New text", (contentPage.Content as Label).Text);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void When_the_xaml_contains_a_sytax_error_the_error_page_is_shown()
|
||||
{
|
||||
When_a_xaml_document_changes("TestPage.xaml", @"
|
||||
<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<ContentPage".Trim());
|
||||
Assert.AreEqual(PreviewState.Error, previewer.State);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void When_the_xaml_contains_an_error_the_error_page_is_shown()
|
||||
{
|
||||
When_a_xaml_document_changes("TestPage.xaml",
|
||||
@"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||
<ContentPage xmlns=""http://xamarin.com/schemas/2014/forms""
|
||||
xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
|
||||
x:Class=""XAMLator.Server.Tests.TestPage"">
|
||||
<ContentPage.Cotent>
|
||||
<Label x:Name=""newLabel"" Text=""Sample""/>
|
||||
</ContentPage.Cotent>
|
||||
</ContentPage>
|
||||
".Trim());
|
||||
Assert.AreEqual(PreviewState.Error, previewer.State);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\XAMLator.Client\XAMLator.Client.projitems" Label="Shared" Condition="Exists('..\XAMLator.Client\XAMLator.Client.projitems')" />
|
||||
<Import Project="..\packages\Xamarin.Forms.3.4.0.1008975\build\Xamarin.Forms.props" Condition="Exists('..\packages\Xamarin.Forms.3.4.0.1008975\build\Xamarin.Forms.props')" />
|
||||
<Import Project="..\packages\NUnit.3.11.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.11.0\build\NUnit.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>XAMLator.Server.Tests</RootNamespace>
|
||||
<AssemblyName>XAMLator.Server.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<XFDisableFrameworkVersionValidation>True</XFDisableFrameworkVersionValidation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="nunit.framework">
|
||||
<HintPath>..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.core">
|
||||
<HintPath>..\packages\SQLitePCLRaw.core.1.1.2\lib\net45\SQLitePCLRaw.core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.provider.e_sqlite3">
|
||||
<HintPath>..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.2\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_green">
|
||||
<HintPath>..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLitePCLRaw.batteries_v2">
|
||||
<HintPath>..\packages\SQLitePCLRaw.bundle_green.1.1.2\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.AppContext">
|
||||
<HintPath>..\packages\System.AppContext.4.3.0\lib\net46\System.AppContext.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Collections.Immutable">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Composition.AttributedModel">
|
||||
<HintPath>..\packages\System.Composition.AttributedModel.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Composition.Convention">
|
||||
<HintPath>..\packages\System.Composition.Convention.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Composition.Runtime">
|
||||
<HintPath>..\packages\System.Composition.Runtime.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Composition.Hosting">
|
||||
<HintPath>..\packages\System.Composition.Hosting.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Composition.TypedParts">
|
||||
<HintPath>..\packages\System.Composition.TypedParts.1.0.31\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Console">
|
||||
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.FileVersionInfo">
|
||||
<HintPath>..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.StackTrace">
|
||||
<HintPath>..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression">
|
||||
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem.Primitives">
|
||||
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem">
|
||||
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reflection.Metadata">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Security.Cryptography.Encoding">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Primitives">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Algorithms">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates">
|
||||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Encoding.CodePages">
|
||||
<HintPath>..\packages\System.Text.Encoding.CodePages.4.3.0\lib\net46\System.Text.Encoding.CodePages.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Thread">
|
||||
<HintPath>..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ValueTuple">
|
||||
<HintPath>..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.ReaderWriter">
|
||||
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml.XmlDocument">
|
||||
<HintPath>..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XPath">
|
||||
<HintPath>..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.XPath.XDocument">
|
||||
<HintPath>..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.2.10.0\lib\netstandard1.3\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.Workspaces.Desktop">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.10.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.Desktop.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.Workspaces">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.Common.2.10.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Workspaces.MSBuild.2.10.0\lib\net46\Microsoft.CodeAnalysis.Workspaces.MSBuild.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Core">
|
||||
<HintPath>..\packages\Xamarin.Forms.3.4.0.1008975\lib\netstandard2.0\Xamarin.Forms.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Platform">
|
||||
<HintPath>..\packages\Xamarin.Forms.3.4.0.1008975\lib\netstandard2.0\Xamarin.Forms.Platform.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Xaml">
|
||||
<HintPath>..\packages\Xamarin.Forms.3.4.0.1008975\lib\netstandard2.0\Xamarin.Forms.Xaml.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK">
|
||||
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.3.4.0.1008975\lib\net45\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="webkit-sharp">
|
||||
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.3.4.0.1008975\lib\net45\webkit-sharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Platform.GTK">
|
||||
<HintPath>..\packages\Xamarin.Forms.Platform.GTK.3.4.0.1008975\lib\net45\Xamarin.Forms.Platform.GTK.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.2.10.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp.Workspaces">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.2.10.0\lib\netstandard1.3\Microsoft.CodeAnalysis.CSharp.Workspaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Castle.Core">
|
||||
<HintPath>..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq">
|
||||
<HintPath>..\packages\Moq.4.10.1\lib\net45\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Xamarin.Forms.Build.Tasks">
|
||||
<HintPath>..\packages\Xamarin.Forms.3.2.0.839982\build\netstandard2.0\Xamarin.Forms.Build.Tasks.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Framework">
|
||||
<HintPath>..\packages\Microsoft.Build.Framework.15.9.20\lib\net46\Microsoft.Build.Framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Xaml" />
|
||||
<Reference Include="Microsoft.VisualStudio.Setup.Configuration.Interop">
|
||||
<HintPath>..\packages\Microsoft.VisualStudio.Setup.Configuration.Interop.1.16.30\lib\net35\Microsoft.VisualStudio.Setup.Configuration.Interop.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation">
|
||||
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Build.Utilities.Core">
|
||||
<HintPath>..\packages\Microsoft.Build.Utilities.Core.15.9.20\lib\net46\Microsoft.Build.Utilities.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="XAMLEvaluationFeature.cs" />
|
||||
<Compile Include="TestPage.xaml.cs">
|
||||
<DependentUpon>TestPage.xaml</DependentUpon>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Compile>
|
||||
<Compile Include="TestWorkspace.cs" />
|
||||
<Compile Include="SetupClass.cs" />
|
||||
<Compile Include="TestTCPCommunicator.cs" />
|
||||
<Compile Include="TestUIToolkit.cs" />
|
||||
<Compile Include="XAMLAndCodeBehindPreviewFeature.cs" />
|
||||
<Compile Include="ViewWithoutXAMLPreviewFeature.cs" />
|
||||
<Compile Include="NonFormsTypesPreviewFeature.cs" />
|
||||
<Compile Include="TestPreviewer.cs" />
|
||||
<Compile Include="XAMLatorFeatureBase.cs" />
|
||||
<Compile Include="UsageFeature.cs" />
|
||||
<Compile Include="CSSUpdateFeature.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="TestPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\XAMLator.Server.Net461\XAMLator.Server.Mono.Net461.csproj">
|
||||
<Project>{E3F80ADC-71F8-454E-BA3B-87BD0D78B051}</Project>
|
||||
<Name>XAMLator.Server.Mono.Net461</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<None Include="webkit-sharp.dll.config" />
|
||||
<None Include="OpenTK.dll.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
|
||||
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
|
||||
<Import Project="..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('..\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.2\build\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
|
||||
<Import Project="..\packages\Xamarin.Forms.3.4.0.1008975\build\Xamarin.Forms.targets" Condition="Exists('..\packages\Xamarin.Forms.3.4.0.1008975\build\Xamarin.Forms.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,91 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using XAMLator.Client;
|
||||
|
||||
namespace XAMLator.Server.Tests
|
||||
{
|
||||
public class XAMLatorFeatureBase
|
||||
{
|
||||
protected TestPreviewer previewer;
|
||||
protected TestWorkspace workspace;
|
||||
protected Mock<IIDE> ideMock;
|
||||
protected TestTCPCommunicator tcpCommunicator;
|
||||
protected TestUIToolkit uiToolkit;
|
||||
protected XAMLatorMonitor xamlatorMonitor;
|
||||
protected PreviewServer previewServer;
|
||||
string tempDir;
|
||||
|
||||
[SetUp]
|
||||
public async Task Given_a_xamlator_server_listening()
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
|
||||
tempDir = GetTemporaryDirectory();
|
||||
workspace = new TestWorkspace(tempDir);
|
||||
ideMock = new Mock<IIDE>();
|
||||
tcpCommunicator = new TestTCPCommunicator();
|
||||
uiToolkit = new TestUIToolkit();
|
||||
|
||||
xamlatorMonitor = new XAMLatorMonitor(ideMock.Object, tcpCommunicator);
|
||||
|
||||
previewer = new TestPreviewer(new Dictionary<Type, object>());
|
||||
previewServer = new PreviewServer();
|
||||
await previewServer.RunInternal(null, previewer, null, Constants.DEFAULT_PORT, uiToolkit, tcpCommunicator);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
FormsViewClassDeclaration.Reset();
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
|
||||
protected async Task When_a_csharp_document_changes(string docName)
|
||||
{
|
||||
var doc = workspace.FindDocument(docName);
|
||||
|
||||
EmitDocumentChanged(doc.FilePath, "",
|
||||
await doc.GetSyntaxTreeAsync(), await doc.GetSemanticModelAsync());
|
||||
}
|
||||
|
||||
protected async Task When_the_code_changes(string docName, string code)
|
||||
{
|
||||
Document doc = workspace.FindDocument(docName);
|
||||
workspace.UpdateDocument(ref doc, code);
|
||||
EmitDocumentChanged(doc.FilePath, code,
|
||||
await doc.GetSyntaxTreeAsync(), await doc.GetSemanticModelAsync());
|
||||
}
|
||||
|
||||
protected void When_a_xaml_document_changes(string docName)
|
||||
{
|
||||
var doc = workspace.FindDocument(docName);
|
||||
EmitDocumentChanged(doc.FilePath, File.ReadAllText(doc.FilePath));
|
||||
}
|
||||
|
||||
protected void When_a_xaml_document_changes(string docName, string xaml)
|
||||
{
|
||||
var doc = workspace.FindDocument(docName);
|
||||
EmitDocumentChanged(doc.FilePath, xaml);
|
||||
}
|
||||
|
||||
protected void EmitDocumentChanged(string filePath, string content,
|
||||
SyntaxTree syntaxTree = null, SemanticModel semanticModel = null)
|
||||
{
|
||||
var args = new DocumentChangedEventArgs(filePath, content, syntaxTree, semanticModel);
|
||||
ideMock.Raise((IIDE obj) => obj.DocumentChanged += null, this, args);
|
||||
}
|
||||
|
||||
string GetTemporaryDirectory()
|
||||
{
|
||||
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(tempDirectory);
|
||||
return tempDirectory;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Castle.Core" version="4.3.1" targetFramework="net461" />
|
||||
<package id="Microsoft.Build.Framework" version="15.9.20" targetFramework="net461" />
|
||||
<package id="Microsoft.Build.Utilities.Core" version="15.9.20" targetFramework="net461" />
|
||||
<package id="Microsoft.CodeAnalysis.Analyzers" version="2.6.1" targetFramework="net461" developmentDependency="true" />
|
||||
<package id="Microsoft.CodeAnalysis.Common" version="2.10.0" targetFramework="net461" />
|
||||
<package id="Microsoft.CodeAnalysis.CSharp" version="2.10.0" targetFramework="net461" />
|
||||
<package id="Microsoft.CodeAnalysis.CSharp.Workspaces" version="2.10.0" targetFramework="net461" />
|
||||
<package id="Microsoft.CodeAnalysis.Workspaces.Common" version="2.10.0" targetFramework="net461" />
|
||||
<package id="Microsoft.CodeAnalysis.Workspaces.MSBuild" version="2.10.0" targetFramework="net461" />
|
||||
<package id="Microsoft.VisualStudio.Setup.Configuration.Interop" version="1.16.30" targetFramework="net461" developmentDependency="true" />
|
||||
<package id="Moq" version="4.10.1" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.11.0" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.bundle_green" version="1.1.2" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.core" version="1.1.2" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.2" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.2" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.2" targetFramework="net461" />
|
||||
<package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.2" targetFramework="net461" />
|
||||
<package id="System.AppContext" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Collections" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
<package id="System.Composition" version="1.0.31" targetFramework="net461" />
|
||||
<package id="System.Composition.AttributedModel" version="1.0.31" targetFramework="net461" />
|
||||
<package id="System.Composition.Convention" version="1.0.31" targetFramework="net461" />
|
||||
<package id="System.Composition.Hosting" version="1.0.31" targetFramework="net461" />
|
||||
<package id="System.Composition.Runtime" version="1.0.31" targetFramework="net461" />
|
||||
<package id="System.Composition.TypedParts" version="1.0.31" targetFramework="net461" />
|
||||
<package id="System.Console" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.StackTrace" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Globalization" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Linq" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Reflection" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net461" />
|
||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Runtime" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Text.Encoding.CodePages" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.ValueTuple" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Xml.XPath" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Xml.XPath.XDocument" version="4.3.0" targetFramework="net461" />
|
||||
<package id="Xamarin.Forms" version="3.4.0.1008975" targetFramework="net461" />
|
||||
<package id="Xamarin.Forms.Platform.GTK" version="3.4.0.1008975" targetFramework="net461" />
|
||||
</packages>
|
|
@ -0,0 +1,5 @@
|
|||
<configuration>
|
||||
<dllmap dll="webkit-1.0" target="libwebkitgtk-1.0.0.dylib"/>
|
||||
<dllmap dll="webkit-1.0" os="linux" target="libwebkitgtk-1.0.so.0"/>
|
||||
<dllmap dll="webkit-1.0" os="windows" target="libwebkitgtk-1.0-0.dll"/>
|
||||
</configuration>
|
|
@ -28,7 +28,7 @@ namespace XAMLator.Server
|
|||
|
||||
public bool IsEvaluationSupported => isEvaluationSupported;
|
||||
|
||||
public async Task<bool> EvaluateCode(string code, EvalResult result)
|
||||
public async Task<bool> EvaluateCode(string code, EvalResult result, string initCode = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(code))
|
||||
{
|
||||
|
@ -38,7 +38,17 @@ namespace XAMLator.Server
|
|||
EnsureConfigured();
|
||||
try
|
||||
{
|
||||
var state = await CSharpScript.RunAsync(code);
|
||||
ScriptState state;
|
||||
if (initCode != null)
|
||||
{
|
||||
state = await CSharpScript.RunAsync(initCode);
|
||||
await state.ContinueWithAsync(code);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = await CSharpScript.RunAsync(code);
|
||||
}
|
||||
result.Result = state.ReturnValue;
|
||||
}
|
||||
catch (CompilationErrorException ex)
|
||||
{
|
||||
|
|
19
XAMLator.sln
19
XAMLator.sln
|
@ -43,6 +43,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8B24F47B
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XAMLator.Server.Mono.Mac", "XAMLator.Server.Mac\XAMLator.Server.Mono.Mac.csproj", "{47C93CC1-2606-4130-922A-A1B2895E895E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XAMLator.Server.Tests", "XAMLator.Server.Tests\XAMLator.Server.Tests.csproj", "{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -247,6 +249,22 @@ Global
|
|||
{47C93CC1-2606-4130-922A-A1B2895E895E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{47C93CC1-2606-4130-922A-A1B2895E895E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{47C93CC1-2606-4130-922A-A1B2895E895E}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Release|iPhone.Build.0 = Release|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{188F8020-6474-43BA-A6E7-0947C385B54C} = {72DE5BCD-BB42-41E2-916A-EEA0B7569529}
|
||||
|
@ -264,6 +282,7 @@ Global
|
|||
{FA699AFA-1165-40C0-AA59-BB63DA16A1B8} = {8B24F47B-470E-4237-8E2B-0A4528598FEE}
|
||||
{B960F8D7-25B3-46E9-A95C-E539192B5744} = {A2B90814-10AD-42D8-AF1C-3272628DE819}
|
||||
{47C93CC1-2606-4130-922A-A1B2895E895E} = {38F4F699-609F-4894-8D3F-1BA1283DAE91}
|
||||
{55BCF24D-7424-4C5E-AD72-BB34F217EBDF} = {8B24F47B-470E-4237-8E2B-0A4528598FEE}
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
Policies = $0
|
||||
|
|
Загрузка…
Ссылка в новой задаче