/*
 * Copyright 2015-2023 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 org.opentest4j;

import static org.junit.Assert.*;

import java.io.Serializable;

import org.junit.Test;

/**
 * Unit tests for {@link ValueWrapper}.
 *
 * @author Marc Philipp
 * @author Sam Brannen
 * @since 1.0
 */
public class ValueWrapperTests {

	@Test
	public void wrapsNull() {
		ValueWrapper wrapper = ValueWrapper.create(null);

		assertNull(wrapper.getType());
		assertNull(wrapper.getValue());
		assertEquals("null", wrapper.getStringRepresentation());
		assertEquals(0, wrapper.getIdentityHashCode());
		assertEquals("null", wrapper.toString());
		assertNull(wrapper.getEphemeralValue());
	}

	@Test
	public void wrapsSerializableValue() {
		ValueWrapper wrapper = ValueWrapper.create(1.2d);

		assertEquals(Double.class, wrapper.getType());
		assertEquals(1.2d, wrapper.getValue());
		assertEquals("1.2", wrapper.getStringRepresentation());
		assertNotEquals(0, wrapper.getIdentityHashCode());
		assertTrue(wrapper.toString().startsWith("1.2 (java.lang.Double@"));
		assertTrue(wrapper.toString().endsWith(")"));
		assertEquals(1.2D, wrapper.getEphemeralValue());
		assertSame(wrapper.getValue(), wrapper.getEphemeralValue());
	}

	@Test
	public void acceptsCustomStringRepresentation() {
		ValueWrapper wrapper = ValueWrapper.create(1.2d, "1,20");

		assertEquals(Double.class, wrapper.getType());
		assertEquals(1.2d, wrapper.getValue());
		assertEquals("1,20", wrapper.getStringRepresentation());
		assertNotEquals(0, wrapper.getIdentityHashCode());
		assertTrue(wrapper.toString().startsWith("1,20 (java.lang.Double@"));
		assertTrue(wrapper.toString().endsWith(")"));
	}

	@Test
	public void doesNotWrapAnotherValueWrapper() {
		ValueWrapper wrapper = ValueWrapper.create(1.2d);

		ValueWrapper same = ValueWrapper.create(wrapper);

		assertSame(wrapper, same);
	}

	@Test
	public void doesNotWrapAnotherValueWrapperWithSameCustomRepresentation() {
		ValueWrapper wrapper = ValueWrapper.create(1.2d, "1,20");

		ValueWrapper same = ValueWrapper.create(wrapper, "1,20");

		assertSame(wrapper, same);
	}

	@Test
	public void doesRepackageValueWrapperWithDifferentStringRepresentation() {
		ValueWrapper wrapper = ValueWrapper.create(1.2d);

		ValueWrapper same = ValueWrapper.create(wrapper, "1,20");

		assertNotSame(wrapper, same);
	}

	@Test
	public void nullForCustomStringRepresentationFallsBackToDefaultToString() {
		ValueWrapper wrapper = ValueWrapper.create(1.2d, null);

		assertEquals(Double.class, wrapper.getType());
		assertEquals(1.2d, wrapper.getValue());
		assertEquals("1.2", wrapper.getStringRepresentation());
		assertNotEquals(0, wrapper.getIdentityHashCode());
		assertTrue(wrapper.toString().startsWith("1.2 (java.lang.Double@"));
		assertTrue(wrapper.toString().endsWith(")"));
	}

	@Test
	public void wrapsNonSerializableValue() {
		class NonSerializable {

			@Override
			public String toString() {
				return "someString";
			}
		}
		NonSerializable value = new NonSerializable();

		ValueWrapper wrapper = ValueWrapper.create(value);

		assertEquals(NonSerializable.class, wrapper.getType());
		assertNull(wrapper.getValue());
		assertEquals("someString", wrapper.getStringRepresentation());
		assertNotEquals(0, wrapper.getIdentityHashCode());
		assertEquals(value, wrapper.getEphemeralValue());

		String toString = wrapper.toString();
		assertTrue(toString, toString.startsWith("someString (" + NonSerializable.class.getName() + "@"));
		assertTrue(toString, toString.endsWith(")"));
	}

	@Test
	public void wrapsWithBrokenToString() {
		class BrokenToString implements Serializable {
			private static final long serialVersionUID = -3072024134414066195L;

			@Override
			public String toString() {
				throw new RuntimeException("toStringFailure");
			}
		}

		BrokenToString value = new BrokenToString();
		ValueWrapper wrapper = ValueWrapper.create(value);

		assertEquals(BrokenToString.class, wrapper.getType());
		assertEquals(value, wrapper.getValue());
		assertEquals(value, wrapper.getEphemeralValue());
		String representation = wrapper.getStringRepresentation();
		assertTrue(representation, representation.contains(RuntimeException.class.getName()));
		assertTrue(representation, representation.contains("toStringFailure"));
		assertNotEquals(0, wrapper.getIdentityHashCode());

		String toString = wrapper.toString();
		assertTrue(toString, toString.contains(RuntimeException.class.getName()));
		assertTrue(toString, toString.contains("toStringFailure"));
	}

}
