summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2021-11-05 20:01:43 +0300
committerSergei Petrunia <psergey@askmonty.org>2021-11-05 20:01:43 +0300
commit2ddeb16841ff10ee5c4178b6aeee52ee285a2838 (patch)
tree2a54e0b4ba6e17c8f08f3f2af7b586eedf9cce0e
parenta51ad4ee623648feab1eac5de4b7a3bbd06a3049 (diff)
downloadmariadb-git-bb-10.5-MDEV-23766.tar.gz
MDEV-23766: Make Json_writer assert when one tries to author invalid JSONbb-10.5-MDEV-23766
- Add unit test.
-rw-r--r--sql/my_json_writer.cc14
-rw-r--r--sql/my_json_writer.h22
-rw-r--r--unittest/sql/CMakeLists.txt5
-rw-r--r--unittest/sql/my_json_writer-t.cc130
4 files changed, 163 insertions, 8 deletions
diff --git a/sql/my_json_writer.cc b/sql/my_json_writer.cc
index 687da202164..96bdf20ee5e 100644
--- a/sql/my_json_writer.cc
+++ b/sql/my_json_writer.cc
@@ -39,7 +39,7 @@ inline void Json_writer::on_start_object()
#ifndef NDEBUG
if(!fmt_helper.is_making_writer_calls())
{
- DBUG_ASSERT(got_name == named_item_expected());
+ VALIDITY_ASSERT(got_name == named_item_expected());
named_items_expectation.push_back(true);
}
#endif
@@ -74,7 +74,7 @@ void Json_writer::start_array()
#ifndef NDEBUG
if(!fmt_helper.is_making_writer_calls())
{
- DBUG_ASSERT(got_name == named_item_expected());
+ VALIDITY_ASSERT(got_name == named_item_expected());
named_items_expectation.push_back(false);
got_name= false;
}
@@ -98,7 +98,7 @@ void Json_writer::end_object()
{
#ifndef NDEBUG
named_items_expectation.pop_back();
- DBUG_ASSERT(!got_name);
+ VALIDITY_ASSERT(!got_name);
got_name= false;
#endif
indent_level-=INDENT_SIZE;
@@ -246,8 +246,8 @@ void Json_writer::add_unquoted_str(const char* str)
void Json_writer::add_unquoted_str(const char* str, size_t len)
{
- DBUG_ASSERT(fmt_helper.is_making_writer_calls() ||
- got_name == named_item_expected());
+ VALIDITY_ASSERT(fmt_helper.is_making_writer_calls() ||
+ got_name == named_item_expected());
if (on_add_str(str, len))
return;
@@ -279,8 +279,8 @@ void Json_writer::add_str(const char *str)
void Json_writer::add_str(const char* str, size_t num_bytes)
{
- DBUG_ASSERT(fmt_helper.is_making_writer_calls() ||
- got_name == named_item_expected());
+ VALIDITY_ASSERT(fmt_helper.is_making_writer_calls() ||
+ got_name == named_item_expected());
if (on_add_str(str, num_bytes))
return;
diff --git a/sql/my_json_writer.h b/sql/my_json_writer.h
index 50b277a5052..6f9ae73c5ee 100644
--- a/sql/my_json_writer.h
+++ b/sql/my_json_writer.h
@@ -16,7 +16,17 @@
#ifndef JSON_WRITER_INCLUDED
#define JSON_WRITER_INCLUDED
#include "my_base.h"
+
+#ifdef JSON_WRITER_UNIT_TEST
+#include "sql_string.h"
+#include <vector>
+// Also, mock objects are defined in my_json_writer-t.cc
+#define VALIDITY_ASSERT(x) if ((!x)) this->invalid_json= true;
+#else
#include "sql_select.h"
+#define VALIDITY_ASSERT(x) DBUG_ASSERT(x)
+#endif
+
class Opt_trace_stmt;
class Opt_trace_context;
class Json_writer;
@@ -191,12 +201,22 @@ private:
class Json_writer
{
#ifndef NDEBUG
-
+ /*
+ In debug mode, Json_writer will fail and assertion if one attempts to
+ produce an invalid JSON document (e.g. JSON array having named elements).
+ */
std::vector<bool> named_items_expectation;
bool named_item_expected() const;
bool got_name;
+
+#ifdef JSON_WRITER_UNIT_TEST
+public:
+ // When compiled for unit test, creating invalid JSON will set this to true
+ // instead of an assertion.
+ bool invalid_json= false;
+#endif
#endif
public:
diff --git a/unittest/sql/CMakeLists.txt b/unittest/sql/CMakeLists.txt
index 987e78433a4..ab174680fab 100644
--- a/unittest/sql/CMakeLists.txt
+++ b/unittest/sql/CMakeLists.txt
@@ -36,3 +36,8 @@ ADD_EXECUTABLE(mf_iocache-t mf_iocache-t.cc ../../sql/mf_iocache_encr.cc)
TARGET_LINK_LIBRARIES(mf_iocache-t mysys mytap mysys_ssl)
ADD_DEPENDENCIES(mf_iocache-t GenError)
MY_ADD_TEST(mf_iocache)
+
+# Json writer needs String which needs sql library
+ADD_EXECUTABLE(my_json_writer-t my_json_writer-t.cc dummy_builtins.cc)
+TARGET_LINK_LIBRARIES(my_json_writer-t sql mytap)
+MY_ADD_TEST(my_json_writer)
diff --git a/unittest/sql/my_json_writer-t.cc b/unittest/sql/my_json_writer-t.cc
new file mode 100644
index 00000000000..46c3f4dc967
--- /dev/null
+++ b/unittest/sql/my_json_writer-t.cc
@@ -0,0 +1,130 @@
+/*
+ Copyright (c) 2021, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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 Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <my_sys.h>
+#include <stdio.h>
+#include <tap.h>
+
+/*
+ Unit tests for class Json_writer. At the moment there are only tests for the
+ "Fail an assertion if one attempts to produce invalid JSON" feature.
+*/
+
+struct TABLE;
+struct JOIN_TAB;
+class Json_writer;
+
+
+/* Several fake objects */
+class Opt_trace
+{
+public:
+ void enable_tracing_if_required() {}
+ void disable_tracing_if_required() {}
+ Json_writer *get_current_json() { return nullptr; }
+};
+
+class THD
+{
+public:
+ Opt_trace opt_trace;
+};
+
+#define JSON_WRITER_UNIT_TEST
+#include "../sql/my_json_writer.h"
+#include "../sql/my_json_writer.cc"
+
+int main(int args, char **argv)
+{
+ plan(NO_PLAN);
+ diag("Testing Json_writer checks");
+
+ {
+ Json_writer w;
+ w.start_object();
+ w.add_member("foo");
+ w.end_object();
+ ok(w.invalid_json, "Started a name but didn't add a value");
+ }
+
+ {
+ Json_writer w;
+ w.start_object();
+ w.add_ull(123);
+ ok(w.invalid_json, "Unnamed value in an object");
+ }
+
+ {
+ Json_writer w;
+ w.start_array();
+ w.add_member("bebebe").add_ull(345);
+ ok(w.invalid_json, "Named member in array");
+ }
+
+ {
+ Json_writer w;
+ w.start_object();
+ w.start_array();
+ ok(w.invalid_json, "Unnamed array in an object");
+ }
+
+ {
+ Json_writer w;
+ w.start_object();
+ w.start_object();
+ ok(w.invalid_json, "Unnamed object in an object");
+ }
+
+ {
+ Json_writer w;
+ w.start_array();
+ w.add_member("zzz");
+ w.start_object();
+ ok(w.invalid_json, "Named object in an array");
+ }
+ {
+ Json_writer w;
+ w.start_array();
+ w.add_member("zzz");
+ w.start_array();
+ ok(w.invalid_json, "Named array in an array");
+ }
+
+ // BAD:
+ {
+ Json_writer w;
+ w.start_array();
+ w.end_object();
+ ok(!w.invalid_json, "BAD: not checked!");
+ }
+
+ // BAD:
+ {
+ Json_writer w;
+ w.start_object();
+ w.end_array();
+ ok(!w.invalid_json, "BAD: not checked!");
+ }
+
+
+
+ diag("Done");
+
+ return exit_status();
+}
+