What is the correct syntax to Verify a mock logger call in F#? - f#

I'm unit testing an F# function that calls ILogger.LogInformation. I'm attempting to verify that the function made the call as expected. Here is the verify statement I have so far:
let mockLogger = Mock<ILogger<MyFunction>>()
// call function that uses ILogger.LogInformation.
mockLogger.Verify(fun x -> x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once)
When I try this I get the following error:
System.ArgumentException: Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit' (Parameter 'a...
System.ArgumentException
Expression of type 'System.Void' cannot be used for constructor parameter of type 'Microsoft.FSharp.Core.Unit' (Parameter 'arguments[0]')
at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
at System.Dynamic.Utils.ExpressionUtils.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments, String methodParamName)
at System.Linq.Expressions.Expression.New(ConstructorInfo constructor, IEnumerable`1 arguments)
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 616
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.ConvExprToLinqInContext(ConvEnv env, FSharpExpr inp) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 599
at Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToLambdaExpression[T](FSharpExpr`1 e) in D:\a\_work\1\s\src\fsharp\FSharp.Core\Linq.fs:line 698
The exception is thrown when it calls the Verify method. How can I change this to get past this error?

I don't know much about Moq, but I think part of the problem here is that you need another pair of parentheses around your lambda to separate it from the Times.Once argument. Try something like this instead:
mockLogger.Verify(
(fun x -> x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.IsAny(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception, string>>())),
Times.Once)
Without the extra parens, your lambda returns a tuple, so your code is currently calling this method:
Verify: expression: Expression<Action<'T>> -> unit
But I think you want to call this method instead:
Verify: expression: Expression<Action<'T>> * times: Times -> unit
Here's a simpler example that should make the difference clear:
Verify(fun x -> x, 1) // call Verify with a single argument (a lambda that returns a tuple)
Verify((fun x -> x), 1) // call Verify with two arguments (a lambda and the literal value 1)

Related

How to declare a function type throwable?

