libamxp  1.4.0
Patterns C Implementation
test_expression.c File Reference
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <fcntl.h>
#include <cmocka.h>
#include <amxc/amxc.h>
#include <amxp/amxp_expression.h>
#include "test_expression.h"
#include <amxc/amxc_macros.h>

Go to the source code of this file.

Data Structures

struct  _evaluator
 

Typedefs

typedef struct _evaluator eval_t
 

Functions

void test_can_create_expression (UNUSED void **state)
 
void test_can_evaluate_expression (UNUSED void **state)
 
void test_precedence_is_respected (UNUSED void **state)
 
void test_comperators_are_correct (UNUSED void **state)
 
void test_can_fetch_fields (UNUSED void **state)
 
void test_invalid_field_names (UNUSED void **state)
 
void test_invalid_syntax (UNUSED void **state)
 
void test_invalid_value_types (UNUSED void **state)
 
static amxp_expr_status_t custom_field_fetcher (UNUSED amxp_expr_t *expr, amxc_var_t *value, const char *path, void *priv)
 
void test_can_use_custom_field_fetcher (UNUSED void **state)
 
void test_api_arguments_validation (UNUSED void **state)
 
void test_selects_first_in_first_existing (UNUSED void **state)
 
void test_fails_with_invalid_regexp (UNUSED void **state)
 
void test_is_empty_function (UNUSED void **state)
 
void test_is_empty_function_with_var (UNUSED void **state)
 
void test_contains (UNUSED void **state)
 
void test_contains_no_get_field (UNUSED void **state)
 
void test_contains_no_data (UNUSED void **state)
 
void test_contains_invalid_usage (UNUSED void **state)
 
void test_flag_expressions (UNUSED void **state)
 
void test_flag_expressions_no_operators (UNUSED void **state)
 
void test_in_operators (UNUSED void **state)
 
void test_buildf_expression (UNUSED void **state)
 
void test_buildf_expression_allocate (UNUSED void **state)
 
void test_buildf_expression_invalid_value (UNUSED void **state)
 
void test_buildf_expression_all_whitelisted (UNUSED void **state)
 
void test_buildf_expression_invalid_args (UNUSED void **state)
 
static void s_testhelper_buildf (bool expect_accepted, const char *string)
 
void test_buildf_are_strings_safe (UNUSED void **state)
 
void test_get_string (UNUSED void **state)
 
void test_get_string_null (UNUSED void **state)
 
void test_expression_with_invalid_list_does_not_memory_leak (UNUSED void **state)
 

Typedef Documentation

◆ eval_t

typedef struct _evaluator eval_t

Function Documentation

◆ custom_field_fetcher()

static amxp_expr_status_t custom_field_fetcher ( UNUSED amxp_expr_t expr,
amxc_var_t *  value,
const char *  path,
void *  priv 
)
static

Definition at line 362 of file test_expression.c.

365  {
367  amxc_var_t* data = (amxc_var_t*) priv;
368  amxc_var_t* field = amxc_var_get_path(data, path, AMXC_VAR_FLAG_DEFAULT);
369  if(amxc_var_is_null(field)) {
370  if(strcmp(path, "available") == 0) {
371  amxc_var_set(bool, value, true);
372  } else {
373  amxc_var_set(bool, value, false);
374  }
375  retval = amxp_expr_status_ok;
376  } else {
377  if(amxc_var_copy(value, field) == 0) {
378  retval = amxp_expr_status_ok;
379  }
380  }
381 
382  return retval;
383 }
enum _expr_status amxp_expr_status_t
Expression status/error codes.
@ amxp_expr_status_unknown_error
@ amxp_expr_status_ok
static amxc_string_t path

◆ s_testhelper_buildf()

static void s_testhelper_buildf ( bool  expect_accepted,
const char *  string 
)
static

Definition at line 810 of file test_expression.c.

