X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Ftestcases%2Forg%2Fsimantics%2Fdataboard%2Ftests%2FTestAccessor.java;fp=bundles%2Forg.simantics.databoard%2Ftestcases%2Forg%2Fsimantics%2Fdataboard%2Ftests%2FTestAccessor.java;h=0d0e3f3c1ed7070d9ad84334e3f9b3b26ee1aea2;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.databoard/testcases/org/simantics/databoard/tests/TestAccessor.java b/bundles/org.simantics.databoard/testcases/org/simantics/databoard/tests/TestAccessor.java new file mode 100644 index 000000000..0d0e3f3c1 --- /dev/null +++ b/bundles/org.simantics.databoard/testcases/org/simantics/databoard/tests/TestAccessor.java @@ -0,0 +1,997 @@ +/******************************************************************************* + * Copyright (c) 2010 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.databoard.tests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import gnu.trove.map.hash.TObjectIntHashMap; + +import java.io.File; +import java.net.InetAddress; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.junit.Before; +import org.junit.Test; +import org.simantics.databoard.Accessors; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.Datatypes; +import org.simantics.databoard.accessor.Accessor; +import org.simantics.databoard.accessor.ArrayAccessor; +import org.simantics.databoard.accessor.BooleanAccessor; +import org.simantics.databoard.accessor.ByteAccessor; +import org.simantics.databoard.accessor.DoubleAccessor; +import org.simantics.databoard.accessor.FloatAccessor; +import org.simantics.databoard.accessor.IntegerAccessor; +import org.simantics.databoard.accessor.LongAccessor; +import org.simantics.databoard.accessor.MapAccessor; +import org.simantics.databoard.accessor.OptionalAccessor; +import org.simantics.databoard.accessor.RecordAccessor; +import org.simantics.databoard.accessor.StringAccessor; +import org.simantics.databoard.accessor.UnionAccessor; +import org.simantics.databoard.accessor.VariantAccessor; +import org.simantics.databoard.accessor.error.AccessorException; +import org.simantics.databoard.accessor.event.Event; +import org.simantics.databoard.accessor.event.InvalidatedEvent; +import org.simantics.databoard.accessor.file.FileVariantAccessor; +import org.simantics.databoard.accessor.impl.ChangeSet; +import org.simantics.databoard.accessor.impl.CompositeRecord; +import org.simantics.databoard.accessor.impl.DirectoryMap; +import org.simantics.databoard.accessor.impl.EventCollection; +import org.simantics.databoard.accessor.interestset.InterestSet; +import org.simantics.databoard.accessor.wire.WireClient; +import org.simantics.databoard.accessor.wire.WireServer; +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.databoard.binding.ArrayBinding; +import org.simantics.databoard.binding.Binding; +import org.simantics.databoard.binding.BooleanBinding; +import org.simantics.databoard.binding.ByteBinding; +import org.simantics.databoard.binding.DoubleBinding; +import org.simantics.databoard.binding.FloatBinding; +import org.simantics.databoard.binding.IntegerBinding; +import org.simantics.databoard.binding.LongBinding; +import org.simantics.databoard.binding.MapBinding; +import org.simantics.databoard.binding.OptionalBinding; +import org.simantics.databoard.binding.RecordBinding; +import org.simantics.databoard.binding.StringBinding; +import org.simantics.databoard.binding.UnionBinding; +import org.simantics.databoard.binding.VariantBinding; +import org.simantics.databoard.binding.factory.BindingScheme; +import org.simantics.databoard.binding.factory.MutableBindingFactory; +import org.simantics.databoard.binding.impl.ObjectArrayBinding; +import org.simantics.databoard.binding.mutable.MutableVariant; +import org.simantics.databoard.binding.util.RandomValue; +import org.simantics.databoard.method.Client; +import org.simantics.databoard.method.Server; +import org.simantics.databoard.serialization.Serializer; +import org.simantics.databoard.type.Datatype; +import org.simantics.databoard.type.UnionType; +import org.simantics.databoard.util.binary.BinaryMemory; + +/** + * o Set Value + * o Get Value + * o Listening + * o apply + * o Rollback + * + * o Java Object + * o Memory Binary + * o File Binary + * + * TODO Test {@link InvalidatedEvent} + * + * @author Toni Kalajainen + */ +public class TestAccessor { + + RandomValue rv; + Map repository; + BindingScheme scheme; + ///////////////////////////////////// + + + public @Before void init() { + rv = new RandomValue(); + repository = new HashMap(); + scheme = new MutableBindingFactory( repository ); + } + + public static File createTmpDir() + { + String tmp = System.getenv("tmp"); + if (tmp==null) tmp = "c:/temp"; + Random r = new Random(); + String randomName = "tmp-"+(r.nextInt(10000)+10000); + File tmpDir = new File(tmp+"/"+randomName); + Boolean ok = tmpDir.mkdirs(); + assertTrue( ok ); + return tmpDir; + } + + public boolean isKeyShortEnough(Binding binding, Object value) throws AdaptException { + String key = (String) Bindings.adapt(value, binding, Bindings.STR_VARIANT); + return key.length()<=200; + } + + public @Test void testWireAccessor() throws Exception { + System.out.println("Wire accessor test"); + + // TODO: Fix this! + if (true) return; + + for (int i=0; i<10000; i++) { + Bindings.defaultBindingRepository.clear(); + Bindings.bindingRepository.clear(); + Bindings.serializerRepository.clear(); + repository.clear(); + System.out.println(i+": "); + rv = new RandomValue(i); + rv.refereableRecords = false; + Datatype type = rv.randomType(0, 3); + Binding binding = scheme.getBindingUnchecked(type); + Object instance = binding.accept(rv); +// System.out.println(binding.printValue(instance, true)); + Accessor accessor = Accessors.getAccessor(binding, instance); + + WireServer wireServer = new WireServer(accessor); + Server server = new Server(0, wireServer.getMethodInterface()); + WireClient wireClient = new WireClient(); + Client client = new Client(InetAddress.getByName("localhost"), server.getPort(), wireClient.getClientMethodInterface()); + wireClient.setServerMethodInterface(client.getConnection().getRemoteMethodInterface()); + Accessor remoteAccessor = (Accessor) wireClient.getAccessor(null); + testAccessor( remoteAccessor, false ); + + wireClient.close(); + client.close(); + server.close(); + } + + } + + public @Test void testBinaryAccessor() throws Exception { + System.out.println("Test Binary Memory:"); + + Datatype type = Datatypes.VARIANT; + Binding binding = scheme.getBindingUnchecked( type ); + Serializer s = binding.serializer(); + TObjectIntHashMap identities = new TObjectIntHashMap(); + + for (int i=0; i<10000; i++) { + Bindings.defaultBindingRepository.clear(); + Bindings.bindingRepository.clear(); + Bindings.serializerRepository.clear(); + repository.clear(); + rv = new RandomValue(i); + rv.getRandom().nextLong(); + rv.refereableRecords = false; + System.out.println(i+": "); + BinaryMemory ram = new BinaryMemory(0); + Object instance = binding.accept(rv); + + binding.assertInstaceIsValid(instance); +// System.out.println(instance); + + identities.clear(); + int size = s.getSize(instance, identities); + + ram.setLength(size); + ram.position(0); + identities.clear(); + s.serialize(ram, identities, instance); + identities.clear(); + + ram.position(0L); + Object instance2 = s.deserialize(ram); + assertTrue( binding.equals(instance, instance2) ); + binding.assertInstaceIsValid(instance2); + + VariantAccessor a = (VariantAccessor) Accessors.getAccessor(ram, type); + + testAccessor(a); + + } + + } + + + public @Test void testJavaAccessor() throws Exception { + System.out.println("Test Java Objects:"); + for (int i=0; i<10000; i++) { + Bindings.defaultBindingRepository.clear(); + Bindings.bindingRepository.clear(); + Bindings.serializerRepository.clear(); + repository.clear(); + System.out.println(i+": "); + rv = new RandomValue(i); + rv.refereableRecords = false; + Datatype type = rv.randomType(0, 3); + Binding binding = scheme.getBindingUnchecked(type); + Object instance = binding.accept(rv); +// System.out.println(binding.printValue(instance, true)); + Accessor accessor = Accessors.getAccessor(binding, instance); + testAccessor(accessor); + } + } + + /** + * This test tests composite record by adding 10 fields, and running the + * composition as a record accessor + */ + public @Test void testCompositeRecord() throws Exception { + System.out.println("Test composite accessor"); + for (int i=0; i<100; i++) { + CompositeRecord record = new CompositeRecord(); + for (int j=1; j<=10; j++) { + + Binding binding = Bindings.MUTABLE_VARIANT; + rv = new RandomValue(i*543+j*23); + rv.getRandom().nextLong(); + rv.refereableRecords = false; + MutableVariant instance = (MutableVariant) binding.accept(rv); + String fieldName = "Field"+j; + Accessor fa = Accessors.getAccessor(instance.getBinding(), instance.getValue()); + record.addField(fieldName, fa); + } + System.out.println(i); + + testAccessor( record ); + } + } + + + public @Test void testFolderMap() throws Exception { + // 1000 tests proves failure + for (int i=0; i<100; i++) { + Bindings.defaultBindingRepository.clear(); + Bindings.bindingRepository.clear(); + Bindings.serializerRepository.clear(); + repository.clear(); + + System.out.println(i+": "); + File dir = createTmpDir(); + DirectoryMap map = Accessors.openDirectory(dir); + Binding keyBinding = Bindings.STR_VARIANT; + try { + System.out.println("Test Folder Map: "+dir); + + // Create 10 files + for (int j=0; j<10; j++) { + rv = new RandomValue(i*231231243+j*213); + rv.refereableRecords = false; + + // Create Key + String key = ""; + do { + key = (String) keyBinding.accept(rv); + } while (key.length() > 240); + + // Create value + Datatype valueType = rv.randomType(0, 2); + Binding valueBinding = scheme.getBindingUnchecked(valueType); + Object value = valueBinding.accept(rv); + + System.out.println(key); + MutableVariant vv = new MutableVariant(valueBinding, value); + map.put(Bindings.STR_VARIANT, key, Bindings.MUTABLE_VARIANT, vv); + } + + // Test the map + testAccessor(map); + + } finally { + // Remove all files in the folder + map.clear(); + map.close(); + System.out.println( dir.listFiles().length + " files."); + dir.delete(); + } + + } + + } + + public @Test void testBinaryFile() throws Exception { + File tmpFile = File.createTempFile("TestAccessor", ".dat"); + System.out.println("Test Binary File: "+tmpFile); + tmpFile.deleteOnExit(); + FileVariantAccessor fa = Accessors.createFile(tmpFile); + Datatype type = Datatypes.VARIANT; + Binding binding = scheme.getBindingUnchecked( type ); + + for (int i=0; i<10000; i++) { + Bindings.bindingRepository.clear(); + Bindings.serializerRepository.clear(); + Bindings.defaultBindingRepository.clear(); + repository.clear(); + + System.out.println(i+": "); + rv = new RandomValue(i); + rv.getRandom().nextLong(); + rv.refereableRecords = false; + + Object instance = binding.accept(rv); + System.out.print(i+": "+ binding.printValueDefinition(instance, true)); + fa.setValue(binding, instance); + testAccessor(fa); + } + fa.close(); + + } + + + ///////////////////////////////////// + + public void testAccessor(Accessor a) throws Exception { + testAccessor(a, true); + } + + public void testAccessor(Accessor a, boolean runTypeSpecific) throws Exception { + // Init + Datatype type = a.type(); + Binding binding = scheme.getBindingUnchecked(type); + InterestSet is = InterestSet.newInterestSet(type, true, true, true); + boolean mutable = !binding.isImmutable(); + + // Original value and test value + Object origValue = a.getValue(binding); + binding.assertInstaceIsValid(origValue); + Object testValue = binding.accept(rv); + + // Test Accessor#getValue(binding, instance); + Binding mutableBinding = Bindings.getMutableBinding(type); + Object mutableInstance = mutableBinding.createDefault(); + a.getValue(mutableBinding, mutableInstance); + assertTrue( Bindings.equals(binding, origValue, mutableBinding, mutableInstance) ); + + boolean same = binding.equals(origValue, testValue); + // Create a reference value and an accessor + Object refValue = binding.clone(origValue); + Accessor ra = Accessors.getAccessor(binding, refValue); + + if ( mutable ) { + + // Write test, without listeners + ra.setValue(binding, testValue); + Object refClone = ra.getValue(binding); + assertTrue( binding.equals(testValue, refClone) ); + ra.setValue(binding, binding.clone(origValue) ); + refClone = ra.getValue(binding); + assertTrue( binding.equals(origValue, refClone) ); + + // Write test, with listeners + ChangeSet cs = new ChangeSet(); // Collects Transformation form origValue to testValue + a.addListener(cs, is, null, null); + a.setValue(binding, testValue); + // There must be events in change set + if (!same) assertFalse(cs.isEmpty()); + + // Verify the accessor now contains the test value + Object x = a.getValue(binding); + assertTrue( binding.equals(testValue, x ) ); + + // Convert reference value to testValue + LinkedList rollback = new LinkedList(); + List events = cs.getAndClearEvents(); // Transformation form origValue to testValue + ra.apply(events, rollback); // Apply transformation from origValue to testValue, and gather rollback, a transformation from testValue to origValue + x = ra.getValue(binding); + assertTrue( binding.equals(x, testValue) ); + + // Revert reference value to origValue using rollback + a.removeListener(cs); + a.apply(rollback, null); // Apply transformation from testValue to origValue + x = a.getValue(binding); + assertTrue( binding.equals( x, origValue ) ); + } + + // Ensure the accessor has the correct value + Object x = a.getValue(binding); + assertTrue( binding.equals( x, origValue) ); + + if (runTypeSpecific) { + // Type specific tests + if (a instanceof ArrayAccessor) testArrayAccessor((ArrayAccessor) a); + if (a instanceof RecordAccessor) testRecordAccessor((RecordAccessor) a); + if (a instanceof MapAccessor) testMapAccessor((MapAccessor) a); + if (a instanceof BooleanAccessor) testBooleanAccessor((BooleanAccessor) a); + if (a instanceof ByteAccessor) testByteAccessor((ByteAccessor) a); + if (a instanceof DoubleAccessor) testDoubleAccessor((DoubleAccessor) a); + if (a instanceof FloatAccessor) testFloatAccessor((FloatAccessor) a); + if (a instanceof IntegerAccessor) testIntegerAccessor((IntegerAccessor) a); + if (a instanceof LongAccessor) testLongAccessor((LongAccessor) a); + if (a instanceof OptionalAccessor) testOptionalAccessor((OptionalAccessor) a); + if (a instanceof StringAccessor) testStringAccessor((StringAccessor) a); + if (a instanceof UnionAccessor) testUnionAccessor((UnionAccessor) a); + if (a instanceof VariantAccessor) testVariantAccessor((VariantAccessor) a); + + // Ensure the accessor has the correct value + a.setValue(binding, origValue); + x = a.getValue(binding); + assertTrue( binding.equals( x, origValue) ); + } + } + + public void testMapAccessor(MapAccessor a) throws Exception { + Datatype type = a.type(); + MapBinding binding = (MapBinding) scheme.getBindingUnchecked(type); + Binding kb = binding.getKeyBinding(); + Binding vb = binding.getValueBinding(); + InterestSet is = InterestSet.newInterestSet(type, true, true, false); + boolean mutable = !binding.isImmutable(); + int len = a.size(); + + // getAll(Binding, Binding, Object[], Object[]) + Object oks[] = new Object[ len ]; + Object ovs[] = new Object[ len ]; + a.getAll(kb, vb, oks, ovs); + + // getAll(Binding, Binding, Map) + TreeMap om = new TreeMap(kb); + a.getAll(kb, vb, om); + + // getKeys(Binding), getValues(Binding) + Object oks2[] = a.getKeys(kb); + Object ovs2[] = a.getValues(vb); + + // assert the results are the same for the getAll()s and getKeys and getValues + for (int i=0; i2) { + // Get all + try { + Object keys[] = new Object[ len ]; + Object values[] = new Object[ len ]; + int c = a.getEntries(kb, a.getFirstKey(kb), true, a.getLastKey(kb), true, + new ObjectArrayBinding(kb), keys, + new ObjectArrayBinding(vb), values, -1); + + assertEquals(len, c); + for (int i=0; i keys = new TreeSet(kb); + for (int i=0; i<10; i++) { + Object key = null; + if (kb.type().equals(Datatypes.VARIANT)) { + do { + key = kb.accept(rv); + } while( !kb.type().equals(Datatypes.VARIANT) || !isKeyShortEnough(kb, key) ); + } else { + key = kb.accept(rv); + } + keys.add( key ); + } + int testValueCount = keys.size(); + Object tks[] = keys.toArray( new Object[testValueCount] ); + Object tvs[] = new Object[ testValueCount ]; + for (int i=0; i=3) { + // getFirstKey(Binding) + Object fk = a.getFirstKey(kb); + assertTrue( kb.equals(fk, oks[0]) ); + + // getLastKey(Binding) + Object lk = a.getLastKey(kb); + assertTrue( kb.equals(lk, oks[len-1]) ); + + // getLowerKey(Binding, Object) + Object k = a.getLowerKey(kb, fk); + assertNull(k); + k = a.getLowerKey(kb, lk); + assertTrue( kb.equals(k, oks[len-2]) ); + + // getFloorKey(Binding, Object) + k = a.getFloorKey(kb, fk); + assertTrue( kb.equals(k, oks[0]) ); + k = a.getFloorKey(kb, lk); + assertTrue( kb.equals(k, oks[len-1]) ); + + // getCeilingKey(Binding, Object) + k = a.getCeilingKey(kb, lk); + assertTrue( kb.equals(k, oks[len-1]) ); + k = a.getCeilingKey(kb, fk); + assertTrue( kb.equals(k, oks[0]) ); + + // getHigherKey(Binding, Object) + k = a.getHigherKey(kb, lk); + assertNull(k); + k = a.getHigherKey(kb, fk); + assertTrue( kb.equals(k, oks[1]) ); + } + + // clear + // putAll(Binding, Binding, Object[], Object[]) + a.clear(); + int size = a.size(); + assertEquals( 0, size ); + a.putAll(kb, vb, oks, ovs); + size = a.size(); + assertEquals( len, size ); + + // clear + // putAll(Binding, Binding, Map) + a.clear(); + assertEquals( 0, a.size() ); + a.putAll(kb, vb, om); + assertEquals( len, a.size() ); + + // containsKey + // containsValue + for (int i=0; i1) + { + int i=0; + a.setComponentValue(i, cbs[i], tvs[i]); + Accessor sa = a.getComponentAccessor(); + EventCollection ec = new EventCollection(); + a.addListener(ec, is, null, null); + i = 1; + a.setComponentValue(i, cbs[i], tvs[i]); + boolean invalidatedEventOk = false; + List events = ec.getAndClearEvents(); + for (Event e : events) { + invalidatedEventOk |= (e instanceof InvalidatedEvent) && (e.reference !=null); + } + a.removeListener(ec); + sa.getClass(); + assertTrue( invalidatedEventOk ); + } + + a.setComponentValue(ot, cbs[ot], ov); + + //// Test sub-accessors with recursion + Accessor sa = a.getComponentAccessor(); + testAccessor(sa); + + } + + public void testVariantAccessor(VariantAccessor a) throws Exception { + Datatype type = a.type(); + VariantBinding binding = (VariantBinding) scheme.getBindingUnchecked(type); + InterestSet is = InterestSet.newInterestSet(type, true, true, true); + + // Remember the original value + Binding ob = scheme.getBindingUnchecked( type ); + Object ov = a.getValue(ob); + ob.assertInstaceIsValid(ov); + boolean mutable = !binding.isImmutable(); + + if (mutable) { + // Create test values + int testValueCount = 10; + Binding tvb[] = new Binding[testValueCount]; + Object tvs[] = new Object[testValueCount]; + for (int i=0; i events = ec.getAndClearEvents(); + for (Event e : events) { + invalidatedEventOk |= (e instanceof InvalidatedEvent) && (e.reference !=null); + } + assertTrue( invalidatedEventOk ); + } + } + } + + //// Test sub-accessors with recursion + Accessor sa = a.getContentAccessor(); + testAccessor(sa); + + // Restore + a.setValue(ob, ov); + } + + public void testByteAccessor(ByteAccessor a) throws Exception { + byte ov = a.getValue(); + ByteBinding b = Bindings.BYTE; + for (int i=0; i<10; i++) { + Byte r = (Byte) rv.visit(b); + a.setValue(r); + assertTrue( r == a.getValue() ); + } + a.setValue(ov); + } + + public void testDoubleAccessor(DoubleAccessor a) throws Exception { + double ov = a.getValue(); + DoubleBinding b = Bindings.DOUBLE; + for (int i=0; i<10; i++) { + Double r = (Double) rv.visit(b); + a.setValue(r); + assertTrue( r == a.getValue() ); + } + a.setValue(ov); + } + + public void testFloatAccessor(FloatAccessor a) throws Exception { + float ov = a.getValue(); + FloatBinding b = Bindings.FLOAT; + for (int i=0; i<10; i++) { + Float r = (Float) rv.visit(b); + a.setValue(r); + assertTrue( r == a.getValue() ); + } + a.setValue(ov); + } + + public void testIntegerAccessor(IntegerAccessor a) throws Exception { + int ov = a.getValue(); + IntegerBinding b = Bindings.INTEGER; + for (int i=0; i<10; i++) { + Integer r = (Integer) rv.visit(b); + a.setValue(r); + assertTrue( r == a.getValue() ); + } + a.setValue(ov); + } + + public void testLongAccessor(LongAccessor a) throws Exception { + long ov = a.getValue(); + LongBinding b = Bindings.LONG; + for (int i=0; i<10; i++) { + Long r = (Long) rv.visit(b); + a.setValue(r); + assertTrue( r == a.getValue() ); + } + a.setValue(ov); + } + + public void testStringAccessor(StringAccessor a) throws Exception { + String ov = a.getValue(); + StringBinding b = Bindings.STRING; + for (int i=0; i<10; i++) { + String r = (String) rv.visit(b); + a.setValue(r); + assertEquals( r, a.getValue() ); + } + a.setValue(ov); + } + + public void testBooleanAccessor(BooleanAccessor a) throws Exception { + Boolean ov = a.getValue(); + BooleanBinding b = Bindings.BOOLEAN; + for (int i=0; i<10; i++) { + Boolean r = (Boolean) rv.visit(b); + a.setValue(r); + assertEquals( r, a.getValue() ); + } + a.setValue(ov); + } + + +} +