/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas.jtests.clients.entity;

import java.util.Collection;
import java.util.Iterator;

import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;

import org.objectweb.jonas.jtests.beans.relation.family.People;
import org.objectweb.jonas.jtests.beans.relation.family.PeopleHome;
import org.objectweb.jonas.jtests.util.JTestCase;

/**
 * This test suite tests relations on beans of the same type.
 * Relations used are OOB, OMU, OMB.
 * It uses the bean family only.
 * Each test is independant from each other, since DataBase is
 * cleaned up after each test (See teardown).
 * @author Philippe Durieux
 */
public class F_FamilyEC2 extends JTestCase {

    /**
     * Reference on the remote Home
     */
    private static PeopleHome home = null;

    /**
     * Standard constructor
     */
    public F_FamilyEC2(String name) {
        super(name);
    }

    protected boolean isInit = false;

    /**
     * setup is called before each test case.
     * If not initialized, load the family bean and lookup the Home.
     */
    protected void setUp() {
        super.setUp();
        if (!isInit) {
            useBeans("family", false);
            try {
                home = (PeopleHome) PortableRemoteObject.narrow(ictx.lookup("FamilyHome"),
                                                                            PeopleHome.class);
            } catch (NamingException e) {
                fail("Cannot get bean home: " + e.getMessage());
            }
            isInit = true;
        }
    }

    /**
     * teardown is called after each test case.
     * Notes for debugging :
     * To see DataBase state after a test is passed :
     * Replace the cleanall() by sync(false).
     */
    protected void tearDown() throws Exception {
        cleanall();
    }

    /**
     * Cleanup all the family after each test, to make tests independant.
     * Use transaction to avoid known bugs during cleanup.
     * (With no transaction -> 1 remove will fail)
     */
    private void cleanall() throws Exception {
        debug("remove all beans");

        // Start the Transaction. In case a Transaction is still running,
        // roll it back first and start a new one.
        try {
            utx.begin();
        } catch (Exception e) {
            debug("rollback first and start a new tx");
            utx.rollback();
            utx.begin();
        }

        // In case there is a problem during remove, we must unload
        // the bean to restart properly.
        try {
            Collection c = home.findAll();
            for (Iterator i = c.iterator(); i.hasNext(); ) {
                People p = (People) PortableRemoteObject.narrow(i.next(), People.class);
                debug("removing " + p.getName());
                p.remove();
            }
            utx.commit();
        } catch (Exception e) {
            error("Exception in cleanup: " + e);
            try {
                utx.rollback();
            } catch (Exception f) {
                error("Exception during rollback: " + f);
            } finally {
                unloadBeans("family");
                isInit = false;
            }
        }
    }
        
    // ---------------------------------------------------------------
    // Set of the tests that are passed automatically.
    // ---------------------------------------------------------------

    /**
     * Test that a create can be done after a remove outside tx.
     * This test should pass.
     */
    public void testRemoveHTCreateIT() throws Exception {
        home.create("Edouard", null, null);
        home.create("Philomene", null, null);
        home.remove("Edouard");
        utx.begin();
        home.create("Edouard", null, null);
        home.union("Edouard", "Philomene");
        utx.commit();
    }

    /**
     * Test that a create can be done after a remove outside tx.
     * This test should pass.
     */
    public void testRemoveHTCreateIT1() throws Exception {
        home.create("Edouard", null, null);
        home.remove("Edouard");
        utx.begin();
        home.create("Edouard", null, null);
        utx.commit();
    }

    /**
     * This test should pass.
     */
    public void testRemoveFatherTx() throws Exception {
        build1920();
        People p1 = home.create("Edouard2", "Edouard", "Philomene");
        utx.begin();
        home.remove("Edouard");
        utx.commit();
        Assert.assertTrue("Edouard2 has no father", p1.hasNoFather());
    }

    /**
     * This test should pass.
     */
    public void testRemoveFather() throws Exception {
        build1920();
        People p1 = home.create("Edouard2", "Edouard", "Philomene");
        home.remove("Edouard");
        Assert.assertTrue("Edouard2 has no father", p1.hasNoFather());
    }

