procedure TNativeClassTestCase.TestInheritance;
// - Shape (x, y) => Object
//   - Circle (x, y, r) => Shape (x, y)
//   - Rectangle (x, y, w, h) => Shape (x, y)
//     - Square (x, y, w) => Rectangle (x, y, w, w)
  Runtime: TChakraCoreRuntime;
  Context: TChakraCoreContext;
  ShapeObj, CircleObj, RectangleObj, SquareObj: JsValueRef;
begin
  Runtime := nil;
  Context := nil;
  try
    Runtime := TChakraCoreRuntime.Create([]);
    Context := TChakraCoreContext.Create(Runtime);
    Context.Activate;
    TRectangle.Project('Rectangle');

    JsRunScript(SScript, SName);

    // var shapeObj = new Shape(10, 10);
    ShapeObj := JsNew('Shape', [IntToJsNumber(10), IntToJsNumber(10)]);
    CheckValueType(JsObject, ShapeObj, 'shapeObj value type');
    CheckTrue(JsInstanceOf(ShapeObj, 'Shape'), 'shapeObj instanceof Shape');
    CheckFalse(JsInstanceOf(ShapeObj, 'Circle'), 'shapeObj instanceof Circle');
    CheckFalse(JsInstanceOf(ShapeObj, 'Rectangle'), 'shapeObj instanceof Rectangle');
    CheckFalse(JsInstanceOf(ShapeObj, 'Square'), 'shapeObj instanceof Square');

    CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x before move');
    CheckEquals(10, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y before move');
    JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], ShapeObj);
    CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'x')), 'shapeObj.x after move');
    CheckEquals(20, JsNumberToInt(JsGetProperty(ShapeObj, 'y')), 'shapeObj.y after move');

    // var circleObj = new Circle(10, 10, 10);
    CircleObj := JsNew('Circle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(10)]);
    CheckValueType(JsObject, CircleObj, 'circleObj value type');
    CheckTrue(JsInstanceOf(CircleObj, 'Shape'), 'circleObj instanceof Shape');
    CheckTrue(JsInstanceOf(CircleObj, 'Circle'), 'circleObj instanceof Circle');
    CheckFalse(JsInstanceOf(CircleObj, 'Rectangle'), 'circleObj instanceof Rectangle');
    CheckFalse(JsInstanceOf(CircleObj, 'Square'), 'circleObj instanceof Square');

    CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x before move');
    CheckEquals(10, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y before move');
    JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], CircleObj);
    CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'x')), 'circleObj.x after move');
    CheckEquals(20, JsNumberToInt(JsGetProperty(CircleObj, 'y')), 'circleObj.y after move');

    // var rectangleObj = new Rectangle(10, 10, 60, 40);
    RectangleObj := JsNew('Rectangle', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(60), IntToJsNumber(40)]);
    CheckValueType(JsObject, RectangleObj, 'rectangleObj value type');
    CheckTrue(JsInstanceOf(RectangleObj, 'Shape'), 'rectangleObj instanceof Shape');
    CheckFalse(JsInstanceOf(RectangleObj, 'Circle'), 'rectangleObj instanceof Circle');
    CheckTrue(JsInstanceOf(RectangleObj, 'Rectangle'), 'rectangleObj instanceof Rectangle');
    CheckFalse(JsInstanceOf(RectangleObj, 'Square'), 'rectangleObj instanceof Square');

    CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x before move');
    CheckEquals(10, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y before move');
    JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], RectangleObj);
    CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'x')), 'rectangleObj.x after move');
    CheckEquals(20, JsNumberToInt(JsGetProperty(RectangleObj, 'y')), 'rectangleObj.y after move');

    // var squareObj = new Square(10, 10, 20);
    SquareObj := JsNew('Square', [IntToJsNumber(10), IntToJsNumber(10), IntToJsNumber(20)]);
    CheckValueType(JsObject, SquareObj, 'squareObj value type');
    CheckTrue(JsInstanceOf(SquareObj, 'Shape'), 'squareObj instanceof Shape');
    CheckFalse(JsInstanceOf(SquareObj, 'Circle'), 'squareObj instanceof Circle');
    CheckTrue(JsInstanceOf(SquareObj, 'Rectangle'), 'squareObj instanceof Rectangle');
    CheckTrue(JsInstanceOf(SquareObj, 'Square'), 'squareObj instanceof Square');

    CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x before move');
    CheckEquals(10, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'sqaureObj.y before move');
    JsCallFunction('move', [IntToJsNumber(10), IntToJsNumber(10)], SquareObj);
    CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'x')), 'squareObj.x after move');
    CheckEquals(20, JsNumberToInt(JsGetProperty(SquareObj, 'y')), 'squareObj.y after move');
  finally
    Context.Free;
    Runtime.Free;
  end;
end;