diff options
| -rw-r--r-- | tools/aidl/Android.mk | 10 | ||||
| -rw-r--r-- | tools/aidl/tests/end_to_end_tests.cpp | 165 | ||||
| -rw-r--r-- | tools/aidl/tests/example_interface_test_data.cpp | 404 | ||||
| -rw-r--r-- | tools/aidl/tests/test_data.h | 33 |
4 files changed, 612 insertions, 0 deletions
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk index d7b200646462..8e6189f6561e 100644 --- a/tools/aidl/Android.mk +++ b/tools/aidl/Android.mk @@ -48,14 +48,23 @@ LOCAL_STATIC_LIBRARIES := libaidl-common include $(BUILD_HOST_EXECUTABLE) +# TODO(wiley) Compile these for mac as well after b/22771504 +ifeq ($(HOST_OS),linux) # Unit tests include $(CLEAR_VARS) LOCAL_MODULE := aidl_unittests LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror +# Tragically, the code is riddled with unused parameters. +LOCAL_CLANG_CFLAGS := -Wno-unused-parameter LOCAL_SRC_FILES := \ options_unittest.cpp \ test_main.cpp \ + tests/end_to_end_tests.cpp \ + tests/example_interface_test_data.cpp \ + +LOCAL_SHARED_LIBRARIES := \ + libchrome-host \ LOCAL_STATIC_LIBRARIES := \ libaidl-common \ @@ -65,5 +74,6 @@ LOCAL_STATIC_LIBRARIES := \ LOCAL_LDLIBS_linux := -lrt include $(BUILD_HOST_NATIVE_TEST) +endif # HOST_OS == linux endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK diff --git a/tools/aidl/tests/end_to_end_tests.cpp b/tools/aidl/tests/end_to_end_tests.cpp new file mode 100644 index 000000000000..54ca60319ce1 --- /dev/null +++ b/tools/aidl/tests/end_to_end_tests.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2015, 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 <memory> +#include <string> +#include <vector> + +#include <base/logging.h> +#include <base/files/file_path.h> +#include <base/files/file_util.h> +#include <gtest/gtest.h> + +#include "aidl.h" +#include "options.h" +#include "tests/test_data.h" + +using base::FilePath; +using std::string; +using std::unique_ptr; +using std::vector; + +using namespace aidl::test_data; + +namespace { + +const char kDiffTemplate[] = "diff %s %s"; +const char kStubInterfaceTemplate[] = "package %s;\ninterface %s { }"; +const char kStubParcelableTemplate[] = "package %s;\nparcelable %s;"; + +FilePath GetPathForPackageClass(const char* package_class, + const char* extension) { + string rel_path{package_class}; + for (char& c : rel_path) { + if (c == '.') { + c = FilePath::kSeparators[0]; + } + } + rel_path += extension; + return FilePath(rel_path); +} + +void SplitPackageClass(const string& package_class, + FilePath* rel_path, + string* package, + string* class_name) { + *package = string{package_class, 0, package_class.rfind('.')}; + *class_name = string{package_class, package_class.rfind('.') + 1}; + *rel_path = GetPathForPackageClass(package_class.c_str(), ".aidl"); +} + +} // namespace + +class EndToEndTest : public ::testing::Test { + protected: + virtual void SetUp() { + ASSERT_TRUE(base::CreateNewTempDirectory( + string{"end_to_end_testsyyyy"}, &tmpDir_)); + inputDir_ = tmpDir_.Append("input"); + outputDir_ = tmpDir_.Append("output"); + ASSERT_TRUE(base::CreateDirectory(inputDir_)); + ASSERT_TRUE(base::CreateDirectory(outputDir_)); + } + + virtual void TearDown() { + ASSERT_TRUE(DeleteFile(tmpDir_, true)) + << "Failed to remove temp directory: " << tmpDir_.value(); + } + + FilePath CreateInputFile(const FilePath& relative_path, + const char contents[], + int size) { + const FilePath created_file = inputDir_.Append(relative_path); + EXPECT_TRUE(base::CreateDirectory(created_file.DirName())); + EXPECT_TRUE(base::WriteFile(created_file, contents, size)); + return created_file; + } + + void CreateStubAidlFile(const string& package_class, + const char* file_template) { + string package, class_name; + FilePath rel_path; + SplitPackageClass(package_class, &rel_path, &package, &class_name); + const size_t buf_len = + strlen(file_template) + package.length() + class_name.length() + 1; + unique_ptr<char[]> contents(new char[buf_len]); + const int written = snprintf(contents.get(), buf_len, file_template, + package.c_str(), class_name.c_str()); + EXPECT_GT(written, 0); + CreateInputFile(rel_path, contents.get(), written); + } + + void WriteStubAidls(const char** parcelables, const char** interfaces) { + while (*parcelables) { + CreateStubAidlFile(string{*parcelables}, kStubParcelableTemplate); + ++parcelables; + } + while (*interfaces) { + CreateStubAidlFile(string{*interfaces}, kStubInterfaceTemplate); + ++interfaces; + } + } + + void CheckFileContents(const FilePath& rel_path, + const string& expected_content) { + string actual_contents; + FilePath actual_path = outputDir_.Append(rel_path); + if (!ReadFileToString(actual_path, &actual_contents)) { + FAIL() << "Failed to read expected output file: " << rel_path.value(); + } + // Generated .java files mention the "original" file as part of their + // comment header. Thus we look for expected_content being a substring. + if (actual_contents.find(expected_content) == string::npos) { + // When the match fails, display a diff of what's wrong. This greatly + // aids in debugging. + FilePath expected_path; + EXPECT_TRUE(CreateTemporaryFileInDir(tmpDir_, &expected_path)); + base::WriteFile(expected_path, expected_content.c_str(), + expected_content.length()); + const size_t buf_len = + strlen(kDiffTemplate) + actual_path.value().length() + + expected_path.value().length() + 1; + unique_ptr<char[]> diff_cmd(new char[buf_len]); + EXPECT_GT(snprintf(diff_cmd.get(), buf_len, kDiffTemplate, + expected_path.value().c_str(), + actual_path.value().c_str()), 0); + system(diff_cmd.get()); + FAIL() << "Actual contents of " << rel_path.value() + << " did not match expected content"; + } + } + + FilePath tmpDir_; + FilePath inputDir_; + FilePath outputDir_; +}; + +TEST_F(EndToEndTest, IExampleInterface) { + Options options; + options.failOnParcelable = true; + options.importPaths.push_back(inputDir_.value()); + options.inputFileName = + CreateInputFile(GetPathForPackageClass(kIExampleInterfaceClass, ".aidl"), + kIExampleInterfaceContents, + strlen(kIExampleInterfaceContents)).value(); + options.autoDepFile = true; + options.outputBaseFolder = outputDir_.value(); + WriteStubAidls(kIExampleInterfaceParcelables, kIExampleInterfaceInterfaces); + EXPECT_EQ(compile_aidl(options), 0); + CheckFileContents(GetPathForPackageClass(kIExampleInterfaceClass, ".java"), + kIExampleInterfaceJava); + // We'd like to check the depends file, but it mentions unique file paths. +} diff --git a/tools/aidl/tests/example_interface_test_data.cpp b/tools/aidl/tests/example_interface_test_data.cpp new file mode 100644 index 000000000000..b17a800a6ac4 --- /dev/null +++ b/tools/aidl/tests/example_interface_test_data.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2015, 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 "tests/test_data.h" + +namespace aidl { +namespace test_data { + +const char kIExampleInterfaceClass[] = "android.test.IExampleInterface"; + +const char* kIExampleInterfaceParcelables[] = { + "android.foo.ExampleParcelable", + "android.test.ExampleParcelable2", + nullptr, +}; + +const char* kIExampleInterfaceInterfaces[] = { + "android.bar.IAuxInterface", + "android.test.IAuxInterface2", + nullptr, +}; + +const char kIExampleInterfaceContents[] = R"( +package android.test; + +import android.foo.ExampleParcelable; +import android.test.ExampleParcelable2; +import android.bar.IAuxInterface; +import android.test.IAuxInterface2; + +interface IExampleInterface { + boolean isEnabled(); + int getState(); + String getAddress(); + + ExampleParcelable[] getParcelables(); + + boolean setScanMode(int mode, int duration); + + void registerBinder(IAuxInterface foo); + IExampleInterface getRecursiveBinder(); + + int takesAnInterface(in IAuxInterface2 arg); + int takesAParcelable(in ExampleParcelable2 arg); +} +)"; + +const char kIExampleInterfaceDeps[] = +R"(/tmp/.org.chromium.Chromium.Cdq7YZ/output/android/test/IExampleInterface.java: \ + /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl \ + /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl \ + /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl \ + /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl \ + /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl + +/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl : +/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl : +/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl : +/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl : +/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl :)"; + +const char kIExampleInterfaceJava[] = +R"(package android.test; +public interface IExampleInterface extends android.os.IInterface +{ +/** Local-side IPC implementation stub class. */ +public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface +{ +private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface"; +/** Construct the stub at attach it to the interface. */ +public Stub() +{ +this.attachInterface(this, DESCRIPTOR); +} +/** + * Cast an IBinder object into an android.test.IExampleInterface interface, + * generating a proxy if needed. + */ +public static android.test.IExampleInterface asInterface(android.os.IBinder obj) +{ +if ((obj==null)) { +return null; +} +android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); +if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) { +return ((android.test.IExampleInterface)iin); +} +return new android.test.IExampleInterface.Stub.Proxy(obj); +} +@Override public android.os.IBinder asBinder() +{ +return this; +} +@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException +{ +switch (code) +{ +case INTERFACE_TRANSACTION: +{ +reply.writeString(DESCRIPTOR); +return true; +} +case TRANSACTION_isEnabled: +{ +data.enforceInterface(DESCRIPTOR); +boolean _result = this.isEnabled(); +reply.writeNoException(); +reply.writeInt(((_result)?(1):(0))); +return true; +} +case TRANSACTION_getState: +{ +data.enforceInterface(DESCRIPTOR); +int _result = this.getState(); +reply.writeNoException(); +reply.writeInt(_result); +return true; +} +case TRANSACTION_getAddress: +{ +data.enforceInterface(DESCRIPTOR); +java.lang.String _result = this.getAddress(); +reply.writeNoException(); +reply.writeString(_result); +return true; +} +case TRANSACTION_getParcelables: +{ +data.enforceInterface(DESCRIPTOR); +android.foo.ExampleParcelable[] _result = this.getParcelables(); +reply.writeNoException(); +reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); +return true; +} +case TRANSACTION_setScanMode: +{ +data.enforceInterface(DESCRIPTOR); +int _arg0; +_arg0 = data.readInt(); +int _arg1; +_arg1 = data.readInt(); +boolean _result = this.setScanMode(_arg0, _arg1); +reply.writeNoException(); +reply.writeInt(((_result)?(1):(0))); +return true; +} +case TRANSACTION_registerBinder: +{ +data.enforceInterface(DESCRIPTOR); +android.bar.IAuxInterface _arg0; +_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder()); +this.registerBinder(_arg0); +reply.writeNoException(); +return true; +} +case TRANSACTION_getRecursiveBinder: +{ +data.enforceInterface(DESCRIPTOR); +android.test.IExampleInterface _result = this.getRecursiveBinder(); +reply.writeNoException(); +reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null))); +return true; +} +case TRANSACTION_takesAnInterface: +{ +data.enforceInterface(DESCRIPTOR); +android.test.IAuxInterface2 _arg0; +_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder()); +int _result = this.takesAnInterface(_arg0); +reply.writeNoException(); +reply.writeInt(_result); +return true; +} +case TRANSACTION_takesAParcelable: +{ +data.enforceInterface(DESCRIPTOR); +android.test.ExampleParcelable2 _arg0; +if ((0!=data.readInt())) { +_arg0 = android.test.ExampleParcelable2.CREATOR.createFromParcel(data); +} +else { +_arg0 = null; +} +int _result = this.takesAParcelable(_arg0); +reply.writeNoException(); +reply.writeInt(_result); +return true; +} +} +return super.onTransact(code, data, reply, flags); +} +private static class Proxy implements android.test.IExampleInterface +{ +private android.os.IBinder mRemote; +Proxy(android.os.IBinder remote) +{ +mRemote = remote; +} +@Override public android.os.IBinder asBinder() +{ +return mRemote; +} +public java.lang.String getInterfaceDescriptor() +{ +return DESCRIPTOR; +} +@Override public boolean isEnabled() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +boolean _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0); +_reply.readException(); +_result = (0!=_reply.readInt()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public int getState() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +int _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0); +_reply.readException(); +_result = _reply.readInt(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public java.lang.String getAddress() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +java.lang.String _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0); +_reply.readException(); +_result = _reply.readString(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +android.foo.ExampleParcelable[] _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0); +_reply.readException(); +_result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +boolean _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeInt(mode); +_data.writeInt(duration); +mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0); +_reply.readException(); +_result = (0!=_reply.readInt()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null))); +mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0); +_reply.readException(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +} +@Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +android.test.IExampleInterface _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0); +_reply.readException(); +_result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder()); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +int _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +_data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null))); +mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0); +_reply.readException(); +_result = _reply.readInt(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +@Override public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException +{ +android.os.Parcel _data = android.os.Parcel.obtain(); +android.os.Parcel _reply = android.os.Parcel.obtain(); +int _result; +try { +_data.writeInterfaceToken(DESCRIPTOR); +if ((arg!=null)) { +_data.writeInt(1); +arg.writeToParcel(_data, 0); +} +else { +_data.writeInt(0); +} +mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0); +_reply.readException(); +_result = _reply.readInt(); +} +finally { +_reply.recycle(); +_data.recycle(); +} +return _result; +} +} +static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); +static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); +static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); +static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3); +static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4); +static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5); +static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6); +static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7); +static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8); +} +public boolean isEnabled() throws android.os.RemoteException; +public int getState() throws android.os.RemoteException; +public java.lang.String getAddress() throws android.os.RemoteException; +public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException; +public boolean setScanMode(int mode, int duration) throws android.os.RemoteException; +public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException; +public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException; +public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException; +public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException; +})"; + +} // namespace test_data +} // namespace aidl diff --git a/tools/aidl/tests/test_data.h b/tools/aidl/tests/test_data.h new file mode 100644 index 000000000000..cd8887ff3d13 --- /dev/null +++ b/tools/aidl/tests/test_data.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015, 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. + */ + +#ifndef AIDL_TESTS_TEST_DATA_H_ +#define AIDL_TESTS_TEST_DATA_H_ + +namespace aidl { +namespace test_data { + +extern const char kIExampleInterfaceClass[]; +extern const char kIExampleInterfaceContents[]; +extern const char* kIExampleInterfaceParcelables[]; +extern const char* kIExampleInterfaceInterfaces[]; + +extern const char kIExampleInterfaceDeps[]; +extern const char kIExampleInterfaceJava[]; + +} // namespace test_data +} // namespace aidl +#endif // AIDL_TESTS_TEST_DATA_H_ |