AddonInfo: const-ified loading and improved errorhandling (#5834)
This commit is contained in:
parent
c7cd091a93
commit
42c3aebda9
|
@ -52,47 +52,73 @@ static std::string parseAddonInfo(AddonInfo& addoninfo, const picojson::value &j
|
||||||
return "Loading " + fileName + " failed. " + json_error;
|
return "Loading " + fileName + " failed. " + json_error;
|
||||||
}
|
}
|
||||||
if (!json.is<picojson::object>())
|
if (!json.is<picojson::object>())
|
||||||
return "Loading " + fileName + " failed. Bad json.";
|
return "Loading " + fileName + " failed. JSON is not an object.";
|
||||||
picojson::object obj = json.get<picojson::object>();
|
|
||||||
if (obj.count("args")) {
|
|
||||||
if (!obj["args"].is<picojson::array>())
|
|
||||||
return "Loading " + fileName + " failed. args must be array.";
|
|
||||||
for (const picojson::value &v : obj["args"].get<picojson::array>())
|
|
||||||
addoninfo.args += " " + v.get<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.count("ctu")) {
|
// TODO: remove/complete default value handling for missing fields
|
||||||
// ctu is specified in the config file
|
const picojson::object& obj = json.get<picojson::object>();
|
||||||
if (!obj["ctu"].is<bool>())
|
|
||||||
return "Loading " + fileName + " failed. ctu must be boolean.";
|
|
||||||
addoninfo.ctu = obj["ctu"].get<bool>();
|
|
||||||
} else {
|
|
||||||
addoninfo.ctu = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.count("python")) {
|
|
||||||
// Python was defined in the config file
|
|
||||||
if (obj["python"].is<picojson::array>()) {
|
|
||||||
return "Loading " + fileName +" failed. python must not be an array.";
|
|
||||||
}
|
|
||||||
addoninfo.python = obj["python"].get<std::string>();
|
|
||||||
} else {
|
|
||||||
addoninfo.python = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj.count("executable")) {
|
|
||||||
if (!obj["executable"].is<std::string>())
|
|
||||||
return "Loading " + fileName + " failed. executable must be a string.";
|
|
||||||
addoninfo.executable = getFullPath(obj["executable"].get<std::string>(), fileName);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!obj.count("script") || !obj["script"].is<std::string>())
|
|
||||||
{
|
{
|
||||||
return "Loading " + fileName + " failed. script must be set to a string value.";
|
const auto it = obj.find("args");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& val = it->second;
|
||||||
|
if (!val.is<picojson::array>())
|
||||||
|
return "Loading " + fileName + " failed. 'args' must be an array.";
|
||||||
|
for (const picojson::value &v : val.get<picojson::array>()) {
|
||||||
|
if (!v.is<std::string>())
|
||||||
|
return "Loading " + fileName + " failed. 'args' entry is not a string.";
|
||||||
|
addoninfo.args += " " + v.get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return addoninfo.getAddonInfo(obj["script"].get<std::string>(), exename);
|
{
|
||||||
|
const auto it = obj.find("ctu");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& val = it->second;
|
||||||
|
// ctu is specified in the config file
|
||||||
|
if (!val.is<bool>())
|
||||||
|
return "Loading " + fileName + " failed. 'ctu' must be a boolean.";
|
||||||
|
addoninfo.ctu = val.get<bool>();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addoninfo.ctu = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto it = obj.find("python");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& val = it->second;
|
||||||
|
// Python was defined in the config file
|
||||||
|
if (!val.is<std::string>()) {
|
||||||
|
return "Loading " + fileName +" failed. 'python' must be a string.";
|
||||||
|
}
|
||||||
|
addoninfo.python = val.get<std::string>();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
addoninfo.python = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto it = obj.find("executable");
|
||||||
|
if (it != obj.cend()) {
|
||||||
|
const auto& val = it->second;
|
||||||
|
if (!val.is<std::string>())
|
||||||
|
return "Loading " + fileName + " failed. 'executable' must be a string.";
|
||||||
|
addoninfo.executable = getFullPath(val.get<std::string>(), fileName);
|
||||||
|
return ""; // TODO: why bail out?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto it = obj.find("script");
|
||||||
|
if (it == obj.cend())
|
||||||
|
return "Loading " + fileName + " failed. 'script' is missing.";
|
||||||
|
|
||||||
|
const auto& val = it->second;
|
||||||
|
if (!val.is<std::string>())
|
||||||
|
return "Loading " + fileName + " failed. 'script' must be a string.";
|
||||||
|
|
||||||
|
return addoninfo.getAddonInfo(val.get<std::string>(), exename);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::string &exename) {
|
std::string AddonInfo::getAddonInfo(const std::string &fileName, const std::string &exename) {
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
|
import json
|
||||||
|
|
||||||
from testutils import cppcheck, assert_cppcheck
|
from testutils import cppcheck, assert_cppcheck
|
||||||
|
|
||||||
|
@ -278,22 +279,6 @@ extern const char* f()
|
||||||
assert stderr == '{}:4:12: warning: strerror is MT-unsafe [threadsafety-unsafe-call]\n'.format(test_file)
|
assert stderr == '{}:4:12: warning: strerror is MT-unsafe [threadsafety-unsafe-call]\n'.format(test_file)
|
||||||
|
|
||||||
|
|
||||||
def test_addon_invalidjson(tmpdir):
|
|
||||||
addon_file = os.path.join(tmpdir, 'invalid.json')
|
|
||||||
with open(addon_file, 'wt') as f:
|
|
||||||
f.write("""
|
|
||||||
{
|
|
||||||
"Script": "addons/something.py"
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
|
|
||||||
args = ['--addon={}'.format(addon_file), '--enable=all', 'nonexistent.cpp']
|
|
||||||
|
|
||||||
exitcode, stdout, stderr = cppcheck(args)
|
|
||||||
assert exitcode != 0
|
|
||||||
assert stdout == 'Loading {} failed. script must be set to a string value.\n'.format(addon_file)
|
|
||||||
|
|
||||||
|
|
||||||
def test_addon_naming(tmpdir):
|
def test_addon_naming(tmpdir):
|
||||||
# the addon does nothing without a config
|
# the addon does nothing without a config
|
||||||
addon_file = os.path.join(tmpdir, 'naming1.json')
|
addon_file = os.path.join(tmpdir, 'naming1.json')
|
||||||
|
@ -644,12 +629,10 @@ def test_invalid_addon_json(tmpdir):
|
||||||
""")
|
""")
|
||||||
|
|
||||||
test_file = os.path.join(tmpdir, 'file.cpp')
|
test_file = os.path.join(tmpdir, 'file.cpp')
|
||||||
with open(test_file, 'wt') as f:
|
with open(test_file, 'wt'):
|
||||||
f.write("""
|
pass
|
||||||
typedef int MISRA_5_6_VIOLATION;
|
|
||||||
""")
|
|
||||||
|
|
||||||
args = ['--addon={}'.format(addon_file), '--enable=all', test_file]
|
args = ['--addon={}'.format(addon_file), test_file]
|
||||||
|
|
||||||
exitcode, stdout, stderr = cppcheck(args)
|
exitcode, stdout, stderr = cppcheck(args)
|
||||||
assert exitcode == 1
|
assert exitcode == 1
|
||||||
|
@ -1124,3 +1107,56 @@ def test_build_dir_j_memleak(tmpdir): #12111
|
||||||
]
|
]
|
||||||
|
|
||||||
assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=out_lines)
|
assert_cppcheck(args, ec_exp=0, err_exp=[], out_exp=out_lines)
|
||||||
|
|
||||||
|
|
||||||
|
def __test_addon_json_invalid(tmpdir, addon_json, expected):
|
||||||
|
addon_file = os.path.join(tmpdir, 'invalid.json')
|
||||||
|
with open(addon_file, 'wt') as f:
|
||||||
|
f.write(addon_json)
|
||||||
|
|
||||||
|
test_file = os.path.join(tmpdir, 'file.cpp')
|
||||||
|
with open(test_file, 'wt'):
|
||||||
|
pass
|
||||||
|
|
||||||
|
args = ['--addon={}'.format(addon_file), test_file]
|
||||||
|
|
||||||
|
exitcode, stdout, stderr = cppcheck(args)
|
||||||
|
assert exitcode == 1
|
||||||
|
lines = stdout.splitlines()
|
||||||
|
assert len(lines) == 1
|
||||||
|
assert lines == [
|
||||||
|
'Loading {} failed. {}'.format(addon_file, expected)
|
||||||
|
]
|
||||||
|
assert stderr == ''
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_no_obj(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps([]), "JSON is not an object.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_args_1(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'args':0}), "'args' must be an array.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_args_2(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'args':[0]}), "'args' entry is not a string.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_ctu(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'ctu':0}), "'ctu' must be a boolean.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_python(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'python':0}), "'python' must be a string.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_executable(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'executable':0}), "'executable' must be a string.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_script_1(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'Script':''}), "'script' is missing.")
|
||||||
|
|
||||||
|
|
||||||
|
def test_addon_json_invalid_script_2(tmpdir):
|
||||||
|
__test_addon_json_invalid(tmpdir, json.dumps({'script':0}), "'script' must be a string.")
|
Loading…
Reference in New Issue