001 /* 002 * Created on Jun 7, 2007 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 005 * the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 011 * specific language governing permissions and limitations under the License. 012 * 013 * Copyright @2007-2009 the original author or authors. 014 */ 015 package org.fest.assertions; 016 017 import static java.lang.String.valueOf; 018 import static org.fest.assertions.ErrorMessages.unexpectedEqual; 019 import static org.fest.assertions.ErrorMessages.unexpectedNotEqual; 020 import static org.fest.assertions.Formatting.inBrackets; 021 import static org.fest.assertions.Threshold.threshold; 022 import static org.fest.util.Objects.areEqual; 023 import static org.fest.util.Strings.concat; 024 import static org.fest.util.Strings.quote; 025 026 import java.awt.Dimension; 027 import java.awt.image.BufferedImage; 028 import java.io.File; 029 import java.io.IOException; 030 031 /** 032 * Understands assertion methods for images. To create a new instance of this class use the method 033 * <code>{@link Assertions#assertThat(BufferedImage)}</code>. 034 * 035 * @author Yvonne Wang 036 * @author Alex Ruiz 037 * @author Ansgar Konermann 038 */ 039 public class ImageAssert extends GenericAssert<BufferedImage> { 040 041 private static final Threshold ZERO_THRESHOLD = threshold(0); 042 043 private static ImageReader imageReader = new ImageReader(); 044 045 /** 046 * Reads the image in the specified path. 047 * @param imageFilePath the path of the image to read. 048 * @return the read image. 049 * @throws NullPointerException if the given path is <code>null</code>. 050 * @throws IllegalArgumentException if the given path does not belong to a file. 051 * @throws IOException if any I/O error occurred while reading the image. 052 */ 053 public static BufferedImage read(String imageFilePath) throws IOException { 054 if (imageFilePath == null) throw new NullPointerException("The path of the image to read should not be null"); 055 File imageFile = new File(imageFilePath); 056 if (!imageFile.isFile()) 057 throw new IllegalArgumentException(concat("The path ", quote(imageFilePath), " does not belong to a file")); 058 return imageReader.read(imageFile); 059 } 060 061 /** 062 * Creates a new </code>{@link ImageAssert}</code>. 063 * @param actual the target to verify. 064 */ 065 protected ImageAssert(BufferedImage actual) { 066 super(actual); 067 } 068 069 /** {@inheritDoc} */ 070 public ImageAssert as(String description) { 071 description(description); 072 return this; 073 } 074 075 /** {@inheritDoc} */ 076 public ImageAssert describedAs(String description) { 077 return as(description); 078 } 079 080 /** {@inheritDoc} */ 081 public ImageAssert as(Description description) { 082 description(description); 083 return this; 084 } 085 086 /** {@inheritDoc} */ 087 public ImageAssert describedAs(Description description) { 088 return as(description); 089 } 090 091 /** 092 * Verifies that the actual image satisfies the given condition. 093 * @param condition the given condition. 094 * @return this assertion object. 095 * @throws NullPointerException if the given condition is <code>null</code>. 096 * @throws AssertionError if the actual image does not satisfy the given condition. 097 * @see #is(Condition) 098 */ 099 public ImageAssert satisfies(Condition<BufferedImage> condition) { 100 assertSatisfies(condition); 101 return this; 102 } 103 104 /** 105 * Verifies that the actual image does not satisfy the given condition. 106 * @param condition the given condition. 107 * @return this assertion object. 108 * @throws NullPointerException if the given condition is <code>null</code>. 109 * @throws AssertionError if the actual image satisfies the given condition. 110 * @see #isNot(Condition) 111 */ 112 public ImageAssert doesNotSatisfy(Condition<BufferedImage> condition) { 113 assertDoesNotSatisfy(condition); 114 return this; 115 } 116 117 /** 118 * Alias for <code>{@link #satisfies(Condition)}</code>. 119 * @param condition the given condition. 120 * @return this assertion object. 121 * @throws NullPointerException if the given condition is <code>null</code>. 122 * @throws AssertionError if the actual image does not satisfy the given condition. 123 * @since 1.2 124 */ 125 public ImageAssert is(Condition<BufferedImage> condition) { 126 assertIs(condition); 127 return this; 128 } 129 130 /** 131 * Alias for <code>{@link #doesNotSatisfy(Condition)}</code>. 132 * @param condition the given condition. 133 * @return this assertion object. 134 * @throws NullPointerException if the given condition is <code>null</code>. 135 * @throws AssertionError if the actual image satisfies the given condition. 136 * @since 1.2 137 */ 138 public ImageAssert isNot(Condition<BufferedImage> condition) { 139 assertIsNot(condition); 140 return this; 141 } 142 143 /** 144 * Verifies that the actual image is equal to the given one. Two images are equal if they have the same size and the 145 * pixels at the same coordinates have the same color. 146 * @param expected the given image to compare the actual image to. 147 * @return this assertion object. 148 * @throws AssertionError if the actual image is not equal to the given one. 149 */ 150 public ImageAssert isEqualTo(BufferedImage expected) { 151 return isEqualTo(expected, ZERO_THRESHOLD); 152 } 153 154 /** 155 * Verifies that the actual image is equal to the given one. Two images are equal if: 156 * <ol> 157 * <li>they have the same size</li> 158 * <li>the difference between the RGB values of the color of each pixel is less than or equal to the given 159 * threshold</li> 160 * </ol> 161 * @param expected the given image to compare the actual image to. 162 * @param threshold the threshold to use to decide if the color of two pixels are similar: two pixels that are 163 * identical to the human eye may still have slightly different color values. For example, by using a threshold of 1 164 * we can indicate that a blue value of 60 is similar to a blue value of 61. 165 * @return this assertion object. 166 * @throws AssertionError if the actual image is not equal to the given one. 167 * @since 1.1 168 */ 169 public ImageAssert isEqualTo(BufferedImage expected, Threshold threshold) { 170 if (areEqual(actual, expected)) return this; 171 failIfNull(expected); 172 failIfNotEqual(sizeOf(actual), sizeOf(expected)); 173 failIfNotEqualColor(expected, threshold); 174 return this; 175 } 176 177 private void failIfNull(BufferedImage expected) { 178 if (expected != null) return; 179 failIfCustomMessageIsSet(); 180 fail(unexpectedNotEqual(actual, null)); 181 } 182 183 private void failIfNotEqual(Dimension a, Dimension e) { 184 if (areEqual(a, e)) return; 185 failIfCustomMessageIsSet(); 186 fail(concat("image size, expected:", inBrackets(e), " but was:", inBrackets(a))); 187 } 188 189 private void failIfNotEqualColor(BufferedImage expected, Threshold threshold) { 190 int w = actual.getWidth(); 191 int h = actual.getHeight(); 192 for (int x = 0; x < w; x++) 193 for (int y = 0; y < h; y++) 194 failIfNotEqual(new RGBColor(actual.getRGB(x, y)), new RGBColor(expected.getRGB(x, y)), threshold, x, y); 195 } 196 197 private void failIfNotEqual(RGBColor a, RGBColor e, Threshold threshold, int x, int y) { 198 if (a.isEqualTo(e, threshold.value())) return; 199 failIfCustomMessageIsSet(); 200 fail(concat("expected:", inBrackets(a), " but was:", inBrackets(e), " at pixel [", valueOf(x), ",", valueOf(y), "]")); 201 } 202 203 /** 204 * Verifies that the actual image is not equal to the given one. Two images are equal if they have the same size and 205 * the pixels at the same coordinates have the same color. 206 * @param image the given image to compare the actual image to. 207 * @return this assertion object. 208 * @throws AssertionError if the actual image is equal to the given one. 209 */ 210 public ImageAssert isNotEqualTo(BufferedImage image) { 211 if (areEqual(actual, image)) { 212 failIfCustomMessageIsSet(); 213 throw failure(unexpectedEqual(actual, image)); 214 } 215 if (image == null) return this; 216 if (areEqual(sizeOf(actual), sizeOf(image)) && hasEqualColor(image)) { 217 failIfCustomMessageIsSet(); 218 throw failure("images are equal"); 219 } 220 return this; 221 } 222 223 private static Dimension sizeOf(BufferedImage image) { 224 return new Dimension(image.getWidth(), image.getHeight()); 225 } 226 227 private boolean hasEqualColor(BufferedImage expected) { 228 int w = actual.getWidth(); 229 int h = actual.getHeight(); 230 for (int x = 0; x < w; x++) 231 for (int y = 0; y < h; y++) 232 if (actual.getRGB(x, y) != expected.getRGB(x, y)) return false; 233 return true; 234 } 235 236 /** 237 * Verifies that the actual image is not <code>null</code>. 238 * @return this assertion object. 239 * @throws AssertionError if the actual image is <code>null</code>. 240 */ 241 public ImageAssert isNotNull() { 242 assertNotNull(); 243 return this; 244 } 245 246 /** 247 * Verifies that the actual image is not the same as the given one. 248 * @param expected the given image to compare the actual image to. 249 * @return this assertion object. 250 * @throws AssertionError if the actual image is the same as the given one. 251 */ 252 public ImageAssert isNotSameAs(BufferedImage expected) { 253 assertNotSameAs(expected); 254 return this; 255 } 256 257 /** 258 * Verifies that the actual image is the same as the given one. 259 * @param expected the given image to compare the actual image to. 260 * @return this assertion object. 261 * @throws AssertionError if the actual image is not the same as the given one. 262 */ 263 public ImageAssert isSameAs(BufferedImage expected) { 264 assertSameAs(expected); 265 return this; 266 } 267 268 /** 269 * Verifies that the size of the actual image is equal to the given one. 270 * @param expected the expected size of the actual image. 271 * @return this assertion object. 272 * @throws AssertionError if the actual image is <code>null</code>. 273 * @throws NullPointerException if the given size is <code>null</code>. 274 * @throws AssertionError if the size of the actual image is not equal to the given one. 275 */ 276 public ImageAssert hasSize(Dimension expected) { 277 isNotNull(); 278 if (expected == null) 279 throw new NullPointerException(formattedErrorMessage("The size to compare to should not be null")); 280 Dimension actualDimension = new Dimension(actual.getWidth(), actual.getHeight()); 281 Fail.failIfNotEqual(customErrorMessage(), rawDescription(), actualDimension, expected); 282 return this; 283 } 284 285 /** {@inheritDoc} */ 286 public ImageAssert overridingErrorMessage(String message) { 287 replaceDefaultErrorMessagesWith(message); 288 return this; 289 } 290 291 static void imageReader(ImageReader newImageReader) { 292 imageReader = newImageReader; 293 } 294 }