/**

The FlowedLaoyut test engine takes expected layouts for a set of conditions. All units
are expected in the horizontal orientation; they will be flipped automatically for vertical
tests (and the view's width/height/fillWidth/etc. settings changed likewise).

- With Wrap, 600x400.
- With wrap, 400x600.
- No wrap, 600x400.
- No wrap, 400x600

The expected positioning should be supplied to the checkPositions method:

{
  wrap: {
    // these are by width (600x400 should use '600')
    '400': [ { left: ..., top: ..., width: ..., height: ... } ],
    '600': ...
  },
  noWrap: {
    ...
  }
}

It is a recursive process; each step has multiple possible varieties, and ALL
combinations are tested. The first variety is always tested twice.

For instance, it tests 600x400, then 400x600, then 600x400 again.

- 600x400 or 400x600
- Wrap on and wrap off
- Horizontal or Vertical

*/

// helper to make a string from a hash var str = function(obj) {

var s = [];
for (var i in obj) {
  s.push("" + i + ": " + obj[i]);
}
return "{ " + s.join(", ") + "}";

};

var checkSteps = [

function wrap(view, positions, context) {
  SC.RunLoop.begin();
  view.set('canWrap', YES);
  SC.RunLoop.end();

  context.performNext(positions.wrap);

  SC.RunLoop.begin();
  view.set('canWrap', NO);
  SC.RunLoop.end();

  context.performNext(positions.noWrap);

  SC.RunLoop.begin();
  view.set('canWrap', YES);
  SC.RunLoop.end();

  context.performNext(positions.wrap);
},

function dimensions(view, positions, context) {
  SC.RunLoop.begin();
  view.set('layout', { left: 0, top: 0, width: 600, height: 400 });
  SC.RunLoop.end();

  context.performNext(positions['600']);

  SC.RunLoop.begin();
  view.set('layout', { left: 0, top: 0, width: 400, height: 600});
  SC.RunLoop.end();

  context.performNext(positions['400']);

  SC.RunLoop.begin();
  view.set('layout', { left: 0, top: 0, width: 600, height: 400 });
  SC.RunLoop.end();

  context.performNext(positions['600']);
},

function orientation(view, positions, context) {
  // we have to convert the positions. By now they should be a simple array,
  // so we just swap width and height.
  var verticalPositions = [];
  for (var idx = 0, len = positions.length; idx < len; idx++) {
    verticalPositions[idx] = {
      left: positions[idx].top,
      top: positions[idx].left,
      width: positions[idx].height,
      height: positions[idx].width
    };
  }

  function flipChildViews() {
    var cvs = view.get('childViews');
    for (var idx = 0, len = cvs.length; idx < len; idx++) {
      var layout = cvs[idx].get('layout');
      layout = SC.clone(layout);

      var tmp = layout.width;
      layout.width = layout.height;
      layout.height = tmp;

      cvs[idx].set('layout', layout);

      var fillWidth = cvs[idx].get('fillWidth');
      cvs[idx].set('fillWidth', cvs[idx].get('fillHeight'));
      cvs[idx].set('fillHeight', fillWidth);
    }
  }

  function flipLayout() {
    var l = SC.clone(view.get('layout'));
    var w = l.width;
    l.width= l.height;
    l.height = w;
    view.set('layout', l);

    if (view.get('flowPadding')) {
      l = SC.clone(view.get('flowPadding'));
      var tmp = l.left;
      l.left = l.top;
      l.top = tmp;

      tmp = l.right;
      l.right = l.bottom;
      l.bottom = tmp;
      view.set('flowPadding', l);
    }
  }

  SC.RunLoop.begin();
  view.set('layoutDirection', SC.LAYOUT_HORIZONTAL);
  SC.RunLoop.end();

  context.performNext(positions);

  SC.RunLoop.begin();
  view.set('layoutDirection', SC.LAYOUT_VERTICAL);
  flipChildViews();
  flipLayout();
  SC.RunLoop.end();

  context.performNext(verticalPositions);

  SC.RunLoop.begin();
  view.set('layoutDirection', SC.LAYOUT_HORIZONTAL);
  flipChildViews();
  flipLayout();
  SC.RunLoop.end();

  context.performNext(positions);
},

function final(view, positions, context) {
  var cvs = view.get('childViews');
  equals(cvs.length, positions.length, "PRECONDITION: number of child views is the same.");

  for (var idx = 0; idx < positions.length; idx++) {
    var cv = cvs[idx], expect = positions[idx], equal = YES;
    for (var i in expect) {
      if (expect.hasOwnProperty(i)) {
        if (cv.get('layout')[i] !== expect[i]) {
          equal = NO;
          break;
        }
      }
    }

    ok(
      equal,
      "Actual: " +
      str(cv.get('layout')) + "; expected: " +
      str(expect) + "; canWrap: " + view.get('canWrap') + "; " +
      "orientation: " + view.get('layoutDirection') + "; " +
      "layout: " + str(view.get('layout'))
    );
  }
}

];