810  {
811  amxp_expr_t expression;
813  amxp_expr_status_t status_build = amxp_expr_buildf(&expression, "'%s' == '%s'", string, string);
814  bool matched = amxp_expr_eval(&expression, &status_eval);
815  if(expect_accepted) {
816  assert_true(matched);
817  assert_int_equal(status_build, amxp_expr_status_ok);
818  amxp_expr_clean(&expression);
819  } else {
820  assert_false(matched);
821  assert_int_not_equal(status_build, amxp_expr_status_ok);
822  }
823 }
bool amxp_expr_eval(amxp_expr_t *expr, amxp_expr_status_t *status)
Evaluates an expression.
amxp_expr_status_t amxp_expr_buildf(amxp_expr_t *expr, const char *expr_fmt,...) __attribute__((format(printf
Initializes an expression structure.
void amxp_expr_clean(amxp_expr_t *expr)
Clean-up the expression structure.

◆ test_api_arguments_validation()

void test_api_arguments_validation ( UNUSED void **  state)

Definition at line 430 of file test_expression.c.

430  {
431  amxp_expr_t* expr = NULL;
432  amxp_expr_t expression;
433 
434  assert_int_not_equal(amxp_expr_new(NULL, ""), 0);
435  assert_int_not_equal(amxp_expr_new(&expr, NULL), 0);
436  assert_ptr_equal(expr, NULL);
437 
438  assert_int_equal(amxp_expr_new(&expr, "10 > 20"), 0);
439  assert_ptr_not_equal(expr, NULL);
440 
441  amxp_expr_delete(&expr);
442  assert_ptr_equal(expr, NULL);
443  amxp_expr_delete(&expr);
444  amxp_expr_delete(NULL);
445 
446  assert_int_not_equal(amxp_expr_init(NULL, "20 < 10"), 0);
447  assert_int_not_equal(amxp_expr_init(&expression, NULL), 0);
448  amxp_expr_clean(NULL);
449 }
amxp_expr_status_t amxp_expr_new(amxp_expr_t **expr, const char *expression)
Allocates and initializes an expression.
amxp_expr_status_t amxp_expr_init(amxp_expr_t *expr, const char *expression)
Initializes an expression structure.
void amxp_expr_delete(amxp_expr_t **expr)
Deletes a previously allocated expression structure.

◆ test_buildf_are_strings_safe()

void test_buildf_are_strings_safe ( UNUSED void **  state)

Definition at line 825 of file test_expression.c.

825  {
826  s_testhelper_buildf(true, "192.168.1.1");
827  s_testhelper_buildf(true, "AA:BB:CC:DD:EE:FF");
828  s_testhelper_buildf(true, "Hello world!");
829  s_testhelper_buildf(true, "Whitelisted according to specs: !#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~");
830  s_testhelper_buildf(true, "");
831 
832  s_testhelper_buildf(false, "notpasword' or '' == '");
833  s_testhelper_buildf(false, "notpasword\" or \"\" == \"");
834  s_testhelper_buildf(false, "192.168.1.1\"); PasswordManager.MasterPassword=hacked; #");
835  s_testhelper_buildf(false, "192.168.1.1\\");
836  s_testhelper_buildf(false, "We ♥ UTF-8 but it is currently not whitelisted");
837 }
static void s_testhelper_buildf(bool expect_accepted, const char *string)

◆ test_buildf_expression()

void test_buildf_expression ( UNUSED void **  state)

Definition at line 760 of file test_expression.c.

760  {
761  amxp_expr_t expression;
762  const char* expr_fmt = "'Some text' in ['%s', '%s']";
763 
764  printf("Building \"%s\"\n", expr_fmt);
765  assert_int_equal(amxp_expr_buildf(&expression, expr_fmt, "some value", "other value"), amxp_expr_status_ok);
766  amxp_expr_clean(&expression);
767 }

◆ test_buildf_expression_all_whitelisted()

void test_buildf_expression_all_whitelisted ( UNUSED void **  state)

Definition at line 787 of file test_expression.c.

787  {
788  amxp_expr_t expression;
789  const char* expr_fmt = "test == '%s'";
790 
791  printf("Building \"%s\"\n", expr_fmt);
792  assert_int_equal(amxp_expr_buildf(&expression, expr_fmt, "Whitelisted according to specs:"
793  "!#$%&()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}~",
794  "other value"), amxp_expr_status_ok);
795  amxp_expr_clean(&expression);
796 }

◆ test_buildf_expression_allocate()

void test_buildf_expression_allocate ( UNUSED void **  state)

Definition at line 769 of file test_expression.c.

769  {
770  amxp_expr_t* expression = NULL;
771  const char* expr_fmt = "'Some text' in ['%s', '%s']";
772 
773  printf("Building \"%s\"\n", expr_fmt);
774  assert_int_equal(amxp_expr_buildf_new(&expression, expr_fmt, "some value", "other value"), amxp_expr_status_ok);
775  amxp_expr_delete(&expression);
776 }
amxp_expr_status_t amxp_expr_buildf_new(amxp_expr_t **expr, const char *expr_fmt,...) __attribute__((format(printf
Allocates and initializes an expression with format-string and safety checks.

◆ test_buildf_expression_invalid_args()

void test_buildf_expression_invalid_args ( UNUSED void **  state)

Definition at line 798 of file test_expression.c.

798  {
799  amxp_expr_t expression;
800  const char* bad_expr_fmt = "test == '%s']";
801  const char* good_expr_fmt = "test == '%s'";
802 
803  assert_int_not_equal(amxp_expr_buildf(&expression, bad_expr_fmt, "test", "other value"), amxp_expr_status_ok);
804  assert_int_not_equal(amxp_expr_buildf(NULL, good_expr_fmt, "test"), amxp_expr_status_ok);
805  assert_int_not_equal(amxp_expr_buildf(&expression, NULL), amxp_expr_status_ok);
806 
807  amxp_expr_clean(&expression);
808 }

◆ test_buildf_expression_invalid_value()

void test_buildf_expression_invalid_value ( UNUSED void **  state)

Definition at line 778 of file test_expression.c.

778  {
779  amxp_expr_t expression;
780  const char* expr_fmt = "password == '%s'";
781 
782  printf("Building \"%s\"\n", expr_fmt);
783  assert_int_not_equal(amxp_expr_buildf(&expression, expr_fmt, "not password' or '' == '"), amxp_expr_status_ok);
784  amxp_expr_clean(&expression);
785 }

◆ test_can_create_expression()

void test_can_create_expression ( UNUSED void **  state)

Definition at line 79 of file test_expression.c.

79  {
80  amxp_expr_t expression;
81  amxp_expr_t* expr = NULL;
82 
83  assert_int_equal(amxp_expr_init(&expression, "true"), 0);
84  assert_string_equal(expression.expression, "true");
85  amxp_expr_clean(&expression);
86  assert_ptr_equal(expression.expression, NULL);
87 
88  assert_int_equal(amxp_expr_new(&expr, "true"), 0);
89  assert_string_equal(expr->expression, "true");
90  amxp_expr_clean(expr);
91  assert_ptr_equal(expr->expression, NULL);
92  amxp_expr_delete(&expr);
93  assert_ptr_equal(expr, NULL);
94 }
char * expression

◆ test_can_evaluate_expression()

void test_can_evaluate_expression ( UNUSED void **  state)

Definition at line 96 of file test_expression.c.

96  {
97  amxp_expr_t expression;
98  amxp_expr_status_t status = 0;
99 
100  eval_t evals[] = {
101  { true, "true" },
102  { false, "false"},
103  { true, "True"},
104  { false, "False"},
105  { true, "TrUe"},
106  { false, "FaLsE"},
107  { false, "true && false" },
108  { true, "true || false" },
109  { true, "" },
110  { true, "True || False" },
111  { false, "True && False" }
112  };
113 
114  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
115  printf("Evaluating \"%s\"\n", evals[i].text);
116  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
117  assert_true(amxp_expr_eval(&expression, &status) == evals[i].result);
118  assert_int_equal(status, 0);
119  amxp_expr_clean(&expression);
120  }
121 }

◆ test_can_fetch_fields()

void test_can_fetch_fields ( UNUSED void **  state)

Definition at line 200 of file test_expression.c.

200  {
201  amxp_expr_t expression;
202  amxc_var_t data;
203  amxc_var_t* subtable;
204  amxc_var_t* subarray;
205  amxc_ts_t now;
206  amxp_expr_status_t status = 0;
207 
208  eval_t evals[] = {
209  { true, "'brown' in CSVText"},
210  { true, "TextField == \"This is text\"" },
211  { true, "MyTable.Text == \"Hello World\"" },
212  { true, ".MyTable.Number == 100" },
213  { true, "MyTable.Boolean" },
214  { true, "MyArray.0 == \"Item1\""},
215  { true, ".MyArray.1 == \"-20000\""},
216  { true, "MyArray.2"},
217  { true, "MyArray.3 > \"1970-01-01T00:00:00Z\""},
218  { true, "\"This is text\" == TextField" },
219  { true, "\"Hello World\" == MyTable.Text;" },
220  { true, "100 == MyTable.Number" },
221  { true, "\"Item1\" == MyArray.0"},
222  { true, "\"-20000\" == MyArray.1;"},
223  { true, "\"1970-01-01T00:00:00Z\" < MyArray.3"},
224  { false, "MyTable.Number > MyArray.1" },
225  { true, "MyArray.1 < MyTable.Number" },
226  { true, "TextField matches \"This.*\""},
227  { false, "TextField matches \"Not This.*\""},
228  { true, "TextField starts with 'This'"},
229  { false, "TextField starts with 'But Not This'"},
230  { true, "'fox' in CSVText"},
231  { false, "'red' in CSVText"}
232  };
233 
234  amxc_var_init(&data);
235  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
236  amxc_ts_now(&now);
237 
238  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
239  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
240  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
241  amxc_var_add_key(uint32_t, subtable, "Number", 100);
242  amxc_var_add_key(bool, subtable, "Boolean", true);
243  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
244  amxc_var_add(cstring_t, subarray, "Item1");
245  amxc_var_add(int64_t, subarray, -20000);
246  amxc_var_add(bool, subarray, true);
247  amxc_var_add(amxc_ts_t, subarray, &now);
248  amxc_var_add_key(csv_string_t, &data, "CSVText", "The,big,brown,fox,jumped");
249 
250  printf("Test data = ");
251  fflush(stdout);
252  amxc_var_dump(&data, STDOUT_FILENO);
253 
254  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
255  bool result = false;
256  printf("Evaluating \"%s\" (expecting %s - ", evals[i].text, evals[i].result ? "true" : "false");
257  fflush(stdout);
258  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
259  amxp_expr_dump_tree(&expression);
260  result = amxp_expr_eval_var(&expression, &data, &status);
261  assert_int_equal(status, 0);
262  printf("got %s)\n", result ? "true" : "false");
263  fflush(stdout);
264  assert_true(result == evals[i].result);
265  amxp_expr_clean(&expression);
266  }
267 
268  subarray = GETP_ARG(&data, "CSVText");
269  assert_int_equal(amxc_var_type_of(subarray), AMXC_VAR_ID_CSV_STRING);
270 
271  amxc_var_clean(&data);
272 }
bool amxp_expr_eval_var(amxp_expr_t *expr, const amxc_var_t *const data, amxp_expr_status_t *status)
Evaluates an expression against a composite variant.
void amxp_expr_dump_tree(amxp_expr_t *expr)
Dumps the binary tree in dot formatted text file to stdout.

◆ test_can_use_custom_field_fetcher()

void test_can_use_custom_field_fetcher ( UNUSED void **  state)

Definition at line 385 of file test_expression.c.

385  {
386  amxp_expr_t expression;
387  amxc_var_t data;
388  amxc_var_t* subtable;
389  amxc_var_t* subarray;
390  amxc_ts_t now;
391  amxp_expr_status_t status = 0;
392 
393  eval_t evals[] = {
394  { true, "available"},
395  { false, "NOT_available"},
396  { true, ".MyTable.Number > 100 || available"},
397  { true, "MyTable.Number > 100 || available"},
398  { false, ".MyTable.Number > 100 || !available"},
399  { false, "MyTable.Number > 100 || !available"},
400  { false, "{MyTable.Number} > 100 || not_available"}
401  };
402 
403  amxc_var_init(&data);
404  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
405  amxc_ts_now(&now);
406 
407  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
408  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
409  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
410  amxc_var_add_key(uint32_t, subtable, "Number", 100);
411  amxc_var_add_key(bool, subtable, "Boolean", true);
412  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
413  amxc_var_add(cstring_t, subarray, "Item1");
414  amxc_var_add(int64_t, subarray, -20000);
415  amxc_var_add(bool, subarray, true);
416  amxc_var_add(amxc_ts_t, subarray, &now);
417 
418  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
419  printf("Evaluating \"%s\"\n", evals[i].text);
420  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
421  assert_true(amxp_expr_evaluate(&expression, custom_field_fetcher, &data, &status) == evals[i].result);
422  assert_int_equal(status, 0);
423  amxp_expr_clean(&expression);
424  fflush(stdout);
425  }
426 
427  amxc_var_clean(&data);
428 }
bool amxp_expr_evaluate(amxp_expr_t *expr, amxp_expr_get_field_t fn, void *priv, amxp_expr_status_t *status)
Evaluates an expression.
static amxp_expr_status_t custom_field_fetcher(UNUSED amxp_expr_t *expr, amxc_var_t *value, const char *path, void *priv)

◆ test_comperators_are_correct()

void test_comperators_are_correct ( UNUSED void **  state)

Definition at line 154 of file test_expression.c.

154  {
155  amxp_expr_t expression;
156  amxp_expr_status_t status = 0;
157 
158  eval_t evals[] = {
159  { true, "10 > 0" },
160  { false, "10 > 10" },
161  { false, "10 < 0"},
162  { false, "10 < 10"},
163  { true, "10 >= 10" },
164  { true, "10 <= 10" },
165  { true, "\"bagpipe\" >= \"b\"" },
166  { true, "\"bagpipe\" >= \"bagpipe\""},
167  { false, "\"bagpipe\" <= \"aardvark\"" },
168  { true, "\"bagpipe\" >= \"aardvark\""},
169  { true, "\"This is some tekst\" != \"Diferent & Also, Text\""},
170  { true, "'Text' in ['bagpipe', 'aardvark', 'Text', 10]"},
171  { false, "'rabbit' in ['bagpipe', 'aardvark', 'Text', 10]"},
172  { true, "'the rabbit went into the rabbit hole' starts with 'the rabbit'"},
173  { false, "'Alice went into the rabbit hole' starts with 'the rabbit'"},
174  { true, "'the rabbit went into the rabbit hole' starts\t with 'the rabbit'"},
175  { true, "'rabbit' in 'the rabbit went into the rabbit hole'"},
176  { true, "'hole' in 'the rabbit went into the rabbit hole'"},
177  { false, "'Alice' in 'the rabbit went into the rabbit hole'"},
178  { false, "'Alice' in 'Al'"},
179  { true, "'Alice' starts with ['Al', 'Ra']" },
180  { true, "'Rabbit' starts with ['Al', 'Ra']" },
181  { true, "is_empty([])"},
182  { false, "is_empty([1,2])"},
183  { true, "'the rabbit went into the rabbit hole' ends with 'rabbit hole'"},
184  { false, "'the rabbit went into the rabbit hole' ends with 'rabbit pit'"},
185  { false, "'the rabbit' ends with 'very long string that does not crash'"},
186  { true, "'Rabbit' ends with ['ce', 'it']" }
187  };
188 
189  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
190  printf("Evaluating \"%s\"\n", evals[i].text);
191  fflush(stdout);
192  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
193  assert_true(amxp_expr_eval(&expression, &status) == evals[i].result);
194  assert_int_equal(status, 0);
195  amxp_expr_dump_tree(&expression);
196  amxp_expr_clean(&expression);
197  }
198 }

◆ test_contains()

void test_contains ( UNUSED void **  state)

Definition at line 587 of file test_expression.c.

587  {
588  amxp_expr_t expression;
589  amxc_var_t data;
590  amxc_var_t* subtable;
591  amxc_var_t* subarray;
592  amxc_ts_t now;
593  amxp_expr_status_t status = 0;
594 
595  eval_t evals[] = {
596  { true, "contains('MyTable.Text')"},
597  { false, "contains('MyTable.Text.Extra')"},
598  { true, "contains('MyArray.0')"},
599  { false, "contains('MyArray.0.Extra')"},
600  { false, "contains('MyArray.99')"},
601  { true, "contains('Test', 'MyArray.0')"},
602  { false, "contains('MyArray.99', 'MyTable.Text.Extra', 'MyArray.0.Extra')"},
603  };
604 
605  amxc_var_init(&data);
606  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
607  amxc_ts_now(&now);
608 
609  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
610  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
611  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
612  amxc_var_add_key(uint32_t, subtable, "Number", 100);
613  amxc_var_add_key(bool, subtable, "Boolean", true);
614  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
615  amxc_var_add(cstring_t, subarray, "Item1");
616  amxc_var_add(int64_t, subarray, -20000);
617  amxc_var_add(bool, subarray, true);
618  amxc_var_add(amxc_ts_t, subarray, &now);
619 
620  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
621  printf("Evaluating \"%s\"\n", evals[i].text);
622  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
623  assert_true(amxp_expr_eval_var(&expression, &data, &status) == evals[i].result);
624  assert_int_equal(status, 0);
625  amxp_expr_clean(&expression);
626  }
627 
628  amxc_var_clean(&data);
629 }

◆ test_contains_invalid_usage()

void test_contains_invalid_usage ( UNUSED void **  state)

Definition at line 682 of file test_expression.c.

682  {
683  amxp_expr_t expression;
684  amxp_expr_status_t status = 0;
685  amxc_var_t data;
686 
687  amxc_var_init(&data);
688  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
689 
690  assert_int_equal(amxp_expr_init(&expression, "contains()"), 0);
691  assert_false(amxp_expr_evaluate(&expression, NULL, &data, &status));
692  assert_int_equal(status, 0);
693  amxp_expr_clean(&expression);
694 
695  assert_int_equal(amxp_expr_init(&expression, "contains(100)"), 0);
696  assert_false(amxp_expr_evaluate(&expression, NULL, &data, &status));
697  assert_int_equal(status, 0);
698  amxp_expr_clean(&expression);
699 
700  amxc_var_clean(&data);
701 }

◆ test_contains_no_data()

void test_contains_no_data ( UNUSED void **  state)

Definition at line 661 of file test_expression.c.

661  {
662  amxp_expr_t expression;
663  amxp_expr_status_t status = 0;
664 
665  eval_t evals[] = {
666  { false, "contains('MyTable.Text')"},
667  { false, "contains('MyTable.Text.Extra')"},
668  { false, "contains('MyArray.0')"},
669  { false, "contains('MyArray.0.Extra')"},
670  { false, "contains('MyArray.99')"},
671  };
672 
673  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
674  printf("Evaluating \"%s\"\n", evals[i].text);
675  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
676  assert_true(amxp_expr_evaluate(&expression, NULL, NULL, &status) == evals[i].result);
677  assert_int_equal(status, 0);
678  amxp_expr_clean(&expression);
679  }
680 }

