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

How to dynamically execute a code written from Visual Studio. #32

Closed
DinisCruz opened this issue Sep 2, 2014 · 2 comments
Closed

How to dynamically execute a code written from Visual Studio. #32

DinisCruz opened this issue Sep 2, 2014 · 2 comments

Comments

@DinisCruz
Copy link
Contributor

(based on this question on the O2 Platform mailing list)

For a simplified example,in Visual Studio:

public class Person
{
     public string Name { get; set; }
}

...and from O2 REPL

Person person = new Person { Name = "foo" };
Console.WriteLine(person.Name);
@DinisCruz
Copy link
Contributor Author

This can be done in multiple ways.

Let's start with a simple example of compiling an extending the Person Object

  1. In VS2010 with the VisualStudio C# REPL - O2 Platform (v5.1) plugin installed:

image

  1. Create a new class project (for example called VS_REPL_Examples

image

  1. With a Person class containing a Name property

image

  1. Open the C# REPL - VisualStudio 2010 API

image

  1. Find the Full path of the current File being edited (in the main VS UI) using
var visualStudio = new VisualStudio_2010();
return visualStudio.dte().ActiveDocument;

image

which in this case is c:\users\o2\documents\visual studio 2010\Projects\VS_REPL_Examples\Person.cs

  1. Dynamically compile that file and create an instance of the Person object using
var person = new VS_REPL_Examples.Person();
person.Name = "This is the Name";
return person;

//O2File:c:\users\o2\documents\visual studio 2010\Projects\VS_REPL_Examples\Person.cs

image

  1. Since the REPL window is on native VS panel, feel free to move it into a convenient location

image

  1. Make a change to the Person object (and save the file)
    public class Person
    {
        public string Name  { get; set; }
        public int    Age   { get; set; }
        public bool   Admin { get; set; }
    }       
}
  1. Make a small change to the REPL script (for example adding some .. to the name), execute the script again and notice that the new fields are already there (on the bottom-right _Output_ window)

image

  1. Note that the REPL auto-complete should have picked up the new fields:

image

  1. Set the new fields values using
var person = new VS_REPL_Examples.Person(); 
person.Name  = "This is the Name..";
person.Admin = true;
person.Age   = 42;
return person;

//O2File:c:\users\o2\documents\visual studio 2010\Projects\VS_REPL_Examples\Person.cs

image

  1. Since the REPL script is a full C# code snippet, you can use set the properties values via the Constructor:
return new VS_REPL_Examples.Person
    {
        Name  = "Now using Properties",
        Admin = true,
        Age   = 42
    };

//O2File:c:\users\o2\documents\visual studio 2010\Projects\VS_REPL_Examples\Person.cs

image

  1. Here is a final example using a Lamda methods (note the special //using VS_REPL_Examples reference):
Func<string,Person> newPerson= 
    (name)=>{
                return new Person
                            {
                                Name  = name,
                                Admin = true,
                                Age   = 42
                            };
            };
return newPerson("Now using a Lamdba method");  

//using VS_REPL_Examples
//O2File:c:\users\o2\documents\visual studio 2010\Projects\VS_REPL_Examples\Person.cs

image

@DinisCruz
Copy link
Contributor Author

Here is a variation of the above example (in this case we are going to run the code changes on top of a large VS projet which contains an WinForms control that hosts an WPF control (in this case GraphX).

  1. After cloning locally https://github.com/panthernet/GraphX and opening up the main solution in VisualStudio (in this case VS 2013), I set the WindowsFormsProject to be the startup project and executed it:

image

  1. Added a new C# class project called GraphX.FluentSharp.Tests

image

  1. In the new project Manage NuGet Dependencies , I added the FluentSharp.NUnit package

image

the FluentSharp.REPL package

image

and the FluentSharp.WPF package

image

  1. Next I renamed the Class.cs file into Test_WindowsFormsProject and added a simple test:
using FluentSharp.NUnit;
using NUnit.Framework;

namespace GraphX.FluentSharp.Tests
{
    [TestFixture]
    public class Test_WindowsFormsProject
    {
        [Test]
        public void Assert_Test_Runs()
        {
            var value = 1;
            (value == 1).assert_True();
            (value != 2).assert_False();
        }
    }
}

image

which I executed using Resharper's Nunit runner:

image

as expected the original test failed (since 1 != 2 is true, not false). Here is the fixed version:

image

  1. Now it is time to show how to use this environment to quickly see code changes made to a complex project (like graphx).

After adding a reference to the WindowsFormsProject

image

I am able to create and instance of the WindowsFormsProject's Form1 object:

image

directly from my UnitTest

using WindowsFormsProject;
using FluentSharp.NUnit;
using NUnit.Framework;

namespace GraphX.FluentSharp.Tests
{
    [TestFixture]
    public class Test_WindowsFormsProject
    {
        [Test]
        public void Create_WindowsFormsProject_MainControl()
        {
            var form1 = new Form1();
            form1.assert_Not_Null();
        }
    }
}

Here is the execution result of the test shown above:

image

(note that in the example shown above, I'm using NCrunch to execute the tests and show code coverage)

  1. Creating the Form1 object inside an STA Thread using the O2Thread API:
        [Test]
        public void Create_WindowsFormsProject_MainControl()
        {
            var form1 = O2Thread.staThread(()=>new Form1());
            form1.assert_Not_Null();
        }

image

  1. At this stage it is good to organise the VS windows, so that the main views (we working on) are all visible:

a) top-left the code/control we are testing
b) bottom-left the UnitTest
c) right the real-time unit test execution result:

