/* * Copyright 2006 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jdave; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.fail; import java.math.BigDecimal; import java.util.Arrays; import java.util.List; import jdave.util.Diff; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; import org.junit.Test; /** * @author Joni Freeman */ public class SpecificationTest { private Specification<EmptyStack> specification; @Before public void setUp() throws Exception { specification = new Specification<EmptyStack>() { }; specification.be = new EmptyStack(); } @Test public void testAliasesToSpecification() { assertSame(specification.should, specification); assertSame(specification.does, specification); assertSame(specification.must, specification); } @Test public void testPassesWhenActualAndExpectedAreBothNull() { final Object actual = null; final Object expected = null; specification.specify(actual, expected); } @Test public void testFailsWhenActualIsNotNull() { final Object object = new Object(); try { specification.specify(object, specification.should.equal(null)); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: null, but was: " + object.toString(), e.getMessage()); } } @Test public void testShouldPassWhenExpectationMet() { specification.specify(1, 1); } @Test public void testShouldFailWithDiffMessageWhenTwoStringsDoNotEqual() { final String actual = "some long string which will get chopped for readability"; final String expected = "some long different string which will get chopped for readability"; final Diff diff = Diff.diff(actual, expected); try { specification.specify(actual, specification.should.equal(expected)); fail(); } catch (final ExpectationFailedException e) { assertEquals("The given strings do not match:\n" + diff.verbose(), e.getMessage()); } } @Test public void testShouldPassWhenInvertedExpectationMet() { specification.specify(1, specification.should.not().equal(2)); } @Test public void testShouldFailWhenInvertedExpectationNotMet() { try { specification.specify(1, specification.should.not().equal(1)); fail(); } catch (final ExpectationFailedException e) { assertEquals("Did not expect: 1, but was: 1", e.getMessage()); } } @Test public void testShouldFailWhenActualIsNullAndExpectedIsNot() { try { specification.specify(null, specification.should.equal("Hello")); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: Hello, but was: null", e.getMessage()); } } @Test public void testChecksNotNull() { specification.specify(1, specification.isNotNull()); assertExpectationFails("Expected a non-null value", new Block() { public void run() throws Throwable { specification.specify(null, specification.isNotNull()); } }); } private void assertExpectationFails(final String expectedMessage, final Block block) { try { block.run(); fail(); } catch (final ExpectationFailedException e) { assertEquals(expectedMessage, e.getMessage()); } catch (final Throwable throwable) { throw new RuntimeException(throwable); } } @Test public void testShouldPassWhenExpectationWithinDelta() { specification.specify(1.0, specification.should.equal(1.001, 0.01)); } @Test public void testShouldPassWhenBigDecimalExpectationWithinDelta() { specification.specify(new BigDecimal(1.0), specification.should.equal( new BigDecimal(1.001), 0.01)); } @Test public void testShouldFailWhenExpectationNotWithinDelta() { try { specification.specify(1.0, specification.should.equal(1.01, 0.001)); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: 1.01, but was: 1.0", e.getMessage()); } } @Test public void testShouldPassWhenExpectationWithinDeltaForWrapper() { specification.specify(1.0, specification.should.equal(1.001, 0.01)); } @Test public void testShouldPassWhenInvertedExpectationWithinDeltaMet() { specification.specify(1.01, specification.should.not().equal(1, 0.001)); } @Test public void testShouldFailWhenInvertedExpectationWithinDeltaNotMet() { try { specification.specify(1.001, specification.should.not().equal(1, 0.01)); fail(); } catch (final ExpectationFailedException e) { assertEquals("Did not expect: 1, but was: 1.001", e.getMessage()); } } @Test public void testShouldFailWhenBooleanExpectationNotMet() { try { specification.specify(null, false); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: true, but was: false", e.getMessage()); } } @Test public void testShouldFailWhenBooleanExpectationWithWrapperNotMet() { try { specification.specify(null, Boolean.FALSE); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: true, but was: false", e.getMessage()); } } @Test public void testShouldFailWhenInvertedBooleanExpectationNotMet() { try { specification.specify(null, specification.not().be.empty()); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: true, but was: false", e.getMessage()); } } @Test public void testShouldFailWhenExpectationNotMet() { try { specification.specify(1, 2); fail(); } catch (final ExpectationFailedException e) { assertEquals("Expected: 2, but was: 1", e.getMessage()); } } @Test public void testShouldPassWhenContainmentExpected() { specification.specify(Arrays.asList(1, 2, 3), specification.contains(2)); } @Test public void testShouldPassWhenContainmentExpectedForObjectArray() { final Integer[] actual = new Integer[] { 1, 2, 3 }; specification.specify(actual, specification.contains(2)); } @Test public void testShouldPassWhenContainmentExpectedForBooleanArray() { final boolean[] actual = new boolean[] { true, false }; specification.specify(actual, specification.contains(true)); } @Test public void testShouldPassWhenContainmentExpectedForByteArray() { final byte[] actual = new byte[] { 1, 2, 3 }; specification.specify(actual, specification.contains((byte) 2)); } @Test public void testShouldPassWhenContainmentExpectedForCharArray() { final char[] actual = new char[] { '1', '2', '3' }; specification.specify(actual, specification.contains('2')); } @Test public void testShouldPassWhenContainmentExpectedForDoubleArray() { final double[] actual = new double[] { 1, 2, 3 }; specification.specify(actual, specification.contains((double) 2)); } @Test public void testShouldPassWhenContainmentExpectedForFloatArray() { final float[] actual = new float[] { 1, 2, 3 }; specification.specify(actual, specification.contains((float) 2)); } @Test public void testShouldPassWhenContainmentExpectedForIntArray() { final int[] actual = new int[] { 1, 2, 3 }; specification.specify(actual, specification.contains(2)); } @Test public void testShouldPassWhenContainmentExpectedForLongArray() { final long[] actual = new long[] { 1, 2, 3 }; specification.specify(actual, specification.contains((long) 2)); } @Test public void testShouldPassWhenContainmentExpectedForShortArray() { final short[] actual = new short[] { 1, 2, 3 }; specification.specify(actual, specification.contains((short) 2)); } @Test public void testShouldPassWhenContainmentExpectedForPrimitiveByteArrayInput() { final byte[] actual = new byte[] { 0, 1, 2 }; specification.specify(actual, specification.containsInOrder(new byte[] { 0, 1, 2 })); specification.specify(actual, specification.containsExactly(new byte[] { 0, 1, 2 })); specification.specify(actual, specification.containsAll(new byte[] { 2, 1, 0 })); specification.specify(actual, specification.containsAny(new byte[] { -1, 1, 3 })); specification.specify(actual, specification.containInOrder(new byte[] { 0, 1, 2 })); specification.specify(actual, specification.containExactly(new byte[] { 0, 1, 2 })); specification.specify(actual, specification.containAll(new byte[] { 2, 1, 0 })); specification.specify(actual, specification.containAny(new byte[] { -1, 1, 3 })); } @Test public void testShouldPassWhenContainmentExpectedForPrimitiveShortArrayInput() { final short[] actual = new short[] { 0, 1, 2 }; specification.specify(actual, specification.containsInOrder(new short[] { 0, 1, 2 })); specification.specify(actual, specification.containsExactly(new short[] { 0, 1, 2 })); specification.specify(actual, specification.containsAll(new short[] { 2, 1, 0 })); specification.specify(actual, specification.containsAny(new short[] { -1, 1, 3 })); specification.specify(actual, specification.containInOrder(new short[] { 0, 1, 2 })); specification.specify(actual, specification.containExactly(new short[] { 0, 1, 2 })); specification.specify(actual, specification.containAll(new short[] { 2, 1, 0 })); specification.specify(actual, specification.containAny(new short[] { -1, 1, 3 })); } @Test public void testShouldPassWhenContainmentExpectedForPrimitiveIntArrayInput() { final int[] actual = new int[] { 0, 1, 2 }; specification.specify(actual, specification.containsInOrder(new int[] { 0, 1, 2 })); specification.specify(actual, specification.containsExactly(new int[] { 0, 1, 2 })); specification.specify(actual, specification.containsAll(new int[] { 2, 1, 0 })); specification.specify(actual, specification.containsAny(new int[] { -1, 1, 3 })); specification.specify(actual, specification.containInOrder(new int[] { 0, 1, 2 })); specification.specify(actual, specification.containExactly(new int[] { 0, 1, 2 })); specification.specify(actual, specification.containAll(new int[] { 2, 1, 0 })); specification.specify(actual, specification.containAny(new int[] { -1, 1, 3 })); } @Test public void testShouldPassWhenContainmentExpectedForPrimitiveLongArrayInput() { final long[] actual = new long[] { 0, 1, 2 }; specification.specify(actual, specification.containsInOrder(new long[] { 0, 1, 2 })); specification.specify(actual, specification.containsExactly(new long[] { 0, 1, 2 })); specification.specify(actual, specification.containsAll(new long[] { 2, 1, 0 })); specification.specify(actual, specification.containsAny(new long[] { -1, 1, 3 })); specification.specify(actual, specification.containInOrder(new long[] { 0, 1, 2 })); specification.specify(actual, specification.containExactly(new long[] { 0, 1, 2 })); specification.specify(actual, specification.containAll(new long[] { 2, 1, 0 })); specification.specify(actual, specification.containAny(new long[] { -1, 1, 3 })); } @Test public void testShouldPassWhenContainmentExpectedForPrimitiveFloatArrayInput() { final float[] actual = new float[] { .0f, .1f, .2f }; specification.specify(actual, specification.containsInOrder(new float[] { .0f, .1f, .2f })); specification.specify(actual, specification.containsExactly(new float[] { .0f, .1f, .2f })); specification.specify(actual, specification.containsAll(new float[] { .2f, .1f, .0f })); specification.specify(actual, specification.containsAny(new float[] { -.1f, .1f, .3f })); specification.specify(actual, specification.containInOrder(new float[] { .0f, .1f, .2f })); specification.specify(actual, specification.containExactly(new float[] { .0f, .1f, .2f })); specification.specify(actual, specification.containAll(new float[] { .2f, .1f, .0f })); specification.specify(actual, specification.containAny(new float[] { -.1f, .1f, .3f })); } @Test public void testShouldPassWhenContainmentExpectedForPrimitiveDoubleArrayInput() { final double[] actual = new double[] { .0d, .1d, .2d }; specification .specify(actual, specification.containsInOrder(new double[] { .0d, .1d, .2d })); specification .specify(actual, specification.containsExactly(new double[] { .0d, .1d, .2d })); specification.specify(actual, specification.containsAll(new double[] { .2d, .1d, .0d })); specification.specify(actual, specification.containsAny(new double[] { -.1d, .1d, .3d })); specification.specify(actual, specification.containInOrder(new double[] { .0d, .1d, .2d })); specification.specify(actual, specification.containExactly(new double[] { .0d, .1d, .2d })); specification.specify(actual, specification.containAll(new double[] { .2d, .1d, .0d })); specification.specify(actual, specification.containAny(new double[] { -.1d, .1d, .3d })); } @Test public void testShouldFailWhenContainmentNotExpected() { try { specification.specify(Arrays.asList(1, 2, 3), specification.contains(0)); fail(); } catch (final ExpectationFailedException e) { assertEquals("The specified collection '[1, 2, 3]' does not contain '0'", e .getMessage()); } } @Test public void testShouldPassWhenNonContainmentExpected() { specification.specify(Arrays.asList(1, 2, 3), specification.does.not().contain(0)); } @Test public void testShouldFailWhenNonContainmentNotExpected() { try { specification.specify(Arrays.asList(1, 2, 3), specification.does.not().contains(1)); fail(); } catch (final ExpectationFailedException e) { assertEquals("The specified collection '[1, 2, 3]' contains '1'", e.getMessage()); } } @Test public void testShouldPassWhenContainmentForAllExpected() { specification.specify(Arrays.asList(1, 2, 3), specification .containsAll(Arrays.asList(2, 3))); } @Test public void testShouldFailWhenContainmentForAllNotExpected() { try { specification.specify(Arrays.asList(1, 2, 3), specification.containsAll(0, 1)); fail(); } catch (final ExpectationFailedException e) { assertEquals("The specified collection '[1, 2, 3]' does not contain '[0, 1]'", e .getMessage()); } } @Test public void testNotDoesNotAffectNextSpecifyStatement() { specification.specify(Arrays.asList(1, 2, 3), specification.does.not().contain(0)); specification.specify(null, true); } @Test public void testPassesWhenHamcrestMatcherPasses() { specification.specify(null, new BaseMatcher<Object>() { public boolean matches(final Object item) { return true; } public void describeTo(final Description description) { } }); } @Test public void testFailsWhenHamcrestMatcherFails() { try { specification.specify(null, new BaseMatcher<Object>() { public boolean matches(final Object item) { return false; } public void describeTo(final Description description) { } }); fail(); } catch (final ExpectationFailedException e) { } } @Test public void testPassesWhenHamcrestMatcherPassesAllElementsWithPrimitiveGetter() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); specification.specify(m, specification.where(new Each<Money>() { { matches(item.value(), is(greaterThan(3))); } })); } @Test public void testPassesWhenHamcrestMatcherPassesAllElementsWithObjectGetter() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); specification.specify(m, specification.where(new Each<Money>() { { matches(item.currency(), is(equalTo(EUR))); } })); } @Test public void testPassesWhenHamcrestMatcherPassesAllElementsWithoutCallingAnyMethodFromItem() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); specification.specify(m, specification.where(new Each<Money>() { { matches(item, instanceOf(Money.class)); } })); } @Test public void testFailsWhenHamcrestMatcherFailsAnyElements() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); try { specification.specify((Iterable<Money>) m, specification.where(new Each<Money>() { { matches(item.value(), is(greaterThan(5))); } })); fail(); } catch (final ExpectationFailedException e) { } } @Test public void testPassesIfAllElementsPassTheirIndividualHamcrestMatcher() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); specification.specify(m, specification.where(new Each<Money>() { { matches(item.value(), is(4), is(5), is(6)); } })); } @Test public void testFailsIfAnyElementFailItsIndividualHamcrestMatcher() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); try { specification.specify(m, specification.where(new Each<Money>() { { matches(item.value(), is(4), is(5), is(7)); } })); fail(); } catch (final ExpectationFailedException e) { } } @Test public void testFailsIfNumberOfHamcrestMatchersIsBiggerThatNumberOfElements() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); try { specification.specify(m, specification.where(new Each<Money>() { { matches(item.value(), is(4), is(5), is(6), is(7)); } })); fail(); } catch (final ExpectationFailedException e) { } } @Test public void testFailsIfNumberOfHamcrestMatchersIsSmallerThatNumberOfElements() { final Currency EUR = new Currency("EUR"); final List<Money> m = Arrays .asList(new Money(4, EUR), new Money(5, EUR), new Money(6, EUR)); try { specification.specify(m, specification.where(new Each<Money>() { { matches(item.value(), is(4), is(5)); } })); fail(); } catch (final ExpectationFailedException e) { } } @Test public void testFailWithMessage() { try { specification.fail("msg"); } catch (final ExpectationFailedException e) { assertEquals("msg", e.getMessage()); } } public static class Money { private final int value; private final Currency currency; public Money(final int value, final Currency currency) { this.value = value; this.currency = currency; } public int value() { return value; } public Currency currency() { return currency; } } public class Currency { private final String name; public Currency(final String name) { this.name = name; } @Override public boolean equals(final Object obj) { if (obj == null || !obj.getClass().equals(Currency.class)) { return false; } final Currency other = (Currency) obj; return name.equals(other.name); } @Override public int hashCode() { return name.hashCode(); } } class EmptyStack { public boolean empty() { return true; } } }