◆ test_contains_no_get_field()

void test_contains_no_get_field ( UNUSED void **  state)

Definition at line 631 of file test_expression.c.

631  {
632  amxp_expr_t expression;
633  amxp_expr_status_t status = 0;
634  amxc_var_t data;
635  amxc_var_t* subtable = NULL;
636 
637  eval_t evals[] = {
638  { false, "contains('MyTable.Text')"},
639  { false, "contains('MyTable.Text.Extra')"},
640  { false, "contains('MyArray.0')"},
641  { false, "contains('MyArray.0.Extra')"},
642  { false, "contains('MyArray.99')"},
643  };
644 
645  amxc_var_init(&data);
646  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
647  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
648  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
649 
650  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
651  printf("Evaluating \"%s\"\n", evals[i].text);
652  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
653  assert_true(amxp_expr_evaluate(&expression, NULL, &data, &status) == evals[i].result);
654  assert_int_equal(status, 0);
655  amxp_expr_clean(&expression);
656  }
657 
658  amxc_var_clean(&data);
659 }

◆ test_expression_with_invalid_list_does_not_memory_leak()

void test_expression_with_invalid_list_does_not_memory_leak ( UNUSED void **  state)

Definition at line 868 of file test_expression.c.

◆ test_fails_with_invalid_regexp()

