Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse expressions from an activity implementation property #318

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions src/Test/TestCases.Workflows/ExpressionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Activities.Expressions;
using System.Activities.Statements;
using System.Activities.Validation;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
Expand Down Expand Up @@ -566,4 +567,98 @@ public void VB_IsCaseInsensitive()
var valid = ActivityValidationServices.Validate(seq, _useValidator);
valid.Errors.ShouldBeEmpty();
}

[Fact]
public void VB_CompileAndInvokeActivityWithValueInImplementation()
{
foreach (var activity in GetActivitiesWithVBValues())
{
var root = new DynamicActivity { Implementation = () => activity };
ActivityXamlServices.Compile(root, new() { CompileExpressions = true });
WorkflowInvoker.Invoke(root);
}
}

[Fact]
public void CS_CompileAndInvokeActivityWithValueInImplementation()
{
foreach (var activity in GetActivitiesWithCSValues())
{
var root = new DynamicActivity { Implementation = () => activity };
ActivityXamlServices.Compile(root, new() { CompileExpressions = true });
WorkflowInvoker.Invoke(root);
}
}

private static IEnumerable<Activity> GetActivitiesWithVBValues()
{
yield return new ActivityWithVBValue("(1 + 2).ToString");
yield return new ActivityWithMultipleNestedVBValues();
}

private static IEnumerable<Activity> GetActivitiesWithCSValues()
{
yield return new ActivityWithCSValue("(1 + 2).ToString()");
yield return new ActivityWithMultipleNestedCSValues();
}

private class ActivityWithVBValue : Activity
{
public ActivityWithVBValue(string expressionText)
{
Implementation = () => new WriteLine() { Text = new InArgument<string>(new VisualBasicValue<string>(expressionText)) };
}
}

private class ActivityWithCSValue : Activity
{
public ActivityWithCSValue(string expressionText)
{
Implementation = () => new WriteLine() { Text = new InArgument<string>(new CSharpValue<string>(expressionText)) };
}
}

private class ActivityWithMultipleNestedVBValues : Activity
{
public ActivityWithMultipleNestedVBValues()
{
Implementation = () => new Sequence()
{
Activities =
{
new ActivityWithVBValue("99.ToString"),
new Sequence()
{
Activities =
{
new ActivityWithVBValue("(1 + 2).ToString"),
}
},
new ActivityWithVBValue("{1, 2, 3}.ToString")
}
};
}
}

private class ActivityWithMultipleNestedCSValues : Activity
{
public ActivityWithMultipleNestedCSValues()
{
Implementation = () => new Sequence()
{
Activities =
{
new ActivityWithCSValue("99.ToString()"),
new Sequence()
{
Activities =
{
new ActivityWithCSValue("(1 + 2).ToString()"),
}
},
new ActivityWithCSValue("(new int[] {1, 2, 3}).ToString()")
}
};
}
}
}
4 changes: 4 additions & 0 deletions src/Test/TestCases.Workflows/TestCases.Workflows.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<ItemGroup>
<Page Remove="**\*.xaml" />
<EmbeddedResource Include="TestXamls\*.xaml" />
<Page Remove="ExpressionCompilerResults\CS_ExpressionCompilerResult" />
<Page Remove="ExpressionCompilerResults\VB_ExpressionCompilerResult" />
<EmbeddedResource Include="ExpressionCompilerResults\CS_ExpressionCompilerResult" />
<EmbeddedResource Include="ExpressionCompilerResults\VB_ExpressionCompilerResult" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AgileObjects.ReadableExpressions" Version="3.1.0" />
Expand Down
103 changes: 103 additions & 0 deletions src/Test/TestCases.Workflows/TextExpressionCompilerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using Xunit;
using System;
using System.IO;
using System.Activities;
using Microsoft.CSharp.Activities;
using System.Activities.Statements;
using Microsoft.VisualBasic.Activities;
using System.Activities.XamlIntegration;