function checkPositions(view, positions) {

view.set('isVisibleInWindow', YES);
var context = {
  position: 0,
  performNext: function(positions) {
    var next = checkSteps[this.position];
    this.position++;
    next(view, positions, this);
    this.position--;
  }
};

context.performNext(positions);

}

module(“FlowedLayout”);

test(“Basic flow”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 300, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

view.destroy();

});

module(“FlowedLayout – Alignment”); test(“Align center”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 300, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.set('align', SC.ALIGN_CENTER);
SC.RunLoop.end();

expect.wrap['400'][2].left = 100;

expect.noWrap['400'][0].left = -100;
expect.noWrap['400'][1].left = 0;
expect.noWrap['400'][2].left = 300;

checkPositions(view, expect);
view.destroy();

});

test(“Align right”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 300, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.set('align', SC.ALIGN_RIGHT);
SC.RunLoop.end();

expect.wrap['400'][2].left = 200;

expect.noWrap['400'][0].left = -200;
expect.noWrap['400'][1].left = -100;
expect.noWrap['400'][2].left = 200;

checkPositions(view, expect);
view.destroy();

});

test(“Align justify”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.set('align', SC.ALIGN_JUSTIFY);
SC.RunLoop.end();

expect.wrap['400'][1].left = 200;

expect.wrap['600'][1].left = 150;
expect.wrap['600'][2].left = 400;

expect.noWrap['600'][1].left = 150;
expect.noWrap['600'][2].left = 400;

checkPositions(view, expect);
view.destroy();

});

module(“FlowedLayout - Flags”);

test(“flowPadding”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.set('flowPadding', { left: 5, top: 8, right: 210, bottom: 0 });
SC.RunLoop.end();

expect.wrap[400][0].left = 5;
expect.wrap[400][0].top = 8;
expect.wrap[400][1].left = 5;
expect.wrap[400][1].top = 108;
expect.wrap[400][2].left = 5;
expect.wrap[400][2].top = 208;

expect.wrap[600][0].left = 5;
expect.wrap[600][0].top = 8;
expect.wrap[600][1].left = 105;
expect.wrap[600][1].top = 8;
expect.wrap[600][2].left = 5;
expect.wrap[600][2].top = 108;

expect.noWrap[400][0].left = 5;
expect.noWrap[400][0].top = 8;
expect.noWrap[400][1].left = 105;
expect.noWrap[400][1].top = 8;
expect.noWrap[400][2].left = 305;
expect.noWrap[400][2].top = 8;

expect.noWrap[600] = expect.noWrap[400];

checkPositions(view, expect);

view.destroy();

});

test(“FlowedLayout - defaultFlowSpacing”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.set('defaultFlowSpacing', 5);
SC.RunLoop.end();

expect.wrap[400][0].left = 5;
expect.wrap[400][0].top = 5;
expect.wrap[400][1].left = 115;
expect.wrap[400][1].top = 5;
expect.wrap[400][2].left = 5;
expect.wrap[400][2].top = 115;

expect.wrap[600][0].left = 5;
expect.wrap[600][0].top = 5;
expect.wrap[600][1].left = 115;
expect.wrap[600][1].top = 5;
expect.wrap[600][2].left = 325;
expect.wrap[600][2].top = 5;

expect.noWrap[600] = expect.noWrap[400] = expect.wrap[600];

checkPositions(view, expect);
view.destroy();

});

module(“FlowedLayout - Child View Flags”);