void test_fails_with_invalid_regexp ( UNUSED void **  state)

Definition at line 495 of file test_expression.c.

495  {
496  amxp_expr_t expression;
497  amxc_var_t data;
498  amxc_var_t* subtable;
499  amxc_var_t* subarray;
500  amxc_ts_t now;
501 
502  amxc_var_init(&data);
503  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
504  amxc_ts_now(&now);
505 
506  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
507  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
508  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
509  amxc_var_add_key(uint32_t, subtable, "Number", 100);
510  amxc_var_add_key(bool, subtable, "Boolean", true);
511  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
512  amxc_var_add(cstring_t, subarray, "Item1");
513  amxc_var_add(int64_t, subarray, -20000);
514  amxc_var_add(bool, subarray, true);
515  amxc_var_add(amxc_ts_t, subarray, &now);
516 
517  assert_int_not_equal(amxp_expr_init(&expression, "MyTable.Text matches \"[(adadasd.[\""), 0);
518 
519  amxc_var_clean(&data);
520 }

◆ test_flag_expressions()

void test_flag_expressions ( UNUSED void **  state)

Definition at line 703 of file test_expression.c.

703  {
704  amxp_expr_t expression;
705  amxp_expr_status_t status = 0;
706  amxc_set_t set;
707 
708  amxc_set_init(&set, false);
709  amxc_set_parse(&set, "bridge ipv6 global lan interface");
710 
711  assert_int_equal(amxp_expr_init(&expression, "ipv4 || (ipv6 && global)"), 0);
712  assert_true(amxp_expr_eval_set(&expression, &set, &status));
713 
714  amxc_set_remove_flag(&set, "ipv6");
715 
716  assert_false(amxp_expr_eval_set(&expression, &set, &status));
717 
718  amxc_set_clean(&set);
719  amxp_expr_clean(&expression);
720 }
bool amxp_expr_eval_set(amxp_expr_t *expr, const amxc_set_t *const data, amxp_expr_status_t *status)
Evaluates an expression against a set.

