/*
  Copyright (c) 2004-2022 The FlameRobin Development Team

  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  without limitation the rights to use, copy, modify, merge, publish,
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:

  The above copyright notice and this permission notice shall be included
  in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

// Regression test for issue #78:
// "Create Selectable SP / EXECUTE BLOCK emits internal RDB$xxx domain names
//  instead of actual datatypes when 'Show both domain and datatype' is set."
//
// Root cause: the DDL-generation paths did not distinguish between a
// user-defined domain (which should appear in SQL) and a system / anonymous
// domain auto-created by Firebird (whose name starts with RDB$, MON$, or
// SEC$ and must be replaced by the underlying primitive datatype).
//
// The key predicate in the production code is:
//   MetadataItem::hasSystemPrefix()  (src/metadata/metadataitem.cpp)
//   Domain::isSystem()               (src/metadata/domain.cpp)
// Both classify a domain as "system" based on its name prefix.
// Parameter::getTypeOf() uses this to decide what to emit in generated SQL.
//
// This test verifies that classification contract in isolation, without
// requiring a live database connection.

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWindows headers
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include <iostream>

namespace
{

// Mirrors MetadataItem::hasSystemPrefix() and the prefix branch of
// Domain::isSystem().  Any domain whose name starts with RDB$, MON$, or
// SEC$ is considered system-generated and must NOT be output as a domain
// reference in DDL; instead the underlying datatype string must be used.
bool isSystemDomainName(const wxString& name)
{
    if (name.length() < 4)
        return false;
    wxString prefix(name.substr(0, 4));
    return prefix == "RDB$" || prefix == "MON$" || prefix == "SEC$";
}

bool check(bool condition, const char* testName)
{
    if (condition)
        return true;
    std::cerr << testName << " failed.\n";
    return false;
}

} // namespace

int main()
{
    bool ok = true;

    // -- System / anonymous domain names (must never appear in generated DDL) --

    // Autogenerated numeric domains: RDB$1, RDB$42, RDB$12345.
    // These are the names that triggered the bug: code was emitting them
    // verbatim in EXECUTE BLOCK / ALTER PROCEDURE output.
    ok = check( isSystemDomainName("RDB$1"),     "RDB$1 is system") && ok;
    ok = check( isSystemDomainName("RDB$42"),    "RDB$42 is system") && ok;
    ok = check( isSystemDomainName("RDB$12345"), "RDB$12345 is system") && ok;

    // Non-numeric RDB$ names (Firebird built-in metadata fields).
    ok = check( isSystemDomainName("RDB$FIELD_NAME"),  "RDB$FIELD_NAME is system") && ok;
    ok = check( isSystemDomainName("RDB$SECURITY_CLASS"), "RDB$SECURITY_CLASS is system") && ok;

    // MON$ monitoring domains.
    ok = check( isSystemDomainName("MON$STAT_ID"),   "MON$STAT_ID is system") && ok;
    ok = check( isSystemDomainName("MON$PAGE_READS"),"MON$PAGE_READS is system") && ok;

    // SEC$ security schema domains.
    ok = check( isSystemDomainName("SEC$USER_NAME"), "SEC$USER_NAME is system") && ok;
    ok = check( isSystemDomainName("SEC$ACTIVE"),    "SEC$ACTIVE is system") && ok;

    // -- User-defined domain names (must be preserved in generated DDL) --

    ok = check(!isSystemDomainName("MY_DOMAIN"),    "MY_DOMAIN is not system") && ok;
    ok = check(!isSystemDomainName("D_ID"),         "D_ID is not system") && ok;
    ok = check(!isSystemDomainName("T_STATUS"),     "T_STATUS is not system") && ok;
    ok = check(!isSystemDomainName("AMOUNT_TYPE"),  "AMOUNT_TYPE is not system") && ok;

    // Raw primitive-type names that may appear as column sources in older
    // metadata (no domain at all); these are not system domains either.
    ok = check(!isSystemDomainName("INTEGER"),   "INTEGER is not system") && ok;
    ok = check(!isSystemDomainName("VARCHAR"),   "VARCHAR is not system") && ok;
    ok = check(!isSystemDomainName("TIMESTAMP"), "TIMESTAMP is not system") && ok;

    // Edge cases: names shorter than 4 characters cannot match any prefix.
    ok = check(!isSystemDomainName(""),    "empty string is not system") && ok;
    ok = check(!isSystemDomainName("RDB"), "3-char RDB is not system") && ok;
    ok = check(!isSystemDomainName("R"),   "single char is not system") && ok;

    return ok ? 0 : 1;
}
