Search code examples
f#fsunit

F# - (NUnit ApplyTo) member matches multiple overloads ... please restrict it to one


I'm trying to write custom equality constraint to compare 2 objects.

open FsUnit
open NUnit.Framework.Constraints

type equalCompany(expected:Company) = 
    inherit Constraints.EqualConstraint(expected)    

    override this.ApplyTo (actual:Company option) = 
        //actual.IsSome |> should equal True
        //actual.Value.Id |> should equal expected.Id

        ConstraintResult(this, actual, true)

// example of usage:
actualCompany |> should equalCompany expectedCompany

It complains because the ApplyTo implementation matches multiple overloads and I can't find the right syntax.
Ideally I like to compare to Company option but still just Company is fine.

The types involved are the following:

type CompanyType =
    | Bank
    | Exchange

type Company = {
    Id: string
    Types: CompanyType list
}

and I'm trying to write my equality constraint because the simple existing equal does not work properly with Types (the list, also if sorted, appears always different)

How can I properly override the ApplyTo function?


Solution

  • I think the issue is that the ApplyTo method that you are trying to override is generic and needs to have a signature ApplyTo<'T> : 'T -> ConstraintResult.

    If I understand your code correctly, you are trying to define a comparison between Company and Company option. To Do this, you would need to check (at runtime) that the value passed to ApplyTo is of the right type. Then you can cast it and implement whatever logic you need.

    Here is a minimal sample that worked for me, written as an F# script file:

    #r "nuget: nunit"
    #r "nuget: fsunit"
    
    type Company(s) = 
      member x.Name = s
    
    open FsUnit
    open NUnit.Framework.Constraints
    
    type equalCompany(expected:Company) = 
        inherit EqualConstraint(expected)    
    
        override this.ApplyTo<'T>(actual:'T) = 
            match box actual with 
            | :? option<Company> as co ->
              ConstraintResult(this, actual, 
                co.IsSome && co.Value.Name = expected.Name)
            | _ ->
              ConstraintResult(this, actual, false)
    
    let actualCompany = Company("Test")
    let expectedCompany = Company("Test")
    
    // This passes, because it has the right type
    Some actualCompany |> should equalCompany expectedCompany
    
    // This does not, because the 'ApplyTo' logic does not handle this type
    actualCompany |> should equalCompany expectedCompany