I know in kotlin-multiplatform, you can annotate a function with #Throws to make it a throwable function. So that converted Java/Swift code has the throws modifier to function signature.
However, when I have a function's parameter who is a function as well, how do I mark this function throwable?
e.g:
fun foo(run : () -> Unit) {}
the above function has a parameter "run", which takes a closure/function. But this parameter will be compiled without "throws" modifier, so that in Java/Swift, I can't throw anything in the closure that is passed to this function.
I tried to add the #Throws annotation to the function. Putting it outside of function declaration results the foo() function marked as "throws". Putting it in the parameter parenthesis, either before or after the colon, results an error saying annotation is not applicable to target "value parameter"/"type usage"
To summarize, what I'm looking for is something like:
fun foo(#Throws(Throwable::class) run : () -> Unit)
or
fun foo(run : #Throws(Throwable::class) () -> Unit)
Any hint/help on this issue is very very appreciated!
You can not annotate function parameter with #Throws, because the annotation has following targets: AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER and AnnotationTarget.CONSTRUCTOR.
Created feature request in Kotlin tracker: https://youtrack.jetbrains.com/issue/KT-39688

How to use the C# action type in F#?

I have this C# method:
public static IDisposable RegisterErrorHandler(Action<string, Exception> errorHandler)
How can I create the errorHandler in F#?
F# will automatically convert lambda functions to delegate if they have the right types of arguments. In your case, you should be able to just provide a lambda function by writing:
Demo.RegisterErrorHandler(fun msg exn ->
printfn "Error with message %s and exception %A" msg exn)
Note that you need to write the two parameters as space separated rather than (msg, exn) which would indicate a tuple. Also, your lambda needs to return unit - otherwise the types won't match.
In cases where you cannot get this to work, it is useful to create the delegate explicitly. This will often make it easier to find out what's wrong with your lambda:
Demo.RegisterErrorHandler(Action<string, Exception>(fun msg exn ->
printfn "Error with message %s and exception %A" msg exn))
In most cases, you do not need explicit Action though.

In Dart2, what is the correct "anything" type to use for generics?

AngularDart has a class called AppView, i.e. abstract class AppView<T> {}.
One (at least) of these are generated for every class annotated with #Component:
// file.dart
#Component(...)
class DashboardComponent {}
// file.template.dart (Generated)
class ViewDashboardComponent extends AppView<DashboardComponent> {}
I have code elsewhere in the framework that doesn't care what this T type is. I'm a little confused with Dart 2 what the "right" "anything" type to use. For example, I could use:
AppView
AppView<dynamic>
AppView<Object>
AppView<Null>
AppView<void>
I think more than one of these will "work". But which is the "right" one to use in this case?
You should be fine to use AppView (or AppView<dynamic>) just about anywhere. I can think of two examples where this will get you into trouble though:
If you are instantiating an AppView, you definitely want that type parameter. See the following error when you don't:
$ cat a.dart
void main() {
List<dynamic> a = ["one", "two", "three"];
List<String> b = a;
}
$ dart --preview-dart-2 a.dart
Unhandled exception:
type 'List' is not a subtype of type 'List<String>' where
List is from dart:core
List is from dart:core
String is from dart:core
#0 main (file:///Users/sam/a.dart:3:20)
#1 _startIsolate.<anonymous closure> (dart:isolate/isolate_patch.dart:279:19)
#2 _RawReceivePortImpl._handleMessage (dart:isolate/isolate_patch.dart:165:12)
If you are ever assigning a closure to a site that expects a closure with one or more typed parameters that involve T, you will see a "uses dynamic as bottom" static error (from the analyzer), and probably a runtime error as well:
$ cat f.dart
void main() {
List a = <String>["one", "two", "three"];
a.map((String s) => s.toUpperCase());
List b = ["one", "two", "three"];
b.map((String s) => s.toUpperCase());
}
$ dart --preview-dart-2 f.dart
f.dart:3:9: Error: A value of type '(dart.core::String) → dart.core::String' can't be assigned to a variable of type '(dynamic) → dynamic'.
Try changing the type of the left hand side, or casting the right hand side to '(dynamic) → dynamic'.
a.map((String s) => s.toUpperCase());
^
f.dart:6:9: Error: A value of type '(dart.core::String) → dart.core::String' can't be assigned to a variable of type '(dynamic) → dynamic'.
Try changing the type of the left hand side, or casting the right hand side to '(dynamic) → dynamic'.
b.map((String s) => s.toUpperCase());
^
(I'm not certain any Dart tool yet has complete Dart 2 runtime and compile time semantics, so this might change slightly.)
In these cases, it is best to use generic classes, generic methods, and generic typedefs to encapsulate, for a given scope, what the values of an object's type parameters might be.
I suspect there is a difference between dynamic and Object in Dart 2, and I think Günter covered this in his response, though if your code "doesn't care what this T type is", then you're probably not calling any methods on the component.
Edit: void
AppView<void> might be a good choice in this case, as an actual check that you actually never touch the underlying component (Object would probably serve the same purpose). See how we are allowed to access properties of a List<void> but not properties of the elements:
$ cat g.dart
void main() {
var c = <String>["one", "two", "three"];
fn(c);
fn2(c);
}
int fn(List<void> list) => list.length;
int fn2(List<void> list) => list.first.length;
$ dart --preview-dart-2 g.dart
g.dart:9:40: Error: The getter 'length' isn't defined for the class 'void'.
Try correcting the name to the name of an existing getter, or defining a getter or field named 'length'.
int fn2(List<void> list) => list.first.length;
^
I assume you know better than me, but my attempt
AppView - works - same as AppView<dynamic>
AppView<dynamic> - works - really means any type
AppView<Object> - works - really means any type
AppView<Null> - won't work, only null and void values match for T
AppView<void> - won't work, only null and void values match for T
AppView<void> - works (see also comment below from lrn)
The difference between <dynamic> and <Object> would be that for values of type T with T == dynamic property or method access won't be checked statically, while for T == Object only methods and properties of the Object class can be accessed without a previous cast.

Why can't a function with byref be converted directly to delegate?

Under normal circumstances, F# functions can be converted to delegates by calling new DelegateType and passing in the function as an argument. But when the delegate contains byref parameter, this is not possible directly. For example the code:
type ActionByRef<'a> = delegate of 'a byref -> unit
let f (x:double byref) =
x <- 6.0
let x = ref 42.0
let d = new ActionByRef<_>(f)
won't compile, giving the following error:
This function value is being used to construct a delegate type whose signature includes a byref argument. You must use an explicit lambda expression taking 1 arguments.
Following the error, modifying the code to use
let d = new ActionByRef<_>(fun x -> f(&x))
works. But my question is: why is this necessary? Why won't F# allow the conversion from named function to this delegate, but conversion from lambda is fine?
I came upon this behavior when researching another question. I realize byref is meant only for compatibility with other .Net languages.
I think the problem is that byref<'T> is not an actual type in F# - it looks like a type (to make the language simpler), but it gets compiled to a parameter marked with the out flag. This means that byref<'T> can be only used in a place where the compiler can actually use the out flag.
The problem with function values is that you can construct function e.g. by partial application:
let foo (n:int) (b:byref<int>) =
b <- n
When you pass foo as an argument to a delegate constructor, it is a specific case of partial application (with no arguments), but partial application actually needs to construct a new method and then give that to the delegate:
type IntRefAction = delegate of byref<int> -> unit
let ac = IntRefAction(foo 5)
The compiler could be clever and generate new method with byref parameter (or out flag) and then pass that by reference to the actual function, but in general, there will be other compiler-generated method when you don't use the fun ... -> ... syntax. Handling this would add complexity and I think that's a relatively rare case, so the F# compiler doesn't do that and asks you to be more explicit...

F# how to AddHandler alike VB.NET

VB.NET code is :
AddHandler TheGrp.DataChanged, AddressOf theGrp_DataChange
So how can I do same with F# ?
theGrp.DataChanged.AddHandler(X.theGrp_DataChange)
Error 1 This function takes too many arguments, or is used in a context where a function is not expected
Try theGrp.DataChanged.AddHandler(fun o e -> X.theGrp_DataChange(o, e)). The signature for AddHandler indicates that it takes a delegate, so you can either explicitly create one (via something like DataChangedEventHandler(fun o e -> X.theGrp_DataChange(o, e))) or you can let the compiler implicitly add the delegate constructor when given a function definition, but you can't just use the method itself.
Alternatively, if you don't want to create a lambda expression explicitly, you can also write (In this case, the function signature matches the signature required by the delegate, so it should work):
theGrp.DataChanged.AddHandler(DataChangedEventHandler(x.theGrp_DataChanged))
Also, if you don't need the sender argument, you can declare the theGrp_DataChanged method to take only the event args argument and then write just:
theGrp.DataChanged.Add(x.theGrp_DataChanged)

Resources