// Copyright 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.

// Flags: --expose-debug-as debug
// Test the mirror object for objects

function MirrorRefCache(json_refs) {
  var tmp = eval('(' + json_refs + ')');
  this.refs_ = [];
  for (var i = 0; i < tmp.length; i++) {
    this.refs_[tmp[i].handle] = tmp[i];
  }
}

MirrorRefCache.prototype.lookup = function(handle) {
  return this.refs_[handle];
}

function testArrayMirror(a, names) {
  // Create mirror and JSON representation.
  var mirror = debug.MakeMirror(a);
  var serializer = debug.MakeMirrorSerializer();
  var json = JSON.stringify(serializer.serializeValue(mirror));
  var refs = new MirrorRefCache(
      JSON.stringify(serializer.serializeReferencedObjects()));

  // Check the mirror hierachy.
  assertTrue(mirror instanceof debug.Mirror, 'Unexpected mirror hierachy');
  assertTrue(mirror instanceof debug.ValueMirror, 'Unexpected mirror hierachy');
  assertTrue(mirror instanceof debug.ObjectMirror, 'Unexpected mirror hierachy');
  assertTrue(mirror instanceof debug.ArrayMirror, 'Unexpected mirror hierachy');

  // Check the mirror properties.
  assertTrue(mirror.isArray(), 'Unexpected mirror');
  assertEquals('object', mirror.type(), 'Unexpected mirror type');
  assertFalse(mirror.isPrimitive(), 'Unexpected primitive mirror');
  assertEquals('Array', mirror.className(), 'Unexpected mirror class name');
  assertTrue(mirror.constructorFunction() instanceof debug.ObjectMirror, 'Unexpected mirror hierachy');
  assertEquals('Array', mirror.constructorFunction().name(), 'Unexpected constructor function name');
  assertTrue(mirror.protoObject() instanceof debug.Mirror, 'Unexpected mirror hierachy');
  assertTrue(mirror.prototypeObject() instanceof debug.Mirror, 'Unexpected mirror hierachy');
  assertEquals(mirror.length(), a.length, "Length mismatch");

  var indexedProperties = mirror.indexedPropertiesFromRange();
  assertEquals(indexedProperties.length, a.length);
  for (var i = 0; i < indexedProperties.length; i++) {
    assertTrue(indexedProperties[i] instanceof debug.Mirror, 'Unexpected mirror hierachy');
    assertTrue(indexedProperties[i] instanceof debug.PropertyMirror, 'Unexpected mirror hierachy');
  }

  // Parse JSON representation and check.
  var fromJSON = eval('(' + json + ')');
  assertEquals('object', fromJSON.type, 'Unexpected mirror type in JSON');
  assertEquals('Array', fromJSON.className, 'Unexpected mirror class name in JSON');
  assertEquals(mirror.constructorFunction().handle(), fromJSON.constructorFunction.ref, 'Unexpected constructor function handle in JSON');
  assertEquals('function', refs.lookup(fromJSON.constructorFunction.ref).type, 'Unexpected constructor function type in JSON');
  assertEquals('Array', refs.lookup(fromJSON.constructorFunction.ref).name, 'Unexpected constructor function name in JSON');
  assertEquals(void 0, fromJSON.namedInterceptor, 'No named interceptor expected in JSON');
  assertEquals(void 0, fromJSON.indexedInterceptor, 'No indexed interceptor expected in JSON');

  // Check that the serialization contains all indexed properties and the length property.
  var length_found = false;
  for (var i = 0; i < fromJSON.properties.length; i++) {
    if (fromJSON.properties[i].name == 'length') {
      length_found = true;
      assertEquals('number', refs.lookup(fromJSON.properties[i].ref).type, "Unexpected type of the length property");
      assertEquals(a.length, refs.lookup(fromJSON.properties[i].ref).value, "Length mismatch in parsed JSON");
    } else {
      var index = parseInt(fromJSON.properties[i].name);
        print(index);
      if (!isNaN(index)) {
        print(index);
        // This test assumes that the order of the indexeed properties is in the
        // same order in the serialization as returned from
        // indexedPropertiesFromRange()
        assertEquals(indexedProperties[index].name(), index);
        assertEquals(indexedProperties[index].value().type(), refs.lookup(fromJSON.properties[i].ref).type, 'Unexpected serialized type');
      }
    }
  }
  assertTrue(length_found, 'Property length not found');

  // Check that the serialization contains all names properties.
  if (names) {
    for (var i = 0; i < names.length; i++) {
      var found = false;
      for (var j = 0; j < fromJSON.properties.length; j++) {
        if (names[i] == fromJSON.properties[j].name) {
          found = true;
        }
      }
      assertTrue(found, names[i])
    }
  }
}


// Test a number of different arrays.
testArrayMirror([]);
testArrayMirror([1]);
testArrayMirror([1,2]);
testArrayMirror(["a", function(){}, [1,2], 2, /[ab]/]);

a=[1];
a[100]=7;
testArrayMirror(a);

a=[1,2,3];
a.x=2.2;
a.y=function(){return null;}
testArrayMirror(a, ['x','y']);

var a = []; a.push(a);
testArrayMirror(a);
