1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2017 Cyril Hrubis <chrubis@suse.cz>
4 */
5
6/*
7 * Basic unit test for the bolean expression parser and evaluator.
8 */
9
10#include <string.h>
11#include <stdio.h>
12#include "tst_test.h"
13#include "tst_bool_expr.h"
14
15static int a, b, c;
16
17static int map(struct tst_expr_tok *var)
18{
19	if (!strncmp(var->tok, "A", var->tok_len))
20		return a;
21
22	if (!strncmp(var->tok, "B", var->tok_len))
23		return b;
24
25	if (!strncmp(var->tok, "C", var->tok_len))
26		return c;
27
28	if (!strncmp(var->tok, "True", var->tok_len))
29		return 1;
30
31	if (!strncmp(var->tok, "False", var->tok_len))
32		return 0;
33
34	return -1;
35}
36
37static void parse_fail(const char *expr)
38{
39	struct tst_expr *res;
40
41	tst_res(TINFO, "Parsing '%s'", expr);
42
43	res = tst_bool_expr_parse(expr);
44
45	if (res) {
46		printf("In RPN: ");
47		tst_bool_expr_print(stdout, res);
48		printf("\n");
49		tst_bool_expr_free(res);
50		tst_res(TFAIL, "Expression was parsed");
51	} else {
52		tst_res(TPASS, "Parser returned an error");
53	}
54}
55
56static void do_eval_test(const char *expr_str, int set_a, int set_b, int set_c, int exp_res)
57{
58	struct tst_expr *expr;
59	int res;
60
61	a = set_a;
62	b = set_b;
63	c = set_c;
64
65	tst_res(TINFO, "'%s' A=%i B=%i C=%i == %i", expr_str, a, b, c, exp_res);
66
67	expr = tst_bool_expr_parse(expr_str);
68
69	if (!expr) {
70		tst_res(TFAIL, "Parser returned error");
71		return;
72	}
73
74	printf("In RPN: ");
75	tst_bool_expr_print(stdout, expr);
76	printf("\n");
77
78	res = tst_bool_expr_eval(expr, map);
79
80	if (res == exp_res)
81		tst_res(TPASS, "Got %i", res);
82	else
83		tst_res(TFAIL, "Got %i", res);
84
85	tst_bool_expr_free(expr);
86}
87
88static void do_test(void)
89{
90	do_eval_test("(A | B) & !!C", 0, 0, 0, 0);
91	do_eval_test("(A | B) & !!C", 1, 0, 1, 1);
92	do_eval_test("!A & B", 1, 0, 0, 0);
93	do_eval_test("!A & B", 0, 1, 0, 1);
94	do_eval_test("A & !B", 1, 0, 0, 1);
95	do_eval_test("!!A & !!B", 0, 1, 0, 0);
96	do_eval_test("!!A & !!B", 1, 1, 0, 1);
97	do_eval_test("!(A & B) & C", 1, 1, 0, 0);
98	do_eval_test("A & (B | C)", 1, 1, 0, 1);
99	do_eval_test("A & B | C", 1, 1, 0, 1);
100	do_eval_test("((((A)))&(B))", 1, 1, 0, 1);
101	do_eval_test("   A  \t", 0, 0, 0, 0);
102	do_eval_test("False & A", 1, 0, 0, 0);
103	do_eval_test("! Undefined", 0, 0, 0, -1);
104
105	do_eval_test("\"(none)\"", 0, 0, 0, -1);
106	do_eval_test("\"(none)\" & \" \"", 0, 0, 0, -1);
107
108	parse_fail("A!");
109	parse_fail("A &");
110	parse_fail("A B");
111	parse_fail("A ) B");
112	parse_fail("A ( B");
113	parse_fail("A ( B )");
114	parse_fail("A |");
115	parse_fail("A ! B");
116	parse_fail("A! & B");
117	parse_fail("A & | B");
118	parse_fail("A & (B |)");
119	parse_fail("A & ( | B)");
120	parse_fail("A & B &");
121	parse_fail("((A )");
122	parse_fail("& A");
123	parse_fail("! &");
124	parse_fail(")");
125	parse_fail("| A");
126	parse_fail("");
127}
128
129static struct tst_test test = {
130	.test_all = do_test,
131};
132