You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
9.7 KiB

/*
** Zabbix
** Copyright (C) 2001-2023 Zabbix SIA
**
** 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; either version 2 of the License, or
** (at your option) any later version.
**
** 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-1301, USA.
**/
#include "zbxmocktest.h"
#include "zbxmockdata.h"
#include "zbxmockassert.h"
#include "zbxmockutil.h"
#include "zbxcommon.h"
#include "zbxexpression.h"
#include "zbxvariant.h"
#include "mock_eval.h"
zbx_uint64_t mock_eval_read_rules(const char *path)
{
zbx_uint64_t rules = 0;
zbx_mock_handle_t hrules, hflag;
zbx_mock_error_t err;
int rules_num = 0;
hrules = zbx_mock_get_parameter_handle(path);
while (ZBX_MOCK_END_OF_VECTOR != (err = (zbx_mock_vector_element(hrules, &hflag))))
{
const char *flag;
if (ZBX_MOCK_SUCCESS != err || ZBX_MOCK_SUCCESS != (err = zbx_mock_string(hflag, &flag)))
fail_msg("Cannot read flag #%d: %s", rules_num, zbx_mock_error_string(err));
if (0 == strcmp(flag, "ZBX_EVAL_PARSE_FUNCTIONID"))
rules |= ZBX_EVAL_PARSE_FUNCTIONID;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_FUNCTION"))
rules |= ZBX_EVAL_PARSE_FUNCTION;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_ITEM_QUERY"))
rules |= ZBX_EVAL_PARSE_ITEM_QUERY;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_MACRO"))
rules |= ZBX_EVAL_PARSE_MACRO;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_USERMACRO"))
rules |= ZBX_EVAL_PARSE_USERMACRO;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_LLDMACRO"))
rules |= ZBX_EVAL_PARSE_LLDMACRO;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_CONST_INDEX"))
rules |= ZBX_EVAL_PARSE_CONST_INDEX;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_MATH"))
rules |= ZBX_EVAL_PARSE_MATH;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_COMPARE_EQ"))
rules |= ZBX_EVAL_PARSE_COMPARE_EQ;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_LOGIC"))
rules |= ZBX_EVAL_PARSE_LOGIC;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_VAR_NUM"))
rules |= ZBX_EVAL_PARSE_VAR_NUM;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_VAR_STR"))
rules |= ZBX_EVAL_PARSE_VAR_STR;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_GROUP"))
rules |= ZBX_EVAL_PARSE_GROUP;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_PROP_TAG"))
rules |= ZBX_EVAL_PARSE_PROP_TAG;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_PROP_GROUP"))
rules |= ZBX_EVAL_PARSE_PROP_GROUP;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_COMPARE"))
rules |= ZBX_EVAL_PARSE_COMPARE;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_VAR"))
rules |= ZBX_EVAL_PARSE_VAR;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_PROPERTY"))
rules |= ZBX_EVAL_PARSE_PROPERTY;
else if (0 == strcmp(flag, "ZBX_EVAL_COMPOSE_LLD"))
rules |= ZBX_EVAL_COMPOSE_LLD;
else if (0 == strcmp(flag, "ZBX_EVAL_COMPOSE_FUNCTIONID"))
rules |= ZBX_EVAL_COMPOSE_FUNCTIONID;
else if (0 == strcmp(flag, "ZBX_EVAL_PROCESS_ERROR"))
rules |= ZBX_EVAL_PROCESS_ERROR;
else if (0 == strcmp(flag, "ZBX_EVAL_PARSE_COMPOUND_CONST"))
rules |= ZBX_EVAL_PARSE_COMPOUND_CONST;
else
fail_msg("Unsupported flag: %s", flag);
rules_num++;
}
return rules;
}
void mock_eval_read_values(zbx_eval_context_t *ctx, const char *path)
{
zbx_mock_handle_t htokens, htoken, hdata;
zbx_mock_error_t err;
if (ZBX_MOCK_SUCCESS != zbx_mock_parameter(path, &htokens))
return;
while (ZBX_MOCK_END_OF_VECTOR != (err = (zbx_mock_vector_element(htokens, &htoken))))
{
const char *data, *value = NULL, *error = NULL;
int i;
size_t data_len;
if (ZBX_MOCK_SUCCESS != err)
fail_msg("cannot read token contents");
data = zbx_mock_get_object_member_string(htoken, "token");
if (ZBX_MOCK_SUCCESS == zbx_mock_object_member(htoken, "value", &hdata))
{
if (ZBX_MOCK_SUCCESS != zbx_mock_string(hdata, &value))
fail_msg("invalid token value");
}
else if (ZBX_MOCK_SUCCESS == zbx_mock_object_member(htoken, "error", &hdata))
{
if (ZBX_MOCK_SUCCESS != zbx_mock_string(hdata, &error))
fail_msg("invalid token error");
}
else
fail_msg("invalid token contents");
data_len = strlen(data);
for (i = 0; i < ctx->stack.values_num; i++)
{
zbx_eval_token_t *token = &ctx->stack.values[i];
if (data_len == token->loc.r - token->loc.l + 1 &&
0 == memcmp(data, ctx->expression + token->loc.l, data_len))
{
if (NULL != value)
zbx_variant_set_str(&token->value, zbx_strdup(NULL, value));
else
zbx_variant_set_error(&token->value, zbx_strdup(NULL, error));
break;
}
}
}
}
static const char *mock_token_type2str(zbx_uint32_t type)
{
#define ZBX_MOCK_TOKEN_CASE(x) case ZBX_EVAL_TOKEN_##x: return "ZBX_EVAL_TOKEN_" #x;
switch(type)
{
ZBX_MOCK_TOKEN_CASE(OP_ADD)
ZBX_MOCK_TOKEN_CASE(OP_SUB)
ZBX_MOCK_TOKEN_CASE(OP_MUL)
ZBX_MOCK_TOKEN_CASE(OP_DIV)
ZBX_MOCK_TOKEN_CASE(OP_MINUS)
ZBX_MOCK_TOKEN_CASE(OP_EQ)
ZBX_MOCK_TOKEN_CASE(OP_LT)
ZBX_MOCK_TOKEN_CASE(OP_GT)
ZBX_MOCK_TOKEN_CASE(OP_LE)
ZBX_MOCK_TOKEN_CASE(OP_GE)
ZBX_MOCK_TOKEN_CASE(OP_NE)
ZBX_MOCK_TOKEN_CASE(OP_AND)
ZBX_MOCK_TOKEN_CASE(OP_OR)
ZBX_MOCK_TOKEN_CASE(OP_NOT)
ZBX_MOCK_TOKEN_CASE(VAR_NUM)
ZBX_MOCK_TOKEN_CASE(VAR_STR)
ZBX_MOCK_TOKEN_CASE(VAR_MACRO)
ZBX_MOCK_TOKEN_CASE(VAR_USERMACRO)
ZBX_MOCK_TOKEN_CASE(VAR_LLDMACRO)
ZBX_MOCK_TOKEN_CASE(FUNCTIONID)
ZBX_MOCK_TOKEN_CASE(FUNCTION)
ZBX_MOCK_TOKEN_CASE(HIST_FUNCTION)
ZBX_MOCK_TOKEN_CASE(GROUP_OPEN)
ZBX_MOCK_TOKEN_CASE(GROUP_CLOSE)
ZBX_MOCK_TOKEN_CASE(COMMA)
ZBX_MOCK_TOKEN_CASE(ARG_QUERY)
ZBX_MOCK_TOKEN_CASE(ARG_PERIOD)
ZBX_MOCK_TOKEN_CASE(ARG_NULL)
ZBX_MOCK_TOKEN_CASE(PROP_TAG)
ZBX_MOCK_TOKEN_CASE(PROP_GROUP)
ZBX_MOCK_TOKEN_CASE(NOP)
}
fail_msg("unknown token type: %d", type);
return NULL;
#undef ZBX_MOCK_TOKEN_CASE
}
static zbx_uint32_t mock_token_str2type(const char *str)
{
#define ZBX_MOCK_TOKEN_IF(x) if (0 == strcmp(str, "ZBX_EVAL_TOKEN_" #x)) return ZBX_EVAL_TOKEN_##x;
ZBX_MOCK_TOKEN_IF(OP_ADD)
ZBX_MOCK_TOKEN_IF(OP_SUB)
ZBX_MOCK_TOKEN_IF(OP_MUL)
ZBX_MOCK_TOKEN_IF(OP_DIV)
ZBX_MOCK_TOKEN_IF(OP_MINUS)
ZBX_MOCK_TOKEN_IF(OP_EQ)
ZBX_MOCK_TOKEN_IF(OP_LT)
ZBX_MOCK_TOKEN_IF(OP_GT)
ZBX_MOCK_TOKEN_IF(OP_LE)
ZBX_MOCK_TOKEN_IF(OP_GE)
ZBX_MOCK_TOKEN_IF(OP_NE)
ZBX_MOCK_TOKEN_IF(OP_AND)
ZBX_MOCK_TOKEN_IF(OP_OR)
ZBX_MOCK_TOKEN_IF(OP_NOT)
ZBX_MOCK_TOKEN_IF(VAR_NUM)
ZBX_MOCK_TOKEN_IF(VAR_STR)
ZBX_MOCK_TOKEN_IF(VAR_MACRO)
ZBX_MOCK_TOKEN_IF(VAR_USERMACRO)
ZBX_MOCK_TOKEN_IF(VAR_LLDMACRO)
ZBX_MOCK_TOKEN_IF(FUNCTIONID)
ZBX_MOCK_TOKEN_IF(FUNCTION)
ZBX_MOCK_TOKEN_IF(HIST_FUNCTION)
ZBX_MOCK_TOKEN_IF(GROUP_OPEN)
ZBX_MOCK_TOKEN_IF(GROUP_CLOSE)
ZBX_MOCK_TOKEN_IF(COMMA)
ZBX_MOCK_TOKEN_IF(ARG_QUERY)
ZBX_MOCK_TOKEN_IF(ARG_PERIOD)
ZBX_MOCK_TOKEN_IF(ARG_NULL)
ZBX_MOCK_TOKEN_IF(PROP_TAG)
ZBX_MOCK_TOKEN_IF(PROP_GROUP)
ZBX_MOCK_TOKEN_IF(NOP)
fail_msg("unknown token type %s", str);
return 0;
#undef ZBX_MOCK_TOKEN_IF
}
void mock_compare_stack(const zbx_eval_context_t *ctx, const char *path)
{
int token_num = 0, len;
zbx_mock_handle_t htokens, htoken;
zbx_mock_error_t err;
zbx_uint32_t expected_type, expected_opt;
const char *expected_token;
const zbx_eval_token_t *token;
htokens = zbx_mock_get_parameter_handle(path);
while (ZBX_MOCK_END_OF_VECTOR != (err = (zbx_mock_vector_element(htokens, &htoken))))
{
if (ZBX_MOCK_SUCCESS != err)
fail_msg("cannot read token #%d: %s", token_num, zbx_mock_error_string(err));
if (token_num == ctx->stack.values_num)
{
mock_dump_stack(ctx);
fail_msg("expected more than %d tokens", token_num);
}
token = &ctx->stack.values[token_num++];
expected_type = mock_token_str2type(zbx_mock_get_object_member_string(htoken, "type"));
expected_token = zbx_mock_get_object_member_string(htoken, "token");
expected_opt = (zbx_uint32_t)zbx_mock_get_object_member_uint64(htoken, "opt");
if (expected_type != token->type)
{
mock_dump_stack(ctx);
fail_msg( "expected token #%d type %s while got %s", token_num,
mock_token_type2str(expected_type), mock_token_type2str(token->type));
}
if (ZBX_EVAL_TOKEN_NOP == token->type)
continue;
if (expected_opt != token->opt)
{
mock_dump_stack(ctx);
fail_msg("expected token optional data %d while got %d", expected_opt, token->opt);
}
len = token->loc.r - token->loc.l + 1;
if (ZBX_EVAL_TOKEN_ARG_NULL != token->type &&
0 != strncmp(expected_token, ctx->expression + token->loc.l, len))
{
mock_dump_stack(ctx);
fail_msg("expected token %s while got %.*s", expected_token, len,
ctx->expression + token->loc.l);
}
}
if (token_num != ctx->stack.values_num)
{
mock_dump_stack(ctx);
fail_msg("expected %d tokens while got more", token_num);
}
}
static void dump_token(const zbx_eval_context_t *ctx, const zbx_eval_token_t *token)
{
if (ZBX_EVAL_TOKEN_ARG_NULL == token->type)
{
printf("\t(null)");
}
if (ZBX_EVAL_TOKEN_OP_MINUS == token->type)
{
printf("\t'-'");
}
if (ZBX_EVAL_TOKEN_NOP == token->type)
{
printf("\t'.'");
}
else
{
if (ZBX_VARIANT_NONE == token->value.type)
printf("\t%.*s", (int)(token->loc.r - token->loc.l + 1), ctx->expression + token->loc.l);
else
printf("\t'%s'", zbx_variant_value_desc(&token->value));
}
printf(" : %s (%u)\n", mock_token_type2str(token->type), (unsigned int)token->opt);
}
void mock_dump_stack(const zbx_eval_context_t *ctx)
{
int i;
printf("STACK:\n");
for (i = 0; i < ctx->stack.values_num; i++)
dump_token(ctx, &ctx->stack.values[i]);
}