unittest/completion_frontend_t.cc (1,895 lines of code) (raw):
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0,
* as published by the Free Software Foundation.
*
* This program is designed to work with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have either included with
* the program or referenced in the documentation.
*
* This program 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, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <gtest/gtest_prod.h>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "mysqlsh/cmdline_shell.h"
#include "mysqlshdk/libs/utils/debug.h"
#include "mysqlshdk/libs/utils/utils_string.h"
#include "unittest/gtest_clean.h"
#include "unittest/test_utils.h"
#include "unittest/test_utils/mocks/gmock_clean.h"
#include "modules/devapi/mod_mysqlx_schema.h"
#include "modules/devapi/mod_mysqlx_session.h"
namespace mysqlsh {
class Completer_frontend : public Shell_core_test_wrapper {
struct linenoiseCompletions {
std::vector<std::string> completionStrings;
};
// mostly matches cmdline_shell.cc:auto_complete()
void completionCallback(const std::string &text, int *start_index,
linenoiseCompletions *completions) {
size_t completion_offset = *start_index;
std::vector<std::string> options(_interactive_shell->completer()->complete(
_interactive_shell->shell_context()->interactive_mode(), {}, text,
&completion_offset));
std::sort(options.begin(), options.end(),
shcore::Case_insensitive_comparator{});
auto last = std::unique(options.begin(), options.end());
options.erase(last, options.end());
*start_index = completion_offset;
// std::cout << "Complete '" << text << "'\n";
for (auto &i : options) {
// std::cout << i << "\n";
completions->completionStrings.push_back(i);
}
}
// mostly matches linenoise.cpp:completeLine()
const char *breakChars = " =+-/\\*?\"'`&<>;|@{([])}";
// just stubs to let completeLine() compile
void beep() {}
void freeCompletions(linenoiseCompletions *) {}
using Utf8String = std::string;
int buflen = 1024;
void copyString32(std::string &buf32, // NOLINT
const std::string &displayText, size_t len) {
buf32 = displayText.substr(0, len);
}
int completeLine(std::string &buf32, int &pos, // NOLINT
linenoiseCompletions *out_lc) {
linenoiseCompletions lc;
int len = static_cast<int>(buf32.size());
// completionCallback() expects a parsable entity, so find the previous
// break character and extract a copy to parse. we also handle the case
// where tab is hit while not at end-of-line.
int startIndex = pos;
while (--startIndex >= 0) {
if (strchr(breakChars, buf32[startIndex])) {
break;
}
}
++startIndex;
int itemLength = pos - startIndex;
Utf8String bufferContents(buf32, 0, pos);
// get a list of completions and the position to start completing from
completionCallback(bufferContents, &startIndex, &lc);
itemLength = pos - startIndex;
// if no completions, we are done
if (lc.completionStrings.size() == 0) {
beep();
freeCompletions(&lc);
return 0;
}
// at least one completion
int longestCommonPrefix = 0;
int displayLength = 0;
if (lc.completionStrings.size() == 1) {
longestCommonPrefix = static_cast<int>(lc.completionStrings[0].length());
} else {
bool keepGoing = true;
while (keepGoing) {
for (size_t j = 0; j < lc.completionStrings.size() - 1; ++j) {
char c1 = lc.completionStrings[j][longestCommonPrefix];
char c2 = lc.completionStrings[j + 1][longestCommonPrefix];
if ((0 == c1) || (0 == c2) || (c1 != c2)) {
keepGoing = false;
break;
}
}
if (keepGoing) {
++longestCommonPrefix;
}
}
}
// if we can extend the item, extend it and return to main loop
if (longestCommonPrefix > itemLength) {
displayLength = len + longestCommonPrefix - itemLength;
if (displayLength > buflen) {
longestCommonPrefix -= displayLength - buflen; // don't overflow buffer
displayLength = buflen; // truncate the insertion
beep(); // and make a noise
}
Utf8String displayText;
displayText.resize(displayLength + 1);
memcpy(&displayText[0], &buf32[0], startIndex);
memcpy(&displayText[startIndex], &lc.completionStrings[0][0],
longestCommonPrefix);
int tailIndex = startIndex + longestCommonPrefix;
memcpy(&displayText[tailIndex], &buf32[pos],
(displayLength - tailIndex + 1));
copyString32(buf32, displayText, displayLength);
pos = startIndex + longestCommonPrefix;
len = displayLength;
*out_lc = lc;
return 0;
}
if (lc.completionStrings.size() != 1) { // beep if ambiguous
beep();
*out_lc = lc;
return 1;
}
return 0;
}
public:
void SetUp() override {
Shell_core_test_wrapper::SetUp();
output_handler.set_errors_to_stderr(true);
}
void SetUpOnce() override {
run_script_classic(
{"create schema if not exists zzz;",
"create schema if not exists zombie;",
"create schema if not exists zoo;", "drop schema if exists actest;",
"create schema actest;", "use actest;",
"create table productTable (id int, name varchar(20));",
"create table creature (a int);", "create table croissant (a int);",
"create table tab_le(col_umn int);",
"create view vi_ew as select * from tab_le;"});
// Explicit create collections for 5.7
{
auto x = mysqlsh::mysqlx::Session();
x.connect(mysqlshdk::db::Connection_options(shell_test_server_uri('x')));
shcore::Dictionary_t options = shcore::make_dict();
options->set("schema", shcore::Value("actest"));
options->set("name", shcore::Value("people"));
x.execute_mysqlx_stmt("create_collection", options);
options->set("name", shcore::Value("person"));
x.execute_mysqlx_stmt("create_collection", options);
}
}
static void TearDownTestCase() {
run_script_classic({"drop schema actest", "drop schema zzz;",
"drop schema zombie;", "drop schema zoo;"});
}
void reset_shell() override {
get_options();
_options->interactive = true;
_options->db_name_cache = true;
replace_shell(get_options(),
std::unique_ptr<shcore::Interpreter_delegate>(
new shcore::Interpreter_delegate(output_handler.deleg)));
execute("\\py");
execute("import sys");
// delete some Python global vars that are leftover from other tests
execute("del globals()['db1']");
execute("del globals()['db2']");
wipe_all();
execute("sys.version.split(' ')[0]");
m_python_version = output_handler.std_out;
}
std::string m_python_version;
public:
std::pair<std::string, std::vector<std::string>> complete(
const std::string &line) {
// refresh the prompt, which triggers auto-complete refresh
_interactive_shell->prompt();
linenoiseCompletions lc;
std::string completed;
int position = line.length();
auto tab = line.find('\t');
if (tab != std::string::npos) {
position = tab;
completed = line.substr(0, tab) + line.substr(tab + 1);
} else {
completed = line;
}
completeLine(completed, position, &lc);
return {completed, lc.completionStrings};
}
bool is_function(const std::string &member) {
wipe_all();
if (_interactive_shell->shell_context()->interactive_mode() ==
shcore::IShell_core::Mode::Python) {
execute_noerr("callable(checkvar." + member + ")");
if (output_handler.std_out == "True\n") return true;
assert(output_handler.std_out == "False\n");
return false;
} else {
execute_noerr(
"['Function', 'm.Function']."
"indexOf(type(checkvar." +
member + ")) >= 0");
if (output_handler.std_out == "true\n") return true;
assert(output_handler.std_out == "false\n");
return false;
}
}
void check_object_member_completions(
const std::string &expr,
std::vector<std::pair<std::string, std::string>> method_args) {
{
SCOPED_TRACE("Autocompletion table completeness for result of " + expr);
check_object_completions(expr);
}
// method_args is a map of method_name -> method_arg_string
// so that evaluating method_name + method_arg_string will return a valid
// object to be tested
wipe_all();
// first evaluate the expression and assign to a temporary variable
execute_noerr("checkvar = " + expr + ";");
// first evaluate and list members of the object
std::vector<std::string> completions(complete("checkvar.").second);
// remove methods unsupported by 5.7
if (_target_server_version < mysqlshdk::utils::Version("8.0")) {
method_args.erase(
remove_if(method_args.begin(), method_args.end(),
[](const auto &other) {
return other.first.compare("replaceOne") == 0 ||
other.first.compare("createIndex") == 0;
}),
method_args.end());
completions.erase(remove_if(completions.begin(), completions.end(),
[](const auto &other) {
return other.compare("replaceOne()") == 0 ||
other.compare("createIndex()") == 0;
}),
completions.end());
}
if (_target_server_version < mysqlshdk::utils::Version("8.0.19")) {
method_args.erase(remove_if(method_args.begin(), method_args.end(),
[](const auto &other) {
return other.first == "modifyCollection";
}),
method_args.end());
completions.erase(remove_if(completions.begin(), completions.end(),
[](const auto &other) {
return other == "modifyCollection()";
}),
completions.end());
}
// first execute the methods with special handling given by the test
for (const auto &method : method_args) {
if (!method.second.empty()) {
std::string member_call = method.first + method.second;
SCOPED_TRACE("Autocompletion table completeness for result of " + expr +
"." + member_call);
check_object_completions("checkvar." + member_call);
}
size_t osize = completions.size();
completions.erase(std::remove_if(completions.begin(), completions.end(),
[&method](const std::string &m) {
return (m == method.first + "()" ||
m == method.first);
}),
completions.end());
if (osize == completions.size()) {
FAIL() << "Expected member " << method.first
<< " not found in completion list for " << expr << "\n"
<< "\t" << shcore::str_join(completions, "\n\t");
}
}
// then for each member, check their completions with the provided args
for (const auto &member : completions) {
size_t p;
if ((p = member.find('(')) != std::string::npos) {
// completion thinks this is a method, confirm
EXPECT_TRUE(is_function(member.substr(0, p)));
} else {
// completion thinks this is not a method, confirm
EXPECT_FALSE(is_function(member));
}
{
SCOPED_TRACE("Autocompletion table completeness for result of " + expr +
"." + member);
check_object_completions("checkvar." + member);
}
}
}
void check_object_completions(const std::string &expr) {
// list members
std::vector<std::string> completions(complete(expr + ".").second);
for (auto &s : completions) {
// strip ()
auto pos = s.find('(');
if (pos != std::string::npos) s = s.substr(0, pos);
}
wipe_all();
// evaluate the expression and compare with the auto-completion list
if (_interactive_shell->shell_context()->interactive_mode() ==
shcore::IShell_core::Mode::Python) {
execute_noerr("tmpvar = " + expr);
wipe_all();
execute_noerr("'shell.Object' in str(type(tmpvar))");
shcore::Value result = shcore::Value::parse(output_handler.std_out);
if (result.descr() == "False") return;
} else {
ASSERT_EQ("", output_handler.std_err);
execute("var tmpvar = " + expr);
// Only deprecation errors are bypassed on the function calls
if (!output_handler.std_err.empty()) {
if (output_handler.std_err.find("is deprecated") == std::string::npos) {
FAIL() << "Only deprecation errors are allowed on autocompletion "
"tests, found: "
<< output_handler.std_err.c_str() << "\n";
}
}
wipe_all();
execute_noerr(
"['m.Array', 'm.Map', 'String', 'Integer', "
"'Boolean'].indexOf(type(tmpvar)) >= 0");
shcore::Value result = shcore::Value::parse(output_handler.std_out);
// don't need to check non-object types
if (result.as_bool()) return;
}
wipe_all();
execute("dir(tmpvar)");
ASSERT_EQ("", output_handler.std_err);
shcore::Value result;
try {
result = shcore::Value::parse(output_handler.std_out);
} catch (std::exception &e) {
if (output_handler.std_out.empty())
ADD_FAILURE() << "Evaluation of " << expr << " produced error:\n "
<< output_handler.std_err << "\n";
else
ADD_FAILURE() << "Evaluation of " << expr << " produced "
<< output_handler.std_out << ": " << e.what() << "\n"
<< output_handler.std_err << "\n";
return;
}
std::vector<std::string> expected;
for (const shcore::Value &value : *result.as_array()) {
// skip __methods from python
if (shcore::str_beginswith(value.get_string(), "__")) continue;
expected.push_back(value.get_string());
}
std::sort(expected.begin(), expected.end());
std::sort(completions.begin(), completions.end());
if (expected != completions) {
ADD_FAILURE() << "Completion list mismatch for '" << expr << "':\n"
<< "Actual (completer): \n\t"
<< shcore::str_join(completions, "\n\t") << "\n"
<< "Should be (dir(obj)): \n\t"
<< shcore::str_join(expected, "\n\t") << "\n";
}
}
};
#ifdef _WIN32
#define PRODUCTTABLE "producttable"
#define DB_PRODUCTTABLE "db.producttable"
#else
#define PRODUCTTABLE "productTable"
#define DB_PRODUCTTABLE "db.productTable"
#endif
using strv = std::vector<std::string>;
// TS_FR2_C01, TS_FR2_C02, TS_FR2_C03, TS_FR2_X01, TS_FR2_X02, TS_FR2_X03
// Check auto-completion on 1 tab
#define EXPECT_AFTER_TAB(text, expected_text) \
do { \
auto r = complete(text); \
EXPECT_EQ(shcore::str_replace(expected_text, "\t", ""), r.first); \
} while (0)
// TS_FR3_C01, TS_FR3_C02, TS_FR3_X01, TS_FR3_X02
// Check completion alternatives on 2 tabs
#define EXPECT_AFTER_TAB_TAB(text, expected_options) \
do { \
auto r = complete(text); \
SCOPED_TRACE(text); \
EXPECT_EQ(shcore::str_replace(text, "\t", ""), r.first); \
EXPECT_EQ(shcore::str_join(expected_options, "\n"), \
shcore::str_join(r.second, "\n")); \
} while (0)
#define EXPECT_TAB_TAB_CONTAINS(text, expected_option) \
do { \
auto r = complete(text); \
SCOPED_TRACE(text); \
EXPECT_THAT(r.second, ::testing::Contains(expected_option)); \
} while (0)
#define EXPECT_TAB_TAB_NOT_CONTAINS(text, unexpected_option) \
do { \
auto r = complete(text); \
SCOPED_TRACE(text); \
EXPECT_THAT(r.second, \
::testing::Not(::testing::Contains(unexpected_option))); \
} while (0)
#define EXPECT_TAB_DOES_NOTHING(text) \
do { \
EXPECT_AFTER_TAB(shcore::str_replace(text, "\t", ""), text); \
EXPECT_AFTER_TAB_TAB(text, strv()); \
} while (0)
#define CHECK_OBJECT_COMPLETIONS(object) \
do { \
SCOPED_TRACE(object); \
check_object_completions(object); \
} while (0)
#define CHECK_OBJECT_MEMBER_COMPLETIONS(object, method_args) \
do { \
SCOPED_TRACE(object); \
check_object_member_completions(object, method_args); \
} while (0)
// TS_FR6.1_C01
TEST_F(Completer_frontend, builtin_use_c) {
connect_classic();
// TS_FR7_C01
EXPECT_TAB_DOES_NOTHING("");
// TS_FR7_C02
EXPECT_TAB_DOES_NOTHING(" ");
EXPECT_AFTER_TAB("\\u", "\\use");
EXPECT_AFTER_TAB("\\us", "\\use");
EXPECT_AFTER_TAB("\\use i", "\\use information_schema");
EXPECT_AFTER_TAB("\\use perf", "\\use performance_schema");
EXPECT_AFTER_TAB("\\use bla", "\\use bla");
}
// TS_FR6_X01, TS_FR6.1_X01
TEST_F(Completer_frontend, builtin_use_x) {
connect_x();
// TS_FR7_X01
EXPECT_TAB_DOES_NOTHING("");
// TS_FR7_X02
EXPECT_TAB_DOES_NOTHING(" ");
EXPECT_AFTER_TAB("\\u", "\\use");
EXPECT_AFTER_TAB("\\us", "\\use");
EXPECT_AFTER_TAB("\\use i", "\\use information_schema");
EXPECT_AFTER_TAB("\\use perf", "\\use performance_schema");
EXPECT_AFTER_TAB("\\use bla", "\\use bla");
}
TEST_F(Completer_frontend, builtin_connect) {
EXPECT_AFTER_TAB("\\co", "\\connect");
// EXPECT_AFTER_TAB("\\connect root@l", "\\connect root@localhost");
}
// TS_FR6_C01,
TEST_F(Completer_frontend, builtin_others) {
EXPECT_AFTER_TAB("\\h", "\\h");
EXPECT_AFTER_TAB_TAB("\\h", strv({"\\help", "\\history"}));
EXPECT_AFTER_TAB("\\hi", "\\history");
EXPECT_AFTER_TAB("\\he", "\\help");
auto expect = strv({"\\", "\\connect", "\\disconnect", "\\edit",
"\\exit", "\\help", "\\history", "\\js",
"\\nopager", "\\nowarnings", "\\option", "\\pager",
"\\py", "\\quit", "\\reconnect", "\\rehash",
"\\show", "\\source", "\\sql", "\\status",
"\\system", "\\use", "\\warnings", "\\watch"});
#ifndef HAVE_JS
expect.erase(std::find(expect.begin(), expect.end(), "\\js"));
#endif
EXPECT_AFTER_TAB_TAB("\\", expect);
}
// FR4
TEST_F(Completer_frontend, sql_keywords) {
execute("\\sql");
EXPECT_AFTER_TAB("sel", "SELECT");
EXPECT_AFTER_TAB("select * fr", "select * FROM");
EXPECT_TAB_DOES_NOTHING("select * FROM");
}
TEST_F(Completer_frontend, sql_schema) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("show tables from info",
"show tables from information_schema");
}
TEST_F(Completer_frontend, sql_table) {
connect_classic();
execute("\\use mysql");
execute("\\sql");
// table name from default schema
EXPECT_AFTER_TAB("select * from plu", "select * from plugin");
execute("\\use actest");
EXPECT_TAB_DOES_NOTHING("select * from plu");
EXPECT_AFTER_TAB("select * from peo", "select * from people");
EXPECT_AFTER_TAB_TAB("select * from `z",
strv({"`zombie`", "`zoo`", "`zzz`"}));
// identifier in `` should skip keywords
EXPECT_AFTER_TAB("cr", "CREATE");
EXPECT_AFTER_TAB("`cr", "`cr");
EXPECT_TAB_DOES_NOTHING("`cr");
}
// try different orders of mode switching
TEST_F(Completer_frontend, sql_table_o1) {
connect_classic();
execute("\\sql");
execute("\\use performance_schema");
// table name from default schema
EXPECT_AFTER_TAB("select * from rw", "select * from rwlock_instances");
execute("\\use mysql");
EXPECT_AFTER_TAB("describe `pl", "describe `plugin`");
}
TEST_F(Completer_frontend, sql_table_o2) {
connect_classic();
execute("\\use performance_schema");
execute("\\sql");
// table name from default schema
EXPECT_AFTER_TAB("select * from rw", "select * from rwlock_instances");
execute("\\use mysql");
EXPECT_AFTER_TAB("describe `pl", "describe `plugin`");
}
TEST_F(Completer_frontend, sql_table_o3) {
execute("\\sql");
connect_classic();
execute("\\use performance_schema");
// table name from default schema
EXPECT_AFTER_TAB("select * from rw", "select * from rwlock_instances");
execute("\\use mysql");
EXPECT_AFTER_TAB("describe `pl", "describe `plugin`");
}
#ifdef HAVE_JS
TEST_F(Completer_frontend, js_keywords) {
execute("\\js");
EXPECT_AFTER_TAB("pri", "print");
EXPECT_AFTER_TAB("x=pri", "x=print");
EXPECT_AFTER_TAB("var x =pri", "var x =print");
EXPECT_AFTER_TAB("println(sh", "println(shell");
EXPECT_AFTER_TAB("println(sh\t)", "println(shell)");
EXPECT_AFTER_TAB("wh", "while");
EXPECT_AFTER_TAB("while (sh", "while (shell");
EXPECT_AFTER_TAB("while (sh\t)", "while (shell)");
EXPECT_AFTER_TAB("while 1: sh", "while 1: shell");
EXPECT_AFTER_TAB("while 1: if (sh", "while 1: if (shell");
EXPECT_AFTER_TAB("while 1: /* bla '*/ if (sh",
"while 1: /* bla '*/ if (shell");
EXPECT_AFTER_TAB("while 1: /* bla \"*/ if (sh",
"while 1: /* bla \"*/ if (shell");
EXPECT_AFTER_TAB("while 1: /* bla /**/ if (sh",
"while 1: /* bla /**/ if (shell");
EXPECT_AFTER_TAB("while 1: /* bla (*/ if (sh",
"while 1: /* bla (*/ if (shell");
EXPECT_AFTER_TAB("while 1: /* bla {*/ if (sh",
"while 1: /* bla {*/ if (shell");
EXPECT_AFTER_TAB("while 1: /* bla }*/ if (sh",
"while 1: /* bla }*/ if (shell");
EXPECT_TAB_DOES_NOTHING("print('");
EXPECT_TAB_DOES_NOTHING("print(\"");
EXPECT_TAB_DOES_NOTHING("print('pri");
EXPECT_TAB_DOES_NOTHING("print(\"pri");
EXPECT_TAB_DOES_NOTHING("var x=px");
EXPECT_TAB_DOES_NOTHING("x = px");
EXPECT_TAB_DOES_NOTHING(".");
EXPECT_TAB_DOES_NOTHING("..");
EXPECT_TAB_DOES_NOTHING(".s");
EXPECT_TAB_DOES_NOTHING("(.s");
EXPECT_TAB_DOES_NOTHING("(.re");
EXPECT_TAB_DOES_NOTHING("shell..");
EXPECT_TAB_DOES_NOTHING("*");
// Session stuff while not connected
EXPECT_AFTER_TAB_TAB("session.", strv({}));
EXPECT_TAB_DOES_NOTHING("db.");
}
TEST_F(Completer_frontend, js_negative) {
execute("\\js");
EXPECT_AFTER_TAB("bogus", "bogus");
EXPECT_AFTER_TAB_TAB("bogus", strv({}));
EXPECT_AFTER_TAB("bogus.", "bogus.");
EXPECT_AFTER_TAB_TAB("bogus.", strv({}));
EXPECT_AFTER_TAB("print(\t)", "print()");
EXPECT_AFTER_TAB("print('pr\t", "print('pr");
EXPECT_AFTER_TAB("print('pr\t')", "print('pr')");
}
TEST_F(Completer_frontend, js_shell) {
execute("\\js");
CHECK_OBJECT_COMPLETIONS("shell");
EXPECT_AFTER_TAB("sh", "shell");
EXPECT_AFTER_TAB("shell.rec", "shell.reconnect()");
EXPECT_AFTER_TAB_TAB("shell.", strv({"addExtensionObjectMember()",
"autoCompleteSql()",
"connect()",
"connectToPrimary()",
"createContext()",
"createExtensionObject()",
"deleteAllCredentials()",
"deleteCredential()",
"disablePager()",
"disconnect()",
"dumpRows()",
"enablePager()",
"getSession()",
"help()",
"listCredentialHelpers()",
"listCredentials()",
"listSshConnections()",
"log()",
"openSession()",
"options",
"parseUri()",
"prompt()",
"reconnect()",
"registerGlobal()",
"registerReport()",
"reports",
"setCurrentSchema()",
"setSession()",
"status()",
"storeCredential()",
"unparseUri()",
"version"}));
EXPECT_TAB_DOES_NOTHING("shell.conect()");
EXPECT_AFTER_TAB_TAB("mysql", strv({"mysql", "mysqlx"}));
EXPECT_AFTER_TAB("mysql.getC", "mysql.getClassicSession()");
EXPECT_AFTER_TAB("mysqlx.get", "mysqlx.getSession()");
// a dynamically created global var
execute("var testobj = {'key_one':1, 'another_key': 2}");
EXPECT_AFTER_TAB("testo", "testobj");
EXPECT_AFTER_TAB_TAB("testobj.", strv({"another_key", "key_one"}));
EXPECT_AFTER_TAB("testobj.k", "testobj.key_one");
EXPECT_TAB_DOES_NOTHING("testobj.key_one");
// TS_FR5.3_C01
CHECK_OBJECT_COMPLETIONS("shell.options");
}
TEST_F(Completer_frontend, js_adminapi) {
execute("\\js");
CHECK_OBJECT_COMPLETIONS("dba");
// TS_FR5.2_C02, TS_FR5.2_X02
EXPECT_AFTER_TAB_TAB("dba.", strv({"checkInstanceConfiguration()",
"configureInstance()",
"configureLocalInstance()",
"configureReplicaSetInstance()",
"createCluster()",
"createReplicaSet()",
"deleteSandboxInstance()",
"deploySandboxInstance()",
"dropMetadataSchema()",
"getCluster()",
"getClusterSet()",
"getReplicaSet()",
"help()",
"killSandboxInstance()",
"rebootClusterFromCompleteOutage()",
"session",
"startSandboxInstance()",
"stopSandboxInstance()",
"upgradeMetadata()",
"verbose"}));
EXPECT_AFTER_TAB("dba.depl", "dba.deploySandboxInstance()");
}
// TS_FR8_X01
TEST_F(Completer_frontend, js_devapi) {
connect_x();
execute("\\js");
CHECK_OBJECT_COMPLETIONS("mysqlx");
CHECK_OBJECT_COMPLETIONS("session");
EXPECT_AFTER_TAB("session.createS", "session.createSchema()");
EXPECT_AFTER_TAB("session.st", "session.startTransaction()");
EXPECT_AFTER_TAB_TAB(
"session.get",
strv({"getCurrentSchema()", "getDefaultSchema()", "getSchema()",
"getSchemas()", "getSshUri()", "getUri()"}));
EXPECT_AFTER_TAB("session.sql", "session.sql()");
EXPECT_AFTER_TAB("session.sql('sele\t", "session.sql('sele");
EXPECT_AFTER_TAB_TAB("session.sql('sele\t", strv({}));
EXPECT_AFTER_TAB("session.sql('select 1')\t", "session.sql('select 1')");
EXPECT_AFTER_TAB_TAB("session.sql('select 1')\t", strv({}));
EXPECT_AFTER_TAB_TAB("session.sql('select 1').",
strv({"bind()", "execute()", "help()"}));
EXPECT_AFTER_TAB("session.sql('select 1').b",
"session.sql('select 1').bind()");
EXPECT_AFTER_TAB("session.sql('select 1').e",
"session.sql('select 1').execute()");
EXPECT_AFTER_TAB_TAB("session.sql(\"select 1\").",
strv({"bind()", "execute()", "help()"}));
EXPECT_AFTER_TAB("session.sql(\"select 1\").b",
"session.sql(\"select 1\").bind()");
EXPECT_AFTER_TAB("session.sql(mkquery()).e",
"session.sql(mkquery()).execute()");
EXPECT_AFTER_TAB("session.sql(mkquery(\"\")).e",
"session.sql(mkquery(\"\")).execute()");
EXPECT_AFTER_TAB_TAB(
"session.get",
strv({"getCurrentSchema()", "getDefaultSchema()", "getSchema()",
"getSchemas()", "getSshUri()", "getUri()"}));
EXPECT_AFTER_TAB("session.getC", "session.getCurrentSchema()");
// TS_FR5.1_X01
EXPECT_AFTER_TAB_TAB("db", strv({"db", "dba"}));
// TS_FR5.1_X02
EXPECT_AFTER_TAB_TAB("mysql", strv({"mysql", "mysqlx"}));
// TS_FR5.1_X03
EXPECT_AFTER_TAB_TAB(
"s", strv({"session", "shell", "source()", "super", "switch", "sys"}));
// TS_FR5.1_X04
EXPECT_AFTER_TAB("ses", "session");
// no schema active
EXPECT_TAB_DOES_NOTHING("db.p");
execute("\\use actest");
EXPECT_AFTER_TAB("db.p", "db.p");
EXPECT_AFTER_TAB_TAB("db.p", strv({"people", "person", PRODUCTTABLE}));
EXPECT_AFTER_TAB("db.peo", "db.people");
EXPECT_AFTER_TAB("db.pr", DB_PRODUCTTABLE);
EXPECT_AFTER_TAB("var p = db.peo", "var p = db.people");
EXPECT_AFTER_TAB("db.getC", "db.getCollection");
EXPECT_AFTER_TAB("db.getCollectionA", "db.getCollectionAsTable()");
EXPECT_AFTER_TAB("db.getT", "db.getTable");
// TS_FR5.2_X01
CHECK_OBJECT_COMPLETIONS("db");
execute("var actest = session.getSchema('actest')");
EXPECT_AFTER_TAB("actest.createC", "actest.createCollection()");
}
// TS_FR5.4_X10, TS_FR5.4_X11, TS_FR5.4_X12, TS_FR5.4_X13, TS_FR5.4_X14
// TS_FR5.4_X15, TS_FR5.4_X16, TS_FR5.4_X17, TS_FR5.4_X18
TEST_F(Completer_frontend, js_devapi_collection) {
connect_x();
execute("\\js");
execute("\\use actest");
execute("session.startTransaction()");
EXPECT_AFTER_TAB("db.peo", "db.people");
EXPECT_AFTER_TAB("db.people.", "db.people.");
EXPECT_AFTER_TAB_TAB(
"db.people.",
strv({"add()", "addOrReplaceOne()", "count()", "createIndex()",
"dropIndex()", "existsInDatabase()", "find()", "getName()",
"getOne()", "getSchema()", "getSession()", "help()", "modify()",
"name", "remove()", "removeOne()", "replaceOne()", "schema",
"session"}));
EXPECT_TAB_DOES_NOTHING("db.people.x");
EXPECT_TAB_DOES_NOTHING("db.people..");
EXPECT_TAB_DOES_NOTHING("db.people.?");
EXPECT_TAB_DOES_NOTHING("db.people.#");
EXPECT_AFTER_TAB("db.people.f", "db.people.find()");
EXPECT_AFTER_TAB("db.people.find().s", "db.people.find().sort()");
EXPECT_AFTER_TAB("db.people.find('foo()').b",
"db.people.find('foo()').bind()");
EXPECT_AFTER_TAB("db.people.find().bind().b",
"db.people.find().bind().bind()");
EXPECT_AFTER_TAB("db.people.find().bind().e",
"db.people.find().bind().execute()");
EXPECT_AFTER_TAB("db.people.find().gr", "db.people.find().groupBy()");
EXPECT_AFTER_TAB("db.people.find().groupBy().ha",
"db.people.find().groupBy().having()");
EXPECT_AFTER_TAB("db.people.find().execute().fe",
"db.people.find().execute().fetch");
EXPECT_AFTER_TAB_TAB("db.people.find().execute().fetch",
strv({"fetchAll()", "fetchOne()"}));
EXPECT_TAB_DOES_NOTHING("db.people.find().bind().s");
EXPECT_TAB_DOES_NOTHING("db.people.find().bind(.s");
EXPECT_TAB_DOES_NOTHING("db.people.find.ex");
EXPECT_TAB_DOES_NOTHING("db.people.find(.ex");
EXPECT_TAB_DOES_NOTHING("db.people.find).ex");
EXPECT_TAB_DOES_NOTHING("db.people.find()");
execute("var people = db.people");
EXPECT_AFTER_TAB("people.", "people.");
EXPECT_AFTER_TAB_TAB(
"people.", strv({"add()", "addOrReplaceOne()", "count()", "createIndex()",
"dropIndex()", "existsInDatabase()", "find()",
"getName()", "getOne()", "getSchema()", "getSession()",
"help()", "modify()", "name", "remove()", "removeOne()",
"replaceOne()", "schema", "session"}));
EXPECT_AFTER_TAB("people.f", "people.find()");
EXPECT_AFTER_TAB("people.find().e", "people.find().execute()");
EXPECT_AFTER_TAB("var f = people.find().b", "var f = people.find().bind()");
execute("var findOp = db.people.find()");
EXPECT_TAB_DOES_NOTHING("findOp.fin");
EXPECT_AFTER_TAB("findOp.exe", "findOp.execute()");
CHECK_OBJECT_COMPLETIONS("people");
CHECK_OBJECT_COMPLETIONS("people.find()");
CHECK_OBJECT_COMPLETIONS("people.find().fields(['x'])");
CHECK_OBJECT_COMPLETIONS("people.find().sort(['x'])");
CHECK_OBJECT_COMPLETIONS("people.find().groupBy(['x'])");
CHECK_OBJECT_COMPLETIONS("people.find().groupBy(['x']).having('x')");
CHECK_OBJECT_COMPLETIONS("people.find().limit(2)");
CHECK_OBJECT_COMPLETIONS("people.find().limit(0).skip(2)");
CHECK_OBJECT_COMPLETIONS("people.find().lockShared()");
CHECK_OBJECT_COMPLETIONS("people.find().lockExclusive()");
CHECK_OBJECT_COMPLETIONS("people.find(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("people.find().execute()");
CHECK_OBJECT_COMPLETIONS("people.modify('1')");
CHECK_OBJECT_COMPLETIONS("people.modify('1').set('x',1)");
CHECK_OBJECT_COMPLETIONS("people.modify('1').unset('x')");
CHECK_OBJECT_COMPLETIONS("people.modify(':x').unset('x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("people.modify('1').unset('x').execute()");
CHECK_OBJECT_COMPLETIONS("people.remove('1')");
CHECK_OBJECT_COMPLETIONS("people.remove('1').sort(['x'])");
CHECK_OBJECT_COMPLETIONS("people.remove(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("people.remove('1').execute()");
CHECK_OBJECT_COMPLETIONS("people.add({_id: '0001'})");
CHECK_OBJECT_COMPLETIONS("people.add({_id: '0002'}).execute()");
execute("session.rollback()");
}
// TS_FR5.4_X01, TS_FR5.4_X02, TS_FR5.4_X03, TS_FR5.4_X04, TS_FR5.4_X05,
// TS_FR5.4_X06, TS_FR5.4_X07, TS_FR5.4_X08, TS_FR5.4_X09
TEST_F(Completer_frontend, js_devapi_table) {
connect_x();
execute("\\js");
execute("\\use actest");
execute("session.startTransaction()");
EXPECT_AFTER_TAB("db.pro", DB_PRODUCTTABLE);
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".", DB_PRODUCTTABLE ".");
EXPECT_AFTER_TAB_TAB(
DB_PRODUCTTABLE ".",
strv({"count()", "delete()", "existsInDatabase()", "getName()",
"getSchema()", "getSession()", "help()", "insert()", "isView()",
"name", "schema", "select()", "session", "update()"}));
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".x");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE "..");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".?");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".#");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".sel", DB_PRODUCTTABLE ".select()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().w",
DB_PRODUCTTABLE ".select().where()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().o",
DB_PRODUCTTABLE ".select().orderBy()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select('foo()').b",
DB_PRODUCTTABLE ".select('foo()').bind()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().bind().b",
DB_PRODUCTTABLE ".select().bind().bind()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().bind().e",
DB_PRODUCTTABLE ".select().bind().execute()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().gr",
DB_PRODUCTTABLE ".select().groupBy()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().groupBy().ha",
DB_PRODUCTTABLE ".select().groupBy().having()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().execute().fe",
DB_PRODUCTTABLE ".select().execute().fetch");
EXPECT_AFTER_TAB_TAB(DB_PRODUCTTABLE ".select().execute().fetch",
strv({"fetchAll()", "fetchOne()", "fetchOneObject()"}));
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select().bind().s");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select().bind(.s");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select.ex");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select(.ex");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select).ex");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select()");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select().hav");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".insert([]).v",
DB_PRODUCTTABLE ".insert([]).values()");
execute("var " PRODUCTTABLE " = " DB_PRODUCTTABLE);
EXPECT_AFTER_TAB(PRODUCTTABLE ".", PRODUCTTABLE ".");
EXPECT_AFTER_TAB_TAB(
PRODUCTTABLE ".",
strv({"count()", "delete()", "existsInDatabase()", "getName()",
"getSchema()", "getSession()", "help()", "insert()", "isView()",
"name", "schema", "select()", "session", "update()"}));
EXPECT_AFTER_TAB(PRODUCTTABLE ".sel", PRODUCTTABLE ".select()");
EXPECT_AFTER_TAB(PRODUCTTABLE ".select([]).e",
PRODUCTTABLE ".select([]).execute()");
EXPECT_AFTER_TAB("var f = " PRODUCTTABLE ".select([]).b",
"var f = " PRODUCTTABLE ".select([]).bind()");
execute("var findOp = " DB_PRODUCTTABLE ".select();");
EXPECT_TAB_DOES_NOTHING("findOp.sel");
EXPECT_AFTER_TAB("findOp.exe", "findOp.execute()");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE);
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select(['x'])");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select(['x']).where('x')");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select(['x']).orderBy(['x'])");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select(['x']).groupBy(['x'])");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE
".select(['x']).groupBy(['x']).having('x')");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select(['x']).limit(2)");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select(['x']).limit(2).offset(2)");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE
".select(['x']).where(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".select().execute()");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".update()");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".update().set('x',1)");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE
".update().set('x',1).where(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".update().set('id',1).orderBy(['x'])");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".update().set('id',1).execute()");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".delete()");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".delete().where('0')");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".delete().orderBy(['x'])");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".delete().where(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".delete().execute()");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".insert([])");
CHECK_OBJECT_COMPLETIONS(PRODUCTTABLE ".insert([]).values([])");
execute("session.rollback()");
}
TEST_F(Completer_frontend, js_classic) {
connect_classic();
execute("\\js");
EXPECT_AFTER_TAB("session.", "session.");
// TS_FR5.2_C05
CHECK_OBJECT_COMPLETIONS("session");
// TS_FR5.2_C06
CHECK_OBJECT_COMPLETIONS("shell");
EXPECT_AFTER_TAB("session.ru", "session.runSql()");
// TS_FR5.2_C03
CHECK_OBJECT_COMPLETIONS("mysql");
}
TEST_F(Completer_frontend, js_devapi_members_x) {
_options->devapi_schema_object_handles = false;
reset_shell();
connect_x();
execute("\\sql");
execute("drop schema if exists dropme;");
execute("drop schema if exists dropme2;");
execute("create table actest.testtab (a int);");
execute("create view actest.veee as select 1;");
execute("create table actest.droptab (a int);");
execute("create view actest.dropview as select 1;");
execute("\\js");
execute("\\use actest");
execute("db.createCollection('testcol')");
execute("db.createCollection('dropcol')");
wipe_all();
std::vector<std::pair<std::string, std::string>> mysqlx_calls{
{"dateValue", ""},
{"expr", ""},
{"getSession", "('mysqlx://" + _uri + "')"},
{"help", ""}};
CHECK_OBJECT_MEMBER_COMPLETIONS("mysqlx", mysqlx_calls);
std::vector<std::pair<std::string, std::string>> session_calls{
{"createSchema", "('dropme2')"},
{"dropSchema", "('dropme2')"},
{"setCurrentSchema", "('actest')"},
{"getSchema", "('actest')"},
{"setFetchWarnings", "(true)"},
{"sql", "('select 1')"},
{"getDefaultSchema", ""},
{"getUri", ""},
{"close", ""},
{"help", ""},
{"quoteName", ""},
{"startTransaction", "()"},
{"setSavepoint", "('name')"},
{"rollbackTo", "('name')"},
{"releaseSavepoint", "('name')"},
{"rollback", "()"},
{"runSql", "('select 1')"},
{"_enableNotices", ""},
{"_fetchNotice", ""},
{"_getSocketFd", ""}};
CHECK_OBJECT_MEMBER_COMPLETIONS("session", session_calls);
std::vector<std::pair<std::string, std::string>> db_calls{
{"createCollection", "('dropme')"},
{"modifyCollection", "('dropme', {'validation': {'level':'off'}})"},
{"dropCollection", "('dropme')"},
{"getCollection", "('testcol')"},
{"getTable", "('testtab')"},
{"getCollectionAsTable", "('testcol')"},
{"getSchema", ""}, // bogus getSchema() in Schema that returns null
{"help", ""}};
CHECK_OBJECT_MEMBER_COMPLETIONS("db", db_calls);
std::vector<std::pair<std::string, std::string>> collection_calls{
{"add", "({})"},
{"addOrReplaceOne", "('0', {})"},
{"modify", "('0')"},
{"remove", "('0')"},
{"removeOne", "('0')"},
{"replaceOne", "('0', {})"},
{"getOne", "('0')"},
{"find", "('0')"},
{"createIndex", "('x', {fields:[{field:'$.field'}]})"},
{"dropIndex", "('x')"},
{"help", ""}};
CHECK_OBJECT_MEMBER_COMPLETIONS("db.getCollection('people')",
collection_calls); // collection
std::vector<std::pair<std::string, std::string>> table_calls{{"help", ""}};
CHECK_OBJECT_MEMBER_COMPLETIONS("db.getTable('productTable')",
table_calls); // table
execute("\\sql");
execute("drop schema if exists dropme;");
}
TEST_F(Completer_frontend, js_devapi_members_classic) {
connect_classic();
execute("\\js");
execute("\\use actest");
std::vector<std::pair<std::string, std::string>> mysql_calls{
{"quoteIdentifier", "('a')"},
{"unquoteIdentifier", "(`a`)"},
{"splitScript", "('a;b;')"},
{"parseStatementAst", "('select 1')"},
{"help", ""},
{"getClassicSession", "('" + _mysql_uri + "')"},
{"getSession", "('" + _mysql_uri + "')"}};
CHECK_OBJECT_MEMBER_COMPLETIONS("mysql", mysql_calls);
std::vector<std::pair<std::string, std::string>> session_calls{
{"help", ""},
{"close", ""},
{"runSql", "('select 1')"},
{"query", "('select 1')"},
{"_getSocketFd", ""}};
CHECK_OBJECT_MEMBER_COMPLETIONS("session", session_calls);
}
#endif
// -----
TEST_F(Completer_frontend, py_keywords) {
execute("\\py");
EXPECT_AFTER_TAB("pri", "print");
EXPECT_AFTER_TAB("x=pri", "x=print");
EXPECT_AFTER_TAB("var x =pri", "var x =print");
EXPECT_AFTER_TAB("print sh", "print shell");
EXPECT_AFTER_TAB("print (sh\t)", "print (shell)");
EXPECT_AFTER_TAB("wh", "while");
EXPECT_AFTER_TAB("while sh", "while shell");
EXPECT_AFTER_TAB("while (sh\t)", "while (shell)");
EXPECT_AFTER_TAB("while 1: sh", "while 1: shell");
EXPECT_AFTER_TAB("while 1: if sh", "while 1: if shell");
EXPECT_TAB_DOES_NOTHING("print '");
EXPECT_TAB_DOES_NOTHING("print \"");
EXPECT_TAB_DOES_NOTHING("print 'pri");
EXPECT_TAB_DOES_NOTHING("print \"pri");
EXPECT_TAB_DOES_NOTHING("x = px");
EXPECT_TAB_DOES_NOTHING(".");
EXPECT_TAB_DOES_NOTHING("..");
EXPECT_TAB_DOES_NOTHING(".s");
EXPECT_TAB_DOES_NOTHING("(.s");
EXPECT_TAB_DOES_NOTHING("(.re");
EXPECT_TAB_DOES_NOTHING("shell..");
// Session stuff while not connected
EXPECT_AFTER_TAB_TAB("session.", strv());
EXPECT_TAB_DOES_NOTHING("db.");
}
TEST_F(Completer_frontend, py_negative) {
execute("\\py");
EXPECT_AFTER_TAB("bogus", "bogus");
EXPECT_AFTER_TAB_TAB("bogus", strv({}));
EXPECT_AFTER_TAB("bogus.", "bogus.");
EXPECT_AFTER_TAB_TAB("bogus.", strv({}));
EXPECT_AFTER_TAB("print(\t)", "print()");
EXPECT_AFTER_TAB("print('pr\t", "print('pr");
EXPECT_AFTER_TAB("print('pr\t')", "print('pr')");
}
TEST_F(Completer_frontend, py_shell) {
execute("\\py");
CHECK_OBJECT_COMPLETIONS("shell");
EXPECT_AFTER_TAB("sh", "shell");
EXPECT_AFTER_TAB("shell.rec", "shell.reconnect()");
EXPECT_AFTER_TAB_TAB("shell.", strv({"add_extension_object_member()",
"auto_complete_sql()",
"connect()",
"connect_to_primary()",
"create_context()",
"create_extension_object()",
"delete_all_credentials()",
"delete_credential()",
"disable_pager()",
"disconnect()",
"dump_rows()",
"enable_pager()",
"get_session()",
"help()",
"list_credential_helpers()",
"list_credentials()",
"list_ssh_connections()",
"log()",
"open_session()",
"options",
"parse_uri()",
"prompt()",
"reconnect()",
"register_global()",
"register_report()",
"reports",
"set_current_schema()",
"set_session()",
"status()",
"store_credential()",
"unparse_uri()",
"version"}));
EXPECT_TAB_DOES_NOTHING("shell.conect()");
EXPECT_AFTER_TAB_TAB("mysql", strv({"mysql", "mysqlx"}));
EXPECT_AFTER_TAB("mysql.get_c", "mysql.get_classic_session()");
EXPECT_AFTER_TAB("mysqlx.get", "mysqlx.get_session()");
// a dynamically created global var
execute("testobj = {'key_one':1, 'another_key': 2}");
EXPECT_AFTER_TAB("testo", "testobj");
std::set<std::string> dict_options = {
"clear()", "copy()", "fromkeys()", "get()", "items()", "keys()",
"pop()", "popitem()", "setdefault()", "update()", "values()"};
if (shcore::str_beginswith(m_python_version, "2.")) {
dict_options.emplace("has_key()");
dict_options.emplace("iteritems()");
dict_options.emplace("iterkeys()");
dict_options.emplace("itervalues()");
}
if (shcore::str_beginswith(m_python_version, "2.7")) {
dict_options.emplace("viewitems()");
dict_options.emplace("viewkeys()");
dict_options.emplace("viewvalues()");
}
EXPECT_AFTER_TAB_TAB("testobj.", dict_options);
EXPECT_AFTER_TAB("testobj.k", "testobj.keys()");
EXPECT_TAB_DOES_NOTHING("testobj.key_one");
// TS_FR5.3_C01
CHECK_OBJECT_COMPLETIONS("shell.options");
}
TEST_F(Completer_frontend, py_adminapi) {
execute("\\py");
CHECK_OBJECT_COMPLETIONS("dba");
// TS_FR5.2_C02, TS_FR5.2_X02
EXPECT_AFTER_TAB_TAB("dba.", strv({"check_instance_configuration()",
"configure_instance()",
"configure_local_instance()",
"configure_replica_set_instance()",
"create_cluster()",
"create_replica_set()",
"delete_sandbox_instance()",
"deploy_sandbox_instance()",
"drop_metadata_schema()",
"get_cluster()",
"get_cluster_set()",
"get_replica_set()",
"help()",
"kill_sandbox_instance()",
"reboot_cluster_from_complete_outage()",
"session",
"start_sandbox_instance()",
"stop_sandbox_instance()",
"upgrade_metadata()",
"verbose"}));
EXPECT_AFTER_TAB("dba.depl", "dba.deploy_sandbox_instance()");
}
TEST_F(Completer_frontend, py_devapi) {
connect_x();
execute("\\py");
CHECK_OBJECT_COMPLETIONS("session");
EXPECT_AFTER_TAB("session.create_s", "session.create_schema()");
EXPECT_AFTER_TAB("session.st", "session.start_transaction()");
EXPECT_AFTER_TAB_TAB(
"session.get_",
strv({"get_current_schema()", "get_default_schema()", "get_schema()",
"get_schemas()", "get_ssh_uri()", "get_uri()"}));
EXPECT_AFTER_TAB("session.sql", "session.sql()");
EXPECT_AFTER_TAB("session.sql('sele\t", "session.sql('sele");
EXPECT_AFTER_TAB_TAB("session.sql('sele\t", strv({}));
EXPECT_AFTER_TAB("session.sql('select 1')\t", "session.sql('select 1')");
EXPECT_AFTER_TAB_TAB("session.sql('select 1')\t", strv({}));
EXPECT_AFTER_TAB_TAB("session.sql('select 1').",
strv({"bind()", "execute()", "help()"}));
EXPECT_AFTER_TAB("session.sql('select 1').b",
"session.sql('select 1').bind()");
EXPECT_AFTER_TAB("session.sql('select 1').e",
"session.sql('select 1').execute()");
EXPECT_AFTER_TAB_TAB("session.sql(\"select 1\").",
strv({"bind()", "execute()", "help()"}));
EXPECT_AFTER_TAB("session.sql(\"select 1\").b",
"session.sql(\"select 1\").bind()");
EXPECT_AFTER_TAB("session.sql(mkquery()).e",
"session.sql(mkquery()).execute()");
EXPECT_AFTER_TAB("session.sql(mkquery(\"\")).e",
"session.sql(mkquery(\"\")).execute()");
EXPECT_AFTER_TAB_TAB(
"session.get_",
strv({"get_current_schema()", "get_default_schema()", "get_schema()",
"get_schemas()", "get_ssh_uri()", "get_uri()"}));
EXPECT_AFTER_TAB("session.get_c", "session.get_current_schema()");
// TS_FR5.1_X01
EXPECT_AFTER_TAB_TAB("db", strv({"db", "dba"}));
// TS_FR5.1_X02
EXPECT_AFTER_TAB_TAB("mysql", strv({"mysql", "mysqlx"}));
// TS_FR5.1_X03
// invalid for python
// TS_FR5.1_X04
EXPECT_AFTER_TAB("ses", "session");
// no schema active
EXPECT_TAB_DOES_NOTHING("db.p");
execute("\\use actest");
EXPECT_AFTER_TAB("db.p", "db.p");
EXPECT_AFTER_TAB_TAB("db.p", strv({"people", "person", PRODUCTTABLE}));
EXPECT_AFTER_TAB("db.peo", "db.people");
EXPECT_AFTER_TAB("db.pr", DB_PRODUCTTABLE);
EXPECT_AFTER_TAB("p = db.peo", "p = db.people");
EXPECT_AFTER_TAB("db.get_c", "db.get_collection");
EXPECT_AFTER_TAB("db.get_collection_a", "db.get_collection_as_table()");
EXPECT_AFTER_TAB("db.get_t", "db.get_table");
// TS_FR5.2_X01
CHECK_OBJECT_COMPLETIONS("db");
execute("actest = session.get_schema('actest')");
EXPECT_AFTER_TAB("actest.create_c", "actest.create_collection()");
}
TEST_F(Completer_frontend, py_devapi_collection) {
connect_x();
execute("\\py");
execute("\\use actest");
execute("session.start_transaction()");
CHECK_OBJECT_COMPLETIONS("db");
EXPECT_AFTER_TAB("db.peo", "db.people");
EXPECT_AFTER_TAB("db.people.", "db.people.");
EXPECT_AFTER_TAB_TAB(
"db.people.",
strv({"add()", "add_or_replace_one()", "count()", "create_index()",
"drop_index()", "exists_in_database()", "find()", "get_name()",
"get_one()", "get_schema()", "get_session()", "help()", "modify()",
"name", "remove()", "remove_one()", "replace_one()", "schema",
"session"}));
EXPECT_TAB_DOES_NOTHING("db.people.x");
EXPECT_TAB_DOES_NOTHING("db.people..");
EXPECT_TAB_DOES_NOTHING("db.people.?");
EXPECT_TAB_DOES_NOTHING("db.people.#");
EXPECT_AFTER_TAB("db.people.f", "db.people.find()");
EXPECT_AFTER_TAB("db.people.find().s", "db.people.find().sort()");
EXPECT_AFTER_TAB("db.people.find('foo()').b",
"db.people.find('foo()').bind()");
EXPECT_AFTER_TAB("db.people.find().bind().b",
"db.people.find().bind().bind()");
EXPECT_AFTER_TAB("db.people.find().bind().e",
"db.people.find().bind().execute()");
EXPECT_AFTER_TAB("db.people.find().gr", "db.people.find().group_by()");
EXPECT_AFTER_TAB("db.people.find().group_by().ha",
"db.people.find().group_by().having()");
EXPECT_AFTER_TAB("db.people.find().execute().fe",
"db.people.find().execute().fetch_");
EXPECT_AFTER_TAB_TAB("db.people.find().execute().fetch_",
strv({"fetch_all()", "fetch_one()"}));
EXPECT_TAB_DOES_NOTHING("db.people.find().bind().s");
EXPECT_TAB_DOES_NOTHING("db.people.find().bind(.s");
EXPECT_TAB_DOES_NOTHING("db.people.find.ex");
EXPECT_TAB_DOES_NOTHING("db.people.find(.ex");
EXPECT_TAB_DOES_NOTHING("db.people.find).ex");
EXPECT_TAB_DOES_NOTHING("db.people.find()");
execute("people = db.people");
EXPECT_AFTER_TAB("people.", "people.");
EXPECT_AFTER_TAB_TAB(
"people.",
strv({"add()", "add_or_replace_one()", "count()", "create_index()",
"drop_index()", "exists_in_database()", "find()", "get_name()",
"get_one()", "get_schema()", "get_session()", "help()", "modify()",
"name", "remove()", "remove_one()", "replace_one()", "schema",
"session"}));
EXPECT_AFTER_TAB("people.f", "people.find()");
EXPECT_AFTER_TAB("people.find().e", "people.find().execute()");
EXPECT_AFTER_TAB("f = people.find().b", "f = people.find().bind()");
execute("findOp = db.people.find()");
EXPECT_TAB_DOES_NOTHING("findOp.fin");
EXPECT_AFTER_TAB("findOp.exe", "findOp.execute()");
CHECK_OBJECT_COMPLETIONS("people");
CHECK_OBJECT_COMPLETIONS("people.find()");
CHECK_OBJECT_COMPLETIONS("people.find().fields(['x'])");
CHECK_OBJECT_COMPLETIONS("people.find().sort(['x'])");
CHECK_OBJECT_COMPLETIONS("people.find().group_by(['x'])");
CHECK_OBJECT_COMPLETIONS("people.find().group_by(['x']).having('x')");
CHECK_OBJECT_COMPLETIONS("people.find().limit(2)");
CHECK_OBJECT_COMPLETIONS("people.find().limit(0).skip(2)");
CHECK_OBJECT_COMPLETIONS("people.find(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("people.find().execute()");
CHECK_OBJECT_COMPLETIONS("people.modify('1')");
CHECK_OBJECT_COMPLETIONS("people.modify('1').set('x',1)");
CHECK_OBJECT_COMPLETIONS("people.modify('1').unset('x')");
CHECK_OBJECT_COMPLETIONS("people.modify(':x').unset('x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("people.modify('1').unset('x').execute()");
CHECK_OBJECT_COMPLETIONS("people.remove('1')");
CHECK_OBJECT_COMPLETIONS("people.remove('1').sort(['x'])");
CHECK_OBJECT_COMPLETIONS("people.remove(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("people.remove('1').execute()");
CHECK_OBJECT_COMPLETIONS("people.add({'_id': '0001'})");
CHECK_OBJECT_COMPLETIONS("people.add({'_id': '0002'}).execute()");
execute("session.rollback()");
}
TEST_F(Completer_frontend, py_devapi_table) {
connect_x();
execute("\\py");
execute("\\use actest");
execute("session.startTransaction()");
EXPECT_AFTER_TAB("db.pro", DB_PRODUCTTABLE);
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".", DB_PRODUCTTABLE ".");
EXPECT_AFTER_TAB_TAB(
DB_PRODUCTTABLE ".",
strv({"count()", "delete()", "exists_in_database()", "get_name()",
"get_schema()", "get_session()", "help()", "insert()", "is_view()",
"name", "schema", "select()", "session", "update()"}));
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".x");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE "..");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".?");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".#");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".sel", DB_PRODUCTTABLE ".select()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().w",
DB_PRODUCTTABLE ".select().where()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().o",
DB_PRODUCTTABLE ".select().order_by()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select('foo()').b",
DB_PRODUCTTABLE ".select('foo()').bind()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().bind().b",
DB_PRODUCTTABLE ".select().bind().bind()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().bind().e",
DB_PRODUCTTABLE ".select().bind().execute()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().gr",
DB_PRODUCTTABLE ".select().group_by()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().group_by().ha",
DB_PRODUCTTABLE ".select().group_by().having()");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".select().execute().fe",
DB_PRODUCTTABLE ".select().execute().fetch_");
EXPECT_AFTER_TAB_TAB(
DB_PRODUCTTABLE ".select().execute().fetch_",
strv({"fetch_all()", "fetch_one()", "fetch_one_object()"}));
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select().bind().s");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select().bind(.s");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select.ex");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select(.ex");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select).ex");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select()");
EXPECT_TAB_DOES_NOTHING(DB_PRODUCTTABLE ".select().hav");
EXPECT_AFTER_TAB(DB_PRODUCTTABLE ".insert([]).v",
DB_PRODUCTTABLE ".insert([]).values()");
execute("productTable = " DB_PRODUCTTABLE);
EXPECT_AFTER_TAB("productTable.", "productTable.");
EXPECT_AFTER_TAB_TAB(
"productTable.",
strv({"count()", "delete()", "exists_in_database()", "get_name()",
"get_schema()", "get_session()", "help()", "insert()", "is_view()",
"name", "schema", "select()", "session", "update()"}));
EXPECT_AFTER_TAB("productTable.sel", "productTable.select()");
EXPECT_AFTER_TAB("productTable.select([]).e",
"productTable.select([]).execute()");
EXPECT_AFTER_TAB("f = productTable.select([]).b",
"f = productTable.select([]).bind()");
execute("findOp = " DB_PRODUCTTABLE ".select();");
EXPECT_TAB_DOES_NOTHING("findOp.sel");
EXPECT_AFTER_TAB("findOp.exe", "findOp.execute()");
CHECK_OBJECT_COMPLETIONS("productTable");
CHECK_OBJECT_COMPLETIONS("productTable.select(['x'])");
CHECK_OBJECT_COMPLETIONS("productTable.select(['x']).where('x')");
CHECK_OBJECT_COMPLETIONS("productTable.select(['x']).order_by(['x'])");
CHECK_OBJECT_COMPLETIONS("productTable.select(['x']).group_by(['x'])");
CHECK_OBJECT_COMPLETIONS(
"productTable.select(['x']).group_by(['x']).having('x')");
CHECK_OBJECT_COMPLETIONS("productTable.select(['x']).limit(2)");
CHECK_OBJECT_COMPLETIONS("productTable.select(['x']).limit(2).offset(2)");
CHECK_OBJECT_COMPLETIONS(
"productTable.select(['x']).where(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("productTable.select().execute()");
CHECK_OBJECT_COMPLETIONS("productTable.update()");
CHECK_OBJECT_COMPLETIONS("productTable.update().set('x',1)");
CHECK_OBJECT_COMPLETIONS(
"productTable.update().set('x',1).where(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("productTable.update().set('id',1).order_by(['x'])");
CHECK_OBJECT_COMPLETIONS("productTable.update().set('id',1).execute()");
CHECK_OBJECT_COMPLETIONS("productTable.delete()");
CHECK_OBJECT_COMPLETIONS("productTable.delete().where('0')");
CHECK_OBJECT_COMPLETIONS("productTable.delete().order_by(['x'])");
CHECK_OBJECT_COMPLETIONS("productTable.delete().where(':x').bind('x',1)");
CHECK_OBJECT_COMPLETIONS("productTable.delete().execute()");
CHECK_OBJECT_COMPLETIONS("productTable.insert([])");
CHECK_OBJECT_COMPLETIONS("productTable.insert([]).values([])");
execute("session.rollback()");
}
TEST_F(Completer_frontend, py_classic) {
connect_classic();
execute("\\py");
EXPECT_AFTER_TAB("session.", "session.");
// TS_FR5.2_C05
CHECK_OBJECT_COMPLETIONS("session");
// TS_FR5.2_C06
CHECK_OBJECT_COMPLETIONS("shell");
EXPECT_AFTER_TAB("session.ru", "session.run_sql()");
// TS_FR5.2_C03
CHECK_OBJECT_COMPLETIONS("mysql");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_1) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("SELECT 1 FROM du", "SELECT 1 FROM DUAL");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_2) {
connect_classic();
execute("\\sql");
EXPECT_TAB_DOES_NOTHING("DELIMITER //");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_1_1) {
connect_classic();
execute("\\sql");
// syntax available in 5.7, but not in 8.0
if (_target_server_version < mysqlshdk::utils::Version(8, 0, 0)) {
EXPECT_AFTER_TAB("SELECT pass", "SELECT PASSWORD()");
EXPECT_AFTER_TAB("FLUSH qu", "FLUSH QUERY CACHE");
} else {
EXPECT_TAB_DOES_NOTHING("SELECT pass");
EXPECT_TAB_DOES_NOTHING("FLUSH qu");
}
}
TEST_F(Completer_frontend, WL13397_TSFR_1_1_1_1) {
#if defined(NDEBUG)
SKIP_TEST("This test requires a debug build.");
#else
DBUG_SET("+d,sql_auto_completion_unsupported_version_lower");
const auto log_level = output_handler.get_log_level();
output_handler.set_log_level(shcore::Logger::LOG_LEVEL::LOG_WARNING);
connect_classic();
execute("\\sql");
// wrong version (lower), auto-completion falls-back to 5.7 server
EXPECT_AFTER_TAB("FLUSH qu", "FLUSH QUERY CACHE");
EXPECT_TAB_DOES_NOTHING("CREATE ro");
MY_EXPECT_LOG_CONTAINS(
"Connected to an unsupported server version 1.2.3, SQL auto-completion "
"is falling back to: 5.7.0");
output_handler.set_log_level(log_level);
DBUG_SET("");
#endif
}
TEST_F(Completer_frontend, WL13397_TSFR_1_1_1_2) {
#if defined(NDEBUG)
SKIP_TEST("This test requires a debug build.");
#else
DBUG_SET("+d,sql_auto_completion_unsupported_version_higher");
const auto log_level = output_handler.get_log_level();
output_handler.set_log_level(shcore::Logger::LOG_LEVEL::LOG_WARNING);
connect_classic();
execute("\\sql");
// wrong version (higher), auto-completion falls-back to latest 8.0 server
EXPECT_TAB_DOES_NOTHING("FLUSH qu");
EXPECT_AFTER_TAB("CREATE ro", "CREATE ROLE");
MY_EXPECT_LOG_CONTAINS(
"Connected to an unsupported server version 10.9.8, SQL auto-completion "
"is falling back to: " MYSH_VERSION);
output_handler.set_log_level(log_level);
DBUG_SET("");
#endif
}
TEST_F(Completer_frontend, WL13397_TSFR_1_1_2_1) {
execute("\\sql");
// no connection, auto-completion falls-back to latest 8.0 server
EXPECT_TAB_DOES_NOTHING("SELECT pass");
EXPECT_AFTER_TAB("CREATE ro", "CREATE ROLE");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_2_1) {
connect_classic();
execute("\\sql");
execute("SET @saved_sql_mode = @@global.sql_mode;");
execute("SET @@global.sql_mode = '';");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\use mysql");
// ANSI_QUOTES is active, "mysql" should be treated as an identifier and
// plugin should be suggested
EXPECT_AFTER_TAB("SELECT \"mysql\".plu", "SELECT \"mysql\".plugin");
execute("SET @@global.sql_mode = @saved_sql_mode;");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_2_2) {
connect_classic();
execute("\\sql");
execute("SET @saved_sql_mode = @@global.sql_mode;");
execute("SET @@global.sql_mode = 'ANSI_QUOTES';");
execute("SET @@sql_mode = '';");
execute("\\use mysql");
// ANSI_QUOTES is not active, "mysql" should be treated as a string and
// nothing is suggested
EXPECT_TAB_DOES_NOTHING("SELECT \"mysql\".plu");
execute("SET @@global.sql_mode = @saved_sql_mode;");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_3_1) {
connect_classic();
execute("\\sql");
EXPECT_TAB_TAB_CONTAINS("SELECT ", "mysql");
EXPECT_TAB_TAB_CONTAINS("SELECT * FROM ", "mysql");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_3_2) {
connect_classic("mysql");
execute("\\sql");
EXPECT_TAB_TAB_CONTAINS("SELECT * FROM ", "plugin");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_3_3) {
connect_classic();
execute("\\sql");
execute("\\use information_schema");
EXPECT_TAB_TAB_NOT_CONTAINS("SELECT * FROM ", "plugin");
EXPECT_TAB_TAB_CONTAINS("SELECT * FROM ", "SCHEMATA");
execute("\\use mysql");
EXPECT_TAB_TAB_CONTAINS("SELECT * FROM ", "plugin");
EXPECT_TAB_TAB_NOT_CONTAINS("SELECT * FROM ", "SCHEMATA");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_3_1_1) {
connect_classic("mysql");
execute("\\sql");
execute("\\disconnect");
EXPECT_TAB_TAB_CONTAINS("SELECT * FROM ", "DUAL");
EXPECT_TAB_TAB_NOT_CONTAINS("SELECT * FROM ", "plugin");
}
TEST_F(Completer_frontend, WL13397_TSFR_1_4_1) {
connect_classic();
execute("\\sql");
EXPECT_TAB_TAB_CONTAINS("CREATE ", "TABLE");
EXPECT_TAB_TAB_CONTAINS("CREATE ", "DATABASE");
EXPECT_TAB_TAB_CONTAINS("CREATE ", "FUNCTION");
}
// tests for BUG#34371461 (quote_*)
TEST_F(Completer_frontend, quote_schema) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("SELECT acte", "SELECT actest");
EXPECT_AFTER_TAB("SELECT `acte", "SELECT `actest`");
EXPECT_TAB_DOES_NOTHING("SELECT \"acte");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT acte", "SELECT actest");
EXPECT_AFTER_TAB("SELECT `acte", "SELECT `actest`");
EXPECT_AFTER_TAB("SELECT \"acte", "SELECT \"actest\"");
}
TEST_F(Completer_frontend, quote_table) {
connect_classic();
execute("\\sql");
execute("\\use actest");
EXPECT_AFTER_TAB("SELECT tab", "SELECT tab_le");
EXPECT_AFTER_TAB("SELECT `actest`.tab", "SELECT `actest`.tab_le");
EXPECT_AFTER_TAB("SELECT `tab", "SELECT `tab_le`");
EXPECT_AFTER_TAB("SELECT actest.`tab", "SELECT actest.`tab_le`");
EXPECT_TAB_DOES_NOTHING("SELECT \"tab");
EXPECT_TAB_DOES_NOTHING("SELECT actest.\"tab");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT tab", "SELECT tab_le");
EXPECT_AFTER_TAB("SELECT \"actest\".tab", "SELECT \"actest\".tab_le");
EXPECT_AFTER_TAB("SELECT `tab", "SELECT `tab_le`");
EXPECT_AFTER_TAB("SELECT actest.`tab", "SELECT actest.`tab_le`");
EXPECT_AFTER_TAB("SELECT \"tab", "SELECT \"tab_le\"");
EXPECT_AFTER_TAB("SELECT `actest`.\"tab", "SELECT `actest`.\"tab_le\"");
}
TEST_F(Completer_frontend, quote_view) {
connect_classic();
execute("\\sql");
execute("\\use actest");
EXPECT_AFTER_TAB("SELECT vi", "SELECT vi_ew");
EXPECT_AFTER_TAB("SELECT `actest`.vi", "SELECT `actest`.vi_ew");
EXPECT_AFTER_TAB("SELECT `vi", "SELECT `vi_ew`");
EXPECT_AFTER_TAB("SELECT actest.`vi", "SELECT actest.`vi_ew`");
EXPECT_TAB_DOES_NOTHING("SELECT \"vi");
EXPECT_TAB_DOES_NOTHING("SELECT actest.\"vi");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT vi", "SELECT vi_ew");
EXPECT_AFTER_TAB("SELECT \"actest\".vi", "SELECT \"actest\".vi_ew");
EXPECT_AFTER_TAB("SELECT `vi", "SELECT `vi_ew`");
EXPECT_AFTER_TAB("SELECT actest.`vi", "SELECT actest.`vi_ew`");
EXPECT_AFTER_TAB("SELECT \"vi", "SELECT \"vi_ew\"");
EXPECT_AFTER_TAB("SELECT `actest`.\"vi", "SELECT `actest`.\"vi_ew\"");
}
TEST_F(Completer_frontend, quote_column) {
connect_classic();
execute("\\sql");
execute("\\use actest");
EXPECT_AFTER_TAB("SELECT tab_le.col", "SELECT tab_le.col_umn");
EXPECT_AFTER_TAB("SELECT `actest`.tab_le.col",
"SELECT `actest`.tab_le.col_umn");
EXPECT_AFTER_TAB("SELECT `tab_le`.`col", "SELECT `tab_le`.`col_umn`");
EXPECT_AFTER_TAB("SELECT actest.`tab_le`.`col",
"SELECT actest.`tab_le`.`col_umn`");
EXPECT_TAB_DOES_NOTHING("SELECT tab_le.\"col");
EXPECT_TAB_DOES_NOTHING("SELECT actest.tab_le.\"col");
EXPECT_AFTER_TAB("SELECT vi_ew.col", "SELECT vi_ew.col_umn");
EXPECT_AFTER_TAB("SELECT `actest`.vi_ew.col",
"SELECT `actest`.vi_ew.col_umn");
EXPECT_AFTER_TAB("SELECT `vi_ew`.`col", "SELECT `vi_ew`.`col_umn`");
EXPECT_AFTER_TAB("SELECT actest.`vi_ew`.`col",
"SELECT actest.`vi_ew`.`col_umn`");
EXPECT_TAB_DOES_NOTHING("SELECT vi_ew.\"col");
EXPECT_TAB_DOES_NOTHING("SELECT actest.vi_ew.\"col");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT tab_le.col", "SELECT tab_le.col_umn");
EXPECT_AFTER_TAB("SELECT \"actest\".tab_le.col",
"SELECT \"actest\".tab_le.col_umn");
EXPECT_AFTER_TAB("SELECT `tab_le`.`col", "SELECT `tab_le`.`col_umn`");
EXPECT_AFTER_TAB("SELECT actest.`tab_le`.`col",
"SELECT actest.`tab_le`.`col_umn`");
EXPECT_AFTER_TAB("SELECT \"tab_le\".\"col", "SELECT \"tab_le\".\"col_umn\"");
EXPECT_AFTER_TAB("SELECT `actest`.\"tab_le\".\"col",
"SELECT `actest`.\"tab_le\".\"col_umn\"");
EXPECT_AFTER_TAB("SELECT vi_ew.col", "SELECT vi_ew.col_umn");
EXPECT_AFTER_TAB("SELECT \"actest\".vi_ew.col",
"SELECT \"actest\".vi_ew.col_umn");
EXPECT_AFTER_TAB("SELECT `vi_ew`.`col", "SELECT `vi_ew`.`col_umn`");
EXPECT_AFTER_TAB("SELECT actest.`vi_ew`.`col",
"SELECT actest.`vi_ew`.`col_umn`");
EXPECT_AFTER_TAB("SELECT \"vi_ew\".\"col", "SELECT \"vi_ew\".\"col_umn\"");
EXPECT_AFTER_TAB("SELECT `actest`.\"vi_ew\".\"col",
"SELECT `actest`.\"vi_ew\".\"col_umn\"");
}
TEST_F(Completer_frontend, quote_internal_column) {
connect_classic();
execute("\\sql");
execute("\\use actest");
EXPECT_AFTER_TAB("ALTER TABLE tab_le ALTER COLUMN col",
"ALTER TABLE tab_le ALTER COLUMN col_umn");
EXPECT_AFTER_TAB("ALTER TABLE actest.tab_le ALTER COLUMN `col",
"ALTER TABLE actest.tab_le ALTER COLUMN `col_umn`");
EXPECT_TAB_DOES_NOTHING("ALTER TABLE tab_le ALTER COLUMN \"col");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("ALTER TABLE actest.tab_le ALTER COLUMN col",
"ALTER TABLE actest.tab_le ALTER COLUMN col_umn");
EXPECT_AFTER_TAB("ALTER TABLE tab_le ALTER COLUMN `col",
"ALTER TABLE tab_le ALTER COLUMN `col_umn`");
EXPECT_AFTER_TAB("ALTER TABLE actest.tab_le ALTER COLUMN \"col",
"ALTER TABLE actest.tab_le ALTER COLUMN \"col_umn\"");
}
TEST_F(Completer_frontend, quote_procedure) {
connect_classic();
execute("\\sql");
execute("CREATE PROCEDURE actest.pro_cedure() BEGIN END;");
execute("\\use actest");
EXPECT_AFTER_TAB("CALL pro", "CALL pro_cedure()");
EXPECT_AFTER_TAB("CALL `actest`.pro", "CALL `actest`.pro_cedure()");
EXPECT_AFTER_TAB("CALL `pro", "CALL `pro_cedure`()");
EXPECT_AFTER_TAB("CALL actest.`pro", "CALL actest.`pro_cedure`()");
EXPECT_TAB_DOES_NOTHING("CALL \"pro");
EXPECT_TAB_DOES_NOTHING("CALL actest.\"pro");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("CALL pro", "CALL pro_cedure()");
EXPECT_AFTER_TAB("CALL \"actest\".pro", "CALL \"actest\".pro_cedure()");
EXPECT_AFTER_TAB("CALL `pro", "CALL `pro_cedure`()");
EXPECT_AFTER_TAB("CALL actest.`pro", "CALL actest.`pro_cedure`()");
EXPECT_AFTER_TAB("CALL \"pro", "CALL \"pro_cedure\"()");
EXPECT_AFTER_TAB("CALL `actest`.\"pro", "CALL `actest`.\"pro_cedure\"()");
}
TEST_F(Completer_frontend, quote_function) {
// BUG#34342966
connect_classic();
execute("\\sql");
execute(
"CREATE FUNCTION actest.fun_ction() RETURNS int DETERMINISTIC return 7;");
execute("\\use actest");
EXPECT_AFTER_TAB("SELECT fun", "SELECT fun_ction()");
EXPECT_AFTER_TAB("SELECT `actest`.fun", "SELECT `actest`.fun_ction()");
EXPECT_AFTER_TAB("SELECT `fun", "SELECT `fun_ction`()");
EXPECT_AFTER_TAB("SELECT actest.`fun", "SELECT actest.`fun_ction`()");
EXPECT_TAB_DOES_NOTHING("SELECT \"fun");
EXPECT_TAB_DOES_NOTHING("SELECT actest.\"fun");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT fun", "SELECT fun_ction()");
EXPECT_AFTER_TAB("SELECT \"actest\".fun", "SELECT \"actest\".fun_ction()");
EXPECT_AFTER_TAB("SELECT `fun", "SELECT `fun_ction`()");
EXPECT_AFTER_TAB("SELECT actest.`fun", "SELECT actest.`fun_ction`()");
EXPECT_AFTER_TAB("SELECT \"fun", "SELECT \"fun_ction\"()");
EXPECT_AFTER_TAB("SELECT `actest`.\"fun", "SELECT `actest`.\"fun_ction\"()");
}
TEST_F(Completer_frontend, quote_trigger) {
connect_classic();
execute("\\sql");
execute(
"CREATE TRIGGER actest.trig_ger BEFORE INSERT ON tab_le FOR EACH ROW "
"BEGIN END;");
execute("\\use actest");
EXPECT_AFTER_TAB("DROP TRIGGER trig", "DROP TRIGGER trig_ger");
EXPECT_AFTER_TAB("DROP TRIGGER `actest`.trig",
"DROP TRIGGER `actest`.trig_ger");
EXPECT_AFTER_TAB("DROP TRIGGER `trig", "DROP TRIGGER `trig_ger`");
EXPECT_AFTER_TAB("DROP TRIGGER actest.`trig",
"DROP TRIGGER actest.`trig_ger`");
EXPECT_TAB_DOES_NOTHING("DROP TRIGGER \"trig");
EXPECT_TAB_DOES_NOTHING("DROP TRIGGER actest.\"trig");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("DROP TRIGGER trig", "DROP TRIGGER trig_ger");
EXPECT_AFTER_TAB("DROP TRIGGER \"actest\".trig",
"DROP TRIGGER \"actest\".trig_ger");
EXPECT_AFTER_TAB("DROP TRIGGER `trig", "DROP TRIGGER `trig_ger`");
EXPECT_AFTER_TAB("DROP TRIGGER actest.`trig",
"DROP TRIGGER actest.`trig_ger`");
EXPECT_AFTER_TAB("DROP TRIGGER \"trig", "DROP TRIGGER \"trig_ger\"");
EXPECT_AFTER_TAB("DROP TRIGGER `actest`.\"trig",
"DROP TRIGGER `actest`.\"trig_ger\"");
}
TEST_F(Completer_frontend, quote_event) {
connect_classic();
execute("\\sql");
execute("CREATE EVENT actest.ev_ent ON SCHEDULE EVERY 1 YEAR DO BEGIN END;");
execute("\\use actest");
EXPECT_AFTER_TAB("DROP EVENT ev", "DROP EVENT ev_ent");
EXPECT_AFTER_TAB("DROP EVENT `actest`.ev", "DROP EVENT `actest`.ev_ent");
EXPECT_AFTER_TAB("DROP EVENT `ev", "DROP EVENT `ev_ent`");
EXPECT_AFTER_TAB("DROP EVENT actest.`ev", "DROP EVENT actest.`ev_ent`");
EXPECT_TAB_DOES_NOTHING("DROP EVENT \"ev");
EXPECT_TAB_DOES_NOTHING("DROP EVENT actest.\"ev");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("DROP EVENT ev", "DROP EVENT ev_ent");
EXPECT_AFTER_TAB("DROP EVENT \"actest\".ev", "DROP EVENT \"actest\".ev_ent");
EXPECT_AFTER_TAB("DROP EVENT `ev", "DROP EVENT `ev_ent`");
EXPECT_AFTER_TAB("DROP EVENT actest.`ev", "DROP EVENT actest.`ev_ent`");
EXPECT_AFTER_TAB("DROP EVENT \"ev", "DROP EVENT \"ev_ent\"");
EXPECT_AFTER_TAB("DROP EVENT `actest`.\"ev",
"DROP EVENT `actest`.\"ev_ent\"");
}
TEST_F(Completer_frontend, quote_engine) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("CREATE TABLE t(id INT) ENGINE=Inno",
"CREATE TABLE t(id INT) ENGINE=InnoDB");
EXPECT_AFTER_TAB("CREATE TABLE t(id INT) ENGINE=`Inno",
"CREATE TABLE t(id INT) ENGINE=`InnoDB`");
EXPECT_TAB_DOES_NOTHING("CREATE TABLE t(id INT) ENGINE=\"Inno");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("CREATE TABLE t(id INT) ENGINE=Inno",
"CREATE TABLE t(id INT) ENGINE=InnoDB");
EXPECT_AFTER_TAB("CREATE TABLE t(id INT) ENGINE=`Inno",
"CREATE TABLE t(id INT) ENGINE=`InnoDB`");
EXPECT_AFTER_TAB("CREATE TABLE t(id INT) ENGINE=\"Inno",
"CREATE TABLE t(id INT) ENGINE=\"InnoDB\"");
}
TEST_F(Completer_frontend, quote_udf) {
if (this->_target_server_version < mysqlshdk::utils::Version(8, 0, 0)) {
SKIP_TEST("This test requires 8.0+ server");
}
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("SELECT mysqlx_e", "SELECT mysqlx_error()");
EXPECT_AFTER_TAB("SELECT `mysqlx_e", "SELECT `mysqlx_error`()");
EXPECT_TAB_DOES_NOTHING("SELECT \"mysqlx_e");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT mysqlx_e", "SELECT mysqlx_error()");
EXPECT_AFTER_TAB("SELECT `mysqlx_e", "SELECT `mysqlx_error`()");
EXPECT_AFTER_TAB("SELECT \"mysqlx_e", "SELECT \"mysqlx_error\"()");
}
TEST_F(Completer_frontend, quote_runtime_function) {
connect_classic();
execute("\\sql");
for (const std::string sql_mode : {"", "ANSI_QUOTES"}) {
execute("SET @@sql_mode = '" + sql_mode + "';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT current_u", "SELECT CURRENT_USER()");
EXPECT_TAB_DOES_NOTHING("SELECT `current_u");
EXPECT_TAB_DOES_NOTHING("SELECT \"current_u");
}
}
TEST_F(Completer_frontend, logfile_group) {
#if defined(NDEBUG)
SKIP_TEST("This test requires a debug build.");
#else
DBUG_SET("+d,sql_auto_completion_logfile_group");
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("DROP LOGFILE GROUP log_",
"DROP LOGFILE GROUP log_file_group");
EXPECT_AFTER_TAB("DROP LOGFILE GROUP `log_",
"DROP LOGFILE GROUP `log_file_group`");
EXPECT_TAB_DOES_NOTHING("DROP LOGFILE GROUP \"log_");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("DROP LOGFILE GROUP log_",
"DROP LOGFILE GROUP log_file_group");
EXPECT_AFTER_TAB("DROP LOGFILE GROUP `log_",
"DROP LOGFILE GROUP `log_file_group`");
EXPECT_AFTER_TAB("DROP LOGFILE GROUP \"log_",
"DROP LOGFILE GROUP \"log_file_group\"");
DBUG_SET("");
#endif
}
TEST_F(Completer_frontend, quote_user_var) {
connect_classic();
execute("\\sql");
execute("set @ab_cd = 1234;");
execute("\\rehash");
for (const std::string sql_mode : {"", "ANSI_QUOTES"}) {
execute("SET @@sql_mode = '" + sql_mode + "';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT @ab", "SELECT @ab_cd");
EXPECT_AFTER_TAB("SELECT @'ab", "SELECT @'ab_cd'");
EXPECT_AFTER_TAB("SELECT @\"ab", "SELECT @\"ab_cd\"");
EXPECT_AFTER_TAB("SELECT @`ab", "SELECT @`ab_cd`");
EXPECT_AFTER_TAB("SET @ab", "SET @ab_cd");
EXPECT_AFTER_TAB("SET @'ab", "SET @'ab_cd'");
EXPECT_AFTER_TAB("SET @\"ab", "SET @\"ab_cd\"");
EXPECT_AFTER_TAB("SET @`ab", "SET @`ab_cd`");
}
}
TEST_F(Completer_frontend, quote_sys_var) {
// BUG#34343266
connect_classic();
execute("\\sql");
for (const std::string sql_mode : {"", "ANSI_QUOTES"}) {
execute("SET @@sql_mode = '" + sql_mode + "';");
execute("\\rehash");
EXPECT_AFTER_TAB("SELECT @@sql_log_b", "SELECT @@sql_log_bin");
EXPECT_AFTER_TAB("SELECT @@`sql_log_b", "SELECT @@`sql_log_bin`");
EXPECT_TAB_DOES_NOTHING("SELECT @@'sql_log_b");
EXPECT_TAB_DOES_NOTHING("SELECT @@\"sql_log_b");
EXPECT_AFTER_TAB("SELECT @@session.sql_log_b",
"SELECT @@session.sql_log_bin");
EXPECT_AFTER_TAB("SELECT @@session.`sql_log_b",
"SELECT @@session.`sql_log_bin`");
EXPECT_TAB_DOES_NOTHING("SELECT @@session.'sql_log_b");
EXPECT_TAB_DOES_NOTHING("SELECT @@session.\"sql_log_b");
EXPECT_AFTER_TAB("SET sql_log_b", "SET sql_log_bin");
EXPECT_AFTER_TAB("SET `sql_log_b", "SET `sql_log_bin`");
EXPECT_TAB_DOES_NOTHING("SET 'sql_log_b");
EXPECT_TAB_DOES_NOTHING("SET \"sql_log_b");
EXPECT_AFTER_TAB("SET PERSIST sql_log_b", "SET PERSIST sql_log_bin");
EXPECT_AFTER_TAB("SET PERSIST `sql_log_b", "SET PERSIST `sql_log_bin`");
EXPECT_TAB_DOES_NOTHING("SET PERSIST 'sql_log_b");
EXPECT_TAB_DOES_NOTHING("SET PERSIST \"sql_log_b");
EXPECT_AFTER_TAB("SET @@sql_log_b", "SET @@sql_log_bin");
EXPECT_AFTER_TAB("SET @@`sql_log_b", "SET @@`sql_log_bin`");
EXPECT_TAB_DOES_NOTHING("SET @@'sql_log_b");
EXPECT_TAB_DOES_NOTHING("SET @@\"sql_log_b");
EXPECT_AFTER_TAB("SET @@session.sql_log_b", "SET @@session.sql_log_bin");
EXPECT_AFTER_TAB("SET @@session.`sql_log_b", "SET @@session.`sql_log_bin`");
EXPECT_TAB_DOES_NOTHING("SET @@session.'sql_log_b");
EXPECT_TAB_DOES_NOTHING("SET @@session.\"sql_log_b");
}
}
TEST_F(Completer_frontend, quote_tablespace) {
connect_classic();
execute("\\sql");
execute("CREATE TABLESPACE table_space ADD DATAFILE 'table_space.ibd';");
execute("\\rehash");
EXPECT_AFTER_TAB("DROP TABLESPACE table_", "DROP TABLESPACE table_space");
EXPECT_AFTER_TAB("DROP TABLESPACE `table_", "DROP TABLESPACE `table_space`");
EXPECT_TAB_DOES_NOTHING("DROP TABLESPACE \"table_");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("DROP TABLESPACE table_", "DROP TABLESPACE table_space");
EXPECT_AFTER_TAB("DROP TABLESPACE `table_", "DROP TABLESPACE `table_space`");
EXPECT_AFTER_TAB("DROP TABLESPACE \"table_",
"DROP TABLESPACE \"table_space\"");
execute("DROP TABLESPACE table_space;");
}
TEST_F(Completer_frontend, quote_user) {
// BUG#34360367
connect_classic();
execute("\\sql");
execute("CREATE USER us_er@ho_st.com;");
for (const std::string sql_mode : {"", "ANSI_QUOTES"}) {
execute("SET @@sql_mode = '" + sql_mode + "';");
execute("\\rehash");
EXPECT_TAB_TAB_CONTAINS("ALTER USER ", "'us_er'@'ho_st.com'");
EXPECT_TAB_TAB_CONTAINS("ALTER USER u", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_e", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@h", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@ho", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@ho_", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@ho_s", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@ho_st", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@ho_st.c", "us_er@ho_st.com");
EXPECT_TAB_TAB_CONTAINS("ALTER USER us_er@ho_st.co", "us_er@ho_st.com");
EXPECT_AFTER_TAB("ALTER USER us_", "ALTER USER us_er@ho_st.com");
EXPECT_AFTER_TAB("ALTER USER `us_", "ALTER USER `us_er`@`ho_st.com`");
EXPECT_AFTER_TAB("ALTER USER 'us_", "ALTER USER 'us_er'@'ho_st.com'");
EXPECT_AFTER_TAB("ALTER USER \"us_", "ALTER USER \"us_er\"@\"ho_st.com\"");
EXPECT_AFTER_TAB("ALTER USER us_er@ho_", "ALTER USER us_er@ho_st.com");
EXPECT_AFTER_TAB("ALTER USER `us_er`@'ho_",
"ALTER USER `us_er`@'ho_st.com'");
EXPECT_AFTER_TAB("ALTER USER us_er@`ho_", "ALTER USER us_er@`ho_st.com`");
EXPECT_AFTER_TAB("ALTER USER \"us_er\"@\"ho_",
"ALTER USER \"us_er\"@\"ho_st.com\"");
}
execute("DROP USER us_er@ho_st.com;");
}
TEST_F(Completer_frontend, quote_charset) {
connect_classic();
execute("\\sql");
for (const std::string sql_mode : {"", "ANSI_QUOTES"}) {
execute("SET @@sql_mode = '" + sql_mode + "';");
execute("\\rehash");
EXPECT_AFTER_TAB("LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET asc",
"LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET ascii");
EXPECT_AFTER_TAB("LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET 'asc",
"LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET 'ascii'");
EXPECT_AFTER_TAB(
"LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET \"asc",
"LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET \"ascii\"");
EXPECT_AFTER_TAB("LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET `asc",
"LOAD DATA INFILE 'f' INTO TABLE t CHARACTER SET `ascii`");
}
}
TEST_F(Completer_frontend, quote_collation) {
connect_classic();
execute("\\sql");
for (const std::string sql_mode : {"", "ANSI_QUOTES"}) {
execute("SET @@sql_mode = '" + sql_mode + "';");
execute("\\rehash");
EXPECT_AFTER_TAB("CREATE TABLE t(c CHAR(32) COLLATE ascii_b",
"CREATE TABLE t(c CHAR(32) COLLATE ascii_bin");
EXPECT_AFTER_TAB("CREATE TABLE t(c CHAR(32) COLLATE 'ascii_b",
"CREATE TABLE t(c CHAR(32) COLLATE 'ascii_bin'");
EXPECT_AFTER_TAB("CREATE TABLE t(c CHAR(32) COLLATE \"ascii_b",
"CREATE TABLE t(c CHAR(32) COLLATE \"ascii_bin\"");
EXPECT_AFTER_TAB("CREATE TABLE t(c CHAR(32) COLLATE `ascii_b",
"CREATE TABLE t(c CHAR(32) COLLATE `ascii_bin`");
}
}
TEST_F(Completer_frontend, quote_plugin) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("UNINSTALL PLUGIN mysql_n",
"UNINSTALL PLUGIN mysql_native_password");
EXPECT_AFTER_TAB("UNINSTALL PLUGIN `mysql_n",
"UNINSTALL PLUGIN `mysql_native_password`");
EXPECT_TAB_DOES_NOTHING("UNINSTALL PLUGIN \"mysql_n");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB("UNINSTALL PLUGIN mysql_n",
"UNINSTALL PLUGIN mysql_native_password");
EXPECT_AFTER_TAB("UNINSTALL PLUGIN `mysql_n",
"UNINSTALL PLUGIN `mysql_native_password`");
EXPECT_AFTER_TAB("UNINSTALL PLUGIN \"mysql_n",
"UNINSTALL PLUGIN \"mysql_native_password\"");
}
TEST_F(Completer_frontend, quote_labels) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB(
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE lab",
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE label1");
EXPECT_AFTER_TAB(
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE `lab",
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE `label1`");
EXPECT_TAB_DOES_NOTHING(
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE \"lab");
execute("SET @@sql_mode = 'ANSI_QUOTES';");
execute("\\rehash");
EXPECT_AFTER_TAB(
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE lab",
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE label1");
EXPECT_AFTER_TAB(
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE `lab",
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE `label1`");
EXPECT_AFTER_TAB(
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE \"lab",
"CREATE PROCEDURE p(i INT) BEGIN label1: LOOP SET i = i + 1; IF i < 10 "
"THEN ITERATE \"label1\"");
}
TEST_F(Completer_frontend, bug_34372040) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("SHOW SL", "SHOW SLAVE");
EXPECT_AFTER_TAB_TAB("SHOW SLAVE ", strv({"HOSTS", "STATUS"}));
if (_target_server_version >= mysqlshdk::utils::Version(8, 0, 0)) {
EXPECT_AFTER_TAB_TAB("SHOW REPLICA", strv({"REPLICA", "REPLICAS"}));
EXPECT_AFTER_TAB("SHOW REPLICA ", "SHOW REPLICA STATUS");
EXPECT_TAB_DOES_NOTHING("SHOW REPLICAS ");
EXPECT_TAB_DOES_NOTHING("SHOW REPLICA H");
}
}
TEST_F(Completer_frontend, bug_34370621) {
if (this->_target_server_version < mysqlshdk::utils::Version(8, 0, 0)) {
SKIP_TEST("This test requires 8.0+ server");
}
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB("RESET PERSIST sql_log_b", "RESET PERSIST sql_log_bin");
EXPECT_AFTER_TAB("RESET PERSIST IF EXISTS sql_log_b",
"RESET PERSIST IF EXISTS sql_log_bin");
}
TEST_F(Completer_frontend, bug_34343279) {
if (this->_target_server_version < mysqlshdk::utils::Version(8, 0, 0)) {
SKIP_TEST("This test requires 8.0+ server");
}
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB_TAB("ALTER INSTANCE ",
strv({"DISABLE", "ENABLE", "RELOAD", "ROTATE"}));
EXPECT_AFTER_TAB_TAB("ALTER INSTANCE RELOAD ", strv({"KEYRING", "TLS"}));
}
TEST_F(Completer_frontend, bug_34353732) {
connect_classic();
execute("\\sql");
EXPECT_AFTER_TAB_TAB("SELECT JSON_ARRAY",
strv({"JSON_ARRAY()", "JSON_ARRAY_APPEND()",
"JSON_ARRAY_INSERT()", "JSON_ARRAYAGG()"}));
EXPECT_AFTER_TAB_TAB("SELECT JSON_ARRAY_",
strv({"JSON_ARRAY_APPEND()", "JSON_ARRAY_INSERT()"}));
}
TEST_F(Completer_frontend, bug_34342946) {
connect_classic("mysql");
execute("\\sql");
// BUG#34370211
EXPECT_TAB_DOES_NOTHING("USE mysql ");
EXPECT_TAB_TAB_NOT_CONTAINS("SELECT mysql.plugin.name ", "dl");
EXPECT_TAB_TAB_NOT_CONTAINS("SELECT mysql.plugin.name ", "name");
EXPECT_TAB_TAB_NOT_CONTAINS("CREATE DEFINER='root'@'localhost' ",
"'root'@'localhost'");
}
TEST_F(Completer_frontend, bug_34365581) {
connect_classic();
execute("\\sql");
execute("SELECT @@GLOBAL.lower_case_table_names\\G");
if (std::string::npos ==
output_handler.std_out.find("@@GLOBAL.lower_case_table_names: 0")) {
SKIP_TEST("This test requires case-sensitive MySQL server");
}
execute("CREATE SCHEMA IF NOT EXISTS ogórek;");
execute("CREATE SCHEMA IF NOT EXISTS ogÓrek;");
execute("\\rehash");
EXPECT_AFTER_TAB_TAB("SELECT ogó", strv({"ogÓrek", "ogórek"}));
execute("DROP SCHEMA ogórek;");
execute("DROP SCHEMA ogÓrek;");
}
TEST_F(Completer_frontend, bug_37528585) {
execute("\\js");
EXPECT_NO_THROW(complete("shell.unexisting."));
}
} // namespace mysqlsh