Fitnesse slim: Call generic method (fitSharp) - fitnesse

Linux 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux
Mono 2.10.8.1 (Debian 2.10.8.1-7) (64-bit)
glib-sharp 2.12.0.0
FitNesse (v20121220)
FitSharp release 2.2 for .net 4.0
I have a C# fixture that contains the following generic method
public Func<T> GetProcedure<T>(string name)
{
return () => default(T);
}
Question: How do I call GetProcedure from a Slim script table?
| show | GetProcedure; <?specify type here?> | text |
I found the following test in the source code, so it should be possible. However, I don't know how to define the type T within the script table so that slim can parse it...
https://github.com/jediwhale/fitsharp/blob/master/source/fitSharpTest/NUnit/Machine/MemberQueryTest.cs
[Test] public void GenericMethodWithParmsIsInvoked() {
var member = new MemberName("genericmethodofsystemint32", "genericmethod", new[] { typeof(int)});
var method = MemberQuery.FindInstance(MemberQuery.FindMember, instance, new MemberSpecification(member, 1));
Assert.IsNotNull(method);
var result = method.Invoke(new object[] {123});
Assert.AreEqual("sample123", result.Value.ToString());
}
// This method found via the reflection above.
// see: fitSharp.Test.Double.SampleClass
public string GenericMethod<T>(T input) {
return "sample" + input;
}

Unfortunately generic methods are not supported in Slim. If you're using the Fit test system, you'd say 'getprocedure of mytype' as the method name.

Related

Why are Java lambdas treated differently from nested classes with respect to instance field initialization?

With javac 1.8.0_77 this class does not compile:
import java.util.function.*;
public class xx {
final Object obj;
final Supplier<Object> supplier1 = new Supplier<Object>() {
#Override
public Object get() {
return xx.this.obj;
}
};
final Supplier<Object> supplier2 = () -> { return this.obj; };
xx(Object obj) {
this.obj = obj;
}
}
Here's the error:
xx.java:12: error: variable obj might not have been initialized
final Supplier<Object> supplier2 = () -> { return this.obj; };
^
1 error
Questions:
Is the generation of this error correct according to the JLS?
If so, what is the reasoning behind the JLS treating a #FunctionalInterface lamba implementation (supplier2) differently from its equivalent inner class implementation (supplier1) in this respect?
EDITED TO ADD (2022/9/21)
FYI here's a simple compiler patch that fixes this. It causes lambdas to be treated like non-constructor methods with respect to field initialization (namely, ignore them) in Flow.AssignAnalyzer:
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
index 20abb281211..7e77d594143 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
## -2820,30 +2909,33 ## public class Flow {
#Override
public void visitLambda(JCLambda tree) {
final Bits prevUninits = new Bits(uninits);
final Bits prevInits = new Bits(inits);
int returnadrPrev = returnadr;
+ int firstadrPrev = firstadr;
int nextadrPrev = nextadr;
ListBuffer<PendingExit> prevPending = pendingExits;
try {
returnadr = nextadr;
+ firstadr = nextadr;
pendingExits = new ListBuffer<>();
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
inits.incl(def.sym.adr);
uninits.excl(def.sym.adr);
}
if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
scanExpr(tree.body);
} else {
scan(tree.body);
}
}
finally {
returnadr = returnadrPrev;
uninits.assign(prevUninits);
inits.assign(prevInits);
pendingExits = prevPending;
+ firstadr = firstadrPrev;
nextadr = nextadrPrev;
}
}
Browsing through the JLS changes from JSR 335, this looks like an omission to me:
Access to blank final fields is regulated by JLS Chapter 16
There is a section "Definite Assignment and Anonymous Classes" which mandates the error in the case of supplier1.
The JSR 335 spec has only one marginal change for chapter 16, never mentioning "lambda" or "method references" throughout this chapter.
In fact the only change in Chap.16 is (using bold type face for additions):
Throughout the rest of this chapter, we will, unless explicitly stated otherwise, write V to represent an in-scope (6.3) local variable or a blank final field (for rules of definite assignment) or a blank final variable (for rules of definite unassignment).
At the bottom line, compilers seem to be right in not complaining in the lambda case, but for consistency JLS should probably be amended to cover this case, too.
Edit:: OpenJDK already has a spec bug for this, changes are being proposed as we speak.