namespace TestCases.Workflows
{
public class TextExpressionCompilerTests
{
[Theory]
[InlineData("VB")]
[InlineData("C#")]
public void EnsureCompilationParity(string expressionLanguage)
{
var actualSourceWriter = new StringWriter();
var currentAsm = typeof(TextExpressionCompilerTests).Assembly;

TextExpressionCompilerSettings settings = new()
{
RootNamespace = null,
ForImplementation = true,
ActivityName = "TestClass",
AlwaysGenerateSource = true,
Language = expressionLanguage,
GenerateAsPartialClass = false,
ActivityNamespace = "TestNamespace",
Activity = new DynamicActivity { Implementation = () => GetActivity(expressionLanguage) },
};

new TextExpressionCompiler(settings).GenerateSource(actualSourceWriter);
var expectedStream = currentAsm.GetManifestResourceStream($"{currentAsm.GetName().Name}.ExpressionCompilerResults.{GetExpectedResourceName(expressionLanguage)}");

var actualSource = actualSourceWriter.ToString();
var expectedSource = new StreamReader(expectedStream).ReadToEnd();
Assert.Equal(expectedSource, actualSource);
}

private static string GetExpectedResourceName(string expressionLanguage)
=> expressionLanguage switch
{
"C#" => "CS_ExpressionCompilerResult",
"VB" => "VB_ExpressionCompilerResult",
_ => throw new NotImplementedException()
};

private static Activity GetActivity(string expressionLanguage)
=> expressionLanguage switch
{
"C#" => GetActivity(v1 => new CSharpValue<bool>(v1), v2 => new CSharpValue<string>(v2), v3 => new CSharpReference<string>(v3)),
"VB" => GetActivity(v1 => new VisualBasicValue<bool>(v1), v2 => new VisualBasicValue<string>(v2), v3 => new VisualBasicReference<string>(v3)),
_ => throw new NotImplementedException()
};

private static Activity GetActivity<T1, T2, T3>(Func<string, T1> boolValueFactory, Func<string, T2> strValueFactory, Func<string, T3> referenceFactory)
where T1 : TextExpressionBase<bool>
where T2 : TextExpressionBase<string>
where T3 : TextExpressionBase<Location<string>>
=> new Sequence()
{
Variables =
{
new Variable<string>("var1")
},
Activities =
{
new WriteLine() { Text = new InArgument<string>(strValueFactory("var1")) },
new Assign() { To = new OutArgument<string>(referenceFactory("var1")), Value = new InArgument<string>("test1") },
new If() {
Condition = new InArgument<bool>(boolValueFactory("var1 != \"test\"")),
Then = new Sequence()
{
Variables =
{
new Variable<string>("var2")
},
Activities =
{
new Assign() { To = new OutArgument<string>(referenceFactory("var2")), Value = new InArgument<string>("test2") },
new WriteLine() { Text = new InArgument<string>(strValueFactory("var2")) },
}
},
Else = new Sequence()
{
Activities =
{
new Sequence()
{
Activities =
{
new WriteLine() { Text = new InArgument<string>(strValueFactory("test3")) },
}
}
}
}
}
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,14 @@ private bool TryGetCurrentCompiledExpressionRoot(ActivityContext activityContext
{
ActivityInstance current = activityContext.CurrentInstance;

while (current != null && current.Activity != _metadataRoot)
while (current != null)
{

if (TryGetCompiledExpressionRoot(current.Activity, true, out ICompiledExpressionRoot currentCompiledExpressionRoot))
if (current.Activity != _metadataRoot
&& TryGetCompiledExpressionRoot(current.Activity, true, out ICompiledExpressionRoot currentCompiledExpressionRoot)
&& CanExecuteExpression(currentCompiledExpressionRoot, out expressionId))
{
if (CanExecuteExpression(currentCompiledExpressionRoot, out expressionId))
{
compiledExpressionRoot = currentCompiledExpressionRoot;
return true;
}
compiledExpressionRoot = currentCompiledExpressionRoot;
return true;
}
current = current.Parent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ protected virtual void Visit(Activity activity, out bool exit)
{
return;
}

VisitImplementationChildren(activity, out exit);
if (exit)
{
return;
}
}

protected virtual void VisitRoot(Activity activity, out bool exit)
Expand Down Expand Up @@ -205,6 +211,22 @@ protected virtual void VisitImportedChildren(Activity activity, out bool exit)
exit = false;
}

protected virtual void VisitImplementationChildren(Activity activity, out bool exit)
{
if (activity.ImplementationChildren is not null)
{
for (int i = 0; i < activity.ImplementationChildren.Count; i++)
{
VisitCore(activity.ImplementationChildren[i], out exit);
if (exit)
{
return;
}
}
}
exit = false;
}

protected virtual void VisitDelegates(Activity activity, out bool exit)
{
if (activity.Delegates != null)
Expand Down Expand Up @@ -370,18 +392,11 @@ private void VisitRootImplementation(Activity activity, out bool exit)
return;
}

if (activity.ImplementationChildren != null)
VisitImplementationChildren(activity, out exit);
if (exit)
{
for (int i = 0; i < activity.ImplementationChildren.Count; i++)
{
VisitCore(activity.ImplementationChildren[i], out exit);
if (exit)
{
return;
}
}
return;
}
exit = false;
}

private void VisitPublicActivities(Activity activity, out bool exit)
Expand Down