// **********************************************************************
//
// 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/CosNaming.h>

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


//
// Test CosNaming_NamingContextExt::resolve_str()
//
void
TestResolveStr(CORBA_ORB_ptr orb, CosNaming_NamingContextExt_ptr root)
{
    CORBA_Object_var obj;
    TestObject_var test = new TestObject_impl;
    CosNaming_Name name1, name2;
    CosNaming_NamingContext_var context;

    //
    // Test exceptions
    //

    try
    {
	//
	// Try to resolve a binding that doesn't exist
	//
	obj = root -> resolve_str("bad.node");
	assert("resolve should not have succeeded" == 0);
    }
    catch(const CosNaming_NamingContext::NotFound& ex)
    {
	assert(ex.why == CosNaming_NamingContext::missing_node);
	assert(strcmp(ex.rest_of_name[0].id, "bad") == 0 &&
	       strcmp(ex.rest_of_name[0].kind, "node") == 0);
    }

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

    try
    {
	//
	// Try to resolve a binding when an object is in the path
	//
	obj = root -> resolve_str("object/my.node");
	assert("resolve should not have succeeded" == 0);
    }
    catch(const CosNaming_NamingContext::NotFound& ex)
    {
	assert(ex.why == CosNaming_NamingContext::not_context);
    }

    //
    // Test resolve
    //
    SUCCEED(obj = root -> resolve_str("object"));
    assert(obj -> _is_equivalent(test));
    SUCCEED(root -> rebind(name1, CORBA_Object::_nil()));
    SUCCEED(obj = root -> resolve_str("object"));
    assert(CORBA_is_nil(obj));
    SUCCEED(root -> unbind(name1));

    try
    {
	//
	// Try to resolve a binding with an invalid name
	//
	root -> resolve_str("");
	assert("resolve should not have succeeded" == 0);
    }
    catch(const CosNaming_NamingContext::InvalidName&)
    {
	// Expected
    }

#if 0
    try
    {
	//
	// Try to resolve a binding with an invalid name
	//
	root -> resolve_str(".");
	assert("resolve should not have succeeded" == 0);
    }
    catch(const CosNaming_NamingContext::InvalidName&)
    {
	// Expected
    }
#endif

    //
    // Bind an intermediate context for use in more tests
    //
    context = root -> new_context();
    name1.length(1);
    name1[0].id = CORBA_string_dup("ctx");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(root -> bind_context(name1, context));

    try
    {
	//
	// Try to resolve a binding when an intermediate context
	// doesn't exist
	//
	root -> resolve_str("ctx/bad.node/my.node");
	assert("resolve should not have succeeded" == 0);
    }
    catch(const 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(context -> bind(name1, test));

    try
    {
	//
	// Try to resolve a binding when an object is in the path
	//
	root -> resolve_str("ctx/object/my.node");
	assert("resolve should not have succeeded" == 0);
    }
    catch(const CosNaming_NamingContext::NotFound& ex)
    {
	assert(ex.why == CosNaming_NamingContext::not_context);
    }

    //
    // Test resolve
    //
    SUCCEED(obj = root -> resolve_str("ctx/object"));
    assert(obj -> _is_equivalent(test));

    SUCCEED(context -> unbind(name1));

    //
    // Clean up context
    //
    name1.length(1);
    name1[0].id = CORBA_string_dup("ctx");
    name1[0].kind = CORBA_string_dup("");
    SUCCEED(root -> unbind(name1));
    SUCCEED(context -> destroy());


    //
    // Test name equality to make sure kind is included in comparisons
    //
    CORBA_Object_var o;
    name1.length(1);
    name1[0].id = CORBA_string_dup("object");
    name1[0].kind = CORBA_string_dup("kind1");
    name2.length(1);
    name2[0].id = CORBA_string_dup("object");
    name2[0].kind = CORBA_string_dup("kind2");
    SUCCEED(root -> bind(name1, test));
    SUCCEED(root -> bind(name2, CORBA_Object::_nil()));
    SUCCEED(o = root -> resolve_str("object.kind1"));
    assert(! CORBA_is_nil(o));
    SUCCEED(o = root -> resolve_str("object.kind2"));
    assert(CORBA_is_nil(o));
    SUCCEED(root -> unbind(name1));
    SUCCEED(root -> unbind(name2));
}
