1/* 2 * Copyright (C) 2013 The Android Open Source Project 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 */ 16 17package com.android.mediaframeworktest.unit; 18 19import android.test.suitebuilder.annotation.SmallTest; 20import android.util.Rational; 21 22import java.io.ByteArrayInputStream; 23import java.io.ByteArrayOutputStream; 24import java.io.IOException; 25import java.io.InvalidObjectException; 26import java.io.ObjectInputStream; 27import java.io.ObjectOutputStream; 28import java.io.Serializable; 29import java.lang.reflect.Field; 30 31import static android.util.Rational.*; 32 33/** 34 * <pre> 35 * adb shell am instrument \ 36 * -e class 'com.android.mediaframeworktest.unit.RationalTest' \ 37 * -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner 38 * </pre> 39 */ 40public class RationalTest extends junit.framework.TestCase { 41 42 /** (1,1) */ 43 private static final Rational UNIT = new Rational(1, 1); 44 45 /** 46 * Test @hide greatest common divisior functionality that cannot be tested in CTS. 47 */ 48 @SmallTest 49 public void testGcd() { 50 assertEquals(1, Rational.gcd(1, 2)); 51 assertEquals(1, Rational.gcd(2, 3)); 52 assertEquals(78, Rational.gcd(5*78, 7*78)); 53 assertEquals(1, Rational.gcd(-1, 2)); 54 assertEquals(1, Rational.gcd(-2, 3)); 55 } 56 57 @SmallTest 58 public void testConstructor() { 59 60 // Simple case 61 Rational r = new Rational(1, 2); 62 assertEquals(1, r.getNumerator()); 63 assertEquals(2, r.getDenominator()); 64 65 // Denominator negative 66 r = new Rational(-1, 2); 67 assertEquals(-1, r.getNumerator()); 68 assertEquals(2, r.getDenominator()); 69 70 // Numerator negative 71 r = new Rational(1, -2); 72 assertEquals(-1, r.getNumerator()); 73 assertEquals(2, r.getDenominator()); 74 75 // Both negative 76 r = new Rational(-1, -2); 77 assertEquals(1, r.getNumerator()); 78 assertEquals(2, r.getDenominator()); 79 80 // Infinity. 81 r = new Rational(1, 0); 82 assertEquals(1, r.getNumerator()); 83 assertEquals(0, r.getDenominator()); 84 85 // Negative infinity. 86 r = new Rational(-1, 0); 87 assertEquals(-1, r.getNumerator()); 88 assertEquals(0, r.getDenominator()); 89 90 // NaN. 91 r = new Rational(0, 0); 92 assertEquals(0, r.getNumerator()); 93 assertEquals(0, r.getDenominator()); 94 } 95 96 @SmallTest 97 public void testEquals() { 98 Rational r = new Rational(1, 2); 99 assertEquals(1, r.getNumerator()); 100 assertEquals(2, r.getDenominator()); 101 102 assertEquals(r, r); 103 assertFalse(r.equals(null)); 104 assertFalse(r.equals(new Object())); 105 106 Rational twoThirds = new Rational(2, 3); 107 assertFalse(r.equals(twoThirds)); 108 assertFalse(twoThirds.equals(r)); 109 110 Rational fourSixths = new Rational(4, 6); 111 assertEquals(twoThirds, fourSixths); 112 assertEquals(fourSixths, twoThirds); 113 114 Rational moreComplicated = new Rational(5*6*7*8*9, 1*2*3*4*5); 115 Rational moreComplicated2 = new Rational(5*6*7*8*9*78, 1*2*3*4*5*78); 116 assertEquals(moreComplicated, moreComplicated2); 117 assertEquals(moreComplicated2, moreComplicated); 118 119 // Ensure negatives are fine 120 twoThirds = new Rational(-2, 3); 121 fourSixths = new Rational(-4, 6); 122 assertEquals(twoThirds, fourSixths); 123 assertEquals(fourSixths, twoThirds); 124 125 moreComplicated = new Rational(-5*6*7*8*9, 1*2*3*4*5); 126 moreComplicated2 = new Rational(-5*6*7*8*9*78, 1*2*3*4*5*78); 127 assertEquals(moreComplicated, moreComplicated2); 128 assertEquals(moreComplicated2, moreComplicated); 129 130 // Zero is always equal to itself 131 Rational zero2 = new Rational(0, 100); 132 assertEquals(ZERO, zero2); 133 assertEquals(zero2, ZERO); 134 135 // NaN is always equal to itself 136 Rational nan = NaN; 137 Rational nan2 = new Rational(0, 0); 138 assertTrue(nan.equals(nan)); 139 assertTrue(nan.equals(nan2)); 140 assertTrue(nan2.equals(nan)); 141 assertFalse(nan.equals(r)); 142 assertFalse(r.equals(nan)); 143 144 // Infinities of the same sign are equal. 145 Rational posInf = POSITIVE_INFINITY; 146 Rational posInf2 = new Rational(2, 0); 147 Rational negInf = NEGATIVE_INFINITY; 148 Rational negInf2 = new Rational(-2, 0); 149 assertEquals(posInf, posInf); 150 assertEquals(negInf, negInf); 151 assertEquals(posInf, posInf2); 152 assertEquals(negInf, negInf2); 153 154 // Infinities aren't equal to anything else. 155 assertFalse(posInf.equals(negInf)); 156 assertFalse(negInf.equals(posInf)); 157 assertFalse(negInf.equals(r)); 158 assertFalse(posInf.equals(r)); 159 assertFalse(r.equals(negInf)); 160 assertFalse(r.equals(posInf)); 161 assertFalse(posInf.equals(nan)); 162 assertFalse(negInf.equals(nan)); 163 assertFalse(nan.equals(posInf)); 164 assertFalse(nan.equals(negInf)); 165 } 166 167 @SmallTest 168 public void testReduction() { 169 Rational moreComplicated = new Rational(5 * 78, 7 * 78); 170 assertEquals(new Rational(5, 7), moreComplicated); 171 assertEquals(5, moreComplicated.getNumerator()); 172 assertEquals(7, moreComplicated.getDenominator()); 173 174 Rational posInf = new Rational(5, 0); 175 assertEquals(1, posInf.getNumerator()); 176 assertEquals(0, posInf.getDenominator()); 177 assertEquals(POSITIVE_INFINITY, posInf); 178 179 Rational negInf = new Rational(-100, 0); 180 assertEquals(-1, negInf.getNumerator()); 181 assertEquals(0, negInf.getDenominator()); 182 assertEquals(NEGATIVE_INFINITY, negInf); 183 184 Rational zero = new Rational(0, -100); 185 assertEquals(0, zero.getNumerator()); 186 assertEquals(1, zero.getDenominator()); 187 assertEquals(ZERO, zero); 188 189 Rational flipSigns = new Rational(1, -1); 190 assertEquals(-1, flipSigns.getNumerator()); 191 assertEquals(1, flipSigns.getDenominator()); 192 193 Rational flipAndReduce = new Rational(100, -200); 194 assertEquals(-1, flipAndReduce.getNumerator()); 195 assertEquals(2, flipAndReduce.getDenominator()); 196 } 197 198 @SmallTest 199 public void testCompareTo() { 200 // unit is equal to itself 201 assertCompareEquals(UNIT, new Rational(1, 1)); 202 203 // NaN is greater than anything but NaN 204 assertCompareEquals(NaN, new Rational(0, 0)); 205 assertGreaterThan(NaN, UNIT); 206 assertGreaterThan(NaN, POSITIVE_INFINITY); 207 assertGreaterThan(NaN, NEGATIVE_INFINITY); 208 assertGreaterThan(NaN, ZERO); 209 210 // Positive infinity is greater than any other non-NaN 211 assertCompareEquals(POSITIVE_INFINITY, new Rational(1, 0)); 212 assertGreaterThan(POSITIVE_INFINITY, UNIT); 213 assertGreaterThan(POSITIVE_INFINITY, NEGATIVE_INFINITY); 214 assertGreaterThan(POSITIVE_INFINITY, ZERO); 215 216 // Negative infinity is smaller than any other non-NaN 217 assertCompareEquals(NEGATIVE_INFINITY, new Rational(-1, 0)); 218 assertLessThan(NEGATIVE_INFINITY, UNIT); 219 assertLessThan(NEGATIVE_INFINITY, POSITIVE_INFINITY); 220 assertLessThan(NEGATIVE_INFINITY, ZERO); 221 222 // A finite number with the same denominator is trivially comparable 223 assertGreaterThan(new Rational(3, 100), new Rational(1, 100)); 224 assertGreaterThan(new Rational(3, 100), ZERO); 225 226 // Compare finite numbers with different divisors 227 assertGreaterThan(new Rational(5, 25), new Rational(1, 10)); 228 assertGreaterThan(new Rational(5, 25), ZERO); 229 230 // Compare finite numbers with different signs 231 assertGreaterThan(new Rational(5, 25), new Rational(-1, 10)); 232 assertLessThan(new Rational(-5, 25), ZERO); 233 } 234 235 @SmallTest 236 public void testConvenienceMethods() { 237 // isFinite 238 assertFinite(ZERO, true); 239 assertFinite(NaN, false); 240 assertFinite(NEGATIVE_INFINITY, false); 241 assertFinite(POSITIVE_INFINITY, false); 242 assertFinite(UNIT, true); 243 244 // isInfinite 245 assertInfinite(ZERO, false); 246 assertInfinite(NaN, false); 247 assertInfinite(NEGATIVE_INFINITY, true); 248 assertInfinite(POSITIVE_INFINITY, true); 249 assertInfinite(UNIT, false); 250 251 // isNaN 252 assertNaN(ZERO, false); 253 assertNaN(NaN, true); 254 assertNaN(NEGATIVE_INFINITY, false); 255 assertNaN(POSITIVE_INFINITY, false); 256 assertNaN(UNIT, false); 257 258 // isZero 259 assertZero(ZERO, true); 260 assertZero(NaN, false); 261 assertZero(NEGATIVE_INFINITY, false); 262 assertZero(POSITIVE_INFINITY, false); 263 assertZero(UNIT, false); 264 } 265 266 @SmallTest 267 public void testValueConversions() { 268 // Unit, simple case 269 assertValueEquals(UNIT, 1.0f); 270 assertValueEquals(UNIT, 1.0); 271 assertValueEquals(UNIT, 1L); 272 assertValueEquals(UNIT, 1); 273 assertValueEquals(UNIT, (short)1); 274 275 // Zero, simple case 276 assertValueEquals(ZERO, 0.0f); 277 assertValueEquals(ZERO, 0.0); 278 assertValueEquals(ZERO, 0L); 279 assertValueEquals(ZERO, 0); 280 assertValueEquals(ZERO, (short)0); 281 282 // NaN is 0 for integers, not-a-number for floating point 283 assertValueEquals(NaN, Float.NaN); 284 assertValueEquals(NaN, Double.NaN); 285 assertValueEquals(NaN, 0L); 286 assertValueEquals(NaN, 0); 287 assertValueEquals(NaN, (short)0); 288 289 // Positive infinity, saturates upwards for integers 290 assertValueEquals(POSITIVE_INFINITY, Float.POSITIVE_INFINITY); 291 assertValueEquals(POSITIVE_INFINITY, Double.POSITIVE_INFINITY); 292 assertValueEquals(POSITIVE_INFINITY, Long.MAX_VALUE); 293 assertValueEquals(POSITIVE_INFINITY, Integer.MAX_VALUE); 294 assertValueEquals(POSITIVE_INFINITY, (short)-1); 295 296 // Negative infinity, saturates downwards for integers 297 assertValueEquals(NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); 298 assertValueEquals(NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); 299 assertValueEquals(NEGATIVE_INFINITY, Long.MIN_VALUE); 300 assertValueEquals(NEGATIVE_INFINITY, Integer.MIN_VALUE); 301 assertValueEquals(NEGATIVE_INFINITY, (short)0); 302 303 // Normal finite values, round down for integers 304 final Rational oneQuarter = new Rational(1, 4); 305 assertValueEquals(oneQuarter, 1.0f / 4.0f); 306 assertValueEquals(oneQuarter, 1.0 / 4.0); 307 assertValueEquals(oneQuarter, 0L); 308 assertValueEquals(oneQuarter, 0); 309 assertValueEquals(oneQuarter, (short)0); 310 311 final Rational nineFifths = new Rational(9, 5); 312 assertValueEquals(nineFifths, 9.0f / 5.0f); 313 assertValueEquals(nineFifths, 9.0 / 5.0); 314 assertValueEquals(nineFifths, 1L); 315 assertValueEquals(nineFifths, 1); 316 assertValueEquals(nineFifths, (short)1); 317 318 final Rational negativeHundred = new Rational(-1000, 10); 319 assertValueEquals(negativeHundred, -100.f / 1.f); 320 assertValueEquals(negativeHundred, -100.0 / 1.0); 321 assertValueEquals(negativeHundred, -100L); 322 assertValueEquals(negativeHundred, -100); 323 assertValueEquals(negativeHundred, (short)-100); 324 325 // Short truncates if the result is too large 326 assertValueEquals(new Rational(Integer.MAX_VALUE, 1), (short)Integer.MAX_VALUE); 327 assertValueEquals(new Rational(0x00FFFFFF, 1), (short)0x00FFFFFF); 328 assertValueEquals(new Rational(0x00FF00FF, 1), (short)0x00FF00FF); 329 } 330 331 @SmallTest 332 public void testSerialize() throws ClassNotFoundException, IOException { 333 /* 334 * Check correct [de]serialization 335 */ 336 assertEqualsAfterSerializing(ZERO); 337 assertEqualsAfterSerializing(NaN); 338 assertEqualsAfterSerializing(NEGATIVE_INFINITY); 339 assertEqualsAfterSerializing(POSITIVE_INFINITY); 340 assertEqualsAfterSerializing(UNIT); 341 assertEqualsAfterSerializing(new Rational(100, 200)); 342 assertEqualsAfterSerializing(new Rational(-100, 200)); 343 assertEqualsAfterSerializing(new Rational(5, 1)); 344 assertEqualsAfterSerializing(new Rational(Integer.MAX_VALUE, Integer.MIN_VALUE)); 345 346 /* 347 * Check bad deserialization fails 348 */ 349 try { 350 Rational badZero = createIllegalRational(0, 100); // [0, 100] , should be [0, 1] 351 Rational results = serializeRoundTrip(badZero); 352 fail("Deserializing " + results + " should not have succeeded"); 353 } catch (InvalidObjectException e) { 354 // OK 355 } 356 357 try { 358 Rational badPosInfinity = createIllegalRational(100, 0); // [100, 0] , should be [1, 0] 359 Rational results = serializeRoundTrip(badPosInfinity); 360 fail("Deserializing " + results + " should not have succeeded"); 361 } catch (InvalidObjectException e) { 362 // OK 363 } 364 365 try { 366 Rational badNegInfinity = 367 createIllegalRational(-100, 0); // [-100, 0] , should be [-1, 0] 368 Rational results = serializeRoundTrip(badNegInfinity); 369 fail("Deserializing " + results + " should not have succeeded"); 370 } catch (InvalidObjectException e) { 371 // OK 372 } 373 374 try { 375 Rational badReduced = createIllegalRational(2, 4); // [2,4] , should be [1, 2] 376 Rational results = serializeRoundTrip(badReduced); 377 fail("Deserializing " + results + " should not have succeeded"); 378 } catch (InvalidObjectException e) { 379 // OK 380 } 381 382 try { 383 Rational badReducedNeg = createIllegalRational(-2, 4); // [-2, 4] should be [-1, 2] 384 Rational results = serializeRoundTrip(badReducedNeg); 385 fail("Deserializing " + results + " should not have succeeded"); 386 } catch (InvalidObjectException e) { 387 // OK 388 } 389 } 390 391 private static void assertValueEquals(Rational object, float expected) { 392 assertEquals("Checking floatValue() for " + object + ";", 393 expected, object.floatValue()); 394 } 395 396 private static void assertValueEquals(Rational object, double expected) { 397 assertEquals("Checking doubleValue() for " + object + ";", 398 expected, object.doubleValue()); 399 } 400 401 private static void assertValueEquals(Rational object, long expected) { 402 assertEquals("Checking longValue() for " + object + ";", 403 expected, object.longValue()); 404 } 405 406 private static void assertValueEquals(Rational object, int expected) { 407 assertEquals("Checking intValue() for " + object + ";", 408 expected, object.intValue()); 409 } 410 411 private static void assertValueEquals(Rational object, short expected) { 412 assertEquals("Checking shortValue() for " + object + ";", 413 expected, object.shortValue()); 414 } 415 416 private static void assertFinite(Rational object, boolean expected) { 417 assertAction("finite", object, expected, object.isFinite()); 418 } 419 420 private static void assertInfinite(Rational object, boolean expected) { 421 assertAction("infinite", object, expected, object.isInfinite()); 422 } 423 424 private static void assertNaN(Rational object, boolean expected) { 425 assertAction("NaN", object, expected, object.isNaN()); 426 } 427 428 private static void assertZero(Rational object, boolean expected) { 429 assertAction("zero", object, expected, object.isZero()); 430 } 431 432 private static <T> void assertAction(String action, T object, boolean expected, 433 boolean actual) { 434 String expectedMessage = expected ? action : ("not " + action); 435 assertEquals("Expected " + object + " to be " + expectedMessage, 436 expected, actual); 437 } 438 439 private static <T extends Comparable<? super T>> void assertLessThan(T left, T right) { 440 assertTrue("Expected (LR) left " + left + " to be less than right " + right, 441 left.compareTo(right) < 0); 442 assertTrue("Expected (RL) left " + left + " to be less than right " + right, 443 right.compareTo(left) > 0); 444 } 445 446 private static <T extends Comparable<? super T>> void assertGreaterThan(T left, T right) { 447 assertTrue("Expected (LR) left " + left + " to be greater than right " + right, 448 left.compareTo(right) > 0); 449 assertTrue("Expected (RL) left " + left + " to be greater than right " + right, 450 right.compareTo(left) < 0); 451 } 452 453 private static <T extends Comparable<? super T>> void assertCompareEquals(T left, T right) { 454 assertTrue("Expected (LR) left " + left + " to be compareEquals to right " + right, 455 left.compareTo(right) == 0); 456 assertTrue("Expected (RL) left " + left + " to be compareEquals to right " + right, 457 right.compareTo(left) == 0); 458 } 459 460 private static <T extends Serializable> byte[] serialize(T obj) throws IOException { 461 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 462 try (ObjectOutputStream objectStream = new ObjectOutputStream(byteStream)) { 463 objectStream.writeObject(obj); 464 } 465 return byteStream.toByteArray(); 466 } 467 468 private static <T extends Serializable> T deserialize(byte[] array, Class<T> klass) 469 throws IOException, ClassNotFoundException { 470 ByteArrayInputStream bais = new ByteArrayInputStream(array); 471 ObjectInputStream ois = new ObjectInputStream(bais); 472 Object obj = ois.readObject(); 473 return klass.cast(obj); 474 } 475 476 @SuppressWarnings("unchecked") 477 private static <T extends Serializable> T serializeRoundTrip(T obj) 478 throws IOException, ClassNotFoundException { 479 Class<T> klass = (Class<T>) obj.getClass(); 480 byte[] arr = serialize(obj); 481 T serialized = deserialize(arr, klass); 482 return serialized; 483 } 484 485 private static <T extends Serializable> void assertEqualsAfterSerializing(T obj) 486 throws ClassNotFoundException, IOException { 487 T serialized = serializeRoundTrip(obj); 488 assertEquals("Expected values to be equal after serialization round-trip", obj, serialized); 489 } 490 491 private static Rational createIllegalRational(int numerator, int denominator) { 492 Rational r = new Rational(numerator, denominator); 493 mutateField(r, "mNumerator", numerator); 494 mutateField(r, "mDenominator", denominator); 495 return r; 496 } 497 498 private static <T> void mutateField(T object, String name, int value) { 499 try { 500 Field f = object.getClass().getDeclaredField(name); 501 f.setAccessible(true); 502 f.set(object, value); 503 } catch (NoSuchFieldException e) { 504 throw new AssertionError(e); 505 } catch (IllegalAccessException e) { 506 throw new AssertionError(e); 507 } catch (IllegalArgumentException e) { 508 throw new AssertionError(e); 509 } 510 } 511} 512