#!/usr/bin/python
# -*- coding: utf-8 -*-

from dbutils import dbtest, POSTGRES_USER, foreign_db_environ
import itertools

objects_listing_headers = ["Schema", "Name", "Type", "Owner", "Size", "Description"]


@dbtest
def test_slash_d(executor):
    results = executor("\d")
    title = None
    rows = [
        ("public", "Inh1", "table", POSTGRES_USER),
        ("public", "inh2", "table", POSTGRES_USER),
        ("public", "mvw1", "materialized view", POSTGRES_USER),
        ("public", "tbl1", "table", POSTGRES_USER),
        ("public", "tbl2", "table", POSTGRES_USER),
        ("public", "tbl2_id2_seq", "sequence", POSTGRES_USER),
        ("public", "tbl3", "table", POSTGRES_USER),
        ("public", "vw1", "view", POSTGRES_USER),
    ]
    headers = objects_listing_headers[:-2]
    status = "SELECT 8"
    expected = [title, rows, headers, status]

    assert results == expected


@dbtest
def test_slash_d_verbose(executor):
    results = executor("\d+")
    title = None
    rows = [
        ("public", "Inh1", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "inh2", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "mvw1", "materialized view", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl1", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl2", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl2_id2_seq", "sequence", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl3", "table", POSTGRES_USER, "0 bytes", None),
        ("public", "vw1", "view", POSTGRES_USER, "0 bytes", None),
    ]
    headers = objects_listing_headers
    status = "SELECT 8"
    expected = [title, rows, headers, status]

    assert results == expected


@dbtest
def test_slash_d_table_1(executor):
    results = executor("\d tbl1")
    title = None
    rows = [
        ["id1", "integer", " not null"],
        ["txt1", "text", " not null"],
    ]
    headers = ["Column", "Type", "Modifiers"]
    status = (
        'Indexes:\n    "id_text" PRIMARY KEY, btree (id1, txt1)\n'
        "Number of child tables: 2 (Use \\d+ to list them.)\n"
    )
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_d_table_2(executor):
    results = executor("\d tbl2")
    title = None
    rows = [
        ["id2", "integer", " not null default nextval('tbl2_id2_seq'::regclass)"],
        ["txt2", "text", ""],
    ]
    headers = ["Column", "Type", "Modifiers"]
    status = "Number of child tables: 1 (Use \\d+ to list them.)\n"
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_d_test_generated_default(executor):
    results = executor("\d schema3.test_generated_default")
    headers = ["Column", "Type", "Modifiers"]
    status = 'Indexes:\n    "test_generated_default_pkey" PRIMARY KEY, btree (id)\n'
    rows = [
        ["id", "integer", " not null generated by default as identity"],
        ["some_stuff", "text", ""],
    ]
    assert rows == results[1]
    assert headers == results[2]
    assert status == results[3]


