// Copyright 2007-2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <stdlib.h>

#include "v8.h"

#include "heap.h"
#include "cctest.h"

using namespace v8;


enum Expectations {
  EXPECT_RESULT,
  EXPECT_EXCEPTION,
  EXPECT_ERROR
};


// A DeclarationContext holds a reference to a v8::Context and keeps
// track of various declaration related counters to make it easier to
// track if global declarations in the presence of interceptors behave
// the right way.
class DeclarationContext {
 public:
  DeclarationContext();

  virtual ~DeclarationContext() {
    if (is_initialized_) {
      context_->Exit();
      context_.Dispose(context_->GetIsolate());
    }
  }

  void Check(const char* source,
             int get, int set, int has,
             Expectations expectations,
             v8::Handle<Value> value = Local<Value>());

  int get_count() const { return get_count_; }
  int set_count() const { return set_count_; }
  int query_count() const { return query_count_; }

 protected:
  virtual v8::Handle<Value> Get(Local<String> key);
  virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
  virtual v8::Handle<Integer> Query(Local<String> key);

  void InitializeIfNeeded();

  // Perform optional initialization steps on the context after it has
  // been created. Defaults to none but may be overwritten.
  virtual void PostInitializeContext(Handle<Context> context) {}

  // Get the holder for the interceptor. Default to the instance template
  // but may be overwritten.
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    return function->InstanceTemplate();
  }

  // The handlers are called as static functions that forward
  // to the instance specific virtual methods.
  static v8::Handle<Value> HandleGet(Local<String> key,
                                     const AccessorInfo& info);
  static v8::Handle<Value> HandleSet(Local<String> key,
                                     Local<Value> value,
                                     const AccessorInfo& info);
  static v8::Handle<Integer> HandleQuery(Local<String> key,
                                         const AccessorInfo& info);

 private:
  bool is_initialized_;
  Persistent<Context> context_;

  int get_count_;
  int set_count_;
  int query_count_;

  static DeclarationContext* GetInstance(const AccessorInfo& info);
};


DeclarationContext::DeclarationContext()
    : is_initialized_(false), get_count_(0), set_count_(0), query_count_(0) {
  // Do nothing.
}


void DeclarationContext::InitializeIfNeeded() {
  if (is_initialized_) return;
  HandleScope scope(Isolate::GetCurrent());
  Local<FunctionTemplate> function = FunctionTemplate::New();
  Local<Value> data = External::New(this);
  GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
                                               &HandleSet,
                                               &HandleQuery,
                                               0, 0,
                                               data);
  context_ = Context::New(0, function->InstanceTemplate(), Local<Value>());
  context_->Enter();
  is_initialized_ = true;
  PostInitializeContext(context_);
}


void DeclarationContext::Check(const char* source,
                               int get, int set, int query,
                               Expectations expectations,
                               v8::Handle<Value> value) {
  InitializeIfNeeded();
  // A retry after a GC may pollute the counts, so perform gc now
  // to avoid that.
  HEAP->CollectGarbage(v8::internal::NEW_SPACE);
  HandleScope scope(Isolate::GetCurrent());
  TryCatch catcher;
  catcher.SetVerbose(true);
  Local<Script> script = Script::Compile(String::New(source));
  if (expectations == EXPECT_ERROR) {
    CHECK(script.IsEmpty());
    return;
  }
  CHECK(!script.IsEmpty());
  Local<Value> result = script->Run();
  CHECK_EQ(get, get_count());
  CHECK_EQ(set, set_count());
  CHECK_EQ(query, query_count());
  if (expectations == EXPECT_RESULT) {
    CHECK(!catcher.HasCaught());
    if (!value.IsEmpty()) {
      CHECK_EQ(value, result);
    }
  } else {
    CHECK(expectations == EXPECT_EXCEPTION);
    CHECK(catcher.HasCaught());
    if (!value.IsEmpty()) {
      CHECK_EQ(value, catcher.Exception());
    }
  }
  HEAP->CollectAllAvailableGarbage();  // Clean slate for the next test.
}


v8::Handle<Value> DeclarationContext::HandleGet(Local<String> key,
                                                const AccessorInfo& info) {
  DeclarationContext* context = GetInstance(info);
  context->get_count_++;
  return context->Get(key);
}


