/*
 * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     dminsky - initial API and implementation
package org.eclipse.persistence.testing.tests.unitofwork;

import java.util.Vector;

import org.junit.Assert;

import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.sessions.*;
import org.eclipse.persistence.testing.framework.TestCase;
import org.eclipse.persistence.testing.framework.TestErrorException;

/**
 * EL Bug 252047 - Mutable attributes are not cloned when isMutable is enabled on a Direct Mapping
 * Regression test to ensure that when an AbstractDirectMapping subclass is set as mutable
 * (setMutable(false)), an attribute of type byte[], java.util.Date or java.util.Calendar (and
 * their subclasses) is cloned before being returned. This will occur as a result of creating
 * a clone of the mapped object which references the mutable attribute.
 * @author dminsky
 */
public class CloneAttributeIfMutableTest extends TestCase {

    protected MutableAttributeObject original;
    protected MutableAttributeObject clone;

    public CloneAttributeIfMutableTest() {
        super();
        setDescription("Test that cloning an object also clones its attributes if their mappings are set as mutable");
    }

    @Override
    public void test() {
        UnitOfWork uow = getSession().acquireUnitOfWork();
        original = MutableAttributeObject.example1();
        clone = (MutableAttributeObject) uow.registerObject(original);
        uow.release();
    }

    @Override
    public void verify() {
        Vector errors = new Vector();
        // extra check to pre-verify that: clone != original
        try {
            Assert.assertNotSame("1. original == clone",
                original,
                clone);
        } catch (Throwable t) {
            errors.add(t);
        }

        // byte[]
        try {
            Assert.assertNotSame("2. original.getByteArray() == clone.getByteArray()",
                original.getByteArray(),
                clone.getByteArray());
        } catch (Throwable t) {
            errors.add(t);
        }

        // java.util.Calendar
        try {
            Assert.assertNotSame("3. original.getUtilCalendar() == clone.getUtilCalendar()",
                original.getUtilCalendar(),
                clone.getUtilCalendar());
        } catch (Throwable t) {
            errors.add(t);
        }

        // java.util.Date
        try {
            Assert.assertNotSame("4. original.getUtilDate() == clone.getUtilDate()",
                original.getUtilDate(),
                clone.getUtilDate());
        } catch (Throwable t) {
            errors.add(t);
        }

        // java.sql.Date
        try {
            Assert.assertNotSame("5. original.getSqlDate() == clone.getSqlDate()",
                original.getSqlDate(),
                clone.getSqlDate());
        } catch (Throwable t) {
            errors.add(t);
        }

        // java.sql.Time
        try {
            Assert.assertNotSame("6. original.getSqlTime() == clone.getSqlTime()",
                original.getSqlTime(),
                clone.getSqlTime());
        } catch (Throwable t) {
            errors.add(t);
        }

        // java.sql.Timestamp
        try {
            Assert.assertNotSame("7. original.getSqlTimestamp() == clone.getSqlTimestamp()",
                original.getSqlTimestamp(),
                clone.getSqlTimestamp());
        } catch (Throwable t) {
            errors.add(t);
        }

        try {
            // Custom java.util.Date subclass
            Assert.assertNotSame("8. original.getDateSubclass() == clone.getDateSubclass()",
                original.getDateSubclass(),
                clone.getDateSubclass());
        } catch (Throwable t) {
            errors.add(t);
        }

        // error handling for all failed assertions
        if (errors.isEmpty() == false) {
            StringBuffer buffer = new StringBuffer();
            buffer.append("The following assertions failed:");
            buffer.append(Helper.cr());
            for (int i = 0; i < errors.size(); i++) {
                Throwable t = (Throwable)errors.get(i);
                buffer.append(t);
                buffer.append(Helper.cr());
            }
            throw new TestErrorException(buffer.toString());
        }
    }

}
