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 package org.graalvm.compiler.graph.test.graphio; 24 25 import java.io.ByteArrayOutputStream; 26 import java.nio.channels.Channels; 27 import java.nio.channels.WritableByteChannel; 28 import java.util.Arrays; 29 import java.util.Collection; 30 import java.util.Collections; 31 import java.util.LinkedHashMap; 32 import java.util.Map; 33 import org.graalvm.graphio.GraphOutput; 34 import org.graalvm.graphio.GraphStructure; 35 import static org.junit.Assert.assertEquals; 36 import static org.junit.Assert.assertFalse; 37 import static org.junit.Assert.assertTrue; 38 import static org.junit.Assert.fail; 39 import org.junit.Before; 40 import org.junit.Test; 41 42 public final class NodeEncodingTest { 43 44 private ByteArrayOutputStream out; 45 46 @Before 47 public void initOutput() { 48 out = new ByteArrayOutputStream(); 49 } 50 51 @Test 52 public void version40TheNodeIsntDumpedWithItsID() throws Exception { 53 runTheNodeIsntDumpedWithItsID(true); 54 } 55 56 @Test 57 public void defaultVersionTheNodeIsntDumpedWithItsID() throws Exception { 58 runTheNodeIsntDumpedWithItsID(false); 59 } 60 61 private void runTheNodeIsntDumpedWithItsID(boolean explicitVersion) throws Exception { 62 WritableByteChannel w = Channels.newChannel(out); 63 MockGraph graph = new MockGraph(); 64 MockNodeClass clazz = new MockNodeClass("clazz"); 65 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 66 try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) { 67 dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node)); 68 dump.endGroup(); 69 } 70 71 assertEquals("Node is always requested", 1, node.nodeRequested); 72 assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested); 73 assertByte(false, out.toByteArray(), 33); 74 assertEquals("Node class of the node has been requested", 1, node.nodeClassRequested); 75 assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried); 76 assertFalse("No to string ops", node.toStringRequested); 77 } 78 79 @Test 80 public void dumpingNodeInVersion10() throws Exception { 81 runTheNodeIsTreatedAsString(true); 82 } 83 84 private void runTheNodeIsTreatedAsString(boolean explicitVersion) throws Exception { 85 WritableByteChannel w = Channels.newChannel(out); 86 MockGraph graph = new MockGraph(); 87 MockNodeClass clazz = new MockNodeClass("clazz"); 88 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 89 try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(1, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) { 90 dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node)); 91 dump.endGroup(); 92 } 93 94 assertEquals("Node is always requested", 1, node.nodeRequested); 95 assertEquals("Nobody asks for id of a node in version 1.0", 0, node.idTested); 96 assertByte(false, out.toByteArray(), 33); 97 assertEquals("Node class was needed to find out it is not a NodeClass instance", 1, node.nodeClassRequested); 98 assertEquals("Node class template name wasn't needed however", 0, clazz.nameTemplateQueried); 99 assertTrue("Node sent as a string version 1.0", node.toStringRequested); 100 } 101 102 @Test 103 public void dumpingNodeInVersion15() throws Exception { 104 runTheNodeIsTreatedPoolEntry(true); 105 } 106 107 private void runTheNodeIsTreatedPoolEntry(boolean explicitVersion) throws Exception { 108 WritableByteChannel w = Channels.newChannel(out); 109 MockGraph graph = new MockGraph(); 110 MockNodeClass clazz = new MockNodeClass("clazz"); 111 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 112 try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(5, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) { 113 dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node)); 114 dump.endGroup(); 115 } 116 117 assertEquals("Node is always requested", 1, node.nodeRequested); 118 assertEquals("Id of our node is requested in version 5.0", 1, node.idTested); 119 assertByte(true, out.toByteArray(), 33); 120 assertTrue("Node class was needed at least once", 1 <= node.nodeClassRequested); 121 assertEquals("Node class template name sent to server", 1, clazz.nameTemplateQueried); 122 assertFalse("Node.toString() isn't needed", node.toStringRequested); 123 } 124 125 @Test 126 public void dumpingNodeTwiceInVersion4() throws Exception { 127 WritableByteChannel w = Channels.newChannel(out); 128 MockGraph graph = new MockGraph(); 129 MockNodeClass clazz = new MockNodeClass("clazz"); 130 MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream 131 try (GraphOutput<MockGraph, ?> dump = GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w)) { 132 Map<String, Object> props = new LinkedHashMap<>(); 133 props.put("node1", node); 134 props.put("node2", node); 135 props.put("node3", node); 136 dump.beginGroup(graph, "test1", "t1", null, 0, props); 137 dump.endGroup(); 138 } 139 140 assertEquals("Node requested three times", 3, node.nodeRequested); 141 assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested); 142 // check there is no encoded string for object #3 143 assertByte(false, out.toByteArray(), 1, 0, 3); 144 assertEquals("Node class of the node has been requested three times", 3, node.nodeClassRequested); 145 assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried); 146 assertFalse("No to string ops", node.toStringRequested); 147 } 148 149 private static void assertByte(boolean shouldBeFound, byte[] arr, int... value) { 150 boolean found = false; 151 int at = 0; 152 for (int i = 0; i < arr.length; i++) { 153 if (arr[i] == value[at]) { 154 if (++at == value.length) { 155 found = true; 156 break; 157 } 158 } else { 159 at = 0; 160 } 161 } 162 if (shouldBeFound == found) { 163 return; 164 } 165 if (shouldBeFound) { 166 fail("Value " + value + " not found in\n" + Arrays.toString(arr)); 167 } else { 168 fail("Value " + value + " surprisingly found in\n" + Arrays.toString(arr)); 169 } 170 } 171 172 private static final class MockStructure implements GraphStructure<MockGraph, MockNode, MockNodeClass, MockNodeClass> { 173 174 @Override 175 public MockGraph graph(MockGraph currentGraph, Object obj) { 176 return obj instanceof MockGraph ? (MockGraph) obj : null; 177 } 178 179 @Override 180 public Iterable<? extends MockNode> nodes(MockGraph graph) { 181 return Collections.emptyList(); 182 } 183 184 @Override 185 public int nodesCount(MockGraph graph) { 186 return 0; 187 } 188 189 @Override 190 public int nodeId(MockNode node) { 191 node.idTested++; 192 return node.id; 193 } 194 195 @Override 196 public boolean nodeHasPredecessor(MockNode node) { 197 return false; 198 } 199 200 @Override 201 public void nodeProperties(MockGraph graph, MockNode node, Map<String, ? super Object> properties) { 202 } 203 204 @Override 205 public MockNode node(Object obj) { 206 if (obj instanceof MockNode) { 207 ((MockNode) obj).nodeRequested++; 208 return (MockNode) obj; 209 } 210 return null; 211 } 212 213 @Override 214 public MockNodeClass nodeClass(Object obj) { 215 if (obj instanceof MockNode) { 216 ((MockNode) obj).nodeClassRequested++; 217 } 218 return obj instanceof MockNodeClass ? (MockNodeClass) obj : null; 219 } 220 221 @Override 222 public MockNodeClass classForNode(MockNode n) { 223 n.nodeClassRequested++; 224 return n.clazz; 225 } 226 227 @Override 228 public String nameTemplate(MockNodeClass nodeClass) { 229 nodeClass.nameTemplateQueried++; 230 return ""; 231 } 232 233 @Override 234 public Object nodeClassType(MockNodeClass nodeClass) { 235 return nodeClass.getClass(); 236 } 237 238 @Override 239 public MockNodeClass portInputs(MockNodeClass nodeClass) { 240 return nodeClass; 241 } 242 243 @Override 244 public MockNodeClass portOutputs(MockNodeClass nodeClass) { 245 return nodeClass; 246 } 247 248 @Override 249 public int portSize(MockNodeClass port) { 250 return 0; 251 } 252 253 @Override 254 public boolean edgeDirect(MockNodeClass port, int index) { 255 return false; 256 } 257 258 @Override 259 public String edgeName(MockNodeClass port, int index) { 260 return null; 261 } 262 263 @Override 264 public Object edgeType(MockNodeClass port, int index) { 265 return null; 266 } 267 268 @Override 269 public Collection<? extends MockNode> edgeNodes(MockGraph graph, MockNode node, MockNodeClass port, int index) { 270 return null; 271 } 272 } 273 274 private static final class MockGraph { 275 276 } 277 278 private static final class MockNode { 279 final MockNodeClass clazz; 280 final int id; 281 int idTested; 282 int nodeClassRequested; 283 int nodeRequested; 284 boolean toStringRequested; 285 286 MockNode(MockNodeClass clazz, int id) { 287 this.clazz = clazz; 288 this.id = id; 289 } 290 291 @Override 292 public String toString() { 293 this.toStringRequested = true; 294 return "MockNode{" + "id=" + id + ", class=" + clazz + '}'; 295 } 296 } 297 298 private static final class MockNodeClass { 299 final String name; 300 int nameTemplateQueried; 301 302 MockNodeClass(String name) { 303 this.name = name; 304 } 305 306 @Override 307 public String toString() { 308 return "MockNodeClass{" + "name=" + name + '}'; 309 } 310 } 311 }