scala - ScalaTest - writing custom matchers -
i running problem while writing custom matcher nodeseq:
private def matchxml(expected: nodeseq) = new matcher[nodeseq] { def apply(left: nodeseq): matchresult = matchresult(left xml_== expected, "xml structure not same (watch spaces in tag texts)", "xml messages equal") } this compiles, following piece of code:
val expected : nodeseq = ... val xml : nodeseq = ... xml should matchxml(expected) causes:
error: overloaded method value should alternatives: (beword: xmlstripdecoratortests.this.beword)xmlstripdecoratortests.this.resultofbewordforanyref[scala.collection.genseq[scala.xml.node]] <and> (notword: xmlstripdecoratortests.this.notword)xmlstripdecoratortests.this.resultofnotwordforanyref[scala.collection.genseq[scala.xml.node]] <and> (haveword: xmlstripdecoratortests.this.haveword)xmlstripdecoratortests.this.resultofhavewordforseq[scala.xml.node] <and> (rightmatcher: org.scalatest.matchers.matcher[scala.collection.genseq[scala.xml.node]])unit cannot applied (org.scalatest.matchers.matcher[scala.xml.nodeseq]) xml should (matchxml(expected)) any ideas means?
why fails typecheck:
the type checker works in following way.
xml.should(matchxml(expected)) - because method
shouldnot part ofnodeseq, compiler tries find implicit conversionxmlshouldmatcher. book "programming in scala" specifies such implicit conversion should specific:
"up through scala 2.7, end of story. whenever multiple implicit conversions applied, compiler refused choose between them. ... scala 2.8 loosens rule. if 1 of available conversions strictly more specific others, compiler choose more specific one. ... 1 implicit conversion more specific if 1 of following applies: argument type of former subtype of latter’s. .."
because
nodeseqextendsseq[node], following functionconverttoseqshouldwrapper[t](o : scala.genseq[t]) : seqshouldwrapper[t]is therefore specific 1 among others.
the program rewritten as:
`converttoseqshouldwrapper(xml).should(matchxml(expected))` where converttoseqshouldwrapper(xml) seqshouldwrapper[t] t = genseq[node].
the method should seqshouldwrapper accepts matcher[t] function of type t => matchresult. therefore, accepts matcher[genseq[node]].
because t appearing left of arrow, matchers not covariant in t, contravariant. nodeseq genseq[node], matcher[genseq[node]] matcher[nodeseq], not opposite.this explains above error, method should cannot accept matcher[nodeseq] , requires matcher[genseq[node]].
2 solutions
- replace instances of
nodeseqgenseq[node]type matches everywhere. alternatively, wrap xml explicitely conversion function.
converttoanyshouldwrapper(xml).should(matchxml(expected))
Comments
Post a Comment