test(“startsNewRow”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

view._doRender();
view._doAttach(document.body);

checkPositions(view, expect);

SC.RunLoop.begin();
view.childViews[1].set('startsNewRow', YES);
SC.RunLoop.end();

expect.wrap[400][1].top = 100;
expect.wrap[400][1].left = 0;

expect.wrap[400][2].left = 200;
expect.wrap[400][2].top = 100;

expect.wrap[600] = expect.wrap[400];
expect.noWrap = expect.wrap;

checkPositions(view, expect);

view.destroy();

});

test(“flowSpacing”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.childViews[1].set('flowSpacing', { left: 20, top: 20, bottom: 20, right: 20 });
SC.RunLoop.end();

expect.wrap[400][1].left = 120;
expect.wrap[400][1].top = 20;
expect.wrap[400][2].top = 140;

expect.wrap[600][1].left = 120;
expect.wrap[600][1].top = 20;
expect.wrap[600][2].left = 340;

// because wrap is off, it should look like the results for wrapping 600 which,
// due to its width, doesn't wrap either.
expect.noWrap[400] = expect.noWrap[600] = expect.wrap[600];

checkPositions(view, expect);

view.destroy();

});

test(“fillHeight”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 50 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 50 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 50 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 50 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 50 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.childViews[1].set('fillHeight', YES);
SC.RunLoop.end();

expect.wrap[400][1].height = 100;
expect.wrap[600][1].height = 100;
expect.noWrap[400][1].height = 100;
expect.noWrap[600][1].height = 100;

checkPositions(view, expect);

view.destroy();

});

test(“isSpacer”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  align: SC.ALIGN_LEFT,

  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 200, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 200, height: 100 },
      { left: 300, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

SC.RunLoop.begin();
view.childViews[1].set('isSpacer', YES);
SC.RunLoop.end();

expect.wrap[400][1].width = 100;
expect.wrap[400][2].top = 0;
expect.wrap[400][2].left = 200;

expect.wrap[600][1].width = 300;
expect.wrap[600][2].left = 400;
expect.noWrap[400] = expect.wrap[400];
expect.noWrap[600] = expect.wrap[600];

checkPositions(view, expect);

view.destroy();

});

test(“undefined and null can be passed for both defaultFlowSpacing and child's flowSpacing”, function() {

var view = SC.View.create(SC.FlowedLayout, {
  childViews: 'a b c'.w(),

  a: SC.View.create({
    layout: { width: 100, height: 100 }
  }),

  b: SC.View.create({
    layout: { width: 300, height: 100 }
  }),

  c: SC.View.create({
    layout: { width: 200, height: 100 }
  })
});

view._doRender();
view._doAttach(document.body);

var expect = {
  wrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 0, top: 100, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  },

  noWrap: {
    400: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ],
    600: [
      { left: 0, top: 0, width: 100, height: 100 },
      { left: 100, top: 0, width: 300, height: 100 },
      { left: 400, top: 0, width: 200, height: 100 }
    ]
  }
};

checkPositions(view, expect);

view.set('defaultFlowSpacing', undefined);

checkPositions(view, expect);

view.destroy();

});

test(“Observed childViews”, function() {

var view;

SC.run(function() {
  view = SC.View.create(SC.FlowedLayout, {
    childViews: 'a b c'.w(),

    a: SC.View.create({
      layout: { width: 100, height: 100 }
    }),

    b: SC.View.create({
      layout: { width: 300, height: 100 }
    }),

    c: SC.View.create({
      layout: { width: 200, height: 100 }
    })
  });
  view._doRender();
  view._doAttach(document.body);
});

// TODO: Redo this without poking private implementations.
ok(view._scfl_isObserving.contains(view.a), "FlowedLayout view should observe all three childViews (a).");
ok(view._scfl_isObserving.contains(view.b), "FlowedLayout view should observe all three childViews (b).");
ok(view._scfl_isObserving.contains(view.c), "FlowedLayout view should observe all three childViews (c).");

// Remove a child view.
SC.run(function() {
  view.removeChild(view.b);
});

ok(!view._scfl_isObserving.contains(view.b), "FlowedLayout view should no longer observe the layout of a removed child view (b).");
ok(view._scfl_isObserving.contains(view.a), "FlowedLayout view should still be observing all three childViews (a).");
ok(view._scfl_isObserving.contains(view.c), "FlowedLayout view should still be observing all three childViews (c).");

// Cleanup
view.destroy();

});