// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
 * COPYRIGHT:
 * Copyright (c) 1997-2014, International Business Machines Corporation and
 * others. All Rights Reserved.
 ********************************************************************/
/* Modification History:
*/

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include <stdlib.h>
#include "unicode/gender.h"
#include "unicode/unum.h"
#include "intltest.h"
#include "cmemory.h"

static const UGender kSingleFemale[] = {UGENDER_FEMALE};
static const UGender kSingleMale[] = {UGENDER_MALE};
static const UGender kSingleOther[] = {UGENDER_OTHER};

static const UGender kAllFemale[] = {UGENDER_FEMALE, UGENDER_FEMALE};
static const UGender kAllMale[] = {UGENDER_MALE, UGENDER_MALE};
static const UGender kAllOther[] = {UGENDER_OTHER, UGENDER_OTHER};

static const UGender kFemaleMale[] = {UGENDER_FEMALE, UGENDER_MALE};
static const UGender kFemaleOther[] = {UGENDER_FEMALE, UGENDER_OTHER};
static const UGender kMaleOther[] = {UGENDER_MALE, UGENDER_OTHER};


class GenderInfoTest : public IntlTest {
public:
    GenderInfoTest() {
    }

    void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par=0);
private:
    void TestGetListGender();
    void TestFallback();
    void check(UGender expected_neutral, UGender expected_mixed, UGender expected_taints, const UGender* genderList, int32_t listLength);
    void checkLocale(const Locale& locale, UGender expected, const UGender* genderList, int32_t listLength);
};

void GenderInfoTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /* par */) {
  if (exec) {
    logln("TestSuite GenderInfoTest: ");
  }
  TESTCASE_AUTO_BEGIN;
  TESTCASE_AUTO(TestGetListGender);
  TESTCASE_AUTO(TestFallback);
  TESTCASE_AUTO_END;
}

void GenderInfoTest::TestGetListGender() {
    check(UGENDER_OTHER, UGENDER_OTHER, UGENDER_OTHER, NULL, 0);
    check(UGENDER_FEMALE, UGENDER_FEMALE, UGENDER_FEMALE, kSingleFemale, UPRV_LENGTHOF(kSingleFemale));
    check(UGENDER_MALE, UGENDER_MALE, UGENDER_MALE, kSingleMale, UPRV_LENGTHOF(kSingleMale));
    check(UGENDER_OTHER, UGENDER_OTHER, UGENDER_OTHER, kSingleOther, UPRV_LENGTHOF(kSingleOther));

    check(UGENDER_OTHER, UGENDER_FEMALE, UGENDER_FEMALE, kAllFemale, UPRV_LENGTHOF(kAllFemale));
    check(UGENDER_OTHER, UGENDER_MALE, UGENDER_MALE, kAllMale, UPRV_LENGTHOF(kAllMale));
    check(UGENDER_OTHER, UGENDER_OTHER, UGENDER_MALE, kAllOther, UPRV_LENGTHOF(kAllOther));

    check(UGENDER_OTHER, UGENDER_OTHER, UGENDER_MALE, kFemaleMale, UPRV_LENGTHOF(kFemaleMale));
    check(UGENDER_OTHER, UGENDER_OTHER, UGENDER_MALE, kFemaleOther, UPRV_LENGTHOF(kFemaleOther));
    check(UGENDER_OTHER, UGENDER_OTHER, UGENDER_MALE, kMaleOther, UPRV_LENGTHOF(kMaleOther));
}

void GenderInfoTest::TestFallback() {
  UErrorCode status = U_ZERO_ERROR;
  const GenderInfo* actual = GenderInfo::getInstance("xx", status);
  if (U_FAILURE(status)) {
    errcheckln(status, "Fail to create GenderInfo - %s", u_errorName(status));
    return;
  }
  const GenderInfo* expected = GenderInfo::getNeutralInstance();
  if (expected != actual) {
    errln("For Neutral, expected %d got %d", expected, actual);
  }
  actual = GenderInfo::getInstance("fr_CA", status);
  if (U_FAILURE(status)) {
    errcheckln(status, "Fail to create GenderInfo - %s", u_errorName(status));
    return;
  }
  expected = GenderInfo::getMaleTaintsInstance();
  if (expected != actual) {
    errln("For Male Taints, Expected %d got %d", expected, actual);
  }
}

void GenderInfoTest::check(
    UGender expected_neutral, UGender expected_mixed, UGender expected_taints, const UGender* genderList, int32_t listLength) {
  checkLocale(Locale::getUS(), expected_neutral, genderList, listLength);
  checkLocale("is", expected_mixed, genderList, listLength);
  checkLocale(Locale::getFrench(), expected_taints, genderList, listLength);
}

void GenderInfoTest::checkLocale(
    const Locale& locale, UGender expected, const UGender* genderList, int32_t listLength) {
  UErrorCode status = U_ZERO_ERROR;
  const GenderInfo* gi = GenderInfo::getInstance(locale, status);
  if (U_FAILURE(status)) {
    errcheckln(status, "Fail to create GenderInfo - %s", u_errorName(status));
    return;
  }
  UGender actual = gi->getListGender(genderList, listLength, status);
  if (U_FAILURE(status)) {
    errcheckln(status, "Fail to get gender of list - %s", u_errorName(status));
    return;
  }
  if (actual != expected) {
    errln("For locale: %s expected: %d got %d", locale.getName(), expected, actual);
  }
}

extern IntlTest *createGenderInfoTest() {
  return new GenderInfoTest();
}

#endif /* #if !UCONFIG_NO_FORMATTING */