    /**
     * This test should pass.
     */
    public void testRemoveMother() throws Exception {
        build1920();
        People p1 = home.create("Sylvain", "Edouard", "Philomene");
        home.remove("Edouard");
        home.remove("Philomene");
        Assert.assertTrue("Sylvain is orphan", p1.isOrphan());
    }

    /**
     * This test should pass.
     */
    public void testRemoveMotherTx() throws Exception {
        utx.begin();
        build1920();
        People p1 = home.create("Sylvain", "Edouard", "Philomene");
        home.remove("Edouard");
        home.remove("Philomene");
        utx.commit();
        Assert.assertTrue("Sylvain is orphan", p1.isOrphan());
    }

    /**
     * Test the findAll without transaction.
     */
    public void testFindAll() throws Exception {
        Collection c = home.findAll();
        home.create("Bob", null, null);
        home.create("Jack", "Bob", null);
        People p3 = home.findByPrimaryKey("Bob");
        int n = p3.kidNumber();
        Collection c3 = home.findAll();
        Assert.assertEquals("findAll 3", 2, c3.size());
    }
    
    /**
     * This test should pass now.
     * The problem was that the finder method looks in the Database, and
     * that the data has not been written, because outside transaction.
     */
    public void testManChildren() throws Exception {
        build1920();
        build1940();
        People p3 = home.findByPrimaryKey("Ernest");
        Assert.assertEquals("Ernest's children", 3, p3.kidNumber());
    }
    
    /**
     * This test should pass now (bug fixed in create HT)
     */
    public void testRollbackUnion() throws Exception {
        home.create("Ernest", null, null);
        home.create("Simone", null, null);
        home.create("Monette", "Ernest", "Simone");
        home.create("Sylvain", null, null);
        utx.begin();
        home.union("Sylvain", "Monette");
        utx.rollback();
        People p3 = home.findByPrimaryKey("Monette");
        Assert.assertTrue("Monette not orphan", !p3.isOrphan());
    }

    /**
     * This test should pass.
     */
    public void testRollbackDivorce() throws Exception {
        home.create("Ernest", null, null);
        home.create("Simone", null, null);
        home.create("Monette", "Ernest", "Simone");
        home.create("Sylvain", null, null);
        home.union("Sylvain", "Monette");
        People p3 = home.create("Philippe", "Sylvain", "Monette");
        People p1 = home.create("Sylvie", null, null);
        home.union("Philippe", "Sylvie");
        utx.begin();
        home.divorce("Philippe", "Sylvie");
        utx.rollback();
        Assert.assertTrue("Philippe not orphan", !p3.isOrphan());
        Assert.assertTrue("Philippe not single", !p3.isSingle());
        Assert.assertTrue("Sylvie not single", !p1.isSingle());
    }

    /**
     * This test should pass.
     */
    public void testDivorce() throws Exception {
        home.create("Sylvain", null, null);
        home.create("Simone", null, null);
        People p2 = home.create("Philippe", "Sylvain", "Simone");
        People p6 = home.create("Pascale", "Sylvain", "Simone");
        People p5 = home.create("Sylvie", null, null);
        People p4 = home.create("Catherine", null, null);
        home.union("Philippe", "Sylvie");
        People p3 = home.create("Thomas", "Philippe", "Sylvie");
        home.divorce("Philippe", "Sylvie");
        People p1 = home.create("Nathan", "Philippe", "Catherine");
        Assert.assertTrue("Philippe single", p2.isSingle());
        Assert.assertTrue("Sylvie single", p5.isSingle());
        Assert.assertTrue("Nathan son of Philippe", p1.myFather().getName().equals("Philippe"));
        Assert.assertTrue("Nathan son of Catherine", p1.myMother().getName().equals("Catherine"));
        Assert.assertTrue("Nathan and Thomas", p3.brotherSisterOf("Nathan"));
        Assert.assertTrue("Philippe and Pascale", p2.brotherSisterOf("Pascale"));
    }

