1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.graph.test.graphio; 26 27 import java.io.ByteArrayOutputStream; 28 import java.nio.channels.Channels; 29 import java.nio.channels.WritableByteChannel; 30 import java.util.Arrays; 31 import java.util.Collection; 32 import java.util.Collections; 33 import java.util.LinkedHashMap; 34 import java.util.Map; 35 import org.graalvm.graphio.GraphOutput; 36 import org.graalvm.graphio.GraphStructure; 37 import static org.junit.Assert.assertEquals; 38 import static org.junit.Assert.assertFalse; 39 import static org.junit.Assert.assertTrue; 40 import static org.junit.Assert.fail; 41 import org.junit.Before; 42 import org.junit.Test; 43 44 public final class NodeEncodingTest { 45 46 private ByteArrayOutputStream out; 47 48 @Before 49 public void initOutput() { 50 out = new ByteArrayOutputStream(); 51 } 52 53 @Test 54 public void version40TheNodeIsntDumpedWithItsID() throws Exception { 55 runTheNodeIsntDumpedWithItsID(true); 56 } 57 58 @Test 59 public void defaultVersionTheNodeIsntDumpedWithItsID() throws Exception { 60 runTheNodeIsntDumpedWithItsID(false); 61 } 62 63 private void runTheNodeIsntDumpedWithItsID(boolean explicitVersion) throws Exception { 64 WritableByteChannel w = Channels.newChannel(out); 65 MockGraph graph = new MockGraph(); 66 MockNodeClass clazz = new MockNodeClass("clazz"); 67 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 68 try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) { 69 dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node)); 70 dump.endGroup(); 71 } 72 73 assertEquals("Node is always requested", 1, node.nodeRequested); 74 assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested); 75 assertByte(false, out.toByteArray(), 33); 76 assertEquals("Node class of the node has been requested", 1, node.nodeClassRequested); 77 assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried); 78 assertFalse("No to string ops", node.toStringRequested); 79 } 80 81 @Test 82 public void dumpingNodeInVersion10() throws Exception { 83 runTheNodeIsTreatedAsString(true); 84 } 85 86 private void runTheNodeIsTreatedAsString(boolean explicitVersion) throws Exception { 87 WritableByteChannel w = Channels.newChannel(out); 88 MockGraph graph = new MockGraph(); 89 MockNodeClass clazz = new MockNodeClass("clazz"); 90 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 91 try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(1, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) { 92 dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node)); 93 dump.endGroup(); 94 } 95 96 assertEquals("Node is always requested", 1, node.nodeRequested); 97 assertEquals("Nobody asks for id of a node in version 1.0", 0, node.idTested); 98 assertByte(false, out.toByteArray(), 33); 99 assertEquals("Node class was needed to find out it is not a NodeClass instance", 1, node.nodeClassRequested); 100 assertEquals("Node class template name wasn't needed however", 0, clazz.nameTemplateQueried); 101 assertTrue("Node sent as a string version 1.0", node.toStringRequested); 102 } 103 104 @Test 105 public void dumpingNodeInVersion15() throws Exception { 106 runTheNodeIsTreatedPoolEntry(true); 107 } 108 109 private void runTheNodeIsTreatedPoolEntry(boolean explicitVersion) throws Exception { 110 WritableByteChannel w = Channels.newChannel(out); 111 MockGraph graph = new MockGraph(); 112 MockNodeClass clazz = new MockNodeClass("clazz"); 113 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 114 try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(5, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) { 115 dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node)); 116 dump.endGroup(); 117 } 118 119 assertEquals("Node is always requested", 1, node.nodeRequested); 120 assertEquals("Id of our node is requested in version 5.0", 1, node.idTested); 121 assertByte(true, out.toByteArray(), 33); 122 assertTrue("Node class was needed at least once", 1 <= node.nodeClassRequested); 123 assertEquals("Node class template name sent to server", 1, clazz.nameTemplateQueried); 124 assertFalse("Node.toString() isn't needed", node.toStringRequested); 125 } 126 127 @Test 128 public void dumpingNodeTwiceInVersion4() throws Exception { 129 WritableByteChannel w = Channels.newChannel(out); 130 MockGraph graph = new MockGraph(); 131 MockNodeClass clazz = new MockNodeClass("clazz"); 132 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 133 try (GraphOutput<MockGraph, ?> dump = GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w)) { 134 Map<String, Object> props = new LinkedHashMap<>(); 135 props.put("node1", node); 136 props.put("node2", node); 137 props.put("node3", node); 138 dump.beginGroup(graph, "test1", "t1", null, 0, props); 139 dump.endGroup(); 140 } 141 142 assertEquals("Node requested three times", 3, node.nodeRequested); 143 assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested); 144 // check there is no encoded string for object #3 145 assertByte(false, out.toByteArray(), 1, 0, 3); 146 assertEquals("Node class of the node has been requested three times", 3, node.nodeClassRequested); 147 assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried); 148 assertFalse("No to string ops", node.toStringRequested); 149 } 150 151 private static void assertByte(boolean shouldBeFound, byte[] arr, int... value) { 152 boolean found = false; 153 int at = 0; 154 for (int i = 0; i < arr.length; i++) { 155 if (arr[i] == value[at]) { 156 if (++at == value.length) { 157 found = true; 158 break; 159 } 160 } else { 161 at = 0; 162 } 163 } 164 if (shouldBeFound == found) { 165 return; 166 } 167 if (shouldBeFound) { 168 fail("Value " + value + " not found in\n" + Arrays.toString(arr)); 169 } else { 170 fail("Value " + value + " surprisingly found in\n" + Arrays.toString(arr)); 171 } 172 } 173 174 private static final class MockStructure implements GraphStructure<MockGraph, MockNode, MockNodeClass, MockNodeClass> { 175 176 @Override 177 public MockGraph graph(MockGraph currentGraph, Object obj) { 178 return obj instanceof MockGraph ? (MockGraph) obj : null; 179 } 180 181 @Override 182 public Iterable<? extends MockNode> nodes(MockGraph graph) { 183 return Collections.emptyList(); 184 } 185 186 @Override 187 public int nodesCount(MockGraph graph) { 188 return 0; 189 } 190 191 @Override 192 public int nodeId(MockNode node) { 193 node.idTested++; 194 return node.id; 195 } 196 197 @Override 198 public boolean nodeHasPredecessor(MockNode node) { 199 return false; 200 } 201 202 @Override 203 public void nodeProperties(MockGraph graph, MockNode node, Map<String, ? super Object> properties) { 204 } 205 206 @Override 207 public MockNode node(Object obj) { 208 if (obj instanceof MockNode) { 209 ((MockNode) obj).nodeRequested++; 210 return (MockNode) obj; 211 } 212 return null; 213 } 214 215 @Override 216 public MockNodeClass nodeClass(Object obj) { 217 if (obj instanceof MockNode) { 218 ((MockNode) obj).nodeClassRequested++; 219 } 220 return obj instanceof MockNodeClass ? (MockNodeClass) obj : null; 221 } 222 223 @Override 224 public MockNodeClass classForNode(MockNode n) { 225 n.nodeClassRequested++; 226 return n.clazz; 227 } 228 229 @Override 230 public String nameTemplate(MockNodeClass nodeClass) { 231 nodeClass.nameTemplateQueried++; 232 return ""; 233 } 234 235 @Override 236 public Object nodeClassType(MockNodeClass nodeClass) { 237 return nodeClass.getClass(); 238 } 239 240 @Override 241 public MockNodeClass portInputs(MockNodeClass nodeClass) { 242 return nodeClass; 243 } 244 245 @Override 246 public MockNodeClass portOutputs(MockNodeClass nodeClass) { 247 return nodeClass; 248 } 249 250 @Override 251 public int portSize(MockNodeClass port) { 252 return 0; 253 } 254 255 @Override 256 public boolean edgeDirect(MockNodeClass port, int index) { 257 return false; 258 } 259 260 @Override 261 public String edgeName(MockNodeClass port, int index) { 262 return null; 263 } 264 265 @Override 266 public Object edgeType(MockNodeClass port, int index) { 267 return null; 268 } 269 270 @Override 271 public Collection<? extends MockNode> edgeNodes(MockGraph graph, MockNode node, MockNodeClass port, int index) { 272 return null; 273 } 274 } 275 276 private static final class MockGraph { 277 278 } 279 280 private static final class MockNode { 281 final MockNodeClass clazz; 282 final int id; 283 int idTested; 284 int nodeClassRequested; 285 int nodeRequested; 286 boolean toStringRequested; 287 288 MockNode(MockNodeClass clazz, int id) { 289 this.clazz = clazz; 290 this.id = id; 291 } 292 293 @Override 294 public String toString() { 295 this.toStringRequested = true; 296 return "MockNode{" + "id=" + id + ", class=" + clazz + '}'; 297 } 298 } 299 300 private static final class MockNodeClass { 301 final String name; 302 int nameTemplateQueried; 303 304 MockNodeClass(String name) { 305 this.name = name; 306 } 307 308 @Override 309 public String toString() { 310 return "MockNodeClass{" + "name=" + name + '}'; 311 } 312 } 313 }