chromium/chrome/test/data/nacl/manifest_file/irt_manifest_file_test.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//
// Test for resource open before PPAPI initialization.
//

#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include <sstream>
#include <string>
#include <vector>

#include "native_client/src/untrusted/irt/irt.h"
#include "native_client/src/untrusted/nacl/nacl_irt.h"

#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array.h"
#include "ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h"


std::vector<std::string> result;

pp::Instance* g_instance = NULL;

std::string LoadManifestSuccess(TYPE_nacl_irt_query *query_func) {
  struct nacl_irt_resource_open nacl_irt_resource_open;
  if (sizeof(nacl_irt_resource_open) !=
      (*query_func)(
          NACL_IRT_RESOURCE_OPEN_v0_1,
          &nacl_irt_resource_open,
          sizeof(nacl_irt_resource_open))) {
    return "irt manifest api not found";
  }
  int desc;
  int error;
  error = nacl_irt_resource_open.open_resource("test_file", &desc);
  if (0 != error) {
    printf("Can't open file, error=%d", error);
    return "Can't open file";
  }

  std::string str;

  char buffer[4096];
  int len;
  while ((len = read(desc, buffer, sizeof buffer - 1)) > 0) {
    // Null terminate.
    buffer[len] = '\0';
    str += buffer;
  }

  if (str != "Test File Content") {
    printf("Wrong file content: \"%s\"\n", str.c_str());
    return "Wrong file content: " + str;
  }

  return "Pass";
}

std::string LoadManifestNonExistentEntry(
    TYPE_nacl_irt_query *query_func) {
  struct nacl_irt_resource_open nacl_irt_resource_open;
  if (sizeof(nacl_irt_resource_open) !=
      (*query_func)(
          NACL_IRT_RESOURCE_OPEN_v0_1,
          &nacl_irt_resource_open,
          sizeof(nacl_irt_resource_open))) {
    return "irt manifest api not found";
  }

  int desc;
  int error = nacl_irt_resource_open.open_resource("non_existent_entry", &desc);

  // We expect ENOENT here, as it does not exist.
  if (error != ENOENT) {
    printf("Unexpected error code: %d\n", error);
    char buf[80];
    snprintf(buf, sizeof(buf), "open_resource() result: %d", error);
    return std::string(buf);
  }

  return "Pass";
}

std::string LoadManifestNonExistentFile(
    TYPE_nacl_irt_query *query_func) {
  struct nacl_irt_resource_open nacl_irt_resource_open;
  if (sizeof(nacl_irt_resource_open) !=
      (*query_func)(
          NACL_IRT_RESOURCE_OPEN_v0_1,
          &nacl_irt_resource_open,
          sizeof(nacl_irt_resource_open))) {
    return "irt manifest api not found";
  }

  int desc;
  int error = nacl_irt_resource_open.open_resource("dummy_test_file", &desc);

  // We expect ENOENT here, as it does not exist.
  if (error != ENOENT) {
    printf("Unexpected error code: %d\n", error);
    char buf[80];
    snprintf(buf, sizeof(buf), "open_resource() result: %d", error);
    return std::string(buf);
  }

  return "Pass";
}

void RunTests() {
  result.push_back(LoadManifestSuccess(&__nacl_irt_query));
  result.push_back(LoadManifestNonExistentEntry(&__nacl_irt_query));
  result.push_back(LoadManifestNonExistentFile(&__nacl_irt_query));
}

void PostReply(void* user_data, int32_t status) {
  pp::VarArray reply = pp::VarArray();
  for (size_t i = 0; i < result.size(); ++i)
    reply.Set(i, pp::Var(result[i]));
  g_instance->PostMessage(reply);
}

void* RunTestsOnBackgroundThread(void *thread_id) {
  RunTests();
  pp::Module::Get()->core()->CallOnMainThread(
      0, pp::CompletionCallback(&PostReply, NULL));
  return NULL;
}

class TestInstance : public pp::Instance {
 public:
  explicit TestInstance(PP_Instance instance) : pp::Instance(instance) {
    g_instance = this;
  }

  virtual ~TestInstance() {}
  virtual void HandleMessage(const pp::Var& var_message) {
    if (!var_message.is_string()) {
      return;
    }
    if (var_message.AsString() != "hello") {
      return;
    }

    pthread_t thread;
    // We test the manifest routines again after PPAPI has initialized to
    // ensure that they still work.
    //
    // irt_open_resource() isn't allowed to be called on the main thread once
    // pepper starts, so these tests must happen on a background thread.
    //
    // TODO(teravest): Check the return value here.
    pthread_create(&thread, NULL, &RunTestsOnBackgroundThread, NULL);
  }
};

class TestModule : public pp::Module {
 public:
  TestModule() : pp::Module() {}
  virtual ~TestModule() {}

  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new TestInstance(instance);
  }
};

namespace pp {
Module* CreateModule() {
  return new TestModule();
}
}

int main() {
  RunTests();
  return PpapiPluginMain();
}