v8::Handle<Value> DeclarationContext::HandleSet(Local<String> key,
                                                Local<Value> value,
                                                const AccessorInfo& info) {
  DeclarationContext* context = GetInstance(info);
  context->set_count_++;
  return context->Set(key, value);
}


v8::Handle<Integer> DeclarationContext::HandleQuery(Local<String> key,
                                                    const AccessorInfo& info) {
  DeclarationContext* context = GetInstance(info);
  context->query_count_++;
  return context->Query(key);
}


DeclarationContext* DeclarationContext::GetInstance(const AccessorInfo& info) {
  void* value = External::Cast(*info.Data())->Value();
  return static_cast<DeclarationContext*>(value);
}


v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
  return v8::Handle<Value>();
}


v8::Handle<Value> DeclarationContext::Set(Local<String> key,
                                          Local<Value> value) {
  return v8::Handle<Value>();
}


v8::Handle<Integer> DeclarationContext::Query(Local<String> key) {
  return v8::Handle<Integer>();
}


// Test global declaration of a property the interceptor doesn't know
// about and doesn't handle.
TEST(Unknown) {
  HandleScope scope(Isolate::GetCurrent());

  { DeclarationContext context;
    context.Check("var x; x",
                  1,  // access
                  1,  // declaration
                  2,  // declaration + initialization
                  EXPECT_RESULT, Undefined());
  }

  { DeclarationContext context;
    context.Check("var x = 0; x",
                  1,  // access
                  2,  // declaration + initialization
                  2,  // declaration + initialization
                  EXPECT_RESULT, Number::New(0));
  }

  { DeclarationContext context;
    context.Check("function x() { }; x",
                  1,  // access
                  0,
                  0,
                  EXPECT_RESULT);
  }

  { DeclarationContext context;
    context.Check("const x; x",
                  1,  // access
                  2,  // declaration + initialization
                  1,  // declaration
                  EXPECT_RESULT, Undefined());
  }

  { DeclarationContext context;
    context.Check("const x = 0; x",
                  1,  // access
                  2,  // declaration + initialization
                  1,  // declaration
                  EXPECT_RESULT, Undefined());  // SB 0 - BUG 1213579
  }
}



class PresentPropertyContext: public DeclarationContext {
 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    return Integer::New(v8::None);
  }
};



TEST(Present) {
  HandleScope scope(Isolate::GetCurrent());

  { PresentPropertyContext context;
    context.Check("var x; x",
                  1,  // access
                  0,
                  2,  // declaration + initialization
                  EXPECT_EXCEPTION);  // x is not defined!
  }

  { PresentPropertyContext context;
    context.Check("var x = 0; x",
                  1,  // access
                  1,  // initialization
                  2,  // declaration + initialization
                  EXPECT_RESULT, Number::New(0));
  }

  { PresentPropertyContext context;
    context.Check("function x() { }; x",
                  1,  // access
                  0,
                  0,
                  EXPECT_RESULT);
  }

  { PresentPropertyContext context;
    context.Check("const x; x",
                  1,  // access
                  1,  // initialization
                  1,  // (re-)declaration
                  EXPECT_RESULT, Undefined());
  }

  { PresentPropertyContext context;
    context.Check("const x = 0; x",
                  1,  // access
                  1,  // initialization
                  1,  // (re-)declaration
                  EXPECT_RESULT, Number::New(0));
  }
}



class AbsentPropertyContext: public DeclarationContext {
 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    return v8::Handle<Integer>();
  }
};


TEST(Absent) {
  HandleScope scope(Isolate::GetCurrent());

  { AbsentPropertyContext context;
    context.Check("var x; x",
                  1,  // access
                  1,  // declaration
                  2,  // declaration + initialization
                  EXPECT_RESULT, Undefined());
  }

  { AbsentPropertyContext context;
    context.Check("var x = 0; x",
                  1,  // access
                  2,  // declaration + initialization
                  2,  // declaration + initialization
                  EXPECT_RESULT, Number::New(0));
  }

  { AbsentPropertyContext context;
    context.Check("function x() { }; x",
                  1,  // access
                  0,
                  0,
                  EXPECT_RESULT);
  }

  { AbsentPropertyContext context;
    context.Check("const x; x",
                  1,  // access
                  2,  // declaration + initialization
                  1,  // declaration
                  EXPECT_RESULT, Undefined());
  }

  { AbsentPropertyContext context;
    context.Check("const x = 0; x",
                  1,  // access
                  2,  // declaration + initialization
                  1,  // declaration
                  EXPECT_RESULT, Undefined());  // SB 0 - BUG 1213579
  }

  { AbsentPropertyContext context;
    context.Check("if (false) { var x = 0 }; x",
                  1,  // access
                  1,  // declaration
                  1,  // declaration + initialization
                  EXPECT_RESULT, Undefined());
  }
}