◆ test_flag_expressions_no_operators()

void test_flag_expressions_no_operators ( UNUSED void **  state)

Definition at line 722 of file test_expression.c.

722  {
723  amxp_expr_t expression;
724  amxp_expr_status_t status = 0;
725  amxc_set_t set;
726 
727  amxc_set_init(&set, false);
728  amxc_set_parse(&set, "bridge ipv6 global lan interface");
729 
730  assert_int_equal(amxp_expr_init(&expression, "ipv6 global"), 0);
731  assert_true(amxp_expr_eval_set(&expression, &set, &status));
732 
733  amxc_set_remove_flag(&set, "ipv6");
734 
735  assert_false(amxp_expr_eval_set(&expression, &set, &status));
736 
737  amxc_set_clean(&set);
738  amxp_expr_clean(&expression);
739 }

◆ test_get_string()

void test_get_string ( UNUSED void **  state)

Definition at line 839 of file test_expression.c.

839  {
840  const char* expr_string = NULL;
841 
842  // GIVEN an expression
843  amxp_expr_t expr;
844  amxp_expr_buildf(&expr, "username == '%s'", "Alice");
845 
846  // WHEN retrieiving its string representation
847  expr_string = amxp_expr_get_string(&expr);
848 
849  // THEN the string representation is returned
850  assert_string_equal("username == 'Alice'", expr_string);
851 
852  amxp_expr_clean(&expr);
853 }
const char * amxp_expr_get_string(amxp_expr_t *expr)
Returns the string representation of the given expression.