Grails Controller Actions may not be overloaded

I'm trying to use an overloaded method to append XML in a controller in Grails 2.3.4.
I have the following overloaded methods in my ReportController.
String makePhotoXml(StringBuilder sb, Report r, String url, String desc) {
sb.append("<photo>")
sb.append(Utilities.makeElementCdata("url", url))
sb.append(Utilities.makeElementCdata("caseId", r.caseId))
sb.append(Utilities.makeElementCdata("type", r.type))
sb.append(Utilities.makeElementCdata("date", r.dateCreated.format('MM/dd/yy')))
sb.append(Utilities.makeElementCdata("address", r.address))
sb.append("<extra>extra</extra>")
sb.append(Utilities.makeElementCdata("description", desc))
sb.append("</photo>")
}
String makePhotoXml(List<Report> reports) {
StringBuilder sb = new StringBuilder()
sb.append("<photos>")
sb.append("<title>Photos</title>")
for (Report r : reports) {
for (Photo photo : r.photos) {
makePhotoXml(sb, r, photo.url(), photo.description)
}
for (Document doc : r.photoDocuments) {
makePhotoXml(sb, r, doc.url(-1), doc.getDescription())
}
}
sb.append("</photos>")
}
When running the application I get this compiler error:
| Error Compilation error: startup failed:
/Users/Anthony/GrailsApps/AppOrderWeb/grails-app/controllers/com/apporder/ReportController.groovy: 1360: Controller actions may not be overloaded. The [makePhotoXml] action has been overloaded in [com.apporder.ReportController]. # line 1360, column 5.
String makePhotoXml(StringBuilder sb, Report r, String url, String desc) {
I thought that Groovy and Grails supported method overloading. Any ideas on how to work around this and make this overloaded method work?
Groovy in general does allow method overloading, but Grails forbids it for the specific case of controller actions. If you want utility methods in your controller, you need to make them private or protected so Grails does not try and treat them as web-visible actions.
Alternatively, it would be more Grails-y to move the helper methods into a service instead of having them in the controller.

FitSharp throws a ParseException when an object instance is stored in a slim symbol that is later used in a function call

I store an instance in a slim symbol ($IT) but when I later try to use the instance in a function call I receive a fitSharp.Machine.Exception.ParseException.
I think the problem is that FitSharp tries to parse the argument instead of casting the object up to its interface.
I have the following class and interface (name space is MySlimTest)
public interface IObject {}
public class ConcreteObject: IObject
{
public string Name { get; set; }
public string Description { get; set; }
}
which I use in my slim fixture which includes the following method and the returned instance I store in a slim symbol.
public IObject CreateConcreteObjectWithNameAndDescription(string name, string description)
{
return new ConcreteObject() {Name = name, Description = description};
}
I call this method from a script table. When rendered after the test has run it looks like this:
$IT<-[MySlimTest.ConcreteObject] | create concrete object | with name | The initial name of the concrete object | and description | empty |
When I try to later use the instance stored in the slim symbol IT, the ParseException is thrown.
the method in the fixture is
public bool SetNameForInstance(string name, IObject obj)
{
return SetAttribute<ConcreteObject>(obj, concreteObject => concreteObject.Name = name);
}
this is used in the test table as
ensure | set name | John Cleese | for instance | $IT->[MySlimTest.ConcreteObject]
Workaround
Interestingly, if I change the method signature to use the implementation (ConcreteObject) instead of the interface then it works.
public bool SetNameForInstance(string name, ConcreteObject obj)
The complete example with fixture code follows as a fitnesse plain text wiki page:
!*> Environment
Linux 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux
Mono 2.10.8.1 (Debian 2.10.8.1-7) (64-bit)
glib-sharp 2.12.0.0
FitNesse (v20121220)
FitSharp release 2.2 for .net 4.0
*!
!*> Fixture Code
{{{
using System;
namespace MySlimTest
{
public interface IObject {}
public class ConcreteObject: IObject
{
public string Name { get; set; }
public string Description { get; set; }
}
public class SymbolTestFixture
{
public SymbolTestFixture ()
{
// Initialisation code here...
// Currently just a mock.
}
public IObject CreateConcreteObjectWithNameAndDescription(string name, string description)
{
return new ConcreteObject() {Name = name, Description = description};
}
public bool SetNameForInstance(string name, IObject obj)
{
return SetAttribute<ConcreteObject>(obj, concreteObject => concreteObject.Name = name);
}
public bool SetDescriptionForInstance(string description, ConcreteObject obj)
{
return SetAttribute<ConcreteObject>(obj, concreteObject => concreteObject.Description = description);
}
private bool SetAttribute<T>(IObject obj, Action<T> fun)
{
if (obj is T)
{
fun((T)obj);
return true;
}
return false;
}
}
}
}}}
*!
!3 Set-up of the test system
!***> Test system set-up
!define TEST_SYSTEM {slim}
!path /path/to/fixture/DLL/SlimTest.dll
!define COMMAND_PATTERN {%m -r fitSharp.Slim.Service.Runner,/path/to/fitSharp.dll %p}
!define TEST_RUNNER {/path/to/Runner.exe}
***!
!**> Usings
!|import |
|MySlimTest|
**!
!2 Scenarios
!|scenario|given concrete object |name |and |description |
|$IT= |create concrete object with name|#name|and description|#description|
!|scenario |given concrete object|name |
|given concrete object|#name |and|empty|
!|scenario|edit concrete object|instance |name to |name|and description to|description|
|ensure |set name |#name |for instance|$IT |
|ensure |set description |#description|for instance|$#instance |
!3 Test the ''slim symbol can hold object as parameter'' feature
!|script|symbol test fixture|
!|script |
|given concrete object|The initial name of the concrete object |
|edit concrete object |IT |name to |John Cleese |and description to|Yes, I am still indeed alive, contrary to rumour, and I am touring my one Cleese show. London.|
It's a bug. I forked, fixed and made a pull request on GitHub
https://github.com/jediwhale/fitsharp/pull/109

Inconsistent error reporting from Dart Editor regarding final fields

Given the following class, Dart Editor (build 5549) gives me some conflicting feedback (per the comments in the constructor body):
class Example {
final int foo;
Example() :
foo = 0
{
foo = 1; // 'cannot assign value to final variable "foo"'
this.foo = 2; // ok
}
}
Even more confusingly, it will happily generate equivalent (working) javascript for both lines. The situation seems to be the same with methods as it is with the constructor; this especially leads me to believe that it was intended to be disallowed in both cases.
The Dart Style Guide suggests using public final fields instead of private fields with public getters. I like this in theory, but non-trivial member construction can't really go into the initializer list.
Am I missing a valid reason for the former to be reported as an error while the latter is not? Or should I be filing a bug right now?
This is surely a bug in the JavaScript generator if you run the following in the Dart VM:
main() {
new Example();
}
class Example {
final int foo;
Example() : foo = 0 {
foo = 1; // this fails in the dart vm
this.foo = 2; // this also fails in the dart vm
}
}
then it refuses to execute both the line foo = 1 and this.foo = 2. This is consistent with the spec which requires (if I read it correctly) that final fields to be final in the constructor body.

Ninject binds to the wrong anonymous method when there is more than one method bound type

I am building a framework that I don't want to couple to a particular IOC container so have created a layer on top of Ninject / structuremap etc.
I have a binding class that accepts a Func to allow binding to a method.
For example
public class Binding
{
public Type Source { get; set; }
public Func<object> Method {get; set; }
public Scope { get; set; }
}
If I have a binding like...
var binding = new Binding() {
Source = typeof(IRepository),
Method = () => new Repository(new LinqToSqlRepository(connectionString)),
Scope = Scope.HttpRequest
};
The framework wrapping Ninject creates Ninject bindings for my generic binding like this
Module :NinjectModule
{
IList<Binding> _Bindings;
public Module(IList<Binding> bindings)
{
_Bindings = bindings;
}
public override void Load() {
foreach (var binding in _Bindings) {
switch(binding.Scope) {
case IocScope.HttpRequest:
Bind(binding.Source).ToMethod(c => binding.Method()).InRequestScope();
break;
// ... omitted for brevity
}
}
}
}
This works fine when there is only one binding being bound to a method. When there are multiple bindings being bound within the same module to methods however the incorrect type is returned. From debugging, it looks as if the last binding is always used.
Thus the problem with an example;
var binding1 = new Binding() {
Source = typeof(IRepository),
Method = () => new Repository(new LinqToSqlRepository(connectionString)),
Scope = Scope.HttpRequest
};
var binding2 = new Binding() {
Source = typeof(ICalendar),
Method = () => new MvcCalendar( ..... )
Scope = Scope.HttpRequest
};
At runtime when Ninject is requested to new up an MVC Controller which takes in an IRepository and an ICalendar, I receive a type conversion error saying that a MvcCalendar cannot be converted to an IRepository. I have discovered that for some reason the last binding is always being returned for the first requested type.
This is a highly simplified version of what is really going on to try and highlight the actual issue, the wrong method being bound to a requested type when there are multiple method bindings. I hope this still explains the issue though.
This appears to be related to some sort of closure scoping issue. I also wonder whether Ninject is getting is getting confused by the Func instead of Func usage.
Unit Test Example
Here is a test module I load into my custom IOC container. This does not depend on any particular IOC framework. When I instantiate a NinjectIocContainer to handle the DI, the internal binding of this in Ninject occurs as example further up (see NinjectModule)
public class MultipleMethodBoundTypesModule : IocModule
{
public override void Load()
{
Bind<IPerson>().To(() => new Person()).In(IocScope.Transient);
Bind<IRobot>().To(() => new Robot(new Person())).In(IocScope.Transient);
}
}
Here is a simple test that tries to retrieve each of the types.
[Test]
public void Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module()
{
// arrange
var container = Get_Container_With_Module(new MultipleMethodBoundTypesModule());
// act
var person = container.Get<IPerson>();
var robot = container.Get<IRobot>();
// assert
Assert.IsNotNull(person);
Assert.IsNotNull(robot);
}
As explained eariler, this throws a type conversion where the last closure (for the robot) is being bound to a person.
TestCase 'Ioc.Test.NinjectContainerTest.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module'
failed: System.InvalidCastException : Unable to cast object of type 'Ioc.Test.Robot' to type 'Ioc.Test.IPerson'.
at System.Linq.Enumerable.d__b11.MoveNext()
at System.Linq.Enumerable.Single[TSource](IEnumerable1 source)
at Ninject.ResolutionExtensions.Get[T](IResolutionRoot root, IParameter[] parameters)
NinjectIocContainer.cs(40,0): at Ioc.Ninject.NinjectIocContainer.GetTInstance
IocTestBase.cs(149,0): at Ioc.Test.IocTestBase.Expect_That_Multiple_Method_Bound_Types_Can_Exist_Within_The_Same_Module()
In the snippet:
Bind(binding.Source).ToMethod(binding.Method()).InRequestScope();
You're dereferencing the Method bit. You want to be doing that as either binding.Method or ()=>binding.Method() (the former may not unambiguously be inferrable based on the C# type inference rules).
You mentioned this is heavily stripped down from your real code. As a result, this may not be the actual issue. I'd still be betting on some form of closure confusion though (see the section Comparing capture strategies: complexity vs power in this CSID excerpt for a nice walkthrough).
You also probably meant to use .InScope(binding.Scope) rather than .InRequestScope() too,.

Resources