  @Test
  public void testHandleMultipleFiles() throws Exception {

    // Triggering code generation
    Descriptors.Descriptor searchRequestDescriptor = SearchRequest.getDescriptor();
    DescriptorProtos.FileDescriptorProto protoFile = searchRequestDescriptor.getFile().toProto();
    TypeMap types = TypeMap.of(protoFile);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    ProtoServiceHandler serviceHandler = new ProtoServiceHandler(
        "io.soliton.protobuf.plugin.testing", types, true, null, null, output);
    serviceHandler.handle(protoFile.getServiceList().get(0));

    // Parsing code generation result
    PluginProtos.CodeGeneratorResponse response = PluginProtos.CodeGeneratorResponse.parseFrom(
        output.toByteArray());
    Assert.assertNotNull(response);
    Assert.assertEquals(1, response.getFileCount());
    Assert.assertEquals("io/soliton/protobuf/plugin/testing/SearchEngine.java",
        response.getFile(0).getName());
    String fileContent = response.getFile(0).getContent();

    // Extracting Java source code and initiating parsing
    JavaFileObject file = new JavaSourceFromString
        ("io.soliton.protobuf.plugin.testing.SearchEngine", fileContent);
    JavacTool compiler = JavacTool.create();
    StringWriter errorOutput = new StringWriter();
    JavaFileManager fileManager = compiler.getStandardFileManager(null, null, Charsets.UTF_8);
    DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
    List<String> compilerOptions = Lists.newArrayList("-classpath",
        System.getProperty("java.class.path"));
    List<JavaFileObject> compilationUnits = Lists.newArrayList(file);
    JavacTask compilationTask = compiler.getTask(errorOutput, fileManager, diagnostics,
        compilerOptions, null, compilationUnits);
    Iterable<? extends CompilationUnitTree> compiledUnits = compilationTask.parse();

    // Checking parsing results
    Assert.assertEquals(1, Iterables.size(compiledUnits));
    CompilationUnitTree compiledUnit = compiledUnits.iterator().next();
    ExpressionTree packageName = compiledUnit.getPackageName();
    Assert.assertEquals("io.soliton.protobuf.plugin.testing", packageName.toString());
    List<? extends Tree> declaredTypes = compiledUnit.getTypeDecls();
    Assert.assertEquals(1, declaredTypes.size());
    Tree rootType = declaredTypes.get(0);
    Assert.assertEquals(Tree.Kind.CLASS, rootType.getKind());

    // Checking root class properties
    ClassTree rootClass = (ClassTree) rootType;
    Assert.assertTrue(rootClass.getModifiers().getFlags().contains(Modifier.PUBLIC));
    Assert.assertTrue(rootClass.getModifiers().getFlags().contains(Modifier.ABSTRACT));
    Assert.assertTrue(rootClass.getSimpleName().contentEquals("SearchEngine"));
    Assert.assertEquals(1, rootClass.getImplementsClause().size());
    Assert.assertEquals(Tree.Kind.MEMBER_SELECT, rootClass.getImplementsClause().get(0).getKind());
    MemberSelectTree serviceInterface = (MemberSelectTree) rootClass.getImplementsClause().get(0);
    Assert.assertEquals("io.soliton.protobuf", serviceInterface.getExpression().toString());
    Assert.assertEquals("Service", serviceInterface.getIdentifier().toString());

    // Checking root class methods
    Map<String, MethodTree> methods = Maps.newHashMap();
    ClassTree interfaceClass = null;
    for (Tree member : rootClass.getMembers()) {
      if (Tree.Kind.METHOD == member.getKind()) {
        MethodTree method = (MethodTree) member;
        methods.put(method.getName().toString(), method);
      } else if (Tree.Kind.INTERFACE == member.getKind()) {
        interfaceClass = (ClassTree) member;
      }
    }

    Assert.assertTrue(methods.containsKey("newStub"));
    MethodTree newStub = methods.get("newStub");
    Assert.assertTrue(((IdentifierTree) newStub.getReturnType()).getName()
        .contentEquals("Interface"));
    Assert.assertEquals(Tree.Kind.MEMBER_SELECT,
        newStub.getParameters().get(0).getType().getKind());
    MemberSelectTree clientParameter = (MemberSelectTree) newStub.getParameters().get(0).getType();
    Assert.assertEquals("io.soliton.protobuf", clientParameter.getExpression().toString());
    Assert.assertEquals("Client", clientParameter.getIdentifier().toString());

    Assert.assertTrue(methods.containsKey("newService"));
    MethodTree newService = methods.get("newService");
    Assert.assertEquals(Tree.Kind.MEMBER_SELECT, newService.getReturnType().getKind());
    MemberSelectTree serviceReturn = (MemberSelectTree) newService.getReturnType();
    Assert.assertEquals("io.soliton.protobuf", serviceReturn.getExpression().toString());
    Assert.assertEquals("Service", serviceReturn.getIdentifier().toString());
    Assert.assertTrue(((IdentifierTree) newService.getParameters().get(0).getType()).getName()
        .contentEquals("Interface"));

    // Checking interface methods
    Assert.assertNotNull(interfaceClass);
    Map<String, MethodTree> interfaceMethods = Maps.newHashMap();
    Assert.assertTrue(interfaceClass.getSimpleName().contentEquals("Interface"));
    for (Tree member : interfaceClass.getMembers()) {
      if (Tree.Kind.METHOD == member.getKind()) {
        MethodTree method = (MethodTree) member;
        interfaceMethods.put(method.getName().toString(), method);
      }
    }

    Assert.assertTrue(interfaceMethods.containsKey("search"));
    MethodTree lookup = interfaceMethods.get("search");
    Assert.assertEquals(Tree.Kind.PARAMETERIZED_TYPE, lookup.getReturnType().getKind());
    ParameterizedTypeTree returnTypeTree = (ParameterizedTypeTree) lookup.getReturnType();
    Assert.assertEquals(Tree.Kind.MEMBER_SELECT, returnTypeTree.getType().getKind());
    MemberSelectTree listenableFutureReturn = (MemberSelectTree) returnTypeTree.getType();
    Assert.assertEquals("com.google.common.util.concurrent",
        listenableFutureReturn.getExpression().toString());
    Assert.assertEquals("ListenableFuture", listenableFutureReturn.getIdentifier().toString());
    Assert.assertTrue(((MemberSelectTree) returnTypeTree.getTypeArguments().get(0)).getIdentifier()
        .toString().contains("SearchResult"));
  }