diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..bb31ae5b --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ + +test: + @gcc src/__tests__/Layout-test.c src/Layout.c && ./a.out + @rm a.out diff --git a/SpecRunner.html b/SpecRunner.html index 6b659bd4..b5283fa6 100755 --- a/SpecRunner.html +++ b/SpecRunner.html @@ -16,6 +16,7 @@ + diff --git a/src/Layout-test-utils.js b/src/Layout-test-utils.js new file mode 100644 index 00000000..9a6e0280 --- /dev/null +++ b/src/Layout-test-utils.js @@ -0,0 +1,119 @@ + +var layoutTestUtils = (function() { + var iframe = (function() { + var iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + var doc = iframe.contentDocument; + + var style = document.createElement('style'); + style.innerText = (function() {/* + body, div { + box-sizing: border-box; + position: relative; + + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: flex-start; + flex-shrink: 0; + + margin: 0; + padding: 0; + } + */} + '').slice(15, -4); + doc.head.appendChild(style); + + return iframe; + })(); + + function computeDOMLayout(node) { + var body = iframe.contentDocument.body; + + function transfer(div, node, name, ext) { + if (name in node.style) { + div.style[name] = node.style[name] + (ext || ''); + } + } + + function transferSpacing(div, node, type) { + transfer(div, node, type, 'px'); + transfer(div, node, type + 'Left', 'px'); + transfer(div, node, type + 'Top', 'px'); + transfer(div, node, type + 'Bottom', 'px'); + transfer(div, node, type + 'Right', 'px'); + } + + function renderNode(parent, node) { + var div = document.createElement('div'); + transfer(div, node, 'width', 'px'); + transfer(div, node, 'height', 'px'); + transfer(div, node, 'top', 'px'); + transfer(div, node, 'left', 'px'); + transfer(div, node, 'right', 'px'); + transfer(div, node, 'bottom', 'px'); + transferSpacing(div, node, 'margin'); + transferSpacing(div, node, 'padding'); + transfer(div, node, 'flexDirection'); + transfer(div, node, 'flex'); + transfer(div, node, 'justifyContent'); + transfer(div, node, 'alignSelf'); + transfer(div, node, 'alignItems'); + transfer(div, node, 'position'); + parent.appendChild(div); + (node.children || []).forEach(function(child) { + renderNode(div, child); + }); + return div; + } + + var div = renderNode(body, node); + + function buildLayout(absoluteRect, div) { + var rect = div.getBoundingClientRect(); + var result = { + width: rect.width, + height: rect.height, + top: rect.top - absoluteRect.top, + left: rect.left - absoluteRect.left + }; + + var children = []; + for (var child = div.firstChild; child; child = child.nextSibling) { + children.push(buildLayout(rect, child)); + } + if (children.length) { + result.children = children; + } + return result; + } + var layout = buildLayout({left: 0, top: 0}, div); + body.removeChild(div); + return layout; + } + + function nameLayout(name, layout) { + var namedLayout = {name: name}; + for (var key in layout) { + namedLayout[key] = layout[key]; + } + return namedLayout; + } + + function testNamedLayout(name, layoutA, layoutB) { + expect(nameLayout(name, layoutA)) + .toEqual(nameLayout(name, layoutB)); + } + + return { + testLayout: function(node, expectedLayout) { + var layout = computeLayout(node); + var domLayout = computeDOMLayout(node); + testNamedLayout('expected-dom', expectedLayout, domLayout); + testNamedLayout('layout-dom', layout, domLayout); + }, + testRandomLayout: function(node, i) { + expect({i: i, node: node, layout: computeLayout(node)}) + .toEqual({i: i, node: node, layout: computeDOMLayout(node)}); + } + } +})(); diff --git a/src/Layout.c b/src/Layout.c index b5ae1754..0754af4f 100644 --- a/src/Layout.c +++ b/src/Layout.c @@ -355,22 +355,3 @@ void layoutNode(css_node_t *node) { node->layout.position[leading[crossAxis]] += getMargin(node, leading[crossAxis]) + getRelativePosition(node, crossAxis); } - - -int main() -{ - css_node_t *node = new_css_node(); - node->style.flex_direction = CSS_FLEX_DIRECTION_ROW; - node->style.dimensions[CSS_WIDTH] = 100; - node->style.align_items = CSS_ALIGN_STRETCH; - - init_css_node_children(node, 3); - node->children[0].style.dimensions[CSS_HEIGHT] = 50; - layoutNode(node); - - print_style(node, 0); - print_layout(node, 0); - - free_css_node(node); -} - diff --git a/src/__tests__/Layout-test.c b/src/__tests__/Layout-test.c new file mode 100644 index 00000000..75bfd030 --- /dev/null +++ b/src/__tests__/Layout-test.c @@ -0,0 +1,34 @@ + +#include "../Layout.h" + +int main() +{ + css_node_t *root_node = new_css_node(); + + css_node_t *node = root_node; + node->style.flex_direction = CSS_FLEX_DIRECTION_ROW; + node->style.dimensions[CSS_WIDTH] = 100; + + init_css_node_children(node, 3); + css_node_t *outer_node = node; + { + css_node_t *node = &outer_node->children[0]; + node->style.dimensions[CSS_HEIGHT] = 50; + node->style.align_items = CSS_ALIGN_STRETCH; + init_css_node_children(node, 3); + css_node_t *outer_node = node; + { + css_node_t *node = &outer_node->children[0]; + node->style.dimensions[CSS_WIDTH] = 50; + } + + node = &outer_node->children[0]; + } + + layoutNode(root_node); + print_style(root_node, 0); + print_layout(root_node, 0); + + free_css_node(node); +} + diff --git a/src/__tests__/Layout-test.js b/src/__tests__/Layout-test.js index 31cdda0d..69164de3 100755 --- a/src/__tests__/Layout-test.js +++ b/src/__tests__/Layout-test.js @@ -1,115 +1,6 @@ - -var iframe = (function() { - var iframe = document.createElement('iframe'); - document.body.appendChild(iframe); - var doc = iframe.contentDocument; - - var style = document.createElement('style'); - style.innerText = (function() {/* - body, div { - box-sizing: border-box; - position: relative; - - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: flex-start; - flex-shrink: 0; - - margin: 0; - padding: 0; - } - */} + '').slice(15, -4); - doc.head.appendChild(style); - - return iframe; -})(); - -function computeDOMLayout(node) { - var body = iframe.contentDocument.body; - - function transfer(div, node, name, ext) { - if (name in node.style) { - div.style[name] = node.style[name] + (ext || ''); - } - } - - function transferSpacing(div, node, type) { - transfer(div, node, type, 'px'); - transfer(div, node, type + 'Left', 'px'); - transfer(div, node, type + 'Top', 'px'); - transfer(div, node, type + 'Bottom', 'px'); - transfer(div, node, type + 'Right', 'px'); - } - - function renderNode(parent, node) { - var div = document.createElement('div'); - transfer(div, node, 'width', 'px'); - transfer(div, node, 'height', 'px'); - transfer(div, node, 'top', 'px'); - transfer(div, node, 'left', 'px'); - transfer(div, node, 'right', 'px'); - transfer(div, node, 'bottom', 'px'); - transferSpacing(div, node, 'margin'); - transferSpacing(div, node, 'padding'); - transfer(div, node, 'flexDirection'); - transfer(div, node, 'flex'); - transfer(div, node, 'justifyContent'); - transfer(div, node, 'alignSelf'); - transfer(div, node, 'alignItems'); - transfer(div, node, 'position'); - parent.appendChild(div); - (node.children || []).forEach(function(child) { - renderNode(div, child); - }); - return div; - } - - var div = renderNode(body, node); - - function buildLayout(absoluteRect, div) { - var rect = div.getBoundingClientRect(); - var result = { - width: rect.width, - height: rect.height, - top: rect.top - absoluteRect.top, - left: rect.left - absoluteRect.left - }; - - var children = []; - for (var child = div.firstChild; child; child = child.nextSibling) { - children.push(buildLayout(rect, child)); - } - if (children.length) { - result.children = children; - } - return result; - } - var layout = buildLayout({left: 0, top: 0}, div); - body.removeChild(div); - return layout; -} - -function nameLayout(name, layout) { - var namedLayout = {name: name}; - for (var key in layout) { - namedLayout[key] = layout[key]; - } - return namedLayout; -} - -function testNamedLayout(name, layoutA, layoutB) { - expect(nameLayout(name, layoutA)) - .toEqual(nameLayout(name, layoutB)); -} - -function testLayout(node, expectedLayout) { - var layout = computeLayout(node); - var domLayout = computeDOMLayout(node); - testNamedLayout('expected-dom', expectedLayout, domLayout); - testNamedLayout('layout-dom', layout, domLayout); -} +var testLayout = layoutTestUtils.testLayout; +var testRandomLayout = layoutTestUtils.testRandomLayout; describe('Layout', function() { it('should layout a single node with width and height', function() { @@ -642,8 +533,7 @@ describe('Layout', function() { delete node.style.flex; delete node.style.position; - expect({i: i, node: node, layout: computeLayout(node)}) - .toEqual({i: i, node: node, layout: computeDOMLayout(node)}); + testRandomLayout(node, i); } })