diff options
-rw-r--r-- | edify/Android.mk | 28 | ||||
-rw-r--r-- | edify/edify_parser.cpp | 89 | ||||
-rw-r--r-- | edify/main.cpp | 219 | ||||
-rw-r--r-- | tests/Android.mk | 2 | ||||
-rw-r--r-- | tests/component/edify_test.cpp | 156 |
5 files changed, 267 insertions, 227 deletions
diff --git a/edify/Android.mk b/edify/Android.mk index b397045cf..d8058c16f 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 @@ LOCAL_STATIC_LIBRARIES += libbase 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 000000000..16ad2ab71 --- /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 6007a3d58..000000000 --- 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 0754c7acf..19cb80940 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -41,11 +41,13 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk 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 000000000..ded8540a0 --- /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()); +} + |