// **********************************************************************
//
// Copyright (c) 1999
// Object Oriented Concepts, Inc.
// Billerica, MA, USA
//
// All Rights Reserved
//
// **********************************************************************

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <OB/CORBA.h>
#include <OB/Util.h>

#include <OB/OBNaming.h>

#include "TestObject_impl.h"
#include "TestMacro.h"


//
// Test CosNaming::OBNamingContext::rename()
//
void
TestRename(CORBA_ORB_ptr orb, CosNaming_NamingContext_ptr root)
{
    CosNaming_OBNamingContext_var ext =
        CosNaming_OBNamingContext::_narrow(root);
    assert(! CORBA_is_nil(ext));

    TestObject_var test = new TestObject_impl;
    CosNaming_Name name1, name2;
    CosNaming_OBNamingContext::ExtendedBindingList_var list;

    //
    // Test exceptions
    //

    try
    {
        //
        // Try to rename using an invalid old name
        //
        name1.length(0);
        name2.length(1);
        name2[0].id = CORBA_string_dup("new_name");
        name2[0].kind = CORBA_string_dup("");
        ext -> rename(name1, name2);
        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::InvalidName&)
    {
        // expected
    }

    try
    {
        //
        // Try to rename a non-existent binding
        //
        name1.length(1);
        name1[0].id = CORBA_string_dup("bad_name");
        name1[0].kind = CORBA_string_dup("");
        name2.length(1);
        name2[0].id = CORBA_string_dup("new_name");
        name2[0].kind = CORBA_string_dup("");
        ext -> rename(name1, name2);
        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::NotFound& ex)
    {
        assert(ex.why == CosNaming_NamingContext::missing_node);
    }

    name1.length(1);
    name1[0].id = CORBA_string_dup("old_name");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(ext -> bind(name1, test));

    try
    {
        //
        // Try to rename using an invalid new name
        //
        name2.length(0);
        ext -> rename(name1, name2);
        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::InvalidName&)
    {
        // expected
    }

    //
    // Verify rename works
    //
    name2.length(1);
    name2[0].id = CORBA_string_dup("new_name");
    name2[0].kind = CORBA_string_dup("new_kind");
    SUCCEED(ext -> rename(name1, name2));
    list = ext -> list_extended();
    assert(list -> length() == 1);
    assert(strcmp(list[0].binding_name[0].id, "new_name") == 0);
    assert(strcmp(list[0].binding_name[0].kind, "new_kind") == 0);

    //
    // Test exceptions
    //

    name1.length(1);
    name1[0].id = CORBA_string_dup("old_name");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(ext -> bind(name1, test));

    try
    {
        //
        // Try to rename old_name to new_name,new_kind - which already exists
        //
        name2.length(1);
        name2[0].id = CORBA_string_dup("new_name");
        name2[0].kind = CORBA_string_dup("new_kind");
        ext -> rename(name1, name2);
        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::AlreadyBound&)
    {
        // expected
    }

    //
    // Clean up
    //
    name1.length(1);
    name1[0].id = CORBA_string_dup("old_name");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(ext -> unbind(name1));
    name1[0].id = CORBA_string_dup("new_name");
    name1[0].kind = CORBA_string_dup("new_kind");
    SUCCEED(ext -> unbind(name1));

    try
    {
        //
        // Try to rename an object when an intermediate context
        // doesn't exist
        //
        name1.length(2);
        name1[0].id = CORBA_string_dup("bad");
        name1[0].kind = CORBA_string_dup("node");
        name1[1].id = CORBA_string_dup("my");
        name1[1].kind = CORBA_string_dup("node");
        name2.length(2);
        name2[0].id = CORBA_string_dup("bad");
        name2[0].kind = CORBA_string_dup("node");
        name2[1].id = CORBA_string_dup("new");
        name2[1].kind = CORBA_string_dup("node");
//        ext -> rename(name1, name2);
//        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::NotFound& ex)
    {
        assert(ex.why == CosNaming_NamingContext::missing_node);
    }

    name1.length(1);
    name1[0].id = CORBA_string_dup("object");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(ext -> bind(name1, test));

    try
    {
        //
        // Try to rename an object when an object is in the path
        //
        name1.length(2);
        name1[0].id = CORBA_string_dup("object");
        name1[0].kind = CORBA_string_dup("");
        name1[1].id = CORBA_string_dup("object1");
        name1[1].kind = CORBA_string_dup("");
        name2.length(2);
        name2[0].id = CORBA_string_dup("object");
        name2[0].kind = CORBA_string_dup("");
        name2[1].id = CORBA_string_dup("object2");
        name2[1].kind = CORBA_string_dup("");
//        ext -> rename(name1, name2);
//        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::NotFound& ex)
    {
        assert(ex.why == CosNaming_NamingContext::not_context);
    }

    name1.length(1);
    name1[0].id = CORBA_string_dup("object");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(ext -> unbind(name1));


    //
    // Create a context, then bind an object in that context.
    // We're going to test how rename() handles two names of
    // different depths.
    //
    name1.length(1);
    name1[0].id = CORBA_string_dup("ctx");
    name1[0].kind = CORBA_string_dup("");
    CosNaming_NamingContext_var context;
    SUCCEED(context = ext -> bind_new_context(name1));
    name1[0].id = CORBA_string_dup("object");
    SUCCEED(context -> bind(name1, test));

    try
    {
        //
        // Try to rename a binding to a new name that has a different
        // depth than the old name
        //
        name1.length(2);
        name1[0].id = CORBA_string_dup("ctx");
        name1[0].kind = CORBA_string_dup("");
        name1[1].id = CORBA_string_dup("object");
        name1[1].kind = CORBA_string_dup("");
        name2.length(1);
        name2[0].id = CORBA_string_dup("new_object");
        name2[0].kind = CORBA_string_dup("");
        ext -> rename(name1, name2);
        assert("rename should not have succeeded" == 0);
    }
    catch(CosNaming_NamingContext::InvalidName&)
    {
        // expected
    }

    name1.length(1);
    name1[0].id = CORBA_string_dup("object");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(context -> unbind(name1));
    name1[0].id = CORBA_string_dup("ctx");
    SUCCEED(ext -> unbind(name1));
    SUCCEED(context -> destroy());
}