image

  1. Create an instance of the Form1 object and confirm that it has 3 controls:
using System.Windows.Forms;
using WindowsFormsProject;
using FluentSharp.CoreLib;
using FluentSharp.CoreLib.API;
using FluentSharp.NUnit;
using FluentSharp.WinForms;
using NUnit.Framework;

namespace GraphX.FluentSharp.Tests
{
    [TestFixture]
    public class Test_WindowsFormsProject
    {
        [Test]
        public void Create_WindowsFormsProject_Form_Directly()
        {
            Form1 form1 = null;
            O2Thread.staThread(()=>
                {
                    form1= new Form1();
                    form1.ShowDialog();
                });
            Processes.getCurrentProcess().waitFor_MainWindowHandle();
            form1.assert_Not_Null(); 
            form1.controls().assert_Size_Is(3);
            form1.waitForClose();
        }

image

  1. Another way to start the Form
        [Test]
        public void Create_WindowsFormsProject_Form_Via_Exe()
        {
            var assembly  = "WindowsFormsProject".assembly().assert_Not_Null();
            var program = assembly.type("Program").assert_Not_Null();
            var main    = program.method("Main").assert_Not_Null();

            O2Thread.staThread(()=>main.invokeStatic());
            Processes.getCurrentProcess().waitFor_MainWindowHandle();
            var form1 = Application.OpenForms.assert_Not_Empty()
                                             .first().cast<Form1>()
                                                     .assert_Not_Null();
            //form1.script_Me_WaitForClose();            
        }

image

Note that both tests execute in less that 2 secs

  1. start a REPL on the form and program it in real time (using form1.script_Me_WaitForClose(); on (for example) the Create_WindowsFormsProject_Form_Via_Exe test) and click programatically on one of the buttons:

image

  1. with that REPL access the WinForms ElementHost that is hosting the WPF graph control:
var elementHost = form1.control<ElementHost>();
return elementHost;


//O2Ref:WindowsFormsProject.exe
//O2Ref:FluentSharp.WPF
//using FluentSharp.WPF
//using System.Windows.Forms.Integration
//O2Ref:WindowsFormsIntegration.dll
//O2Ref:PresentationCore.dll
//O2Ref:WindowsBase.dll
//O2Ref:PresentationFramework.dll
//O2Ref:System.Xaml.dll

image

  1. access the WPF control directly (via return elementHost.Child.typeFullName();)

image

  1. access the child WPF controls (via return elementHost.Child.controls_Wpf();). Note that most of the controls shown on the Output window are the Graph's Nodes and Edges:

image

  1. Adding a reference to the GraphX.Controls.dll assembly we can get a strongly typed list of the GraphX.VertexControl
var elementHost = form1.control<ElementHost>();
var vertextControls = elementHost.Child.controls_Wpf<GraphX.VertexControl>();
return vertextControls;
//O2Ref:GraphX.Controls.dll

image

  1. Getting a reference to the GraphAreaExample object and listing its base types:
var elementHost = form1.control<ElementHost>();
var vertextControls = elementHost.Child.controls_Wpf<GraphX.VertexControl>();

var graphAreaExample = elementHost.Child.control_Wpf<WindowsFormsProject.GraphAreaExample>();
//graphAreaExample.add_Label_Wpf("This is a new Label");
//return graphAreaExample.type().baseTypes();

return graphAreaExample.controls_Wpf();

//O2Ref:GraphX.Controls.dll
//O2Ref:GraphX.Common.dll
//O2Ref:QuickGraph.dll

//O2Ref:FluentSharp.WPF
//using FluentSharp.WPF
//using System.Windows.Forms.Integration

//O2Ref:WindowsFormsProject.exe
//O2Ref:WindowsFormsIntegration.dll
//O2Ref:PresentationCore.dll
//O2Ref:WindowsBase.dll
//O2Ref:PresentationFramework.dll
//O2Ref:System.Xaml.dll

image

  1. Finally to confirm that we can make changes to the WPF control and test it without having to load the main app, let's add a WinForms label to the WPF Host form (in the image below called 'label1')

image

Which will (after building the project) make the first unit test written fail

image

To fix the unit test we need to change the expected size in form1.controls().assert_Size_Is(3); to 4:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant