 /**************************************************************************
 * DESCRIPTION:
 *
 * To add a test to megatest, you have to:
 *
 *   1. write a testname_moduleinit function that initializes the module.
 *   2. write a testname_init function that starts the test.
 *   3. declare the testname_init function inside this module.
 *   4. extend the tests[] table in this module to include the new test.
 *   5. add extern module statement to megatest.ci
 *
 **************************************************************************/

#include <stdio.h>
#include "megatest.h"
#include "groupring.h"
#include "nodering.h"
#include "varsizetest.h"
#include "varraystest.h"
#include "groupcast.h"
#include "nodecast.h"
#include "synctest.h"
#include "fib.h"
#include "arrayring.h"
#include "tempotest.h"
#include "packtest.h"
#include "queens.h"
#include "migration.h"
#include "priomsg.h"
#include "priotest.h"
#include "templates.h"

/******************************************************************************
 *
 * Test Configuration Section
 *
 *****************************************************************************/

extern void groupring_init(void);
extern void nodering_init(void);
extern void varsizetest_init(void);
extern void varraystest_init(void);
extern void groupcast_init(void);
extern void nodecast_init(void);
extern void synctest_init(void);
extern void fib_init(void);
extern void arrayring_init(void);
extern void tempotest_init(void);
extern void packtest_init(void);
extern void queens_init(void);
extern void migration_init(void);
extern void priomsg_init(void);
extern void templates_init(void);
extern void priotest_init(void);

extern void groupring_moduleinit(void);
extern void nodering_moduleinit(void);
extern void varsizetest_moduleinit(void);
extern void varraystest_moduleinit(void);
extern void groupcast_moduleinit(void);
extern void nodecast_moduleinit(void);
extern void synctest_moduleinit(void);
extern void fib_moduleinit(void);
extern void arrayring_moduleinit(void);
extern void tempotest_moduleinit(void);
extern void packtest_moduleinit(void);
extern void queens_moduleinit(void);
extern void migration_moduleinit(void);
extern void priomsg_moduleinit(void);
extern void templates_moduleinit(void);
extern void priotest_moduleinit(void);

struct testinfo
{
  const char *name;
  const char *author;
  void (*initiator)(void);
  void (*initializer)(void);
  int reentrant;
} tests[] = {
  { "groupring", "milind", groupring_init, groupring_moduleinit, 1 },
  { "nodering", "milind", nodering_init, nodering_moduleinit, 1 },
  { "varsize", "mjlang", varsizetest_init, varsizetest_moduleinit, 1 },
  { "varraystest", "milind", varraystest_init, varraystest_moduleinit, 1 },
  { "groupcast", "mjlang", groupcast_init, groupcast_moduleinit, 1 },
  { "nodecast", "milind", nodecast_init, nodecast_moduleinit, 1 },
  { "synctest", "mjlang", synctest_init, synctest_moduleinit, 1 },
  { "fib", "jackie", fib_init, fib_moduleinit, 1 },
  { "arrayring", "fang", arrayring_init, arrayring_moduleinit, 1 },
  { "tempotest", "fang", tempotest_init, tempotest_moduleinit, 1 },
  { "packtest", "fang", packtest_init, packtest_moduleinit, 1 },
  { "queens", "jackie", queens_init, queens_moduleinit, 0 },
  { "migration", "jackie", migration_init, migration_moduleinit, 1 },
  { "priomsg", "fang", priomsg_init, priomsg_moduleinit, 1 },
  { "priotest", "milind", priotest_init, priotest_moduleinit, 1 },
  { "templates", "milind", templates_init, templates_moduleinit, 0 },
  { 0,0,0,0,0 },
};

/******************************************************************************
 *
 * Central Control Section
 *
 *****************************************************************************/

CkChareID main::handle;

int main::megatest_skip(const char *test)
{
  int i;
  int num_skip = num_tests_to_skip;
  char **skip;
  skip = tests_to_skip;
  for (i=0; i<num_skip; i++) {
    if ((skip[i][0]=='-')&&(strcmp(skip[i]+1, test)==0))
      return 1 - test_negate_skip;
  }
  return test_negate_skip;
}

void main::megatest_next(void)
{
  int i, pos, idx, num, bank;

  bank = test_bank_size;
  num = next_test_number;
nextidx:
  idx = next_test_index;
  if (idx < bank) {
    if (megatest_skip(tests[idx].name)) {
      next_test_index++;
      goto nextidx;
    }
    test_start_time = CkWallTimer();
    CkPrintf("test %d: initiated [%s (%s)]\n", num, tests[idx].name, 
                                               tests[idx].author);
    acks_expected = 1;
    acks_received = 0;
    (tests[idx].initiator)();
    return; 
  }
  if (idx < (2*bank)) {
    pos = idx - bank;
    if (!tests[pos].reentrant||(megatest_skip(tests[pos].name))||
        test_negate_skip) {
      next_test_index++;
      goto nextidx;
    }
    acks_expected = 5;
    acks_received = 0;
    test_start_time = CkWallTimer();
    CmiPrintf("test %d: initiated [multi %s (%s)]\n", num, tests[pos].name,
                                                      tests[pos].author);
    for (i=0; i<5; i++) (tests[pos].initiator)();
    return;
  }
  if (idx== (2*bank)) {
    acks_expected = 1;
    acks_received = 0;
    test_start_time = CkWallTimer();
    CmiPrintf("test %d: initiated [all-at-once]\n", num);
    for (i=0; i<bank; i++) {
      if (!megatest_skip(tests[i].name)) {
	acks_expected++;
	(tests[i].initiator)();
      }
    }
    finishTest();
    return;
  }
  if (idx== ((2*bank)+1)) {
    CkPrintf("All tests completed, exiting\n");
    CkExit();
  }
}

void main::finish(void)
{
    acks_received++;
    if(acks_expected != acks_received)
      return;
    CkPrintf("test %d: completed (%1.2f sec)\n",
	      next_test_number,
	      CkWallTimer() - test_start_time);
    next_test_number++;
    next_test_index++;
    megatest_next();
}

main::main(CkArgMsg *msg)
{
  int argc = msg->argc;
  char **argv = msg->argv;
  int numtests, i;
  delete msg;
  handle = thishandle;
  for (i=0; (tests[i].initializer); i++)
    (tests[i].initializer)();
  for (numtests=0; tests[numtests].name; numtests++);
  test_bank_size = numtests;
  next_test_index = 0;
  next_test_number = 0;
  test_negate_skip=0;
  for (i=1; i<argc; i++)
    if (strcmp(argv[i],"-only")==0)
      test_negate_skip = 1;
  num_tests_to_skip = argc;
  if(test_negate_skip) {
    num_tests_to_skip--;
  }
  tests_to_skip = argv;
  megatest_next();
}

#include "megatest.def.h"