◆ test_get_string_null()

void test_get_string_null ( UNUSED void **  state)

Definition at line 855 of file test_expression.c.

855  {
856  const char* expr_string = NULL;
857 
858  // GIVEN a NULL expression
859  amxp_expr_t* expr = NULL;
860 
861  // WHEN retrieving its string representation
862  expr_string = amxp_expr_get_string(expr);
863 
864  // THEN NULL is returned
865  assert_null(expr_string);
866 }

◆ test_in_operators()

void test_in_operators ( UNUSED void **  state)

Definition at line 741 of file test_expression.c.

741  {
742  amxp_expr_t expression;
743  amxp_expr_status_t status = 0;
744  eval_t evals[] = {
745  { true, "'Some text' in ['Some text', 'other value']"},
746  { false, "'Some text' in ['some value', 'other value']"},
747  { true, "['Some text', 'other value'] ~= 'Some text'"},
748  { false, "['some value', 'other value'] ~= 'Some text'"},
749  };
750 
751  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
752  printf("Evaluating \"%s\"\n", evals[i].text);
753  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
754  assert_true(amxp_expr_evaluate(&expression, NULL, NULL, &status) == evals[i].result);
755  assert_int_equal(status, 0);
756  amxp_expr_clean(&expression);
757  }
758 }

