org.scalatest.matchers.MatchResult.scala Maven / Gradle / Ivy
/* * Copyright 2001-2013 Artima, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.scalatest.matchers import org.scalactic.Prettifier import org.scalatest.Resources /** * The result of a match operation, such as one performed by aor. * For example: * * *Matcheror *BeMatcher, which * contains one field that indicates whether the match succeeded, four fields that provide * raw failure messages to report under different circumstances, four fields providing * arguments used to construct the final failure messages using raw failure messages * and aPrettifier. Using the default constructor, * failure messages will be constructed lazily (when required). * ** A
* *MatchResult'smatchesfield indicates whether a match succeeded. If it succeeded, *matcheswill betrue. * There are four methods,failureMessage,negatedfailureMessage,midSentenceFailureMessage* andnegatedMidSentenceFailureMessagethat can be called to get final failure message strings, one of which will be * presented to the user in case of a match failure. If a match succeeds, none of these strings will be used, because no failure * message will be reported (i.e., because there was no failure to report). If a match fails (matchesisfalse), * thefailureMessage(ormidSentenceFailure—more on that below) will be reported to help the user understand what went wrong. *Understanding
* *negatedFailureMessage* The
* *negatedFailureMessageexists so that it can become thefailureMessageif the matcher is inverted, * which happens, for instance, if it is passed tonot. Here's an example: ** val equalSeven = equal (7) * val notEqualSeven = not (equalSeven) ** ** The
* *Matcher[Int]that results from passing 7 toequal, which is assigned to theequalSeven* variable, will compareInts passed to its *applymethod with 7. If 7 is passed, theequalSevenmatch will succeed. If anything other than 7 is passed, it * will fail. By contrast, thenotEqualSevenmatcher, which results from passingequalSeventonot, does * just the opposite. If 7 is passed, thenotEqualSevenmatch will fail. If anything other than 7 is passed, it will succeed. ** For example, if 8 is passed,
* *equalSeven'sMatchResultwill contain: ** expression: equalSeven(8) * matches: false * failureMessage: 8 did not equal 7 * negatedFailureMessage: 8 equaled 7 ** ** Although the
* *negatedFailureMessageis nonsensical, it will not be reported to the user. Only thefailureMessage, * which does actually explain what caused the failure, will be reported by the user. If you pass 8 tonotEqualSeven'sapply* method, by contrast, thefailureMessageandnegatedFailureMessagewill be: ** expression: notEqualSeven(8) * matches: true * failureMessage: 8 equaled 7 * negatedFailureMessage: 8 did not equal 7 ** ** Note that the messages are swapped from the
* *equalSevenmessages. This swapping was effectively performed by thenotmatcher, * which in addition to swapping thefailureMessageandnegatedFailureMessage, also inverted the *matchesvalue. Thus when you pass the same value to bothequalSevenandnotEqualSeventhematches* field of oneMatchResultwill betrueand the otherfalse. Because the *matchesfield of theMatchResultreturned bynotEqualSeven(8)istrue, * the nonsensicalfailureMessage, "8 equaled 7", will not be reported to the user. ** If 7 is passed, by contrast, the
* *failureMessageandnegatedFailureMessageofequalSeven* will be: ** expression: equalSeven(7) * matches: true * failureMessage: 7 did not equal 7 * negatedFailureMessage: 7 equaled 7 ** ** In this case
* *equalSeven'sfailureMessageis nonsensical, but because the match succeeded, the nonsensical message will * not be reported to the user. * If you pass 7 tonotEqualSeven'sapply* method, you'll get: ** expression: notEqualSeven(7) * matches: false * failureMessage: 7 equaled 7 * negatedFailureMessage: 7 did not equal 7 ** ** Again the messages are swapped from the
* *equalSevenmessages, but this time, thefailureMessagemakes sense * and explains what went wrong: thenotEqualSevenmatch failed because the number passed did in fact equal 7. Since * the match failed, this failure message, "7 equaled 7", will be reported to the user. *Understanding the "
* *midSentence" messages* When a ScalaTest matcher expression that involves
andororfails, the failure message that * results is composed from the failure messages of the left and right matcher operatnds toandor* 8 should (equal (7) or equal (9)) ** ** This above expression would fail with the following failure message reported to the user: *
* ** 8 did not equal 7, and 8 did not equal 9 ** ** This works fine, but what if the failure messages being combined begin with a capital letter, such as: *
* ** The name property did not equal "Ricky" ** ** A combination of two such failure messages might result in an abomination of English punctuation, such as: *
* ** The name property did not equal "Ricky", and The name property did not equal "Bobby" ** ** Because ScalaTest is an internationalized application, taking all of its strings from a property file * enabling it to be localized, it isn't a good idea to force the first character to lower case. Besides, * it might actually represent a String value which should stay upper case. The
* *midSentenceFailureMessage* exists for this situation. If the failure message is used at the beginning of the sentence,failureMessage* will be used. But if it appears mid-sentence, or at the end of the sentence,midSentenceFailureMessage* will be used. Given these failure message strings: ** failureMessage: The name property did not equal "Bobby" * midSentenceFailureMessage: the name property did not equal "Bobby" ** ** The resulting failure of the
* *orexpression involving to matchers would make any English teacher proud: ** The name property did not equal "Ricky", and the name property did not equal "Bobby" ** * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @param rawMidSentenceFailureMessage raw failure message suitable for appearing mid-sentence * @param rawMidSentenceNegatedFailureMessage raw negated failure message suitable for appearing mid-sentence * @param failureMessageArgs arguments for constructing failure message to report if a match fails * @param negatedFailureMessageArgs arguments for constructing message with a meaning opposite to that of the failure message * @param midSentenceFailureMessageArgs arguments for constructing failure message suitable for appearing mid-sentence * @param midSentenceNegatedFailureMessageArgs arguments for constructing negated failure message suitable for appearing mid-sentence * @param prettifier aPrettifierto prettify arguments before constructing the messages * * @author Bill Venners * @author Chee Seng */ final case class MatchResult( matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String, rawMidSentenceFailureMessage: String, rawMidSentenceNegatedFailureMessage: String, failureMessageArgs: IndexedSeq[Any], negatedFailureMessageArgs: IndexedSeq[Any], midSentenceFailureMessageArgs: IndexedSeq[Any], midSentenceNegatedFailureMessageArgs: IndexedSeq[Any], prettifier: Prettifier = Prettifier.default ) { /** * Constructs a newMatchResultwith passedmatches,rawFailureMessage, and *rawNegativeFailureMessagefields. TherawMidSentenceFailureMessagewill return the same * string asrawFailureMessage, and therawMidSentenceNegatedFailureMessagewill return the * same string asrawNegatedFailureMessage.failureMessageArgs,negatedFailureMessageArgs, *midSentenceFailureMessageArgs,midSentenceNegatedFailureMessageArgswill beVector.empty* andPrettifier.defaultwill be used. * * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message */ def this(matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String) = this( matches, rawFailureMessage, rawNegatedFailureMessage, rawFailureMessage, rawNegatedFailureMessage, Vector.empty, Vector.empty, Vector.empty, Vector.empty, Prettifier.default ) /** * Construct failure message to report if a match fails, usingrawFailureMessage,failureMessageArgsandprettifier* * @return failure message to report if a match fails */ def failureMessage: String = if (failureMessageArgs.isEmpty) rawFailureMessage else makeString(rawFailureMessage, failureMessageArgs) /** * Construct message with a meaning opposite to that of the failure message, usingrawNegatedFailureMessage,negatedFailureMessageArgsandprettifier* * @return message with a meaning opposite to that of the failure message */ def negatedFailureMessage: String = if (negatedFailureMessageArgs.isEmpty) rawNegatedFailureMessage else makeString(rawNegatedFailureMessage, negatedFailureMessageArgs) /** * Construct failure message suitable for appearing mid-sentence, usingrawMidSentenceFailureMessage,midSentenceFailureMessageArgsandprettifier* * @return failure message suitable for appearing mid-sentence */ def midSentenceFailureMessage: String = if (midSentenceFailureMessageArgs.isEmpty) rawMidSentenceFailureMessage else makeString(rawMidSentenceFailureMessage, midSentenceFailureMessageArgs) /** * Construct negated failure message suitable for appearing mid-sentence, usingrawMidSentenceNegatedFailureMessage,midSentenceNegatedFailureMessageArgsandprettifier* * @return negated failure message suitable for appearing mid-sentence */ def midSentenceNegatedFailureMessage: String = if (midSentenceNegatedFailureMessageArgs.isEmpty) rawMidSentenceNegatedFailureMessage else makeString(rawMidSentenceNegatedFailureMessage, midSentenceNegatedFailureMessageArgs) /** * Get a negated version of this MatchResult, matches field will be negated and all messages field will be substituted with its counter-part. * * @return a negated version of this MatchResult */ def negated: MatchResult = MatchResult(!matches, rawNegatedFailureMessage, rawFailureMessage, rawMidSentenceNegatedFailureMessage, rawMidSentenceFailureMessage, negatedFailureMessageArgs, failureMessageArgs, midSentenceNegatedFailureMessageArgs, midSentenceFailureMessageArgs) private def makeString(rawString: String, args: IndexedSeq[Any]): String = Resources.formatString(rawString, args.map(prettifier).toArray) } /** * Companion object for theMatchResultcase class. * * @author Bill Venners */ object MatchResult { /** * Factory method that constructs a newMatchResultwith passedmatches,failureMessage, *negativeFailureMessage,midSentenceFailureMessage, *midSentenceNegatedFailureMessage,failureMessageArgs, andnegatedFailureMessageArgsfields. *failureMessageArgs, andnegatedFailureMessageArgswill be used in place ofmidSentenceFailureMessageArgs* andmidSentenceNegatedFailureMessageArgs. * * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @param rawMidSentenceFailureMessage raw failure message to report if a match fails * @param rawMidSentenceNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @param failureMessageArgs arguments for constructing failure message to report if a match fails * @param negatedFailureMessageArgs arguments for constructing message with a meaning opposite to that of the failure message * @return aMatchResultinstance */ def apply(matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String, rawMidSentenceFailureMessage: String, rawMidSentenceNegatedFailureMessage: String, failureMessageArgs: IndexedSeq[Any], negatedFailureMessageArgs: IndexedSeq[Any]): MatchResult = new MatchResult(matches, rawFailureMessage, rawNegatedFailureMessage, rawMidSentenceFailureMessage, rawMidSentenceNegatedFailureMessage, failureMessageArgs, negatedFailureMessageArgs, failureMessageArgs, negatedFailureMessageArgs, Prettifier.default) /** * Factory method that constructs a newMatchResultwith passedmatches,rawFailureMessage, *rawNegativeFailureMessage,rawMidSentenceFailureMessage, and *rawMidSentenceNegatedFailureMessagefields. All argument fields will haveVector.emptyvalues. * This is suitable to create MatchResult with eager error messages, and its mid-sentence messages need to be different. * * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @param rawMidSentenceFailureMessage raw failure message to report if a match fails * @param rawMidSentenceNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @return aMatchResultinstance */ def apply(matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String, rawMidSentenceFailureMessage: String, rawMidSentenceNegatedFailureMessage: String): MatchResult = new MatchResult(matches, rawFailureMessage, rawNegatedFailureMessage, rawMidSentenceFailureMessage, rawMidSentenceNegatedFailureMessage, Vector.empty, Vector.empty, Vector.empty, Vector.empty, Prettifier.default) /** * Factory method that constructs a newMatchResultwith passedmatches,rawFailureMessage, and *rawNegativeFailureMessagefields. TherawMidSentenceFailureMessagewill return the same * string asrawFailureMessage, and therawMidSentenceNegatedFailureMessagewill return the * same string asrawNegatedFailureMessage. All argument fields will haveVector.emptyvalues. * This is suitable to create MatchResult with eager error messages that have same mid-sentence messages. * * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @return aMatchResultinstance */ def apply(matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String): MatchResult = new MatchResult(matches, rawFailureMessage, rawNegatedFailureMessage, rawFailureMessage, rawNegatedFailureMessage, Vector.empty, Vector.empty, Vector.empty, Vector.empty, Prettifier.default) /** * Factory method that constructs a newMatchResultwith passedmatches,rawFailureMessage, *rawNegativeFailureMessageandargsfields. TherawMidSentenceFailureMessagewill return the same * string asrawFailureMessage, and therawMidSentenceNegatedFailureMessagewill return the * same string asrawNegatedFailureMessage. All argument fields will useargsas arguments. * This is suitable to create MatchResult with lazy error messages that have same mid-sentence messages and arguments. * * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @param args arguments for error messages construction * @return aMatchResultinstance */ def apply(matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String, args: IndexedSeq[Any]) = new MatchResult( matches, rawFailureMessage, rawNegatedFailureMessage, rawFailureMessage, rawNegatedFailureMessage, args, args, args, args, Prettifier.default ) /** * Factory method that constructs a newMatchResultwith passedmatches,rawFailureMessage, *rawNegativeFailureMessage,failureMessageArgsandnegatedFailureMessageArgsfields. * TherawMidSentenceFailureMessagewill return the same string asrawFailureMessage, and the *rawMidSentenceNegatedFailureMessagewill return the same string asrawNegatedFailureMessage. * ThemidSentenceFailureMessageArgswill return the same asfailureMessageArgs, and the *midSentenceNegatedFailureMessageArgswill return the same asnegatedFailureMessageArgs. * This is suitable to create MatchResult with lazy error messages that have same mid-sentence and use different arguments for * negated messages. * * @param matches indicates whether or not the matcher matched * @param rawFailureMessage raw failure message to report if a match fails * @param rawNegatedFailureMessage raw message with a meaning opposite to that of the failure message * @param failureMessageArgs arguments for constructing failure message to report if a match fails * @param negatedFailureMessageArgs arguments for constructing message with a meaning opposite to that of the failure message * @return aMatchResultinstance */ def apply(matches: Boolean, rawFailureMessage: String, rawNegatedFailureMessage: String, failureMessageArgs: IndexedSeq[Any], negatedFailureMessageArgs: IndexedSeq[Any]) = new MatchResult( matches, rawFailureMessage, rawNegatedFailureMessage, rawFailureMessage, rawNegatedFailureMessage, failureMessageArgs, negatedFailureMessageArgs, failureMessageArgs, negatedFailureMessageArgs, Prettifier.default ) }