Skip to content

Commit 9001e98

Browse files
committed
Merge pull request #51 from marschall/overflow-tests
Tests for various edge cases in FastMoney:, provided by marschall.
2 parents 602ff38 + 98ede13 commit 9001e98

File tree

2 files changed

+105
-3
lines changed

2 files changed

+105
-3
lines changed

src/main/java/org/javamoney/moneta/FastMoney.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,7 @@ public FastMoney multiply(long multiplicand) {
787787
if (multiplicand == 0) {
788788
return new FastMoney(0L, this.currency);
789789
}
790-
return new FastMoney(multiplicand * this.number, this.currency);
790+
return new FastMoney(Math.multiplyExact(multiplicand, this.number), this.currency);
791791
}
792792

793793
@Override

src/test/java/org/javamoney/moneta/FastMoneyTest.java

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.testng.annotations.Test;
1919

2020
import javax.money.*;
21+
2122
import java.io.*;
2223
import java.math.BigDecimal;
2324
import java.math.BigInteger;
@@ -248,6 +249,15 @@ public void testAbs(){
248249
m = FastMoney.of(-10, "CHF");
249250
assertEquals(m.negate(), m.abs());
250251
assertTrue(m != m.abs());
252+
253+
// Long.MIN_VALUE * -1 == Long.MIN_VALUE
254+
m = FastMoney.of(new BigDecimal(Long.MIN_VALUE).movePointLeft(5), "CHF");
255+
assertFalse(m.isPositiveOrZero());
256+
try {
257+
assertTrue(m.abs().isPositiveOrZero());
258+
} catch (ArithmeticException e) {
259+
// should happen
260+
}
251261
}
252262

253263
/**
@@ -260,6 +270,15 @@ public void testAdd(){
260270
FastMoney moneyResult = money1.add(money2);
261271
assertNotNull(moneyResult);
262272
assertEquals(11d, moneyResult.getNumber().doubleValue(), 0d);
273+
274+
FastMoney money3 = FastMoney.of(90000000000000L, "CHF");
275+
try {
276+
// the maximum value for FastMoney is 92233720368547.75807 so this should overflow
277+
money3.add(money3);
278+
fail("overflow should raise ArithmeticException");
279+
} catch (ArithmeticException e) {
280+
// should happen
281+
}
263282
}
264283

265284
/**
@@ -268,8 +287,38 @@ public void testAdd(){
268287
@Test
269288
public void testDivideNumber(){
270289
FastMoney m = FastMoney.of(100, "CHF");
271-
assertEquals(FastMoney.of(BigDecimal.valueOf(100).divide(BigDecimal.valueOf(5)), "CHF"),
272-
m.divide(BigDecimal.valueOf(5)));
290+
assertEquals(FastMoney.of(BigDecimal.valueOf(20), "CHF"), m.divide(BigDecimal.valueOf(5)));
291+
292+
// the maximum value for FastMoney is 92233720368547.75807
293+
// so this should fit right below this limit
294+
BigDecimal baseValue = new BigDecimal("90000000000000");
295+
BigDecimal expectedValue = new BigDecimal("0.00009");
296+
// the argument exceeds the numeric capabilities but the result will not
297+
BigDecimal divisor = new BigDecimal("1000000000000000000");
298+
299+
// verify the expected results
300+
assertEquals(0, expectedValue.compareTo(baseValue.divide(divisor)));
301+
302+
m = FastMoney.of(baseValue, "CHF");
303+
assertEquals(FastMoney.of(expectedValue, "CHF"), m.divide(divisor));
304+
}
305+
306+
/**
307+
* Test method for {@link org.javamoney.moneta.FastMoney#divide(long)}.
308+
*/
309+
@Test
310+
public void testDivideLong(){
311+
FastMoney m = FastMoney.of(100, "CHF");
312+
assertEquals(FastMoney.of(BigDecimal.valueOf(20), "CHF"), m.divide(5L));
313+
}
314+
315+
/**
316+
* Test method for {@link org.javamoney.moneta.FastMoney#divide(double)}.
317+
*/
318+
@Test
319+
public void testDividedouble(){
320+
FastMoney m = FastMoney.of(100, "CHF");
321+
assertEquals(FastMoney.of(BigDecimal.valueOf(20), "CHF"), m.divide(5.0d));
273322
}
274323

275324
/**
@@ -310,10 +359,54 @@ public void testDivideToIntegralValueNumber(){
310359
*/
311360
@Test
312361
public void testMultiplyNumber(){
362+
FastMoney m = FastMoney.of(100, "CHF");
363+
assertEquals(FastMoney.of(10, "CHF"), m.multiply(new BigDecimal("0.1")));
364+
365+
// the maximum value for FastMoney is 92233720368547.75807
366+
// so this should fit right below this limit
367+
BigDecimal baseValue = new BigDecimal("90000000000000");
368+
BigDecimal expectedValue = new BigDecimal("90000000000000.00009");
369+
BigDecimal multiplicant = new BigDecimal("1.000000000000000001");
370+
371+
// verify the expected results
372+
assertEquals(0, expectedValue.compareTo(baseValue.multiply(multiplicant)));
373+
374+
m = FastMoney.of(baseValue, "CHF");
375+
376+
try {
377+
m.multiply(baseValue);
378+
fail("overflow should raise ArithmeticException");
379+
} catch (ArithmeticException e) {
380+
// should happen
381+
}
382+
}
383+
384+
/**
385+
* Test method for {@link org.javamoney.moneta.FastMoney#multiply(long)}.
386+
*/
387+
@Test
388+
public void testMultiplyLong(){
313389
FastMoney m = FastMoney.of(100, "CHF");
314390
assertEquals(FastMoney.of(400, "CHF"), m.multiply(4));
315391
assertEquals(FastMoney.of(200, "CHF"), m.multiply(2));
316392
assertEquals(FastMoney.of(new BigDecimal("50.0"), "CHF"), m.multiply(0.5));
393+
394+
try {
395+
// the maximum value for FastMoney is 92233720368547.75807 so this should overflow
396+
FastMoney.of(90000000000000L, "CHF").multiply(90000000000000L);
397+
fail("overflow should raise ArithmeticException");
398+
} catch (ArithmeticException e) {
399+
// should happen
400+
}
401+
}
402+
403+
/**
404+
* Test method for {@link org.javamoney.moneta.FastMoney#multiply(double)}.
405+
*/
406+
@Test
407+
public void testMultiplyDouble(){
408+
FastMoney m = FastMoney.of(100, "CHF");
409+
assertEquals(FastMoney.of(new BigDecimal("50.0"), "CHF"), m.multiply(0.5));
317410
}
318411

319412
/**
@@ -325,6 +418,15 @@ public void testNegate(){
325418
assertEquals(FastMoney.of(-100, "CHF"), m.negate());
326419
m = FastMoney.of(-123.234, "CHF");
327420
assertEquals(FastMoney.of(123.234, "CHF"), m.negate());
421+
422+
// Long.MIN_VALUE * -1 == Long.MIN_VALUE
423+
m = FastMoney.of(new BigDecimal(Long.MIN_VALUE).movePointLeft(5), "CHF");
424+
assertTrue(m.isNegative());
425+
try {
426+
assertFalse(m.negate().isNegative());
427+
} catch (ArithmeticException e) {
428+
// should happen
429+
}
328430
}
329431

330432
/**

0 commit comments

Comments
 (0)