// $Id: Service_Config_Test.cpp,v 4.17 1999/07/05 09:51:45 nanbor Exp $

// ============================================================================
//
// = LIBRARY
//    tests
//
// = FILENAME
//    Service_Config_Test.cpp
//
// = DESCRIPTION
//      This is a simple test to make sure the Service_Configurator is
//      working correctly.
//
// = AUTHOR
//    David Levine
//
// ============================================================================

#include "test_config.h"
#include "ace/Object_Manager.h"
#include "ace/Service_Config.h"

ACE_RCSID(tests, Service_Config_Test, "$Id: Service_Config_Test.cpp,v 4.17 1999/07/05 09:51:45 nanbor Exp $")

#if defined(__BORLANDC__) && __BORLANDC__ >= 0x0530
USELIB("..\ace\aced.lib");
//---------------------------------------------------------------------------
#endif /* defined(__BORLANDC__) && __BORLANDC__ >= 0x0530 */

static const u_int VARIETIES = 3;

static u_int error = 0;

class Test_Singleton
  // = TITLE
  //   Test the Singleton
  //
  // = DESCRIPTION
  //   This should be a template class, with singleton instantiations.
  //   But to avoid having to deal with compilers that want template
  //   declarations in separate files, it's just a plain class.  The
  //   instance argument differentiates the "singleton" instances.  It
  //   also demonstrates the use of the param arg to the cleanup ()
  //   function.
{
public:
  static Test_Singleton *instance (u_short variety);
  ~Test_Singleton (void);

private:
  u_short variety_;
  static u_short current_;

  Test_Singleton (u_short variety);

  friend class misspelled_verbase_friend_declaration_to_avoid_compiler_warning_with_private_ctor;
};

u_short Test_Singleton::current_ = 0;

extern "C" void
test_singleton_cleanup (void *object, void *param)
{
  // We can't reliably use ACE_Log_Msg in a cleanup hook.  Yet.
  ACE_UNUSED_ARG (param);
  /* ACE_DEBUG ((LM_DEBUG, "cleanup %d\n", (u_short) param)); */

  delete (Test_Singleton *) object;
}

Test_Singleton *
Test_Singleton::instance (u_short variety)
{
  static Test_Singleton *instances[VARIETIES] = { 0 };

  if (instances[variety] == 0)
    ACE_NEW_RETURN (instances[variety],
                    Test_Singleton (variety),
                    0);

  ACE_Object_Manager::at_exit (instances[variety],
                               test_singleton_cleanup,
                               (void *) variety);
  return instances[variety];
}

Test_Singleton::Test_Singleton (u_short variety)
  : variety_ (variety)
{
  if (variety_ != current_++)
    {
      ACE_DEBUG ((LM_ERROR,
                  ASYS_TEXT ("ERROR: instance %u created out of order!\n"),
                 variety_));
      ++error;
    }
}

// We can't reliably use ACE_Log_Msg in a destructor that is called by
// ACE_Object_Manager.  Yet.

Test_Singleton::~Test_Singleton (void)
{
  /* ACE_DEBUG ((LM_DEBUG, ASYS_TEXT ("Test_Singleton %u dtor\n"), variety_)); */

  if (variety_ != --current_)
    {
      ACE_OS::fprintf (stderr,
                       ASYS_TEXT ("ERROR: instance %u destroyed out of order!\n"),
                       variety_);
      /* ACE_DEBUG ((LM_ERROR, ASYS_TEXT ("ERROR: instance %u destroyed out of order!\n"),
                 variety_)); */
      ++error;
    }
}

static void
run_test (int argc, ASYS_TCHAR *argv[])
{
  // We need this scope to make sure that the destructor for the
  // <ACE_Service_Config> gets called.
  ACE_Service_Config daemon;

  ACE_ASSERT (daemon.open (argc, argv) != -1 || errno == ENOENT);

  ACE_Time_Value tv (argc > 1 ? ACE_OS::atoi (argv[1]) : 2);

  ACE_ASSERT (ACE_Reactor::run_event_loop (tv) == 0);
}

int
main (int argc, ASYS_TCHAR *argv[])
{
  ACE_START_TEST (ASYS_TEXT ("Service_Config_Test"));

  for (u_int i = 0; i < VARIETIES; ++i)
    {
      Test_Singleton *s = Test_Singleton::instance (i);

      if (s == 0)
        ACE_ERROR_RETURN ((LM_ERROR,
                           ASYS_TEXT ("instance () allocate failed!\n")),
                          1);
    }

  run_test (argc, argv);

  ACE_END_TEST;
  return error == 0 ? 0 : 1;
}
