edify: Move the testcases to gtest.
Now they live in tests/component/edify_test.cpp.
Also rename edify/main.cpp to edify/edify_parser.cpp. It becomes a
host-side debugging tool that validates the input edify script. However,
it supports edify builtin functions only and doesn't recognize the ones
defined via updater.
Test: recovery_component_test passes on device.
Change-Id: Ib94a787bf15098a9cc078d256b6a6dc96ff12b2e
diff --git a/edify/Android.mk b/edify/Android.mk
index b397045..d8058c1 100644
--- a/edify/Android.mk
+++ b/edify/Android.mk
@@ -1,24 +1,36 @@
# Copyright 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
LOCAL_PATH := $(call my-dir)
edify_src_files := \
- lexer.ll \
- parser.yy \
- expr.cpp
+ lexer.ll \
+ parser.yy \
+ expr.cpp
#
-# Build the host-side command line tool
+# Build the host-side command line tool (host executable)
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- $(edify_src_files) \
- main.cpp
+ $(edify_src_files) \
+ edify_parser.cpp
LOCAL_CFLAGS := -Werror
LOCAL_CPPFLAGS := -g -O0
-LOCAL_MODULE := edify
+LOCAL_MODULE := edify_parser
LOCAL_YACCFLAGS := -v
LOCAL_CPPFLAGS += -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-deprecated-register
@@ -29,7 +41,7 @@
include $(BUILD_HOST_EXECUTABLE)
#
-# Build the device-side library
+# Build the device-side library (static library)
#
include $(CLEAR_VARS)
diff --git a/edify/edify_parser.cpp b/edify/edify_parser.cpp
new file mode 100644
index 0000000..16ad2ab
--- /dev/null
+++ b/edify/edify_parser.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * This is a host-side tool for validating a given edify script file.
+ *
+ * We used to have edify test cases here, which have been moved to
+ * tests/component/edify_test.cpp.
+ *
+ * Caveat: It doesn't recognize functions defined through updater, which
+ * makes the tool less useful. We should either extend the tool or remove it.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "expr.h"
+#include "parser.h"
+
+void ExprDump(int depth, Expr* n, char* script) {
+ printf("%*s", depth*2, "");
+ char temp = script[n->end];
+ script[n->end] = '\0';
+ printf("%s %p (%d-%d) \"%s\"\n",
+ n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end,
+ script+n->start);
+ script[n->end] = temp;
+ for (int i = 0; i < n->argc; ++i) {
+ ExprDump(depth+1, n->argv[i], script);
+ }
+}
+
+int main(int argc, char** argv) {
+ RegisterBuiltins();
+ FinishRegistration();
+
+ if (argc != 2) {
+ printf("Usage: %s <edify script>\n", argv[0]);
+ return 1;
+ }
+
+ FILE* f = fopen(argv[1], "r");
+ if (f == NULL) {
+ printf("%s: %s: No such file or directory\n", argv[0], argv[1]);
+ return 1;
+ }
+ char buffer[8192];
+ int size = fread(buffer, 1, 8191, f);
+ fclose(f);
+ buffer[size] = '\0';
+
+ Expr* root;
+ int error_count = 0;
+ int error = parse_string(buffer, &root, &error_count);
+ printf("parse returned %d; %d errors encountered\n", error, error_count);
+ if (error == 0 || error_count > 0) {
+
+ ExprDump(0, root, buffer);
+
+ State state;
+ state.cookie = NULL;
+ state.script = buffer;
+ state.errmsg = NULL;
+
+ char* result = Evaluate(&state, root);
+ if (result == NULL) {
+ printf("result was NULL, message is: %s\n",
+ (state.errmsg == NULL ? "(NULL)" : state.errmsg));
+ free(state.errmsg);
+ } else {
+ printf("result is [%s]\n", result);
+ }
+ }
+ return 0;
+}
diff --git a/edify/main.cpp b/edify/main.cpp
deleted file mode 100644
index 6007a3d..0000000
--- a/edify/main.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-
-#include "expr.h"
-#include "parser.h"
-
-extern int yyparse(Expr** root, int* error_count);
-
-int expect(const char* expr_str, const char* expected, int* errors) {
- Expr* e;
- char* result;
-
- printf(".");
-
- int error_count = parse_string(expr_str, &e, &error_count);
- if (error_count > 0) {
- printf("error parsing \"%s\" (%d errors)\n",
- expr_str, error_count);
- ++*errors;
- return 0;
- }
-
- State state;
- state.cookie = NULL;
- state.script = strdup(expr_str);
- state.errmsg = NULL;
-
- result = Evaluate(&state, e);
- free(state.errmsg);
- free(state.script);
- if (result == NULL && expected != NULL) {
- printf("error evaluating \"%s\"\n", expr_str);
- ++*errors;
- return 0;
- }
-
- if (result == NULL && expected == NULL) {
- return 1;
- }
-
- if (strcmp(result, expected) != 0) {
- printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n",
- expr_str, expected, result);
- ++*errors;
- free(result);
- return 0;
- }
-
- free(result);
- return 1;
-}
-
-int test() {
- int errors = 0;
-
- expect("a", "a", &errors);
- expect("\"a\"", "a", &errors);
- expect("\"\\x61\"", "a", &errors);
- expect("# this is a comment\n"
- " a\n"
- " \n",
- "a", &errors);
-
-
- // sequence operator
- expect("a; b; c", "c", &errors);
-
- // string concat operator
- expect("a + b", "ab", &errors);
- expect("a + \n \"b\"", "ab", &errors);
- expect("a + b +\nc\n", "abc", &errors);
-
- // string concat function
- expect("concat(a, b)", "ab", &errors);
- expect("concat(a,\n \"b\")", "ab", &errors);
- expect("concat(a + b,\nc,\"d\")", "abcd", &errors);
- expect("\"concat\"(a + b,\nc,\"d\")", "abcd", &errors);
-
- // logical and
- expect("a && b", "b", &errors);
- expect("a && \"\"", "", &errors);
- expect("\"\" && b", "", &errors);
- expect("\"\" && \"\"", "", &errors);
- expect("\"\" && abort()", "", &errors); // test short-circuiting
- expect("t && abort()", NULL, &errors);
-
- // logical or
- expect("a || b", "a", &errors);
- expect("a || \"\"", "a", &errors);
- expect("\"\" || b", "b", &errors);
- expect("\"\" || \"\"", "", &errors);
- expect("a || abort()", "a", &errors); // test short-circuiting
- expect("\"\" || abort()", NULL, &errors);
-
- // logical not
- expect("!a", "", &errors);
- expect("! \"\"", "t", &errors);
- expect("!!a", "t", &errors);
-
- // precedence
- expect("\"\" == \"\" && b", "b", &errors);
- expect("a + b == ab", "t", &errors);
- expect("ab == a + b", "t", &errors);
- expect("a + (b == ab)", "a", &errors);
- expect("(ab == a) + b", "b", &errors);
-
- // substring function
- expect("is_substring(cad, abracadabra)", "t", &errors);
- expect("is_substring(abrac, abracadabra)", "t", &errors);
- expect("is_substring(dabra, abracadabra)", "t", &errors);
- expect("is_substring(cad, abracxadabra)", "", &errors);
- expect("is_substring(abrac, axbracadabra)", "", &errors);
- expect("is_substring(dabra, abracadabrxa)", "", &errors);
-
- // ifelse function
- expect("ifelse(t, yes, no)", "yes", &errors);
- expect("ifelse(!t, yes, no)", "no", &errors);
- expect("ifelse(t, yes, abort())", "yes", &errors);
- expect("ifelse(!t, abort(), no)", "no", &errors);
-
- // if "statements"
- expect("if t then yes else no endif", "yes", &errors);
- expect("if \"\" then yes else no endif", "no", &errors);
- expect("if \"\" then yes endif", "", &errors);
- expect("if \"\"; t then yes endif", "yes", &errors);
-
- // numeric comparisons
- expect("less_than_int(3, 14)", "t", &errors);
- expect("less_than_int(14, 3)", "", &errors);
- expect("less_than_int(x, 3)", "", &errors);
- expect("less_than_int(3, x)", "", &errors);
- expect("greater_than_int(3, 14)", "", &errors);
- expect("greater_than_int(14, 3)", "t", &errors);
- expect("greater_than_int(x, 3)", "", &errors);
- expect("greater_than_int(3, x)", "", &errors);
-
- // big string
- expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str(), &errors);
-
- printf("\n");
-
- return errors;
-}
-
-void ExprDump(int depth, Expr* n, char* script) {
- printf("%*s", depth*2, "");
- char temp = script[n->end];
- script[n->end] = '\0';
- printf("%s %p (%d-%d) \"%s\"\n",
- n->name == NULL ? "(NULL)" : n->name, n->fn, n->start, n->end,
- script+n->start);
- script[n->end] = temp;
- int i;
- for (i = 0; i < n->argc; ++i) {
- ExprDump(depth+1, n->argv[i], script);
- }
-}
-
-int main(int argc, char** argv) {
- RegisterBuiltins();
- FinishRegistration();
-
- if (argc == 1) {
- return test() != 0;
- }
-
- FILE* f = fopen(argv[1], "r");
- if (f == NULL) {
- printf("%s: %s: No such file or directory\n", argv[0], argv[1]);
- return 1;
- }
- char buffer[8192];
- int size = fread(buffer, 1, 8191, f);
- fclose(f);
- buffer[size] = '\0';
-
- Expr* root;
- int error_count = 0;
- int error = parse_string(buffer, &root, &error_count);
- printf("parse returned %d; %d errors encountered\n", error, error_count);
- if (error == 0 || error_count > 0) {
-
- ExprDump(0, root, buffer);
-
- State state;
- state.cookie = NULL;
- state.script = buffer;
- state.errmsg = NULL;
-
- char* result = Evaluate(&state, root);
- if (result == NULL) {
- printf("result was NULL, message is: %s\n",
- (state.errmsg == NULL ? "(NULL)" : state.errmsg));
- free(state.errmsg);
- } else {
- printf("result is [%s]\n", result);
- }
- }
- return 0;
-}
diff --git a/tests/Android.mk b/tests/Android.mk
index 0754c7a..19cb809 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -41,11 +41,13 @@
LOCAL_MODULE := recovery_component_test
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_SRC_FILES := \
+ component/edify_test.cpp \
component/verifier_test.cpp \
component/applypatch_test.cpp
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_STATIC_LIBRARIES := \
libapplypatch \
+ libedify \
libotafault \
libverifier \
libcrypto_utils \
diff --git a/tests/component/edify_test.cpp b/tests/component/edify_test.cpp
new file mode 100644
index 0000000..ded8540
--- /dev/null
+++ b/tests/component/edify_test.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <gtest/gtest.h>
+
+#include "edify/expr.h"
+
+static void expect(const char* expr_str, const char* expected) {
+ Expr* e;
+ int error_count;
+ EXPECT_EQ(parse_string(expr_str, &e, &error_count), 0);
+
+ State state;
+ state.cookie = nullptr;
+ state.errmsg = nullptr;
+ state.script = strdup(expr_str);
+
+ char* result = Evaluate(&state, e);
+
+ if (expected == nullptr) {
+ EXPECT_EQ(result, nullptr);
+ } else {
+ EXPECT_STREQ(result, expected);
+ }
+
+ free(state.errmsg);
+ free(state.script);
+ free(result);
+}
+
+class EdifyTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ RegisterBuiltins();
+ FinishRegistration();
+ }
+};
+
+TEST_F(EdifyTest, parsing) {
+ expect("a", "a");
+ expect("\"a\"", "a");
+ expect("\"\\x61\"", "a");
+ expect("# this is a comment\n"
+ " a\n"
+ " \n",
+ "a");
+}
+
+TEST_F(EdifyTest, sequence) {
+ // sequence operator
+ expect("a; b; c", "c");
+}
+
+TEST_F(EdifyTest, concat) {
+ // string concat operator
+ expect("a + b", "ab");
+ expect("a + \n \"b\"", "ab");
+ expect("a + b +\nc\n", "abc");
+
+ // string concat function
+ expect("concat(a, b)", "ab");
+ expect("concat(a,\n \"b\")", "ab");
+ expect("concat(a + b,\nc,\"d\")", "abcd");
+ expect("\"concat\"(a + b,\nc,\"d\")", "abcd");
+}
+
+TEST_F(EdifyTest, logical) {
+ // logical and
+ expect("a && b", "b");
+ expect("a && \"\"", "");
+ expect("\"\" && b", "");
+ expect("\"\" && \"\"", "");
+ expect("\"\" && abort()", ""); // test short-circuiting
+ expect("t && abort()", nullptr);
+
+ // logical or
+ expect("a || b", "a");
+ expect("a || \"\"", "a");
+ expect("\"\" || b", "b");
+ expect("\"\" || \"\"", "");
+ expect("a || abort()", "a"); // test short-circuiting
+ expect("\"\" || abort()", NULL);
+
+ // logical not
+ expect("!a", "");
+ expect("! \"\"", "t");
+ expect("!!a", "t");
+}
+
+TEST_F(EdifyTest, precedence) {
+ // precedence
+ expect("\"\" == \"\" && b", "b");
+ expect("a + b == ab", "t");
+ expect("ab == a + b", "t");
+ expect("a + (b == ab)", "a");
+ expect("(ab == a) + b", "b");
+}
+
+TEST_F(EdifyTest, substring) {
+ // substring function
+ expect("is_substring(cad, abracadabra)", "t");
+ expect("is_substring(abrac, abracadabra)", "t");
+ expect("is_substring(dabra, abracadabra)", "t");
+ expect("is_substring(cad, abracxadabra)", "");
+ expect("is_substring(abrac, axbracadabra)", "");
+ expect("is_substring(dabra, abracadabrxa)", "");
+}
+
+TEST_F(EdifyTest, ifelse) {
+ // ifelse function
+ expect("ifelse(t, yes, no)", "yes");
+ expect("ifelse(!t, yes, no)", "no");
+ expect("ifelse(t, yes, abort())", "yes");
+ expect("ifelse(!t, abort(), no)", "no");
+}
+
+TEST_F(EdifyTest, if_statement) {
+ // if "statements"
+ expect("if t then yes else no endif", "yes");
+ expect("if \"\" then yes else no endif", "no");
+ expect("if \"\" then yes endif", "");
+ expect("if \"\"; t then yes endif", "yes");
+}
+
+TEST_F(EdifyTest, comparison) {
+ // numeric comparisons
+ expect("less_than_int(3, 14)", "t");
+ expect("less_than_int(14, 3)", "");
+ expect("less_than_int(x, 3)", "");
+ expect("less_than_int(3, x)", "");
+ expect("greater_than_int(3, 14)", "");
+ expect("greater_than_int(14, 3)", "t");
+ expect("greater_than_int(x, 3)", "");
+ expect("greater_than_int(3, x)", "");
+}
+
+TEST_F(EdifyTest, big_string) {
+ // big string
+ expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str());
+}
+