    /**
     * This test should pass
     */
    public void testRemoveRb() throws Exception {
        home.create("Ernest", null, null);
        home.create("Monette", "Ernest", null);
        home.create("Philippe", null, "Monette");
        utx.begin();
        home.remove("Ernest");
        utx.rollback();
        People p2 = home.findByPrimaryKey("Monette");
        Assert.assertEquals("Monette's children", 1, p2.kidNumber());
    }

    /**
     * This test should pass
     */
    public void testRemoveRb2() throws Exception {
        home.create("Ernest", null, null);
        home.create("Monette", "Ernest", null);
        home.create("Philippe", null, "Monette");
        utx.begin();
        home.remove("Monette");
        utx.rollback();
        People p2 = home.findByPrimaryKey("Monette");
        Assert.assertEquals("Monette's children", 1, p2.kidNumber());
    }

    /**
     * This test should pass
     */
    public void testRemoveRb3() throws Exception {
        home.create("Ernest", null, null);
        home.create("Monette", "Ernest", null);
        home.create("Philippe", null, "Monette");
        utx.begin();
        home.remove("Philippe");
        utx.rollback();
        People p2 = home.findByPrimaryKey("Monette");
        Assert.assertEquals("Monette's children", 1, p2.kidNumber());
    }

    /**
     * Same than testRemoveRb, with a sync before transaction.
     * This test should pass
     */
    public void testRemoveRbSync() throws Exception {
        home.create("Ernest", null, null);
        home.create("Monette", "Ernest", null);
        home.create("Philippe", null, "Monette");
        sync(false);
        utx.begin();
        home.remove("Ernest");
        utx.rollback();
        People p2 = home.findByPrimaryKey("Monette");
        Assert.assertEquals("Monette's children", 1, p2.kidNumber());
    }

    /**
     * This test a create followed by a home method that will
     * be rolled back (pb with reusing of contexts)
     */
    public void testCreateHomeRB() throws Exception {
        home.create("Lucien", null, null);
        utx.begin();
        home.create("Odette", null, null);
        home.union("Lucien", "Odette");
        utx.rollback();
        home.create("Odette", null, null);
    }

    // -------------------------------------------------------------------------
    // Tests different states, with different transaction contexts
    // Always build 1920 before 1940, 1940 before 1960, ...
    // All these tests can be run independantly.
    // For debugging : To check database state, see tearDown().
    // -------------------------------------------------------------------------

    public void test1920() throws Exception {
        build1920();
        check1920();
    }

    public void test1920co() throws Exception {
        utx.begin();
        build1920();
        utx.commit();
        check1920();
    }

    public void test1920rb() throws Exception {
        utx.begin();
        build1920();
        utx.rollback();
        build1920();
        check1920();
    }

    public void test1920rb1() throws Exception {
        build1920();
        utx.begin();
        build1940();
        utx.rollback();
        check1920();
    }