◆ test_invalid_field_names()

void test_invalid_field_names ( UNUSED void **  state)

Definition at line 274 of file test_expression.c.

274  {
275  amxp_expr_t expression;
276  amxc_var_t data;
277  amxc_var_t* subtable;
278  amxc_var_t* subarray;
279  amxc_ts_t now;
280  amxp_expr_status_t status = 0;
281 
282  eval_t evals[] = {
283  { false, "MyArray.NotExisting == \"Item1\""},
284  { false, "MyTable.99"},
285  { false, "\"TEXT\" matches Not.Existing.Field.0"},
286  };
287 
288  amxc_var_init(&data);
289  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
290  amxc_ts_now(&now);
291 
292  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
293  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
294  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
295  amxc_var_add_key(uint32_t, subtable, "Number", 100);
296  amxc_var_add_key(bool, subtable, "Boolean", true);
297  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
298  amxc_var_add(cstring_t, subarray, "Item1");
299  amxc_var_add(int64_t, subarray, -20000);
300  amxc_var_add(bool, subarray, true);
301  amxc_var_add(amxc_ts_t, subarray, &now);
302  amxc_var_dump(&data, STDOUT_FILENO);
303 
304  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
305  printf("Evaluating \"%s\"\n", evals[i].text);
306  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
307  assert_false(amxp_expr_eval_var(&expression, &data, &status));
308  assert_int_not_equal(status, 0);
309  amxp_expr_clean(&expression);
310  fflush(stdout);
311  }
312 
313  amxc_var_clean(&data);
314 }

◆ test_invalid_syntax()

void test_invalid_syntax ( UNUSED void **  state)

Definition at line 316 of file test_expression.c.

316  {
317  amxp_expr_t expression;
318  amxp_expr_t* expr = NULL;
319  eval_t evals[] = {
320  { false, "Hello <> Goobey"},
321  { false, "\"Text\"Field @ Hello World"},
322  { false, "100"},
323  { false, "['a', 'b', 'c'] in 'abc'"},
324  { false, "'Alice' in 1024"}
325  };
326 
327  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
328  printf("Evaluating \"%s\"\n", evals[i].text);
329  assert_int_not_equal(amxp_expr_init(&expression, evals[i].text), 0);
330  fflush(stdout);
331  }
332 
333  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
334  assert_int_not_equal(amxp_expr_new(&expr, evals[i].text), 0);
335  assert_ptr_equal(expr, NULL);
336  fflush(stdout);
337  }
338 }

◆ test_invalid_value_types()

void test_invalid_value_types ( UNUSED void **  state)

Definition at line 340 of file test_expression.c.

340  {
341  amxp_expr_t expression;
342  amxp_expr_t* expr = NULL;
343 
344  eval_t evals[] = {
345  { false, "'Some text' == ['Some', 'text']"},
346  { false, "[1,2,3,4] > 10"},
347  { false, "[1,2,3,4] matches ['Part1', 'Part2']"}
348  };
349 
350  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
351  assert_int_equal(amxp_expr_init(&expression, evals[i].text), amxp_expr_status_invalid_value);
352  fflush(stdout);
353  }
354 
355  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
356  assert_int_equal(amxp_expr_new(&expr, evals[i].text), amxp_expr_status_invalid_value);
357  assert_ptr_equal(expr, NULL);
358  fflush(stdout);
359  }
360 }
@ amxp_expr_status_invalid_value

◆ test_is_empty_function()

void test_is_empty_function ( UNUSED void **  state)

Definition at line 522 of file test_expression.c.

522  {
523  amxp_expr_t expression;
524  amxp_expr_status_t status = 0;
525 
526  eval_t evals[] = {
527  { true, "is_empty([])"},
528  { false, "is_empty([1,2])"}
529  };
530 
531  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
532  printf("Evaluating \"%s\"\n", evals[i].text);
533  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
534  assert_true(amxp_expr_eval(&expression, &status) == evals[i].result);
535  assert_int_equal(status, 0);
536  amxp_expr_clean(&expression);
537  }
538 }

◆ test_is_empty_function_with_var()

void test_is_empty_function_with_var ( UNUSED void **  state)

Definition at line 540 of file test_expression.c.