class AppearingPropertyContext: public DeclarationContext {
 public:
  enum State {
    DECLARE,
    INITIALIZE_IF_ASSIGN,
    UNKNOWN
  };

  AppearingPropertyContext() : state_(DECLARE) { }

 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    switch (state_) {
      case DECLARE:
        // Force declaration by returning that the
        // property is absent.
        state_ = INITIALIZE_IF_ASSIGN;
        return Handle<Integer>();
      case INITIALIZE_IF_ASSIGN:
        // Return that the property is present so we only get the
        // setter called when initializing with a value.
        state_ = UNKNOWN;
        return Integer::New(v8::None);
      default:
        CHECK(state_ == UNKNOWN);
        break;
    }
    // Do the lookup in the object.
    return v8::Handle<Integer>();
  }

 private:
  State state_;
};


TEST(Appearing) {
  HandleScope scope(Isolate::GetCurrent());

  { AppearingPropertyContext context;
    context.Check("var x; x",
                  1,  // access
                  1,  // declaration
                  2,  // declaration + initialization
                  EXPECT_RESULT, Undefined());
  }

  { AppearingPropertyContext context;
    context.Check("var x = 0; x",
                  1,  // access
                  2,  // declaration + initialization
                  2,  // declaration + initialization
                  EXPECT_RESULT, Number::New(0));
  }

  { AppearingPropertyContext context;
    context.Check("function x() { }; x",
                  1,  // access
                  0,
                  0,
                  EXPECT_RESULT);
  }

  { AppearingPropertyContext context;
    context.Check("const x; x",
                  1,  // access
                  2,  // declaration + initialization
                  1,  // declaration
                  EXPECT_RESULT, Undefined());
  }

  { AppearingPropertyContext context;
    context.Check("const x = 0; x",
                  1,  // access
                  2,  // declaration + initialization
                  1,  // declaration
                  EXPECT_RESULT, Undefined());
                  // Result is undefined because declaration succeeded but
                  // initialization to 0 failed (due to context behavior).
  }
}



class ReappearingPropertyContext: public DeclarationContext {
 public:
  enum State {
    DECLARE,
    DONT_DECLARE,
    INITIALIZE,
    UNKNOWN
  };

  ReappearingPropertyContext() : state_(DECLARE) { }

 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    switch (state_) {
      case DECLARE:
        // Force the first declaration by returning that
        // the property is absent.
        state_ = DONT_DECLARE;
        return Handle<Integer>();
      case DONT_DECLARE:
        // Ignore the second declaration by returning
        // that the property is already there.
        state_ = INITIALIZE;
        return Integer::New(v8::None);
      case INITIALIZE:
        // Force an initialization by returning that
        // the property is absent. This will make sure
        // that the setter is called and it will not
        // lead to redeclaration conflicts (yet).
        state_ = UNKNOWN;
        return Handle<Integer>();
      default:
        CHECK(state_ == UNKNOWN);
        break;
    }
    // Do the lookup in the object.
    return Handle<Integer>();
  }

 private:
  State state_;
};


TEST(Reappearing) {
  HandleScope scope(Isolate::GetCurrent());

  { ReappearingPropertyContext context;
    context.Check("const x; var x = 0",
                  0,
                  3,  // const declaration+initialization, var initialization
                  3,  // 2 x declaration + var initialization
                  EXPECT_RESULT, Undefined());
  }
}



class ExistsInPrototypeContext: public DeclarationContext {
 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    // Let it seem that the property exists in the prototype object.
    return Integer::New(v8::None);
  }

  // Use the prototype as the holder for the interceptors.
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    return function->PrototypeTemplate();
  }
};


