1/* 2 * Copyright 2001-2008 Artima, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package org.scalatest.matchers 17 18import org.scalatest._ 19import scala.collection.mutable.ListBuffer 20 21trait CustomMatchers { 22 23 class FileExistsMatcher extends Matcher[java.io.File] { 24 25 def apply(left: java.io.File) = { 26 27 val fileOrDir = if (left.isFile) "file" else "directory" 28 29 val failureMessageSuffix = 30 fileOrDir + " named " + left.getName + " did not exist" 31 32 val negatedFailureMessageSuffix = 33 fileOrDir + " named " + left.getName + " existed" 34 35 MatchResult( 36 left.exists, 37 "The " + failureMessageSuffix, 38 "The " + negatedFailureMessageSuffix, 39 "the " + failureMessageSuffix, 40 "the " + negatedFailureMessageSuffix 41 ) 42 } 43 } 44 45 val exist = new FileExistsMatcher 46} 47 48class CustomMatcherSpec extends Spec with ShouldMatchers with CustomMatchers { 49 50 describe("A customer matcher") { 51 52 it("should work when used in various combinations of and, or, and not, when the file does not exist") { 53 54 val imaginaryFile = new java.io.File("imaginary.txt") 55 56 imaginaryFile should not (exist) 57 58 val caught1 = intercept[TestFailedException] { 59 imaginaryFile should exist 60 } 61 assert(caught1.getMessage === "The directory named imaginary.txt did not exist") 62 63 imaginaryFile should (not be a ('file) and not (exist)) 64 65 val caught2 = intercept[TestFailedException] { 66 imaginaryFile should (not be a ('file) and exist) 67 } 68 assert(caught2.getMessage === "imaginary.txt was not a file, but the directory named imaginary.txt did not exist") 69 } 70 71 it("should work when used in various combinations of and, or, and not, when the file does exist") { 72 73 val tempFile = java.io.File.createTempFile("delete", "me") 74 75 try { 76 tempFile should exist 77 78 val caught1 = intercept[TestFailedException] { 79 tempFile should not (exist) 80 } 81 assert(caught1.getMessage === "The file named " + tempFile.getName + " existed") 82 caught1.getMessage should startWith ("The file named delete") 83 caught1.getMessage should endWith ("me existed") 84 85 tempFile should (be a ('file) and exist) 86 87 val caught2 = intercept[TestFailedException] { 88 tempFile should (be a ('file) and not (exist)) 89 } 90 caught2.getMessage should endWith (", but the file named " + tempFile.getName + " existed") 91 } 92 finally { 93 tempFile.delete() 94 } 95 } 96 } 97 98 describe("the compose method") { 99 describe("on functions that return a matcher") { 100 it("should return another function that returns a usable matcher") { 101 val beAsIntEqual = (equal (_: Int)) compose ((_: String).toInt) 102 3 should beAsIntEqual ("3") 103 3 should not (beAsIntEqual ("4")) 104 } 105 } 106 107 describe("on matchers themselves") { 108 it("should return a usable matcher") { 109 val beOdd = 110 new Matcher[Int] { 111 def apply(left: Int) = 112 MatchResult( 113 left % 2 == 1, 114 left + " was not odd", 115 left + " was odd" 116 ) 117 } 118 119 3 should beOdd 120 4 should not (beOdd) 121 122 // val beOddAsInt = beOdd compose ((_: String).toInt) 123 val beOddAsInt = beOdd compose { (s: String) => s.toInt } 124 125 "3" should beOddAsInt 126 "4" should not (beOddAsInt) 127 128 case class Product(name: String) 129 case class LineItem(product: Product) 130 def haveProduct(p: Product) = equal(p) compose { (lineItem: LineItem) => lineItem.product } 131 132 LineItem(Product("widgets")) should (haveProduct(Product("widgets"))) 133 } 134 } 135 } 136 137 describe("A factory method on Matcher's companion object") { 138 it("should produce a matcher that executes the passed function when its apply is called") { 139 val f = { (s: String) => MatchResult(s.length < 3, "s was not less than 3", "s was less than 3") } 140 val haveLengthLessThanThree = Matcher(f) 141 "" should haveLengthLessThanThree 142 "x" should haveLengthLessThanThree 143 "xx" should haveLengthLessThanThree 144 "xxx" should not (haveLengthLessThanThree) 145 "xxxx" should not (haveLengthLessThanThree) 146 } 147 } 148} 149 150