Update CSSNodeFree for C#, Java and Objective-C

Summary:
- Update CSSNodeFree to unlink parent and children for C#, Java and Objective-C bindings finalizer.
- [C#] Fix build (Fix #232)
- [C#] Add Clear API for convenience as CSSNodeFreeRecursive.
- [C#] Revise and add unit tests

Reviewed By: emilsjolander

Differential Revision: D4069655

fbshipit-source-id: 1fd764059784d7968af38b6aaf7fb6f70fdee8ee
This commit is contained in:
Kazuki Sakamoto
2016-10-25 07:38:06 -07:00
committed by Facebook Github Bot
parent 4d0e657653
commit 2168d68007
3 changed files with 67 additions and 94 deletions

View File

@@ -155,6 +155,17 @@ CSSNodeRef CSSNodeNew(void) {
} }
void CSSNodeFree(const CSSNodeRef node) { void CSSNodeFree(const CSSNodeRef node) {
if (node->parent) {
CSSNodeListDelete(node->parent->children, node);
node->parent = NULL;
}
const uint32_t childCount = CSSNodeChildCount(node);
for (uint32_t i = 0; i < childCount; i++) {
const CSSNodeRef child = CSSNodeGetChild(node, i);
child->parent = NULL;
}
CSSNodeListFree(node->children); CSSNodeListFree(node->children);
free(node); free(node);
gNodeInstanceCount--; gNodeInstanceCount--;

View File

@@ -15,7 +15,7 @@ using System.Text;
namespace Facebook.CSSLayout namespace Facebook.CSSLayout
{ {
public class CSSNode : IDisposable, IEnumerable<CSSNode> public class CSSNode : IEnumerable<CSSNode>
{ {
private IntPtr _cssNode; private IntPtr _cssNode;
@@ -35,7 +35,6 @@ namespace Facebook.CSSLayout
{ {
throw new InvalidOperationException("Failed to allocate native memory"); throw new InvalidOperationException("Failed to allocate native memory");
} }
} }
~CSSNode() ~CSSNode()
@@ -483,6 +482,14 @@ namespace Facebook.CSSLayout
Native.CSSNodeRemoveChild(_cssNode, child._cssNode); Native.CSSNodeRemoveChild(_cssNode, child._cssNode);
} }
public void Clear()
{
while (_children.Count > 0)
{
RemoveAt(0);
}
}
public int IndexOf(CSSNode node) public int IndexOf(CSSNode node)
{ {
return _children.IndexOf(node); return _children.IndexOf(node);

View File

@@ -52,117 +52,50 @@ namespace Facebook.CSSLayout
} }
[Test] [Test]
[ExpectedException("System.InvalidOperationException")] public void TestReset()
public void TestAlreadyInitialize()
{ {
CSSNode node = new CSSNode();
node.Reinitialize();
}
[Test]
[ExpectedException("System.InvalidOperationException")]
public void TestNullNativePointer()
{
CSSNode node = new CSSNode();
node.Free();
node.CalculateLayout();
}
[Test]
[ExpectedException("System.InvalidOperationException")]
public void TestDoubleFree()
{
CSSNode node = new CSSNode();
node.Free();
node.Free();
}
[Test]
public void TestReinitialize()
{
CSSNode node = new CSSNode();
node.Free();
node.Reinitialize();
}
[Test]
[ExpectedException("System.ObjectDisposedException")]
public void TestDisposed()
{
CSSNode node = new CSSNode();
node.Dispose();
node.CalculateLayout();
}
[Test]
public void TestFree()
{
CSSNode node = new CSSNode();
node.Free();
}
[Test]
public void TestDispose()
{
ForceGC();
int instanceCount = CSSNode.GetInstanceCount(); int instanceCount = CSSNode.GetInstanceCount();
CSSNode node = new CSSNode(); CSSNode node = new CSSNode();
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount()); Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
node.Dispose(); node.Reset();
Assert.AreEqual(instanceCount, CSSNode.GetInstanceCount()); Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
}
[Test]
public void TestDisposeWithUsing()
{
ForceGC();
int instanceCount = CSSNode.GetInstanceCount();
using (CSSNode node = new CSSNode())
{
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
}
Assert.AreEqual(instanceCount, CSSNode.GetInstanceCount());
} }
[Test] [Test]
[ExpectedException("System.InvalidOperationException")] [ExpectedException("System.InvalidOperationException")]
public void TestFreeParent() public void TestResetParent()
{ {
CSSNode parent = new CSSNode(); CSSNode parent = new CSSNode();
CSSNode child = new CSSNode(); CSSNode child = new CSSNode();
parent.Insert(0, child); parent.Insert(0, child);
parent.Free(); parent.Reset();
} }
[Test] [Test]
[ExpectedException("System.InvalidOperationException")] [ExpectedException("System.InvalidOperationException")]
public void TestFreeChild() public void TestResetChild()
{ {
CSSNode parent = new CSSNode(); CSSNode parent = new CSSNode();
CSSNode child = new CSSNode(); CSSNode child = new CSSNode();
parent.Insert(0, child); parent.Insert(0, child);
child.Free(); child.Reset();
} }
[Test] [Test]
public void TestDisposeChild() public void TestClear()
{ {
ForceGC();
int instanceCount = CSSNode.GetInstanceCount(); int instanceCount = CSSNode.GetInstanceCount();
CSSNode parent = new CSSNode(); CSSNode parent = new CSSNode();
CSSNode child0 = new CSSNode(); Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
CSSNode child1 = new CSSNode(); CSSNode child = new CSSNode();
Assert.AreEqual(instanceCount + 3, CSSNode.GetInstanceCount());
Assert.AreEqual(0, parent.Count);
parent.Insert(0, child1);
Assert.AreEqual(0, parent.IndexOf(child1));
parent.Insert(0, child0);
Assert.AreEqual(0, parent.IndexOf(child0));
Assert.AreEqual(1, parent.IndexOf(child1));
child0.Dispose();
Assert.AreEqual(instanceCount + 2, CSSNode.GetInstanceCount()); Assert.AreEqual(instanceCount + 2, CSSNode.GetInstanceCount());
parent.Insert(0, child);
Assert.AreEqual(1, parent.Count); Assert.AreEqual(1, parent.Count);
Assert.AreEqual(0, parent.IndexOf(child1)); Assert.AreEqual(parent, child.Parent);
parent.Clear();
Assert.AreEqual(0, parent.Count);
Assert.IsNull(child.Parent);
Assert.AreEqual(instanceCount + 2, CSSNode.GetInstanceCount());
} }
[Test] [Test]
@@ -257,26 +190,48 @@ namespace Facebook.CSSLayout
} }
[Test] [Test]
public void TestDisposeParent() public void TestParentDestructor()
{ {
ForceGC(); ForceGC();
int instanceCount = CSSNode.GetInstanceCount(); int instanceCount = CSSNode.GetInstanceCount();
CSSNode parent = new CSSNode(); CSSNode child = new CSSNode();
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount()); Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
TestDisposeParentForGC(parent, instanceCount + 1);
TestParentDestructorForGC(child, instanceCount + 1);
ForceGC(); ForceGC();
Assert.AreEqual(instanceCount + 2, CSSNode.GetInstanceCount());
parent.Dispose(); Assert.IsNull(child.Parent);
ForceGC(); Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
Assert.AreEqual(instanceCount, CSSNode.GetInstanceCount());
} }
private void TestDisposeParentForGC(CSSNode parent, int instanceCount) private void TestParentDestructorForGC(CSSNode child, int instanceCount)
{
CSSNode parent = new CSSNode();
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
parent.Insert(0, child);
}
[Test]
public void TestClearWithChildDestructor()
{
ForceGC();
int instanceCount = CSSNode.GetInstanceCount();
CSSNode node = new CSSNode();
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
TestClearWithChildDestructorForGC(node, instanceCount + 1);
ForceGC();
Assert.AreEqual(instanceCount + 2, CSSNode.GetInstanceCount());
node.Clear();
Assert.AreEqual(0, node.Count);
ForceGC();
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
}
private void TestClearWithChildDestructorForGC(CSSNode parent, int instanceCount)
{ {
CSSNode child = new CSSNode(); CSSNode child = new CSSNode();
Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount()); Assert.AreEqual(instanceCount + 1, CSSNode.GetInstanceCount());
parent.Insert(0, child); parent.Insert(0, child);
child = null;
} }
#endif #endif
} }