/*
  This file is part of Anastasis
  Copyright (C) 2026 Anastasis SARL

  Anastasis is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
  Foundation; either version 3, or (at your option) any later version.

  Anastasis 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along with
  Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
*/
/**
 * @file reducer/test_validation.c
 * @brief testcase for the validation-logic dispatch table
 * @author Christian Grothoff
 */
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include "validation.h"

/**
 * Every name that appears as a "validation-logic" value in
 * contrib/redux.*.json.  All of them must resolve.
 */
static const char *known[] = {
  "BE_NRN_check",
  "CH_AHV_check",
  "CZ_BN_check",
  "DE_SVN_check",
  "DE_TIN_check",
  "ES_DNI_check",
  "FR_INSEE_check",
  "IN_AADHAR_check",
  "IT_CF_check",
  "NL_BSN_check",
  "XX_SQUARE_check",
  "XY_PRIME_check",
  NULL
};

/**
 * Names that must NOT resolve; "system" and "abort" are the reason the old
 * dlsym() dispatch was a remote code execution bug.
 */
static const char *unknown[] = {
  "system",
  "abort",
  "printf",
  "",
  "NL_BSN_check ",
  "nl_bsn_check",
  NULL
};


int
main (int argc,
      const char *const argv[])
{
  GNUNET_log_setup ("test-validation",
                    "WARNING",
                    NULL);
  for (unsigned int i = 0; NULL != known[i]; i++)
    if (NULL == ANASTASIS_REDUX_validation_lookup_ (known[i]))
    {
      GNUNET_break (0);
      fprintf (stderr,
               "validation logic `%s' does not resolve\n",
               known[i]);
      return 1;
    }
  for (unsigned int i = 0; NULL != unknown[i]; i++)
    if (NULL != ANASTASIS_REDUX_validation_lookup_ (unknown[i]))
    {
      GNUNET_break (0);
      fprintf (stderr,
               "`%s' must not resolve to a validation function\n",
               unknown[i]);
      return 1;
    }
  if (NULL != ANASTASIS_REDUX_validation_lookup_ (NULL))
  {
    GNUNET_break (0);
    return 1;
  }

  /* Belgian national register number: 93.05.18-223.61 is the documented
     example; 97 - (930518223 % 97) == 61.  As the century is not encoded we
     also accept the variant computed with the '2' prefix (check digits 90). */
  if (! BE_NRN_check ("93051822361"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (! BE_NRN_check ("93051822390"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (BE_NRN_check ("93051822362"))
  {
    GNUNET_break (0);
    return 1;
  }
  /* born in 2017: only the '2'-prefixed variant matches */
  if (! BE_NRN_check ("17060612328"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (BE_NRN_check ("17060612327"))
  {
    GNUNET_break (0);
    return 1;
  }
  /* malformed input */
  if (BE_NRN_check (""))
  {
    GNUNET_break (0);
    return 1;
  }
  if (BE_NRN_check ("9305182236"))     /* too short */
  {
    GNUNET_break (0);
    return 1;
  }
  if (BE_NRN_check ("930518223611"))   /* too long */
  {
    GNUNET_break (0);
    return 1;
  }
  if (BE_NRN_check ("9305182236x"))    /* not a digit */
  {
    GNUNET_break (0);
    return 1;
  }

  /* French NIR: mainland and both Corsican department codes.  2A must map to
     19 and 2B to 18, so the two must not produce the same check digits. */
  if (! FR_INSEE_check ("180057512345627"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (! FR_INSEE_check ("180052A12345684"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (! FR_INSEE_check ("180052B12345614"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (FR_INSEE_check ("180052A12345614"))   /* 2B's key on a 2A number */
  {
    GNUNET_break (0);
    return 1;
  }
  if (FR_INSEE_check ("180052C12345684"))   /* no such department letter */
  {
    GNUNET_break (0);
    return 1;
  }

  /* Czech birth numbers.  The modern form carries a check digit and must be
     divisible by 11; the nine-digit pre-1954 form has none and is accepted
     on the strength of its date alone. */
  if (! CZ_BN_check ("850615/0004"))
  {
    GNUNET_break (0);
    return 1;
  }
  if (! CZ_BN_check ("756203/0003"))     /* woman: month carries +50 */
  {
    GNUNET_break (0);
    return 1;
  }
  if (CZ_BN_check ("850615/0005"))       /* wrong check digit */
  {
    GNUNET_break (0);
    return 1;
  }
  if (! CZ_BN_check ("480615/123"))      /* born 1948: legacy form */
  {
    GNUNET_break (0);
    return 1;
  }
  if (CZ_BN_check ("850615/123"))        /* 1985 cannot use the legacy form */
  {
    GNUNET_break (0);
    return 1;
  }
  if (CZ_BN_check ("851315/0004"))       /* month 13 */
  {
    GNUNET_break (0);
    return 1;
  }
  if (CZ_BN_check ("850635/0004"))       /* day 35 */
  {
    GNUNET_break (0);
    return 1;
  }
  if (CZ_BN_check ("8506150004"))        /* the slash is not optional */
  {
    GNUNET_break (0);
    return 1;
  }
  if (CZ_BN_check ("482115/123"))        /* +20 months postdate the 9-digit form */
  {
    GNUNET_break (0);
    return 1;
  }

  /* Albania has no check-digit implementation, so contrib/redux.al.json
     carries no "validation-logic" at all and the name must not resolve. */
  if (NULL != ANASTASIS_REDUX_validation_lookup_ ("AL_NID_check"))
  {
    GNUNET_break (0);
    return 1;
  }
  return 0;
}


/* end of test_validation.c */
