Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ba44aaa authored by Christopher Wiley's avatar Christopher Wiley Committed by Android Git Automerger
Browse files

am 80a679c4: am b1db04f3: Merge "aidl: Add end to end test"

* commit '80a679c4':
  aidl: Add end to end test
parents c9c24467 80a679c4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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
+165 −0
Original line number Diff line number Diff line
/*
 * 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.
}
+404 −0
Original line number Diff line number Diff line
/*
 * 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
+33 −0
Original line number Diff line number Diff line
/*
 * 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_