540  {
541  amxp_expr_t expression;
542  amxp_expr_status_t status = 0;
543  amxc_var_t data;
544  amxc_var_t* subtable;
545  amxc_var_t* subarray;
546  amxc_ts_t now;
547 
548  eval_t evals[] = {
549  { false, "is_empty({MyTable})"},
550  { false, "is_empty({MyArray})"},
551  { true, "is_empty({EmptyArray})"},
552  { true, "is_empty({EmptyTable})"},
553  { true, "is_empty({MyTable.NotExisting})"},
554  { true, "is_empty({MyArray.99})"},
555  { false, "is_empty({})"},
556  { true, "is_empty()"},
557  };
558 
559  amxc_var_init(&data);
560  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
561  amxc_ts_now(&now);
562 
563  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
564  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
565  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
566  amxc_var_add_key(uint32_t, subtable, "Number", 100);
567  amxc_var_add_key(bool, subtable, "Boolean", true);
568  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
569  amxc_var_add(cstring_t, subarray, "Item1");
570  amxc_var_add(int64_t, subarray, -20000);
571  amxc_var_add(bool, subarray, true);
572  amxc_var_add(amxc_ts_t, subarray, &now);
573  amxc_var_add_key(amxc_llist_t, &data, "EmptyArray", NULL);
574  amxc_var_add_key(amxc_htable_t, &data, "EmptyTable", NULL);
575 
576  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
577  printf("Evaluating \"%s\"\n", evals[i].text);
578  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
579  assert_true(amxp_expr_eval_var(&expression, &data, &status) == evals[i].result);
580  assert_int_equal(status, 0);
581  amxp_expr_clean(&expression);
582  }
583 
584  amxc_var_clean(&data);
585 }

◆ test_precedence_is_respected()

void test_precedence_is_respected ( UNUSED void **  state)

Definition at line 123 of file test_expression.c.

123  {
124  amxp_expr_t expression;
125  amxp_expr_status_t status = 0;
126 
127  eval_t evals[] = {
128  { true, "true || false && true" },
129  { true, "(true || false) && true"},
130  { false, "false || true && false" },
131  { false, "(false || true) && false" },
132  { false, "false || false && false" },
133  { false, "true && false || true && false"},
134  { false, "false || false && true || false"},
135  { true, "!(false || false) && true || false"},
136  { true, "!false && true"},
137  { true, "!false || false"},
138  { true, "!false || true"},
139  { false, "!(false || true)"},
140  { true, "true || false && false || false" },
141  { false, "(true || false) && (false || false)" },
142  };
143 
144  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
145  printf("Evaluating \"%s\"\n", evals[i].text);
146  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
147  assert_true(amxp_expr_eval(&expression, &status) == evals[i].result);
148  assert_int_equal(status, 0);
149  amxp_expr_dump_tree(&expression);
150  amxp_expr_clean(&expression);
151  }
152 }

◆ test_selects_first_in_first_existing()

void test_selects_first_in_first_existing ( UNUSED void **  state)

Definition at line 451 of file test_expression.c.

451  {
452  amxp_expr_t expression;
453  amxc_var_t data;
454  amxc_var_t* subtable;
455  amxc_var_t* subarray;
456  amxc_ts_t now;
457  amxp_expr_status_t status = 0;
458 
459  eval_t evals[] = {
460  { false, "first_existing(MyTable.Text, .MyArray.0) == \"Item1\""},
461  { true, "first_existing(MyTable.Text, MyArray.0) == \"Hello World\""},
462  { true, "first_existing(.MyTable.NotExistingText, MyArray.0) == \"Item1\""},
463  { true, "first_existing(.MyTable.NotExistingText, MyArray.99, FakeItem.0.NotExisting, 'Item1') == \"Item1\""},
464  { false, "first_existing(.MyTable.NotExistingText, MyArray.99, FakeItem.0.NotExisting, MyTable.Text) == \"Item1\""},
465  };
466 
467  amxc_var_init(&data);
468  amxc_var_set_type(&data, AMXC_VAR_ID_HTABLE);
469  amxc_ts_now(&now);
470 
471  amxc_var_add_key(cstring_t, &data, "TextField", "This is text");
472  subtable = amxc_var_add_key(amxc_htable_t, &data, "MyTable", NULL);
473  amxc_var_add_key(cstring_t, subtable, "Text", "Hello World");
474  amxc_var_add_key(uint32_t, subtable, "Number", 100);
475  amxc_var_add_key(bool, subtable, "Boolean", true);
476  subarray = amxc_var_add_key(amxc_llist_t, &data, "MyArray", NULL);
477  amxc_var_add(cstring_t, subarray, "Item1");
478  amxc_var_add(int64_t, subarray, -20000);
479  amxc_var_add(bool, subarray, true);
480  amxc_var_add(amxc_ts_t, subarray, &now);
481  amxc_var_dump(&data, 1);
482 
483  for(uint32_t i = 0; i < sizeof(evals) / sizeof(evals[0]); i++) {
484  printf("Evaluating \"%s\"\n", evals[i].text);
485  assert_int_equal(amxp_expr_init(&expression, evals[i].text), 0);
486  assert_true(amxp_expr_eval_var(&expression, &data, &status) == evals[i].result);
487  assert_int_equal(status, 0);
488  amxp_expr_dump_tree(&expression);
489  amxp_expr_clean(&expression);
490  }
491 
492  amxc_var_clean(&data);
493 }