| /******************************************************************************* |
| * Copyright (c) 2015, 2016 Google, Inc and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Stefan Xenos (Google) - Initial implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.nd; |
| |
| import org.eclipse.jdt.core.tests.nd.util.BaseTestCase; |
| import org.eclipse.jdt.internal.core.nd.Nd; |
| import org.eclipse.jdt.internal.core.nd.NdNode; |
| import org.eclipse.jdt.internal.core.nd.NdNodeTypeRegistry; |
| import org.eclipse.jdt.internal.core.nd.field.FieldOneToOne; |
| import org.eclipse.jdt.internal.core.nd.field.StructDef; |
| |
| import junit.framework.Test; |
| |
| public class FieldOneToOneTest extends BaseTestCase { |
| static int struct2Deletions; |
| static int structDeletions; |
| |
| public static class TestStruct extends NdNode { |
| public static final FieldOneToOne<TestStruct2> ANOTHER_STRUCT; |
| public static final FieldOneToOne<TestStruct2> OWNED; |
| |
| @SuppressWarnings("hiding") |
| public static final StructDef<TestStruct> type; |
| |
| static { |
| type = StructDef.create(TestStruct.class, NdNode.type); |
| |
| ANOTHER_STRUCT = FieldOneToOne.create(type, TestStruct2.type, TestStruct2.ANOTHER_STRUCT); |
| OWNED = FieldOneToOne.create(type, TestStruct2.type, TestStruct2.OWNER); |
| type.done(); |
| } |
| |
| public TestStruct(Nd nd) { |
| super(nd); |
| } |
| |
| public TestStruct(Nd nd, long record) { |
| super(nd, record); |
| } |
| |
| public void setAnother(TestStruct2 toSet) { |
| ANOTHER_STRUCT.put(getNd(), this.address, toSet); |
| } |
| |
| public TestStruct2 getAnother() { |
| return ANOTHER_STRUCT.get(getNd(), this.address); |
| } |
| |
| public void setOwned(TestStruct2 owned) { |
| OWNED.put(getNd(), this.address, owned); |
| } |
| |
| public TestStruct2 getOwned() { |
| return OWNED.get(getNd(), this.address); |
| } |
| |
| @Override |
| public void destruct() { |
| super.destruct(); |
| FieldOneToOneTest.structDeletions++; |
| } |
| } |
| |
| public static class TestStruct2 extends NdNode { |
| public static final FieldOneToOne<TestStruct> OWNER; |
| public static final FieldOneToOne<TestStruct> ANOTHER_STRUCT; |
| |
| @SuppressWarnings("hiding") |
| public static final StructDef<TestStruct2> type; |
| |
| static { |
| type = StructDef.create(TestStruct2.class, NdNode.type); |
| |
| OWNER = FieldOneToOne.createOwner(type, TestStruct.type, TestStruct.OWNED); |
| ANOTHER_STRUCT = FieldOneToOne.create(type, TestStruct.type, TestStruct.ANOTHER_STRUCT); |
| |
| type.done(); |
| } |
| |
| public TestStruct2(Nd nd) { |
| super(nd); |
| } |
| |
| public TestStruct2(Nd nd, long record) { |
| super(nd, record); |
| } |
| |
| public void setAnother(TestStruct toSet) { |
| ANOTHER_STRUCT.put(getNd(), this.address, toSet); |
| } |
| |
| public TestStruct getAnother() { |
| return ANOTHER_STRUCT.get(getNd(), this.address); |
| } |
| |
| public void setOwner(TestStruct owner) { |
| OWNER.put(getNd(), this.address, owner); |
| } |
| |
| public TestStruct getOwner() { |
| return OWNER.get(getNd(), this.address); |
| } |
| |
| @Override |
| public void destruct() { |
| super.destruct(); |
| FieldOneToOneTest.struct2Deletions++; |
| } |
| } |
| |
| TestStruct referencer; |
| TestStruct owner; |
| TestStruct2 referenced; |
| TestStruct2 owned; |
| private Nd nd; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| |
| structDeletions = 0; |
| struct2Deletions = 0; |
| NdNodeTypeRegistry<NdNode> registry = new NdNodeTypeRegistry<>(); |
| registry.register(0, TestStruct2.type.getFactory()); |
| registry.register(1, TestStruct.type.getFactory()); |
| this.nd = DatabaseTestUtil.createEmptyNd(getName(), registry); |
| this.nd.getDB().setExclusiveLock(); |
| this.referencer = new TestStruct(this.nd); |
| this.owner = new TestStruct(this.nd); |
| this.referenced = new TestStruct2(this.nd); |
| this.owned = new TestStruct2(this.nd); |
| |
| this.owner.setOwned(this.owned); |
| this.referencer.setAnother(this.referenced); |
| } |
| |
| public static Test suite() { |
| return BaseTestCase.suite(FieldOneToOneTest.class); |
| } |
| |
| public void testPointersSetCorrectly() { |
| assertEquals(this.owner.address, this.owned.getOwner().address); |
| assertEquals(this.owned.address, this.owner.getOwned().address); |
| assertEquals(this.referencer.address, this.referenced.getAnother().address); |
| assertEquals(this.referenced.address, this.referencer.getAnother().address); |
| } |
| |
| public void testClearingOwnerDeletesOwned() { |
| long freed = this.nd.getDB().getBytesFreed(); |
| |
| this.owner.setOwned(null); |
| |
| this.nd.processDeletions(); |
| |
| assertEquals(null, this.owner.getOwned()); |
| assertTrue(this.nd.getDB().getBytesFreed() - freed >= TestStruct2.type.size()); |
| assertEquals(1, struct2Deletions); |
| } |
| |
| public void testDeletingOwnerDeletesOwned() { |
| long freed = this.nd.getDB().getBytesFreed(); |
| |
| this.owner.delete(); |
| |
| this.nd.processDeletions(); |
| |
| assertTrue(this.nd.getDB().getBytesFreed() - freed >= TestStruct2.type.size() + TestStruct.type.size()); |
| assertEquals(1, struct2Deletions); |
| assertEquals(1, structDeletions); |
| } |
| |
| public void testReassignedOwnerDeletesOwned() { |
| long freed = this.nd.getDB().getBytesFreed(); |
| TestStruct2 newOwned = new TestStruct2(this.nd); |
| |
| this.owner.setOwned(newOwned); |
| |
| this.nd.processDeletions(); |
| |
| long freed2 = this.nd.getDB().getBytesFreed(); |
| |
| assertEquals(newOwned, this.owner.getOwned()); |
| assertTrue(freed2 - freed >= TestStruct2.type.size()); |
| assertEquals(1, struct2Deletions); |
| } |
| |
| public void testMovingToNewOwnerDoesntDeleteOwned() { |
| long freed = this.nd.getDB().getBytesFreed(); |
| TestStruct newOwner = new TestStruct(this.nd); |
| |
| this.owned.setOwner(newOwner); |
| |
| this.nd.processDeletions(); |
| |
| long freed2 = this.nd.getDB().getBytesFreed(); |
| |
| assertEquals(freed, freed2); |
| assertEquals(null, this.owner.getOwned()); |
| assertEquals(this.owned, newOwner.getOwned()); |
| assertEquals(0, struct2Deletions); |
| assertEquals(0, structDeletions); |
| } |
| |
| public void testMovingToNewOwnerAfterClearingOwnerPointerDoesntDeleteOwned() { |
| long freed = this.nd.getDB().getBytesFreed(); |
| TestStruct newOwner = new TestStruct(this.nd); |
| |
| this.owner.setOwned(null); |
| this.owned.setOwner(newOwner); |
| |
| this.nd.processDeletions(); |
| |
| long freed2 = this.nd.getDB().getBytesFreed(); |
| |
| assertEquals(freed, freed2); |
| assertEquals(null, this.owner.getOwned()); |
| assertEquals(this.owned, newOwner.getOwned()); |
| assertEquals(0, struct2Deletions); |
| assertEquals(0, structDeletions); |
| } |
| |
| public void testClearingOwnerPointerDeletesOwned() { |
| long freed = this.nd.getDB().getBytesFreed(); |
| |
| this.owned.setOwner(null); |
| |
| this.nd.processDeletions(); |
| |
| long freed2 = this.nd.getDB().getBytesFreed(); |
| |
| assertTrue(freed2 - freed >= TestStruct2.type.size()); |
| assertEquals(null, this.owner.getOwned()); |
| assertEquals(1, struct2Deletions); |
| assertEquals(0, structDeletions); |
| } |
| |
| public void testMovingReferenceClearsOldBackPointer() { |
| TestStruct2 newTarget = new TestStruct2(this.nd); |
| |
| long freed = this.nd.getDB().getBytesFreed(); |
| this.referencer.setAnother(newTarget); |
| this.nd.processDeletions(); |
| |
| long freed2 = this.nd.getDB().getBytesFreed(); |
| assertEquals(newTarget, this.referencer.getAnother()); |
| assertEquals(null, this.referenced.getAnother()); |
| assertEquals(freed, freed2); |
| } |
| } |