// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.


function TestBasics() {
  var log = [];

  var proxy = new Proxy({}, {
    get: function(target, key) {
      log.push("get " + String(key));
      if (key === 'x') return 1;
    },
    has: function(target, key) {
      log.push("has " + String(key));
      if (key === 'x') return true;
      return false;
    }
  });

  var x = 'local';

  with (proxy) {
    assertEquals(1, x);
  }

  assertEquals(['has assertEquals', 'has x', 'get Symbol(Symbol.unscopables)',
                'get x'], log);
}
TestBasics();


function TestInconsistent() {
  var log = [];

  var proxy = new Proxy({}, {
    get: function(target, key) {
      log.push("get " + String(key));
      return undefined;
    },
    has: function(target, key) {
      log.push("has " + String(key));
      if (key === 'x') return true;
      return false;
    }
  });

  var x = 'local';

  with (proxy) {
    assertEquals(void 0, x);
  }

  assertEquals(['has assertEquals', 'has x', 'get Symbol(Symbol.unscopables)',
                'get x'], log);
}
TestInconsistent();


function TestUseProxyAsUnscopables() {
  var x = 1;
  var object = {
    x: 2
  };
  var calls = 0;
  var proxy = new Proxy({}, {
    has: function() {
      assertUnreachable();
    },
    get: function(target, key) {
      assertEquals('x', key);
      calls++;
      return calls === 2 ? true : undefined;
    }
  });

  object[Symbol.unscopables] = proxy;

  with (object) {
    assertEquals(2, x);
    assertEquals(1, x);
  }

  // HasBinding, HasBinding
  assertEquals(2, calls);
}
TestUseProxyAsUnscopables();


function TestThrowInHasUnscopables() {
  var x = 1;
  var object = {
    x: 2
  };

  function CustomError() {}

  var calls = 0;
  var proxy = new Proxy({}, {
    has: function() {
      assertUnreachable();
    },
    get: function(target, key) {
      if (calls++ === 0) {
        throw new CustomError();
      }
      assertUnreachable();
    }
  });

  object[Symbol.unscopables] = proxy;

  assertThrows(function() {
    with (object) {
      x;
    }
  }, CustomError);
}
TestThrowInHasUnscopables();


var global = this;
function TestGlobalShouldIgnoreUnscopables() {
  global.x = 1;
  var proxy = new Proxy({}, {
    get: function() {
      assertUnreachable();
    },
    has: function() {
      assertUnreachable();
    }
  });
  global[Symbol.unscopables] = proxy;

  assertEquals(1, global.x);
  assertEquals(1, x);

  global.x = 2;
  assertEquals(2, global.x);
  assertEquals(2, x);

  x = 3;
  assertEquals(3, global.x);
  assertEquals(3, x);
}
TestGlobalShouldIgnoreUnscopables();