TEST(ExistsInPrototype) {
  i::FLAG_es52_globals = true;
  HandleScope scope(Isolate::GetCurrent());

  // Sanity check to make sure that the holder of the interceptor
  // really is the prototype object.
  { ExistsInPrototypeContext context;
    context.Check("this.x = 87; this.x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT, Number::New(87));
  }

  { ExistsInPrototypeContext context;
    context.Check("var x; x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT, Undefined());
  }

  { ExistsInPrototypeContext context;
    context.Check("var x = 0; x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT, Number::New(0));
  }

  { ExistsInPrototypeContext context;
    context.Check("const x; x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT, Undefined());
  }

  { ExistsInPrototypeContext context;
    context.Check("const x = 0; x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT, Number::New(0));
  }
}



class AbsentInPrototypeContext: public DeclarationContext {
 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    // Let it seem that the property is absent in the prototype object.
    return Handle<Integer>();
  }

  // Use the prototype as the holder for the interceptors.
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    return function->PrototypeTemplate();
  }
};


TEST(AbsentInPrototype) {
  i::FLAG_es52_globals = true;
  HandleScope scope(Isolate::GetCurrent());

  { AbsentInPrototypeContext context;
    context.Check("if (false) { var x = 0; }; x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT, Undefined());
  }
}



class ExistsInHiddenPrototypeContext: public DeclarationContext {
 public:
  ExistsInHiddenPrototypeContext() {
    hidden_proto_ = FunctionTemplate::New();
    hidden_proto_->SetHiddenPrototype(true);
  }

 protected:
  virtual v8::Handle<Integer> Query(Local<String> key) {
    // Let it seem that the property exists in the hidden prototype object.
    return Integer::New(v8::None);
  }

  // Install the hidden prototype after the global object has been created.
  virtual void PostInitializeContext(Handle<Context> context) {
    Local<Object> global_object = context->Global();
    Local<Object> hidden_proto = hidden_proto_->GetFunction()->NewInstance();
    context->DetachGlobal();
    context->Global()->SetPrototype(hidden_proto);
    context->ReattachGlobal(global_object);
  }

  // Use the hidden prototype as the holder for the interceptors.
  virtual Local<ObjectTemplate> GetHolder(Local<FunctionTemplate> function) {
    return hidden_proto_->InstanceTemplate();
  }

 private:
  Local<FunctionTemplate> hidden_proto_;
};


TEST(ExistsInHiddenPrototype) {
  i::FLAG_es52_globals = true;
  HandleScope scope(Isolate::GetCurrent());

  { ExistsInHiddenPrototypeContext context;
    context.Check("var x; x",
                  1,  // access
                  0,
                  2,  // declaration + initialization
                  EXPECT_EXCEPTION);  // x is not defined!
  }

  { ExistsInHiddenPrototypeContext context;
    context.Check("var x = 0; x",
                  1,  // access
                  1,  // initialization
                  2,  // declaration + initialization
                  EXPECT_RESULT, Number::New(0));
  }

  { ExistsInHiddenPrototypeContext context;
    context.Check("function x() { }; x",
                  0,
                  0,
                  0,
                  EXPECT_RESULT);
  }

  // TODO(mstarzinger): The semantics of global const is vague.
  { ExistsInHiddenPrototypeContext context;
    context.Check("const x; x",
                  0,
                  0,
                  1,  // (re-)declaration
                  EXPECT_RESULT, Undefined());
  }

  // TODO(mstarzinger): The semantics of global const is vague.
  { ExistsInHiddenPrototypeContext context;
    context.Check("const x = 0; x",
                  0,
                  0,
                  1,  // (re-)declaration
                  EXPECT_RESULT, Number::New(0));
  }
}



class SimpleContext {
 public:
  SimpleContext() {
    context_ = Context::New(0);
    context_->Enter();
  }

  virtual ~SimpleContext() {
    context_->Exit();
    context_.Dispose(context_->GetIsolate());
  }

  void Check(const char* source,
             Expectations expectations,
             v8::Handle<Value> value = Local<Value>()) {
    HandleScope scope(context_->GetIsolate());
    TryCatch catcher;
    catcher.SetVerbose(true);
    Local<Script> script = Script::Compile(String::New(source));
    if (expectations == EXPECT_ERROR) {
      CHECK(script.IsEmpty());
      return;
    }
    CHECK(!script.IsEmpty());
    Local<Value> result = script->Run();
    if (expectations == EXPECT_RESULT) {
      CHECK(!catcher.HasCaught());
      if (!value.IsEmpty()) {
        CHECK_EQ(value, result);
      }
    } else {
      CHECK(expectations == EXPECT_EXCEPTION);
      CHECK(catcher.HasCaught());
      if (!value.IsEmpty()) {
        CHECK_EQ(value, catcher.Exception());
      }
    }
  }

 private:
  Persistent<Context> context_;
};


TEST(CrossScriptReferences) {
  HandleScope scope(Isolate::GetCurrent());

  { SimpleContext context;
    context.Check("var x = 1; x",
                  EXPECT_RESULT, Number::New(1));
    context.Check("var x = 2; x",
                  EXPECT_RESULT, Number::New(2));
    context.Check("const x = 3; x",
                  EXPECT_RESULT, Number::New(3));
    context.Check("const x = 4; x",
                  EXPECT_RESULT, Number::New(4));
    context.Check("x = 5; x",
                  EXPECT_RESULT, Number::New(5));
    context.Check("var x = 6; x",
                  EXPECT_RESULT, Number::New(6));
    context.Check("this.x",
                  EXPECT_RESULT, Number::New(6));
    context.Check("function x() { return 7 }; x()",
                  EXPECT_RESULT, Number::New(7));
  }

  { SimpleContext context;
    context.Check("const x = 1; x",
                  EXPECT_RESULT, Number::New(1));
    context.Check("var x = 2; x",  // assignment ignored
                  EXPECT_RESULT, Number::New(1));
    context.Check("const x = 3; x",
                  EXPECT_RESULT, Number::New(1));
    context.Check("x = 4; x",  // assignment ignored
                  EXPECT_RESULT, Number::New(1));
    context.Check("var x = 5; x",  // assignment ignored
                  EXPECT_RESULT, Number::New(1));
    context.Check("this.x",
                  EXPECT_RESULT, Number::New(1));
    context.Check("function x() { return 7 }; x",
                  EXPECT_EXCEPTION);
  }
}


TEST(CrossScriptReferencesHarmony) {
  i::FLAG_use_strict = true;
  i::FLAG_harmony_scoping = true;
  i::FLAG_harmony_modules = true;

  HandleScope scope(Isolate::GetCurrent());

  const char* decs[] = {
    "var x = 1; x", "x", "this.x",
    "function x() { return 1 }; x()", "x()", "this.x()",
    "let x = 1; x", "x", "this.x",
    "const x = 1; x", "x", "this.x",
    "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
    NULL
  };

  for (int i = 0; decs[i] != NULL; i += 3) {
    SimpleContext context;
    context.Check(decs[i], EXPECT_RESULT, Number::New(1));
    context.Check(decs[i+1], EXPECT_RESULT, Number::New(1));
    // TODO(rossberg): The current ES6 draft spec does not reflect lexical
    // bindings on the global object. However, this will probably change, in
    // which case we reactivate the following test.
    if (i/3 < 2) context.Check(decs[i+2], EXPECT_RESULT, Number::New(1));
  }
}


TEST(CrossScriptConflicts) {
  i::FLAG_use_strict = true;
  i::FLAG_harmony_scoping = true;
  i::FLAG_harmony_modules = true;

  HandleScope scope(Isolate::GetCurrent());

  const char* firsts[] = {
    "var x = 1; x",
    "function x() { return 1 }; x()",
    "let x = 1; x",
    "const x = 1; x",
    "module x { export let a = 1 }; x.a",
    NULL
  };
  const char* seconds[] = {
    "var x = 2; x",
    "function x() { return 2 }; x()",
    "let x = 2; x",
    "const x = 2; x",
    "module x { export let a = 2 }; x.a",
    NULL
  };

  for (int i = 0; firsts[i] != NULL; ++i) {
    for (int j = 0; seconds[j] != NULL; ++j) {
      SimpleContext context;
      context.Check(firsts[i], EXPECT_RESULT, Number::New(1));
      // TODO(rossberg): All tests should actually be errors in Harmony,
      // but we currently do not detect the cases where the first declaration
      // is not lexical.
      context.Check(seconds[j],
                    i < 2 ? EXPECT_RESULT : EXPECT_ERROR, Number::New(2));
    }
  }
}