    public void test1920rb2() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        build1980();
        build1990();
        utx.rollback();
        check1920();
    }

    public void test1940() throws Exception {
        build1920();
        build1940();
        check1940();
    }

    public void test1940co() throws Exception {
        utx.begin();
        build1920();
        build1940();
        utx.commit();
        check1940();
    }

    public void test1940co2() throws Exception {
        build1920();
        utx.begin();
        build1940();
        utx.commit();
        check1940();
    }

    public void test1940rb() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        utx.rollback();
        check1940();
    }

    public void test1940rb2() throws Exception {
        utx.begin();
        build1920();
        build1940();
        utx.commit();
        utx.begin();
        build1960();
        utx.rollback();
        check1940();
    }

    public void test1940rb3() throws Exception {
        build1920();
        utx.begin();
        build1940();
        utx.commit();
        utx.begin();
        build1960();
        build1980();
        build1990();
        utx.rollback();
        check1940();
    }

    public void test1940rb4() throws Exception {
        utx.begin();
        build1920();
        utx.rollback();
        build1920();
        check1920();
        utx.begin();
        build1940();
        utx.rollback();
        check1920();
        build1940();
        check1940();
    }

    public void test1960() throws Exception {
        build1920();
        build1940();
        build1960();
        check1960();
    }

    public void test1960co() throws Exception {
        utx.begin();
        build1920();
        build1940();
        build1960();
        utx.commit();
        check1960();
    }

    public void test1960co1() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        utx.commit();
        check1960();
    }

    public void test1960co2() throws Exception {
        build1920();
        utx.begin();
        build1940();
        utx.commit();
        build1960();
        check1960();
    }

    public void test1960rb() throws Exception {
        build1920();
        utx.begin();
        build1940();
        utx.commit();
        utx.begin();
        build1960();
        build1980();
        utx.rollback();
        build1960();
        check1960();
    }

    public void test1960rb1() throws Exception {
        build1920();
        build1940();
        build1960();
        utx.begin();
        build1980();
        utx.rollback();
        check1960();
    }

    public void test1960rb2() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        utx.commit();
        utx.begin();
        build1980();
        utx.rollback();
        check1960();
    }

    public void test1960rb3() throws Exception {
        utx.begin();
        build1920();
        build1940();
        utx.commit();
        build1960();
        utx.begin();
        build1980();
        utx.rollback();
        check1960();
    }

    public void test1960rb4() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        utx.commit();
        utx.begin();
        build1980();
        build1990();
        utx.rollback();
        check1960();
    }

    public void test1980() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        check1980();
    }

    public void test1980co() throws Exception {
        utx.begin();
        build1920();
        build1940();
        build1960();
        build1980();
        utx.commit();
        check1980();
    }

    public void test1980co1() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        utx.commit();
        build1980();
        check1980();
    }

    public void test1980co2() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        utx.commit();
        build1980();
        check1980();
    }

    public void test1980rb() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        utx.begin();
        build1990();
        utx.rollback();
        check1980();
    }

    public void test1980rb2() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        utx.commit();
        build1980();
        utx.begin();
        build1990();
        utx.rollback();
        check1980();
    }

    public void test1980rb3() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        build1980();
        utx.commit();
        utx.begin();
        build1990();
        utx.rollback();
        check1980();
    }

    public void test1980rb4() throws Exception {
        build1920();
        build1940();
        build1960();
        utx.begin();
        build1980();
        utx.commit();
        utx.begin();
        build1990();
        utx.rollback();
        check1980();
    }

    public void test1980rb5() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        utx.begin();
        build1990();
        build2000();
        utx.rollback();
        check1980();
    }

    public void test1980rb5s() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        sync(false);
        utx.begin();
        build1990();
        build2000();
        utx.rollback();
        check1980();
    }

    public void test1980rb5s2() throws Exception {
        build1920();
        build1940();
        build1960();
        sync(false);
        build1980();
        utx.begin();
        build1990();
        build2000();
        utx.rollback();
        check1980();
    }

    public void test1980rb5s3() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        utx.begin();
        build1990();
        sync(false);
        build2000();
        utx.rollback();
        check1980();
    }

    public void test1990() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        build1990();
        check1990();
    }

    public void test1990co() throws Exception {
        utx.begin();
        build1920();
        build1940();
        build1960();
        build1980();
        build1990();
        utx.commit();
        check1990();
    }

    public void test1990co1() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        build1980();
        build1990();
        utx.commit();
        check1990();
    }

    public void test1990co2() throws Exception {
        build1920();
        utx.begin();
        build1940();
        build1960();
        utx.commit();
        build1980();
        build1990();
        check1990();
    }

    public void test1990co3() throws Exception {
        utx.begin();
        build1920();
        build1940();
        utx.commit();
        build1960();
        build1980();
        build1990();
        check1990();
    }

    public void test1990rb() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        build1990();
        utx.begin();
        build2000();
        utx.rollback();
        check1990();
    }

    public void test1990rb2() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        utx.begin();
        build1990();
        utx.commit();
        utx.begin();
        build2000();
        utx.rollback();
        check1990();
    }

    public void test1990rb3() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        build1980();
        utx.commit();
        build1990();
        utx.begin();
        build2000();
        utx.rollback();
        check1990();
    }

    public void test2000() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        build1990();
        build2000();
        check2000();
    }

    public void test2000co() throws Exception {
        utx.begin();
        build1920();
        build1940();
        build1960();
        build1980();
        build1990();
        build2000();
        utx.commit();
        check2000();
    }

    public void test2000co2() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        build1980();
        build1990();
        build2000();
        utx.commit();
        check2000();
    }

    public void test2000co3() throws Exception {
        build1920();
        build1940();
        utx.begin();
        build1960();
        build1980();
        build1990();
        utx.commit();
        build2000();
        check2000();
    }

    public void test2000co4() throws Exception {
        utx.begin();
        build1920();
        utx.commit();
        build1940();
        utx.begin();
        build1960();
        build1980();
        build1990();
        utx.commit();
        build2000();
        check2000();
    }

    public void test2000co5() throws Exception {
        utx.begin();
        build1920();
        utx.commit();
        build1940();
        build1960();
        utx.begin();
        build1980();
        utx.commit();
        build1990();
        build2000();
        check2000();
    }

    // --------------------------------------------------------------------------
    // These tests print data on stdout, there are not passed automatically.
    // --------------------------------------------------------------------------

    public void vtestP1() throws Exception {
        build1920();
        build1940();
        printAncestors(home.findByPrimaryKey("Sylvain"));
    }

    public void vtestP2() throws Exception {
        build1920();
        build1940();
        build1960();
        printAncestors(home.findByPrimaryKey("Philippe"));
    }

    public void vtestP3() throws Exception {
        build1920();
        build1940();
        build1960();
        build1980();
        printAncestors(home.findByPrimaryKey("Isabelle"));
    }

    // --------------------------------------------------------------------------
    // private methods to build family, and check state is OK.
    // --------------------------------------------------------------------------

    private void build1920() throws Exception {
        debug("Build 1920");
        home.create("Edouard", null, null);
        home.create("Philomene", null, null);
        home.create("Ernest", null, null);
        home.create("Simone", null, null);
        home.create("Lucienne", null, null);
    }

    private void check1920() throws Exception {
        debug("Check 1920");
        People p1 = home.findByPrimaryKey("Edouard");
        Assert.assertTrue("Edouard is single", p1.isSingle());
        People p2 = home.findByPrimaryKey("Ernest");
        Assert.assertTrue("Ernest is single", p2.isSingle());
        People p3 = home.findByPrimaryKey("Philomene");
        Assert.assertTrue("Philomene is single", p3.isSingle());
        People p4 = home.findByPrimaryKey("Simone");
        Assert.assertTrue("Simone is single", p4.isSingle());
    }
        

    private void build1940() throws Exception {
        debug("Build 1940");
        home.union("Edouard", "Philomene");
        home.union("Ernest", "Simone");
        home.create("Edouard2", "Edouard", "Philomene");
        home.create("Genevieve", null, null);
        home.create("Odette", "Edouard", "Philomene");
        home.create("Lucien", null, null);
        home.create("Blanche", "Edouard", "Philomene");
        home.create("Paul", null, null);
        home.create("Sylvain", "Edouard", "Philomene");
        home.create("Tines", "Ernest", "Simone");
        home.create("Suzanne", null, null);
        home.create("Monette", "Ernest", "Simone");
        home.create("Francis", null, null);
        home.create("Marose", "Ernest", "Simone");
    }

    private void check1940() throws Exception {
        debug("Check 1940");
        People p1 = home.findByPrimaryKey("Edouard");
        People p2 = p1.mySpouse();
        People p3 = home.findByPrimaryKey("Ernest");
        People p4 = p3.mySpouse();
        Assert.assertTrue("Edouard is married", p2.getName().equals("Philomene"));
        Assert.assertTrue("Philomene is married", p2.mySpouse().getName().equals("Edouard"));
        Assert.assertEquals("Simone's children", 3, p4.kidNumber());
    }

    private void build1960() throws Exception {
        debug("Build 1960");
        home.create("Pierre", "Ernest", "Simone");
        home.union("Lucien", "Odette");
        home.union("Paul", "Blanche");
        home.union("Sylvain", "Monette");
        home.union("Tines", "Suzanne");
        home.union("Francis", "Marose");
        home.create("Jean Paul", null, null);
        home.create("Chantal", "Edouard2", "Genevieve");
        home.create("Daniel", "Lucien", "Odette");
        home.create("Genevieve2", "Edouard2", "Genevieve");
        home.create("Marie Paule", "Paul", "Blanche");
        home.create("Emmanuel", null, null);
        home.create("Dominique", null, null);
        home.create("Philippe", "Sylvain", "Monette");
        home.create("Michel", "Edouard2", "Genevieve");
        home.create("Pascale", "Sylvain", "Monette");
        home.create("Veronique", "Francis", "Marose");
        home.create("Francois", "Tines", "Suzanne");
        home.create("Monique", null, null);
        home.create("Roch", null, null);
        home.create("Florence", "Francis", "Marose");
        home.create("Sylvie", null, null);
        home.create("Catherine", null, "Lucienne");
    }

    private void check1960() throws Exception {
        debug("Check 1960");
        People p1 = home.findByPrimaryKey("Ernest");
        People p2 = home.findByPrimaryKey("Monette");
        People p3 = home.findByPrimaryKey("Francois");
        Assert.assertTrue("Monette is married", p2.mySpouse().getName().equals("Sylvain"));
        Assert.assertEquals("Monette's children", 2, p2.kidNumber());
        Assert.assertTrue("Monette has a father", p2.myFather().getName().equals("Ernest"));
        Assert.assertTrue("Francois has a mother", p3.myMother().getName().equals("Suzanne"));
    }

    private void build1980() throws Exception {
        debug("Build 1980");
        home.create("Thierry", "Tines", "Suzanne");
        home.create("Valerie", "Francis", "Marose");
        home.create("Jerome", "Francis", "Marose");
        home.union("Pierre", "Chantal");
        home.remove("Edouard");
        home.remove("Philomene");
        home.remove("Simone");
        home.union("Jean Paul", "Veronique");
        home.union("Dominique", "Genevieve2");
        home.create("Isabelle", "Pierre", "Chantal");
        home.create("Wilfried", "Pierre", "Chantal");
        home.union("Roch", "Florence");
    }

    private void check1980() throws Exception {
        debug("Check 1980");
        People p1 = home.findByPrimaryKey("Marose");
        People p2 = home.findByPrimaryKey("Sylvain");
        People p3 = home.findByPrimaryKey("Philippe");
        People p4 = home.findByPrimaryKey("Jerome");
        People p5 = home.findByPrimaryKey("Ernest");
        Assert.assertEquals("Marose's children", 4, p1.kidNumber());
        Assert.assertTrue("Sylvain is orphan", p2.isOrphan());
        Assert.assertTrue("Philippe and Pascale", p3.brotherSisterOf("Pascale"));
        Assert.assertTrue("Jerome and Veronique", p4.brotherSisterOf("Veronique"));
        Assert.assertTrue("Ernest single", p5.isSingle());
    }

    private void build1990() throws Exception {
        debug("Build 1990");
        home.union("Emmanuel", "Pascale");
        home.union("Philippe", "Sylvie");
        home.union("Francois", "Monique");
        home.create("Lucie", "Jean Paul", "Veronique");
        home.create("Amandine", "Emmanuel", "Pascale");
        home.create("Julien", "Emmanuel", "Pascale");
        home.create("Thomas", "Philippe", "Sylvie");
        home.create("Florent", "Philippe", "Sylvie");
        home.create("Fanny", "Emmanuel", "Pascale");
        home.divorce("Roch", "Florence");
        home.create("Charles Guillaume", "Francois", "Monique");
        home.create("Pierre Olivier", "Francois", "Monique");
    }

    private void check1990() throws Exception {
        debug("Check 1990");
        People p2 = home.findByPrimaryKey("Monette");
        People p3 = home.findByPrimaryKey("Pascale");
        Assert.assertEquals("Monette's children", 2, p2.kidNumber());
        Assert.assertEquals("Pascale's children", 3, p3.kidNumber());
    }

    private void build2000() throws Exception {
        debug("Build 2000");
        home.divorce("Philippe", "Sylvie");
        home.divorce("Jean Paul", "Veronique");
        home.remove("Ernest");
        home.create("Nathan", "Philippe", "Catherine");
    }

    private void check2000() throws Exception {
        debug("Check 2000");
        People p1 = home.findByPrimaryKey("Nathan");
        People p2 = home.findByPrimaryKey("Philippe");
        People p3 = home.findByPrimaryKey("Thomas");
        People p4 = home.findByPrimaryKey("Catherine");
        People p5 = home.findByPrimaryKey("Sylvie");
        People p6 = home.findByPrimaryKey("Pascale");
        People p7 = home.findByPrimaryKey("Monette");
        Assert.assertTrue("Philippe single", p2.isSingle());
        Assert.assertTrue("Sylvie single", p5.isSingle());
        Assert.assertTrue("Nathan son of Philippe", p1.myFather().getName().equals("Philippe"));
        Assert.assertTrue("Nathan son of Catherine", p1.myMother().getName().equals("Catherine"));
        Assert.assertTrue("Nathan and Thomas", p3.brotherSisterOf("Nathan"));
        Assert.assertTrue("Monette orphan", p7.isOrphan());
        Assert.assertTrue("Philippe and Pascale", p2.brotherSisterOf("Pascale"));
    }

    private void printParents(People p) throws Exception {
        People father = p.myFather();
        People mother = p.myMother();
        System.out.print(p.getName() + "\t--->\t");
        System.out.print(father != null ? father.getName() : "-");
        System.out.print("\t");
        System.out.println(mother != null ? mother.getName() : "-");
    }

    private void printAncestors(People p) throws Exception {
        if (p != null) {
            printParents(p);
            printAncestors(p.myFather());
            printAncestors(p.myMother());
        }
    }

    protected static void callTest(String testname) throws Exception {
        JTestCase.callTest("entity.F_FamilyEC2", testname);
    }

    /**
     * Run tests for perf mesures
     */
    protected static void perfs() throws Exception {
        callTest("testEmpty");
        callTest("test1920");
        callTest("test1940");
        callTest("test1960");
        callTest("test1980");
        callTest("test1990");
        callTest("test2000");
        callTest("test1920co");
        callTest("test1940co");
        callTest("test1960co");
        callTest("test1980co");
        callTest("test1990co");
        callTest("test2000co");
    }
        
    /**
     * Run a selected set of the test cases
     * F10 pass (should fails) but cleanup fails !!!
     */
    public static Test suite2() {
        TestSuite suite = new TestSuite();
        suite.addTest(new F_FamilyEC2("testF6"));
        suite.addTest(new F_FamilyEC2("testF8"));
        suite.addTest(new F_FamilyEC2("testF9"));
        suite.addTest(new F_FamilyEC2("testF10"));
        return suite;
    }

    /**
     * Run a selected set of the test cases
     */
    public static Test suite1() {
        TestSuite suite = new TestSuite();
        suite.addTest(new F_FamilyEC2("testF11"));
        suite.addTest(new F_FamilyEC2("testF12"));
        suite.addTest(new F_FamilyEC2("testF13"));
        suite.addTest(new F_FamilyEC2("testF14"));
        suite.addTest(new F_FamilyEC2("testF15"));
        suite.addTest(new F_FamilyEC2("testF16"));
        suite.addTest(new F_FamilyEC2("testF17"));
        suite.addTest(new F_FamilyEC2("testF18"));
        suite.addTest(new F_FamilyEC2("testF19"));
        return suite;
    }

    /**
     * Run all the tests of this suite.
     */
    public static Test suite() {
        return new TestSuite(F_FamilyEC2.class);
    }

    public static void main(String args[]) throws Exception {
        String testtorun = null;
        
        // Get args
        for (int argn = 0; argn < args.length; argn++) {
            String sarg = args[argn];
            if (sarg.equals("-n")) {
                testtorun = args[++argn];
            }
        }
        if (testtorun == null) {
            junit.textui.TestRunner.run(suite());
        } else {
            if (testtorun.equals("perfs")) {
                perfs();
            } else if (testtorun.equals("suite1")) {
                junit.textui.TestRunner.run(suite1());
            } else if (testtorun.equals("suite2")) {
                junit.textui.TestRunner.run(suite2());
            } else {
                junit.textui.TestRunner.run(new F_FamilyEC2(testtorun));
            }
        }
    }

}