@dbtest
def test_slash_d_table_verbose_1(executor):
    title = None
    headers = ["Column", "Type", "Modifiers", "Storage", "Stats target", "Description"]

    results = executor("\d+ tbl1")
    rows = [
        ["id1", "integer", " not null", "plain", None, None],
        ["txt1", "text", " not null", "extended", None, None],
    ]
    status = (
        'Indexes:\n    "id_text" PRIMARY KEY, btree (id1, txt1)\n'
        'Child tables: "Inh1",\n'
        "              inh2\n"
        "Has OIDs: no\n"
    )
    expected = [title, rows, headers, status]
    assert results == expected

    results = executor('\d+ "Inh1"')
    rows = [
        ["id1", "integer", " not null", "plain", None, None],
        ["txt1", "text", " not null", "extended", None, None],
        ["value1", "integer", "", "plain", None, None],
    ]
    status = "Inherits: tbl1\n" "Has OIDs: no\n"
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_d_table_verbose_2(executor):
    title = None
    headers = ["Column", "Type", "Modifiers", "Storage", "Stats target", "Description"]

    results = executor("\d+ tbl2")
    rows = [
        [
            "id2",
            "integer",
            " not null default nextval('tbl2_id2_seq'::regclass)",
            "plain",
            None,
            None,
        ],
        ["txt2", "text", "", "extended", None, None],
    ]
    status = "Child tables: inh2\n" "Has OIDs: no\n"
    expected = [title, rows, headers, status]
    assert results == expected

    results = executor("\d+ inh2")
    rows = [
        ["id1", "integer", " not null", "plain", None, None],
        ["txt1", "text", " not null", "extended", None, None],
        [
            "id2",
            "integer",
            " not null default nextval('tbl2_id2_seq'::regclass)",
            "plain",
            None,
            None,
        ],
        ["txt2", "text", "", "extended", None, None],
        ["value2", "integer", "", "plain", None, None],
    ]
    status = "Inherits: tbl1,\n" "          tbl2\n" "Has OIDs: no\n"
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_d_table_with_exclusion(executor):
    results = executor("\d tbl3")
    title = None
    rows = [["c3", "circle", ""]]
    headers = ["Column", "Type", "Modifiers"]
    status = 'Indexes:\n    "tbl3_c3_excl" EXCLUDE USING gist (c3 WITH &&)\n'
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_d_table_2_in_schema(executor):
    results = executor("\d schema2.tbl2")
    title = None
    rows = [
        [
            "id2",
            "integer",
            " not null default nextval('schema2.tbl2_id2_seq'::regclass)",
        ],
        ["txt2", "text", ""],
    ]
    headers = ["Column", "Type", "Modifiers"]
    status = ""
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dn(executor):
    """List all schemas."""
    results = executor("\dn")
    title = None
    rows = [
        ("public", POSTGRES_USER),
        ("schema1", POSTGRES_USER),
        ("schema2", POSTGRES_USER),
        ("schema3", POSTGRES_USER),
    ]
    headers = ["Name", "Owner"]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dp(executor):
    """List all schemas."""
    results = executor("\dp")
    title = None
    rows = [
        ("public", "Inh1", "table", None, "", ""),
        ("public", "inh2", "table", None, "", ""),
        ("public", "mvw1", "materialized view", None, "", ""),
        ("public", "tbl1", "table", None, "", ""),
        ("public", "tbl2", "table", None, "", ""),
        ("public", "tbl2_id2_seq", "sequence", None, "", ""),
        ("public", "tbl3", "table", None, "", ""),
        ("public", "vw1", "view", None, "", ""),
    ]

    headers = [
        "Schema",
        "Name",
        "Type",
        "Access privileges",
        "Column privileges",
        "Policies",
    ]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dp_pattern(executor):
    """List all schemas."""
    results = executor("\dp i*2")
    title = None
    rows = [("public", "inh2", "table", None, "", "")]
    headers = [
        "Schema",
        "Name",
        "Type",
        "Access privileges",
        "Column privileges",
        "Policies",
    ]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dp_pattern_alias(executor):
    """List all schemas."""
    results = executor("\z i*2")
    title = None
    rows = [("public", "inh2", "table", None, "", "")]
    headers = [
        "Schema",
        "Name",
        "Type",
        "Access privileges",
        "Column privileges",
        "Policies",
    ]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dt(executor):
    """List all tables in public schema."""
    results = executor("\dt")
    title = None
    rows = [
        ("public", "Inh1", "table", POSTGRES_USER),
        ("public", "inh2", "table", POSTGRES_USER),
        ("public", "tbl1", "table", POSTGRES_USER),
        ("public", "tbl2", "table", POSTGRES_USER),
        ("public", "tbl3", "table", POSTGRES_USER),
    ]
    headers = objects_listing_headers[:-2]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dt_verbose(executor):
    """List all tables in public schema in verbose mode."""
    results = executor("\dt+")
    title = None
    rows = [
        ("public", "Inh1", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "inh2", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl1", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl2", "table", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl3", "table", POSTGRES_USER, "0 bytes", None),
    ]
    headers = objects_listing_headers
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dv(executor):
    """List all views in public schema."""
    results = executor("\dv")
    title = None
    row = [("public", "vw1", "view", POSTGRES_USER)]
    headers = objects_listing_headers[:-2]
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_dv_verbose(executor):
    """List all views in s1 schema in verbose mode."""
    results = executor("\dv+ schema1.*")
    title = None
    row = [("schema1", "s1_vw1", "view", POSTGRES_USER, "0 bytes", None)]
    headers = objects_listing_headers
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_dm(executor):
    """List all materialized views in schema1."""
    results = executor("\dm schema1.*")
    title = None
    row = [("schema1", "s1_mvw1", "materialized view", POSTGRES_USER)]
    headers = objects_listing_headers[:-2]
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_dm_verbose(executor):
    """List all materialized views in public schema in verbose mode."""
    results = executor("\dm+")
    title = None
    row = [("public", "mvw1", "materialized view", POSTGRES_USER, "8192 bytes", None)]
    headers = objects_listing_headers
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_ds(executor):
    """List all sequences in public schema."""
    results = executor("\ds")
    title = None
    row = [("public", "tbl2_id2_seq", "sequence", POSTGRES_USER)]
    headers = objects_listing_headers[:-2]
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_ds_verbose(executor):
    """List all sequences in public schema in verbose mode."""
    results = executor("\ds+")
    title = None
    row = [("public", "tbl2_id2_seq", "sequence", POSTGRES_USER, "8192 bytes", None)]
    headers = objects_listing_headers
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_di(executor):
    """List all indexes in public schema."""
    results = executor("\di")
    title = None
    row = [
        ("public", "id_text", "index", POSTGRES_USER),
        ("public", "tbl3_c3_excl", "index", POSTGRES_USER),
    ]
    headers = objects_listing_headers[:-2]
    status = "SELECT %s" % len(row)
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_di_verbose(executor):
    """List all indexes in public schema in verbose mode."""
    results = executor("\di+")
    title = None
    row = [
        ("public", "id_text", "index", POSTGRES_USER, "8192 bytes", None),
        ("public", "tbl3_c3_excl", "index", POSTGRES_USER, "8192 bytes", None),
    ]
    headers = objects_listing_headers
    status = "SELECT 2"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_dx(executor):
    """List all extensions."""
    results = executor("\dx")
    title = None
    row = [("plpgsql", "1.0", "pg_catalog", "PL/pgSQL procedural language")]
    headers = ["Name", "Version", "Schema", "Description"]
    status = "SELECT 1"
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_dx_verbose(executor):
    """List all extensions in verbose mode."""
    results = executor("\dx+")
    title = '\nObjects in extension "plpgsql"'
    row = [
        ("function plpgsql_call_handler()",),
        ("function plpgsql_inline_handler(internal)",),
        ("function plpgsql_validator(oid)",),
        ("language plpgsql",),
    ]
    headers = ["Object Description"]
    status = "SELECT %s" % len(row)
    expected = [title, row, headers, status]
    assert results == expected


@dbtest
def test_slash_dT(executor):
    """List all datatypes."""
    results = executor("\dT")
    title = None
    rows = [("public", "foo", None), ("public", "gender_t", None)]
    headers = ["Schema", "Name", "Description"]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dD(executor):
    title = None
    headers = ["Schema", "Name", "Type", "Modifier", "Check"]
    results = executor("\dD")
    rows = [
        (
            "public",
            "gender_t",
            "character(1)",
            "",
            "CHECK (VALUE = ANY (ARRAY['F'::bpchar, 'M'::bpchar]))",
        )
    ]
    status = "SELECT 1"
    expected = [title, rows, headers, status]
    assert results == expected

    results = executor("\dD schema1.*")
    rows = [
        ("schema1", "bigint_t", "bigint", "", ""),
        ("schema1", "smallint_t", "smallint", "", ""),
    ]
    status = "SELECT %s" % len(rows)
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dD_verbose(executor):
    title = None
    headers = [
        "Schema",
        "Name",
        "Type",
        "Modifier",
        "Check",
        "Access privileges",
        "Description",
    ]
    results = executor("\dD+")
    rows = [
        (
            "public",
            "gender_t",
            "character(1)",
            "",
            "CHECK (VALUE = ANY (ARRAY['F'::bpchar, 'M'::bpchar]))",
            None,
            None,
        )
    ]
    status = "SELECT 1"
    expected = [title, rows, headers, status]
    assert results == expected

    results = executor("\dD+ schema1.bigint_t")
    rows = [("schema1", "bigint_t", "bigint", "", "", None, "a really large integer")]
    status = "SELECT 1"
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dF(executor):
    title, rows, header, status = executor("\dF")
    assert title is None
    assert header == ["Schema", "Name", "Description"]
    assert ("pg_catalog", "spanish", "configuration for spanish language") in rows

    results = executor("\dD *ian")
    assert title is None
    assert header == ["Schema", "Name", "Description"]
    assert ("pg_catalog", "russian", "configuration for russian language") in rows

    results = executor("\dD ge*")
    assert title is None
    assert header == ["Schema", "Name", "Description"]
    assert ("pg_catalog", "german", "configuration for german language") in rows


@dbtest
def test_slash_dF_verbose(executor):
    results = executor("\dF+")[1]
    assert ("asciihword", "simple") in results

    results = executor("\dF+ *panish")[1]
    assert ("asciihword", "spanish_stem") in results

    results = executor("\dF+ swed*")[1]
    assert ("asciihword", "swedish_stem") in results

    results = executor("\dF+ jap")
    assert results == [None, None, None, 'Did not find any results for pattern "jap".']


@dbtest
def test_slash_db(executor):
    """List all tablespaces."""
    title, rows, header, status = executor("\db")
    assert title is None
    assert header == ["Name", "Owner", "Location"]
    assert "pg_default" in rows[0]


@dbtest
def test_slash_db_name(executor):
    """List tablespace by name."""
    title, rows, header, status = executor("\db pg_default")
    assert title is None
    assert header == ["Name", "Owner", "Location"]
    assert "pg_default" in rows[0]
    assert status == "SELECT 1"


@dbtest
def test_slash_df(executor):
    results = executor("\df")
    title = None
    rows = [("public", "func1", "integer", "", "normal")]
    headers = ["Schema", "Name", "Result data type", "Argument data types", "Type"]
    status = "SELECT 1"
    expected = [title, rows, headers, status]
    assert results == expected


help_rows = [
    [
        "ABORT",
        "ALTER AGGREGATE",
        "ALTER COLLATION",
        "ALTER CONVERSION",
        "ALTER DATABASE",
        "ALTER DEFAULT PRIVILEGES",
    ],
    [
        "ALTER DOMAIN",
        "ALTER EVENT TRIGGER",
        "ALTER EXTENSION",
        "ALTER FOREIGN DATA WRAPPER",
        "ALTER FOREIGN TABLE",
        "ALTER FUNCTION",
    ],
    [
        "ALTER GROUP",
        "ALTER INDEX",
        "ALTER LANGUAGE",
        "ALTER LARGE OBJECT",
        "ALTER MATERIALIZED VIEW",
        "ALTER OPCLASS",
    ],
    [
        "ALTER OPERATOR",
        "ALTER OPFAMILY",
        "ALTER POLICY",
        "ALTER ROLE",
        "ALTER RULE",
        "ALTER SCHEMA",
    ],
    [
        "ALTER SEQUENCE",
        "ALTER SERVER",
        "ALTER SYSTEM",
        "ALTER TABLE",
        "ALTER TABLESPACE",
        "ALTER TRIGGER",
    ],
    [
        "ALTER TSCONFIG",
        "ALTER TSDICTIONARY",
        "ALTER TSPARSER",
        "ALTER TSTEMPLATE",
        "ALTER TYPE",
        "ALTER USER",
    ],
    ["ALTER USER MAPPING", "ALTER VIEW", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE"],
    ["CLUSTER", "COMMENT", "COMMIT", "COMMIT PREPARED", "COPY", "CREATE AGGREGATE"],
    [
        "CREATE CAST",
        "CREATE COLLATION",
        "CREATE CONVERSION",
        "CREATE DATABASE",
        "CREATE DOMAIN",
        "CREATE EVENT TRIGGER",
    ],
    [
        "CREATE EXTENSION",
        "CREATE FOREIGN DATA WRAPPER",
        "CREATE FOREIGN TABLE",
        "CREATE FUNCTION",
        "CREATE GROUP",
        "CREATE INDEX",
    ],
    [
        "CREATE LANGUAGE",
        "CREATE MATERIALIZED VIEW",
        "CREATE OPCLASS",
        "CREATE OPERATOR",
        "CREATE OPFAMILY",
        "CREATE POLICY",
    ],
    [
        "CREATE ROLE",
        "CREATE RULE",
        "CREATE SCHEMA",
        "CREATE SEQUENCE",
        "CREATE SERVER",
        "CREATE TABLE",
    ],
    [
        "CREATE TABLE AS",
        "CREATE TABLESPACE",
        "CREATE TRANSFORM",
        "CREATE TRIGGER",
        "CREATE TSCONFIG",
        "CREATE TSDICTIONARY",
    ],
    [
        "CREATE TSPARSER",
        "CREATE TSTEMPLATE",
        "CREATE TYPE",
        "CREATE USER",
        "CREATE USER MAPPING",
        "CREATE VIEW",
    ],
    ["DEALLOCATE", "DECLARE", "DELETE", "DISCARD", "DO", "DROP AGGREGATE"],
    [
        "DROP CAST",
        "DROP COLLATION",
        "DROP CONVERSION",
        "DROP DATABASE",
        "DROP DOMAIN",
        "DROP EVENT TRIGGER",
    ],
    [
        "DROP EXTENSION",
        "DROP FOREIGN DATA WRAPPER",
        "DROP FOREIGN TABLE",
        "DROP FUNCTION",
        "DROP GROUP",
        "DROP INDEX",
    ],
    [
        "DROP LANGUAGE",
        "DROP MATERIALIZED VIEW",
        "DROP OPCLASS",
        "DROP OPERATOR",
        "DROP OPFAMILY",
        "DROP OWNED",
    ],
    [
        "DROP POLICY",
        "DROP ROLE",
        "DROP RULE",
        "DROP SCHEMA",
        "DROP SEQUENCE",
        "DROP SERVER",
    ],
    [
        "DROP TABLE",
        "DROP TABLESPACE",
        "DROP TRANSFORM",
        "DROP TRIGGER",
        "DROP TSCONFIG",
        "DROP TSDICTIONARY",
    ],
    [
        "DROP TSPARSER",
        "DROP TSTEMPLATE",
        "DROP TYPE",
        "DROP USER",
        "DROP USER MAPPING",
        "DROP VIEW",
    ],
    ["END", "EXECUTE", "EXPLAIN", "FETCH", "GRANT", "IMPORT FOREIGN SCHEMA"],
    ["INSERT", "LISTEN", "LOAD", "LOCK", "MOVE", "NOTIFY"],
    [
        "PGBENCH",
        "PREPARE",
        "PREPARE TRANSACTION",
        "REASSIGN OWNED",
        "REFRESH MATERIALIZED VIEW",
        "REINDEX",
    ],
    [
        "RELEASE SAVEPOINT",
        "RESET",
        "REVOKE",
        "ROLLBACK",
        "ROLLBACK PREPARED",
        "ROLLBACK TO",
    ],
    ["SAVEPOINT", "SECURITY LABEL", "SELECT", "SELECT INTO", "SET", "SET CONSTRAINTS"],
    [
        "SET ROLE",
        "SET SESSION AUTH",
        "SET TRANSACTION",
        "SHOW",
        "START TRANSACTION",
        "TRUNCATE",
    ],
    ["UNLISTEN", "UPDATE", "VACUUM", "VALUES"],
]


@dbtest
def test_slash_h(executor):
    """List all commands."""
    results = executor("\h")
    expected = [None, help_rows, [], None]
    assert results == expected


@dbtest
def test_slash_h_command(executor):
    """Check help is returned for all commands"""
    for command in itertools.chain(*help_rows):
        results = executor("\h %s" % command)
        assert results[3].startswith("Description\n")
        assert "Syntax" in results[3]


@dbtest
def test_slash_h_alias(executor):
    """\? is properly aliased to \h"""
    h_results = executor("\h SELECT")
    results = executor("\? SELECT")
    assert results[3] == h_results[3]


@dbtest
def test_slash_copy_to_tsv(executor, tmpdir):
    filepath = tmpdir.join("pycons.tsv")
    executor(
        "\copy (SELECT 'Montréal', 'Portland', 'Cleveland') TO '{0}' ".format(filepath)
    )
    infile = filepath.open(encoding="utf-8")
    contents = infile.read()
    assert len(contents.splitlines()) == 1
    assert "Montréal" in contents


@dbtest
def test_slash_copy_to_stdout(executor, capsys):
    executor("\copy (SELECT 'Montréal', 'Portland', 'Cleveland') TO stdout")
    (out, err) = capsys.readouterr()
    assert out == "Montréal\tPortland\tCleveland\n"


@dbtest
def test_slash_copy_to_csv(executor, tmpdir):
    filepath = tmpdir.join("pycons.tsv")
    executor(
        "\copy (SELECT 'Montréal', 'Portland', 'Cleveland') TO '{0}' WITH csv".format(
            filepath
        )
    )
    infile = filepath.open(encoding="utf-8")
    contents = infile.read()
    assert len(contents.splitlines()) == 1
    assert "Montréal" in contents
    assert "," in contents


@dbtest
def test_slash_copy_from_csv(executor, connection, tmpdir):
    filepath = tmpdir.join("tbl1.csv")
    executor("\copy (SELECT 22, 'elephant') TO '{0}' WITH csv".format(filepath))
    executor("\copy tbl1 FROM '{0}' WITH csv".format(filepath))
    cur = connection.cursor()
    cur.execute("SELECT * FROM tbl1 WHERE id1 = 22")
    row = cur.fetchone()
    assert row[1] == "elephant"


@dbtest
def test_slash_sf(executor):
    results = executor("\sf func1")
    title = None
    rows = [
        (
            "CREATE OR REPLACE FUNCTION public.func1()\n"
            " RETURNS integer\n"
            " LANGUAGE sql\n"
            "AS $function$select 1$function$\n",
        ),
    ]
    headers = ["source"]
    status = None
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_sf_unknown(executor):
    try:
        executor("\sf non_existing")
    except Exception as e:
        assert "non_existing" in str(e)
    else:
        assert False, "Expected an exception"


@dbtest
def test_slash_sf_parens(executor):
    results = executor("\sf func1()")
    title = None
    rows = [
        (
            "CREATE OR REPLACE FUNCTION public.func1()\n"
            " RETURNS integer\n"
            " LANGUAGE sql\n"
            "AS $function$select 1$function$\n",
        ),
    ]
    headers = ["source"]
    status = None
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_sf_verbose(executor):
    results = executor("\sf+ schema1.s1_func1")
    title = None
    rows = [
        (
            "        CREATE OR REPLACE FUNCTION schema1.s1_func1()\n"
            "         RETURNS integer\n"
            "         LANGUAGE sql\n"
            "1       AS $function$select 2$function$\n",
        ),
    ]
    headers = ["source"]
    status = None
    expected = [title, rows, headers, status]
    assert results == expected


@dbtest
def test_slash_dE(executor):

    with foreign_db_environ():
        results = executor("\dE")
        title = None
        rows = [("public", "foreign_foo", "foreign table", "postgres")]
        headers = ["Schema", "Name", "Type", "Owner"]
        status = "SELECT 1"
        expected = [title, rows, headers, status]
        assert results == expected


@dbtest
def test_slash_dE_with_pattern(executor):

    with foreign_db_environ():
        results = executor("\dE foreign_foo")
        title = None
        rows = [("public", "foreign_foo", "foreign table", "postgres")]
        headers = ["Schema", "Name", "Type", "Owner"]
        status = "SELECT 1"
        expected = [title, rows, headers, status]
        assert results == expected

        results = executor("\dE *_foo")
        assert results == expected

        results = executor("\dE no_such_table")
        rows = []
        status = "SELECT 0"
        expected = [title, rows, headers, status]
        assert results == expected


@dbtest
def test_slash_dE_verbose(executor):

    with foreign_db_environ():
        results = executor("\dE+")
        title = None
        rows = [("public", "foreign_foo", "foreign table", "postgres", "0 bytes", None)]
        headers = ["Schema", "Name", "Type", "Owner", "Size", "Description"]
        status = "SELECT 1"
        expected = [title, rows, headers, status]
        assert results == expected
