summaryrefslogtreecommitdiff
path: root/cras/src/tests/expr_unittest.cc
diff options
context:
space:
mode:
authorChih-Chung Chang <chihchung@chromium.org>2012-11-13 19:27:44 +0800
committerGerrit <chrome-bot@google.com>2012-12-05 23:46:56 -0800
commit5d3c38538845869fb38cde16ec12e96245bc996f (patch)
tree3522b8d2e2c8028f0017c1a533c201809a742d07 /cras/src/tests/expr_unittest.cc
parent0ffebbda6ce1bd2f33bee5a2f4e0f78c1317939a (diff)
downloadadhd-5d3c38538845869fb38cde16ec12e96245bc996f.tar.gz
CRAS: DSP - Add expression parsing and evaluation functions and unit tests.
The expression facility will be used to determine whether a plugin needs to be enabled. For example, if we have this line in the ini file for the DRC plugin: disable=(or disable_drc (equal? output_device "HDMI")) then the plugin will be disabled when this expression is evaluated to true (that is, when the variable "disable_drc" is true or the variable "output_device" equals to "HDMI". The expression syntax generally follows the syntax in the Scheme programming language, but we only use a (very small) subset of it. BUG=chromium-os:36300 TEST=make check Change-Id: If57f4f0ba2863ef5ed2d7592d3563a6dd5bee05d Reviewed-on: https://gerrit.chromium.org/gerrit/38379 Commit-Ready: Chih-Chung Chang <chihchung@chromium.org> Reviewed-by: Chih-Chung Chang <chihchung@chromium.org> Tested-by: Chih-Chung Chang <chihchung@chromium.org>
Diffstat (limited to 'cras/src/tests/expr_unittest.cc')
-rw-r--r--cras/src/tests/expr_unittest.cc245
1 files changed, 245 insertions, 0 deletions
diff --git a/cras/src/tests/expr_unittest.cc b/cras/src/tests/expr_unittest.cc
new file mode 100644
index 00000000..07dd98a9
--- /dev/null
+++ b/cras/src/tests/expr_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "cras_expr.h"
+
+namespace {
+
+TEST(ExprTest, UnparsibleExpression) {
+ struct cras_expr_expression *expr;
+
+ /* un-parsable input */
+ expr = cras_expr_expression_parse("#");
+ EXPECT_EQ(NULL, expr);
+
+ expr = cras_expr_expression_parse(NULL);
+ EXPECT_EQ(NULL, expr);
+
+ cras_expr_expression_free(expr);
+}
+
+TEST(ExprTest, LiteralExpression) {
+ struct cras_expr_expression *expr;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+ struct cras_expr_env env = CRAS_EXPR_ENV_INIT;
+ int integer = 0;
+
+ /* parse integer literal */
+ expr = cras_expr_expression_parse(" -2");
+ EXPECT_EQ(EXPR_TYPE_LITERAL, expr->type);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_INT, expr->u.literal.type);
+ EXPECT_EQ(-2, expr->u.literal.u.integer);
+
+ /* evaluate integer literal */
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_INT, value.type);
+ EXPECT_EQ(-2, value.u.integer);
+
+ EXPECT_EQ(0, cras_expr_expression_eval_int(expr, &env, &integer));
+ EXPECT_EQ(-2, integer);
+ cras_expr_expression_free(expr);
+
+ /* parse string literal */
+ expr = cras_expr_expression_parse("\"hello\" ");
+ EXPECT_EQ(EXPR_TYPE_LITERAL, expr->type);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_STRING, expr->u.literal.type);
+ EXPECT_STREQ("hello", expr->u.literal.u.string);
+
+ /* evaluate string literal */
+ cras_expr_expression_eval(expr, &env, &value);
+ ASSERT_EQ(CRAS_EXPR_VALUE_TYPE_STRING, value.type);
+ EXPECT_STREQ("hello", value.u.string);
+
+ cras_expr_value_free(&value);
+ cras_expr_expression_free(expr);
+ cras_expr_env_free(&env);
+}
+
+TEST(ExprTest, Variable) {
+ struct cras_expr_expression *expr;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+ struct cras_expr_env env = CRAS_EXPR_ENV_INIT;
+ int integer = 0;
+
+ /* parse variable */
+ expr = cras_expr_expression_parse("a");
+ ASSERT_EQ(EXPR_TYPE_VARIABLE, expr->type);
+ EXPECT_STREQ("a", expr->u.variable);
+
+ /* evaluate variable (undefined now) */
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_NONE, value.type);
+
+ /* undefined variable */
+ EXPECT_EQ(-1, cras_expr_expression_eval_int(expr, &env, &integer));
+
+ /* now define a variable with integer value 2 */
+ cras_expr_env_set_variable_integer(&env, "a", 2);
+
+ /* re-evaluate the variable */
+ EXPECT_EQ(0, cras_expr_expression_eval_int(expr, &env, &integer));
+ EXPECT_EQ(2, integer);
+
+ cras_expr_value_free(&value);
+ cras_expr_expression_free(expr);
+ cras_expr_env_free(&env);
+}
+
+TEST(ExprTest, Compound) {
+ struct cras_expr_expression *expr, *expr1, *expr2;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+ struct cras_expr_env env = CRAS_EXPR_ENV_INIT;
+
+ /* parse empty compound expression */
+ expr = cras_expr_expression_parse("()");
+ ASSERT_EQ(EXPR_TYPE_COMPOUND, expr->type);
+ EXPECT_EQ(0, ARRAY_COUNT(&expr->u.children));
+
+ /* evaluate empty compound expression */
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_NONE, value.type);
+ cras_expr_expression_free(expr);
+
+ /* parse non-empty compound expression */
+ expr = cras_expr_expression_parse("(foo bar)");
+ ASSERT_EQ(EXPR_TYPE_COMPOUND, expr->type);
+ EXPECT_EQ(2, ARRAY_COUNT(&expr->u.children));
+
+ /* evaluate non-empty compound expression */
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_NONE, value.type);
+ cras_expr_expression_free(expr);
+
+ /* parse nested compound expression */
+ expr = cras_expr_expression_parse("((foo 3)bar )");
+ ASSERT_EQ(EXPR_TYPE_COMPOUND, expr->type);
+ ASSERT_EQ(2, ARRAY_COUNT(&expr->u.children));
+
+ expr1 = *ARRAY_ELEMENT(&expr->u.children, 0);
+ ASSERT_EQ(EXPR_TYPE_COMPOUND, expr1->type);
+ ASSERT_EQ(2, ARRAY_COUNT(&expr1->u.children));
+
+ expr2 = *ARRAY_ELEMENT(&expr1->u.children, 1);
+ ASSERT_EQ(EXPR_TYPE_LITERAL, expr2->type);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_INT, expr2->u.literal.type);
+ EXPECT_EQ(3, expr2->u.literal.u.integer);
+
+ /* evaluate nested compound expression */
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_NONE, value.type);
+ cras_expr_expression_free(expr);
+
+ cras_expr_value_free(&value);
+ cras_expr_env_free(&env);
+}
+
+TEST(ExprTest, Environment) {
+ struct cras_expr_expression *expr;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+ struct cras_expr_env env1 = CRAS_EXPR_ENV_INIT;
+ struct cras_expr_env env2 = CRAS_EXPR_ENV_INIT;
+ int integer = 0;
+ char boolean = 0;
+
+ /* parse variable */
+ expr = cras_expr_expression_parse("baz");
+
+ /* put baz=4 into env1 */
+ cras_expr_env_set_variable_integer(&env1, "baz", 4);
+
+ /* evaluate expr against env1 and env2 */
+ EXPECT_EQ(0, cras_expr_expression_eval_int(expr, &env1, &integer));
+ EXPECT_EQ(4, integer);
+ EXPECT_EQ(-1, cras_expr_expression_eval_int(expr, &env2, &integer));
+
+ /* put baz=5 into env2 */
+ cras_expr_env_set_variable_integer(&env2, "baz", 5);
+
+ /* evaluate again */
+ EXPECT_EQ(0, cras_expr_expression_eval_int(expr, &env1, &integer));
+ EXPECT_EQ(4, integer);
+ EXPECT_EQ(0, cras_expr_expression_eval_int(expr, &env2, &integer));
+ EXPECT_EQ(5, integer);
+
+ /* an integer is not a boolean */
+ EXPECT_EQ(-1, cras_expr_expression_eval_boolean(expr, &env2, &boolean));
+
+ cras_expr_value_free(&value);
+ cras_expr_expression_free(expr);
+ cras_expr_env_free(&env1);
+ cras_expr_env_free(&env2);
+}
+
+static void expect_int(int expected, const char *str, struct cras_expr_env *env)
+{
+ struct cras_expr_expression *expr;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+
+ expr = cras_expr_expression_parse(str);
+ cras_expr_expression_eval(expr, env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_INT, value.type);
+ EXPECT_EQ(expected, value.u.integer);
+ cras_expr_expression_free(expr);
+}
+
+static void expect_boolean(char expected, const char *str,
+ struct cras_expr_env *env)
+{
+ struct cras_expr_expression *expr;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+
+ expr = cras_expr_expression_parse(str);
+ cras_expr_expression_eval(expr, env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_BOOLEAN, value.type);
+ EXPECT_EQ(expected, value.u.boolean);
+ cras_expr_expression_free(expr);
+}
+
+TEST(ExprTest, Builtin) {
+ struct cras_expr_expression *expr;
+ struct cras_expr_value value = CRAS_EXPR_VALUE_INIT;
+ struct cras_expr_env env = CRAS_EXPR_ENV_INIT;
+
+ cras_expr_env_install_builtins(&env);
+
+ /* parse variable */
+ expr = cras_expr_expression_parse("or");
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_FUNCTION, value.type);
+ cras_expr_expression_free(expr);
+
+ /* test builtin functions */
+ expect_boolean(1, "(and)", &env);
+ expect_int(3, "(and 1 2 3)", &env);
+ expect_boolean(0, "(and #f 4)", &env);
+ expect_boolean(0, "(or)", &env);
+ expect_boolean(1, "(or #t)", &env);
+ expect_boolean(0, "(or #f #f)", &env);
+ expect_int(2, "(or #f #f 2)", &env);
+ expect_int(3, "(or #f (or 3))", &env);
+ expect_boolean(0, "(equal? \"hello\" 3)", &env);
+ expect_boolean(1, "(equal? \"hello\" \"hello\")", &env);
+
+ /* a more complex example a="hello" b="world"*/
+ expr = cras_expr_expression_parse("(or (equal? \"test\" a) b)");
+ cras_expr_env_set_variable_string(&env, "a", "hello");
+ cras_expr_env_set_variable_string(&env, "b", "world");
+
+ cras_expr_expression_eval(expr, &env, &value);
+ EXPECT_EQ(CRAS_EXPR_VALUE_TYPE_STRING, value.type);
+ EXPECT_STREQ("world", value.u.string);
+ cras_expr_expression_free(expr);
+
+ cras_expr_value_free(&value);
+ cras_expr_env_free(&env);
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}