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 org.scalatest.prop.Checkers 20import org.scalacheck._ 21import Arbitrary._ 22import Prop._ 23import scala.reflect.BeanProperty 24 25// TODO: check not not and not not not to make sure those negative failure messages make sense. 26class ShouldHavePropertiesSpec extends Spec with ShouldMatchers with Checkers with ReturnsNormallyThrowsAssertion with BookPropertyMatchers { 27 28 // Checking for a specific size 29 describe("The 'have (' syntax") { 30 31 describe("on an object with properties") { 32 33 val book = new Book("A Tale of Two Cities", "Dickens", 1859, 45, true) 34 val badBook = new Book("A Tale of Two Cities", "Dickens", 1859, 45, false) 35 // val bookshelf = new Bookshelf(book, badBook, book) 36 37 it("should do nothing if there's just one property and it matches") { 38 book should have (title ("A Tale of Two Cities")) 39 book should have ('title ("A Tale of Two Cities")) 40 } 41 42 it("should do nothing if all the properties match") { 43 book should have ( 44 title ("A Tale of Two Cities"), 45 author ("Dickens"), 46 pubYear (1859) 47 ) 48 book should have ( 49 'title ("A Tale of Two Cities"), 50 'author ("Dickens"), 51 'pubYear (1859) 52 ) 53 } 54 55 it("should do nothing if there's just one property and it does not match, when used with not") { 56 book should not have (title ("One Hundred Years of Solitude")) 57 book should not have ('title ("One Hundred Years of Solitude")) 58 } 59 60 // title/author matches | have | have not 61 // 0 0 | 0 | 1 62 // 0 1 | 0 | 1 63 // 1 0 | 0 | 1 64 // 1 1 | 1 | 0 65 it("should do nothing if at least one of the properties does not match, when used with not") { 66 67 // 0 0 68 book should not have ( 69 title ("Moby Dick"), 70 author ("Melville") 71 ) 72 book should not have ( 73 'title ("Moby Dick"), 74 'author ("Melville") 75 ) 76 77 // 0 1 78 book should not have ( 79 title ("Moby Dick"), 80 author ("Dickens") 81 ) 82 book should not have ( 83 'title ("Moby Dick"), 84 'author ("Dickens") 85 ) 86 87 // 1 0 88 book should not have ( 89 title ("A Tale of Two Cities"), 90 author ("Melville") 91 ) 92 book should not have ( 93 'title ("A Tale of Two Cities"), 94 'author ("Melville") 95 ) 96 } 97 98 it("should do nothing if all properties match, when used with and") { 99 book should (have (title ("A Tale of Two Cities")) and (have (author ("Dickens")))) 100 book should (have (title ("A Tale of Two Cities")) and have (author ("Dickens"))) 101 book should (have ('title ("A Tale of Two Cities")) and (have ('author ("Dickens")))) 102 book should (have ('title ("A Tale of Two Cities")) and have ('author ("Dickens"))) 103 } 104 105 it("should do nothing if at least one property matches, when used with or") { 106 107 // both true 108 book should (have (title ("A Tale of Two Cities")) or (have (author ("Dickens")))) 109 book should (have (title ("A Tale of Two Cities")) or have (author ("Dickens"))) 110 book should (have ('title ("A Tale of Two Cities")) or (have ('author ("Dickens")))) 111 book should (have ('title ("A Tale of Two Cities")) or have ('author ("Dickens"))) 112 113 // first true 114 book should (have (title ("A Tale of Two Cities")) or (have (author ("Melville")))) 115 book should (have (title ("A Tale of Two Cities")) or have (author ("Melville"))) 116 book should (have ('title ("A Tale of Two Cities")) or (have ('author ("Melville")))) 117 book should (have ('title ("A Tale of Two Cities")) or have ('author ("Melville"))) 118 119 // second true 120 book should (have (title ("Moby Dick")) or (have (author ("Dickens")))) 121 book should (have (title ("Moby Dick")) or have (author ("Dickens"))) 122 book should (have ('title ("Moby Dick")) or (have ('author ("Dickens")))) 123 book should (have ('title ("Moby Dick")) or have ('author ("Dickens"))) 124 } 125 126 it("should do nothing if no properties match, when used with and and not") { 127 128 // just one property 129 book should (not have (title ("Moby Dick")) and (not have (author ("Melville")))) 130 book should (not have (title ("Moby Dick")) and not (have (author ("Melville")))) 131 book should (not have (title ("Moby Dick")) and not have (author ("Melville"))) 132 book should (not have ('title ("Moby Dick")) and (not have ('author ("Melville")))) 133 book should (not have ('title ("Moby Dick")) and not (have ('author ("Melville")))) 134 book should (not have ('title ("Moby Dick")) and not have ('author ("Melville"))) 135 136 // multiple properties 137 book should (not have (title ("Moby Dick"), pubYear (1859)) and (not have (pubYear (1859), author ("Melville")))) 138 book should (not have (title ("Moby Dick"), pubYear (1859)) and not (have (pubYear (1859), author ("Melville")))) 139 book should (not have (title ("Moby Dick"), pubYear (1859)) and not have (pubYear (1859), author ("Melville"))) 140 book should (not have ('title ("Moby Dick"), pubYear (1859)) and (not have ('pubYear (1859), 'author ("Melville")))) 141 book should (not have ('title ("Moby Dick"), pubYear (1859)) and not (have ('pubYear (1859), 'author ("Melville")))) 142 book should (not have ('title ("Moby Dick"), pubYear (1859)) and not have ('pubYear (1859), 'author ("Melville"))) 143 } 144 145 it("should do nothing if no properties match, when used with or and not") { 146 147 // both true 148 // just one property 149 book should (not have (title ("Moby Dick")) or (not have (author ("Melville")))) 150 book should (not have (title ("Moby Dick")) or not (have (author ("Melville")))) 151 book should (not have (title ("Moby Dick")) or not have (author ("Melville"))) 152 book should (not have ('title ("Moby Dick")) or (not have ('author ("Melville")))) 153 book should (not have ('title ("Moby Dick")) or not (have ('author ("Melville")))) 154 book should (not have ('title ("Moby Dick")) or not have ('author ("Melville"))) 155 156 // multiple properties 157 book should (not have (title ("Moby Dick"), pubYear (1859)) or (not have (pubYear (1859), author ("Melville")))) 158 book should (not have (title ("Moby Dick"), pubYear (1859)) or not (have (pubYear (1859), author ("Melville")))) 159 book should (not have (title ("Moby Dick"), pubYear (1859)) or not have (pubYear (1859), author ("Melville"))) 160 book should (not have ('title ("Moby Dick"), pubYear (1859)) or (not have ('pubYear (1859), 'author ("Melville")))) 161 book should (not have ('title ("Moby Dick"), pubYear (1859)) or not (have ('pubYear (1859), 'author ("Melville")))) 162 book should (not have ('title ("Moby Dick"), pubYear (1859)) or not have ('pubYear (1859), 'author ("Melville"))) 163 164 // first true 165 // just one property 166 book should (not have (title ("Moby Dick")) or (not have (author ("Dickens")))) 167 book should (not have (title ("Moby Dick")) or not (have (author ("Dickens")))) 168 book should (not have (title ("Moby Dick")) or not have (author ("Dickens"))) 169 book should (not have ('title ("Moby Dick")) or (not have ('author ("Dickens")))) 170 book should (not have ('title ("Moby Dick")) or not (have ('author ("Dickens")))) 171 book should (not have ('title ("Moby Dick")) or not have ('author ("Dickens"))) 172 173 // multiple properties 174 book should (not have (title ("Moby Dick"), pubYear (1859)) or (not have (pubYear (1859), author ("Dickens")))) 175 book should (not have (title ("Moby Dick"), pubYear (1859)) or not (have (pubYear (1859), author ("Dickens")))) 176 book should (not have (title ("Moby Dick"), pubYear (1859)) or not have (pubYear (1859), author ("Dickens"))) 177 book should (not have ('title ("Moby Dick"), pubYear (1859)) or (not have ('pubYear (1859), 'author ("Dickens")))) 178 book should (not have ('title ("Moby Dick"), pubYear (1859)) or not (have ('pubYear (1859), 'author ("Dickens")))) 179 book should (not have ('title ("Moby Dick"), pubYear (1859)) or not have ('pubYear (1859), 'author ("Dickens"))) 180 181 // second true 182 // just one property 183 book should (not have (title ("A Tale of Two Cities")) or (not have (author ("Melville")))) 184 book should (not have (title ("A Tale of Two Cities")) or not (have (author ("Melville")))) 185 book should (not have (title ("A Tale of Two Cities")) or not have (author ("Melville"))) 186 book should (not have ('title ("A Tale of Two Cities")) or (not have ('author ("Melville")))) 187 book should (not have ('title ("A Tale of Two Cities")) or not (have ('author ("Melville")))) 188 book should (not have ('title ("A Tale of Two Cities")) or not have ('author ("Melville"))) 189 190 // multiple properties 191 book should (not have (title ("A Tale of Two Cities"), pubYear (1859)) or (not have (pubYear (1859), author ("Melville")))) 192 book should (not have (title ("A Tale of Two Cities"), pubYear (1859)) or not (have (pubYear (1859), author ("Melville")))) 193 book should (not have (title ("A Tale of Two Cities"), pubYear (1859)) or not have (pubYear (1859), author ("Melville"))) 194 book should (not have ('title ("A Tale of Two Cities"), pubYear (1859)) or (not have ('pubYear (1859), 'author ("Melville")))) 195 book should (not have ('title ("A Tale of Two Cities"), pubYear (1859)) or not (have ('pubYear (1859), 'author ("Melville")))) 196 book should (not have ('title ("A Tale of Two Cities"), pubYear (1859)) or not have ('pubYear (1859), 'author ("Melville"))) 197 } 198 199 it("should throw TestFailedException if trying to check for a non existent property") { 200 val thrown = evaluating { 201 new Object should have ('nonExistentProperty ("something")) 202 } should produce [TestFailedException] 203 thrown.getMessage should equal("have nonExistentProperty (something) used with an object that had no public field or method named nonExistentProperty or getNonExistentProperty") 204 } 205 206 it("should throw TestFailedException if there's just one property and it doesn't match") { 207 208 val caught1 = intercept[TestFailedException] { 209 book should have (author ("Gibson")) 210 } 211 assert(caught1.getMessage === "The author property had value \"Dickens\", instead of its expected value \"Gibson\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 212 213 val caught2 = intercept[TestFailedException] { 214 book should have ('author ("Gibson")) 215 } 216 assert(caught2.getMessage === "The author property had value \"Dickens\", instead of its expected value \"Gibson\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 217 } 218 219 it("should throw TestFailedException if at least one of the properties doesn't match") { 220 221 val caught1 = intercept[TestFailedException] { 222 book should have ( 223 title ("A Tale of Two Cities"), 224 author ("Gibson"), 225 pubYear (1859) 226 ) 227 } 228 assert(caught1.getMessage === "The author property had value \"Dickens\", instead of its expected value \"Gibson\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 229 230 val caught2 = intercept[TestFailedException] { 231 book should have ( 232 title ("A Tale of Two Cities"), 233 'author ("Gibson"), 234 pubYear (1859) 235 ) 236 } 237 assert(caught2.getMessage === "The author property had value \"Dickens\", instead of its expected value \"Gibson\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 238 239 val caught3 = intercept[TestFailedException] { 240 book should have ( 241 'title ("A Tale of Two Cities"), 242 'author ("Dickens"), 243 'pubYear (1959) 244 ) 245 } 246 assert(caught3.getMessage === "The pubYear property had value 1859, instead of its expected value 1959, on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 247 } 248 249 it("should throw TestFailedException if there's just one property and it matches, when used with not") { 250 251 val caught1 = intercept[TestFailedException] { 252 book should not have (author ("Dickens")) 253 } 254 assert(caught1.getMessage === "The author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 255 256 val caught2 = intercept[TestFailedException] { 257 book should not have ('author ("Dickens")) 258 } 259 assert(caught2.getMessage === "The author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 260 } 261 262 /* 263 Not (matcher) needs to yield the opposite result as (matcher) itself, and 264 that means that not (matcher) will be true if at least one 265 266 title/author/pubYear matches | have | not have 267 0 0 0 | 0 | 1 268 0 0 1 | 0 | 1 269 0 1 0 | 0 | 1 270 0 1 1 | 0 | 1 271 1 0 0 | 0 | 1 272 1 0 1 | 0 | 1 273 1 1 0 | 0 | 1 274 1 1 1 | 1 | 0 275 276 So 'not have" means that at least one is false, not all are false. 277 278 To reduce the number of tests cases just use two: 279 280 title/author matches | have | have not 281 0 0 | 0 | 1 282 0 1 | 0 | 1 283 1 0 | 0 | 1 284 1 1 | 1 | 0 285 286 287 have matches (1 1) all properties matched. 288 have does not match (0 0, 0 1, 1 0) the (first property found that doesn't match) didn't match 289 not have matches (0 0, 0 1, 1 0) the (first property found that doesn't match), as expected 290 not have does not match (1, 1) all properties matched. 291 */ 292 it("should throw TestFailedException if all of the properties match, when used with not") { 293 val caught1 = intercept[TestFailedException] { 294 book should not have ( 295 title ("A Tale of Two Cities"), 296 author ("Dickens") 297 ) 298 } 299 assert(caught1.getMessage === "All properties had their expected values, respectively, on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 300 } 301 302 it("should throw TestFailedException if at least one property does not match, when used with and") { 303 304 // second false 305 val caught1 = intercept[TestFailedException] { 306 book should (have (title ("A Tale of Two Cities")) and (have (author ("Melville")))) 307 } 308 assert(caught1.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 309 310 val caught2 = intercept[TestFailedException] { 311 book should (have (title ("A Tale of Two Cities")) and have (author ("Melville"))) 312 } 313 assert(caught2.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 314 315 val caught3 = intercept[TestFailedException] { 316 book should (have ('title ("A Tale of Two Cities")) and (have ('author ("Melville")))) 317 } 318 assert(caught3.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 319 320 val caught4 = intercept[TestFailedException] { 321 book should (have ('title ("A Tale of Two Cities")) and have ('author ("Melville"))) 322 } 323 assert(caught4.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 324 325 // first false 326 val caught11 = intercept[TestFailedException] { 327 book should (have (title ("Moby Dick")) and (have (author ("Dickens")))) 328 } 329 assert(caught11.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 330 331 val caught12 = intercept[TestFailedException] { 332 book should (have (title ("Moby Dick")) and have (author ("Dickens"))) 333 } 334 assert(caught12.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 335 336 val caught13 = intercept[TestFailedException] { 337 book should (have ('title ("Moby Dick")) and (have ('author ("Dickens")))) 338 } 339 assert(caught13.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 340 341 val caught14 = intercept[TestFailedException] { 342 book should (have ('title ("Moby Dick")) and have ('author ("Dickens"))) 343 } 344 assert(caught14.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 345 346 // both false 347 val caught21 = intercept[TestFailedException] { 348 book should (have (title ("Moby Dick")) and (have (author ("Melville")))) 349 } 350 assert(caught21.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 351 352 val caught22 = intercept[TestFailedException] { 353 book should (have (title ("Moby Dick")) and have (author ("Melville"))) 354 } 355 assert(caught22.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 356 357 val caught23 = intercept[TestFailedException] { 358 book should (have ('title ("Moby Dick")) and (have ('author ("Melville")))) 359 } 360 assert(caught23.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 361 362 val caught24 = intercept[TestFailedException] { 363 book should (have ('title ("Moby Dick")) and have ('author ("Melville"))) 364 } 365 assert(caught24.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 366 } 367 368 it("should throw TestFailedException if neither property matches, when used with or") { 369 370 // both false 371 val caught21 = intercept[TestFailedException] { 372 book should (have (title ("Moby Dick")) or (have (author ("Melville")))) 373 } 374 assert(caught21.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 375 376 val caught22 = intercept[TestFailedException] { 377 book should (have (title ("Moby Dick")) or have (author ("Melville"))) 378 } 379 assert(caught22.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 380 381 val caught23 = intercept[TestFailedException] { 382 book should (have ('title ("Moby Dick")) or (have ('author ("Melville")))) 383 } 384 assert(caught23.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 385 386 val caught24 = intercept[TestFailedException] { 387 book should (have ('title ("Moby Dick")) or have ('author ("Melville"))) 388 } 389 assert(caught24.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had value \"Dickens\", instead of its expected value \"Melville\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 390 } 391 392 it("should throw TestFailedException if at least one property does not match, when used with and and not") { 393 394 // second false 395 val caught1 = intercept[TestFailedException] { 396 book should (not have (title ("A Tale of Two Cities")) and not (have (author ("Melville")))) 397 } 398 assert(caught1.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 399 400 val caught2 = intercept[TestFailedException] { 401 book should (not have (title ("A Tale of Two Cities")) and not have (author ("Melville"))) 402 } 403 assert(caught2.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 404 405 val caught3 = intercept[TestFailedException] { 406 book should (not have ('title ("A Tale of Two Cities")) and not (have ('author ("Melville")))) 407 } 408 assert(caught3.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 409 410 val caught4 = intercept[TestFailedException] { 411 book should (not have ('title ("A Tale of Two Cities")) and not have ('author ("Melville"))) 412 } 413 assert(caught4.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 414 415 val caught5 = intercept[TestFailedException] { 416 book should (not have (title ("A Tale of Two Cities")) and (not have (author ("Melville")))) 417 } 418 assert(caught5.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 419 420 val caught6 = intercept[TestFailedException] { 421 book should (not have ('title ("A Tale of Two Cities")) and (not have ('author ("Melville")))) 422 } 423 assert(caught6.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 424 425 // first false 426 val caught11 = intercept[TestFailedException] { 427 book should (not have (title ("Moby Dick")) and not (have (author ("Dickens")))) 428 } 429 assert(caught11.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 430 431 val caught12 = intercept[TestFailedException] { 432 book should (not have (title ("Moby Dick")) and not have (author ("Dickens"))) 433 } 434 assert(caught12.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 435 436 val caught13 = intercept[TestFailedException] { 437 book should (not have ('title ("Moby Dick")) and (not have ('author ("Dickens")))) 438 } 439 assert(caught13.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 440 441 val caught14 = intercept[TestFailedException] { 442 book should (not have ('title ("Moby Dick")) and not have ('author ("Dickens"))) 443 } 444 assert(caught14.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 445 446 val caught15 = intercept[TestFailedException] { 447 book should (not have (title ("Moby Dick")) and (not have (author ("Dickens")))) 448 } 449 assert(caught15.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 450 451 val caught16 = intercept[TestFailedException] { 452 book should (not have ('title ("Moby Dick")) and (not have ('author ("Dickens")))) 453 } 454 assert(caught16.getMessage === "The title property had value \"A Tale of Two Cities\", instead of its expected value \"Moby Dick\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), but the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 455 456 // both true 457 val caught21 = intercept[TestFailedException] { 458 book should (not have (title ("A Tale of Two Cities")) and (not have (author ("Dickens")))) 459 } 460 assert(caught21.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 461 462 val caught22 = intercept[TestFailedException] { 463 book should (not have (title ("A Tale of Two Cities")) and not have (author ("Dickens"))) 464 } 465 assert(caught22.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 466 467 val caught23 = intercept[TestFailedException] { 468 book should (not have ('title ("A Tale of Two Cities")) and (not have ('author ("Dickens")))) 469 } 470 assert(caught23.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 471 472 val caught24 = intercept[TestFailedException] { 473 book should (not have ('title ("A Tale of Two Cities")) and not have ('author ("Dickens"))) 474 } 475 assert(caught24.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 476 477 val caught25 = intercept[TestFailedException] { 478 book should (not have (title ("A Tale of Two Cities")) and (not (have (author ("Dickens"))))) 479 } 480 assert(caught25.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 481 482 val caught26 = intercept[TestFailedException] { 483 book should (not have ('title ("A Tale of Two Cities")) and (not (have ('author ("Dickens"))))) 484 } 485 assert(caught26.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 486 } 487 488 it("should throw TestFailedException if both properties match, when used with or and not") { 489 490 // both false 491 val caught21 = intercept[TestFailedException] { 492 book should (not have (title ("A Tale of Two Cities")) or (not have (author ("Dickens")))) 493 } 494 assert(caught21.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 495 496 val caught22 = intercept[TestFailedException] { 497 book should (not have (title ("A Tale of Two Cities")) or not have (author ("Dickens"))) 498 } 499 assert(caught22.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 500 501 val caught23 = intercept[TestFailedException] { 502 book should (not have ('title ("A Tale of Two Cities")) or (not have ('author ("Dickens")))) 503 } 504 assert(caught23.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 505 506 val caught24 = intercept[TestFailedException] { 507 book should (not have ('title ("A Tale of Two Cities")) or not have ('author ("Dickens"))) 508 } 509 assert(caught24.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 510 511 val caught25 = intercept[TestFailedException] { 512 book should (not have (title ("A Tale of Two Cities")) or (not have (author ("Dickens")))) 513 } 514 assert(caught25.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 515 516 val caught26 = intercept[TestFailedException] { 517 book should (not have ('title ("A Tale of Two Cities")) or (not have ('author ("Dickens")))) 518 } 519 assert(caught26.getMessage === "The title property had its expected value \"A Tale of Two Cities\", on object Book(A Tale of Two Cities,Dickens,1859,45,true), and the author property had its expected value \"Dickens\", on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 520 521 // A double one, so that I can see the mid-sentence version of the 'all properties...' error message 522 val caught31 = intercept[TestFailedException] { 523 book should ( 524 not have ( 525 title ("A Tale of Two Cities"), 526 author ("Dickens") 527 ) or not have ( 528 author ("Dickens"), 529 pubYear (1859) 530 ) 531 ) 532 } 533 assert(caught31.getMessage === "All properties had their expected values, respectively, on object Book(A Tale of Two Cities,Dickens,1859,45,true), and all properties had their expected values, respectively, on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 534 } 535 536/* 537The book1 result class doesn't compile in 2.8, and rightly so. It had a type error that the 2.7 compiler didn't find. Had already 538decided that I didn't like nesting, so not too concerned if there's not a way for it to work. Trouble is that it looks too 539hard to read. Better to have people pull things out and then just do a non-nested match on that. More readable. 540 it("should throw TestFailedException if a nested property matcher expression is used and a nested property doesn't match") { 541 542 // I'm not too hot on this syntax, but can't prevent it and wouldn't want to. If people want do to nested property 543 // checks, they can do it this way. 544 val caught1 = intercept[TestFailedException] { 545 bookshelf should have ( 546 book1 ( 547 title ("A Tale of Two Cities"), 548 author ("Gibson"), 549 pubYear (1859) 550 ) 551 ) 552 } 553 assert(caught1.getMessage === "The book1.author property had value \"Dickens\", instead of its expected value \"Gibson\", on object Bookshelf(Book(A Tale of Two Cities,Dickens,1859,45,true),Book(A Tale of Two Cities,Dickens,1859,45,false),Book(A Tale of Two Cities,Dickens,1859,45,true))") 554 } 555*/ 556 557 it("should work with length not a symbol without anything special, in case someone forgets you don't need the parens with length") { 558 559 val caught1 = intercept[TestFailedException] { 560 book should have (length (43)) 561 } 562 assert(caught1.getMessage === "The length property had value 45, instead of its expected value 43, on object Book(A Tale of Two Cities,Dickens,1859,45,true)") 563 } 564 565 it("should throw TestFailedException if length used in parens but the length property is not an integral type") { 566 567 class LengthSeven { 568 def length = "seven" 569 } 570 571 val caught1 = intercept[TestFailedException] { 572 (new LengthSeven) should have (length (43)) 573 } 574 assert(caught1.getMessage === "The length property was none of Byte, Short, Int, or Long.") 575 } 576 577 it("should work with size not a symbol without anything special, in case someone forgets you don't need the parens with size") { 578 579 case class Size(val size: Int) 580 581 val caught1 = intercept[TestFailedException] { 582 (new Size(7)) should have (size (43)) 583 } 584 assert(caught1.getMessage === "The size property had value 7, instead of its expected value 43, on object Size(7)") 585 } 586 587 it("should throw TestFailedException if size used in parens but the size property is not an integral type") { 588 589 class SizeSeven { 590 def size = "seven" 591 } 592 593 val caught1 = intercept[TestFailedException] { 594 (new SizeSeven) should have (size (43)) 595 } 596 assert(caught1.getMessage === "The size property was none of Byte, Short, Int, or Long.") 597 } 598 599/* 600I decided not to support this syntax in 0.9.5, and maybe never. It is not clear to me that it is 601readable enough. I can't prevent someone from making HavePropertyMatchers to do this kind of thing, 602and that's fine. It actually gives them a way to do it if they want to do it. 603 it("should throw TestFailedException if a nested property matcher expression with a symbol is used and a nested property doesn't match") { 604 605 val caught1 = intercept[TestFailedException] { 606 bookshelf should have ( 607 'book1 ( 608 title ("A Tale of Two Cities"), 609 author ("Gibson"), 610 pubYear (1859) 611 ) 612 ) 613 } 614 assert(caught1.getMessage === "expected property book1.author to have value \"Gibson\", but it had value \"Dickens\"") 615 } 616*/ 617 618 /* 619 This does not compile, which is what I want 620 it("should not compile if you don't enter any verifiers") { 621 book should have () 622 } 623 */ 624 } 625 } 626 627 describe("the compose method on HavePropertyMatcher") { 628 it("should return another HavePropertyMatcher") { 629 val book1 = new Book("A Tale of Two Cities", "Dickens", 1859, 45, true) 630 val book2 = new Book("The Handmaid's Tail", "Atwood", 1985, 200, true) 631 val badBook = new Book("Some Bad Book", "Bad Author", 1999, 150, false) 632 case class Library(books: List[Book]) 633 val goodLibrary = Library(List(book1, book2)) 634 val badLibrary = Library(List(badBook, book1, book2)) 635 636 def goodBooksToRead(expectedValue: Boolean) = 637 new GoodReadMatcher(expectedValue) compose { (lib: Library) => lib.books.head } 638 639 goodLibrary should have (goodBooksToRead(true)) 640 badLibrary should not be (goodBooksToRead(true)) 641 } 642 } 643 644 describe("A factory method on HavePropertyMatcher's companion object") { 645 it("should produce a have-matcher that executes the passed function when its apply is called") { 646 case class Person(name: String) 647 def name(expectedName: String) = { 648 HavePropertyMatcher { 649 (person: Person) => HavePropertyMatchResult( 650 person.name == expectedName, 651 "name", 652 expectedName, 653 person.name 654 ) 655 } 656 } 657 Person("Bob") should have (name("Bob")) 658 Person("Sally") should not have (name("George")) 659 Person("Cindy") should have (name("Cindy")) 660 Person("Doug") should have (name("Doug")) 661 Person("Alicia") should have (name("Alicia")) 662 } 663 } 664} 665