1 /*
   2  * Copyright (c) 2019, 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 static org.junit.Assert.assertArrayEquals;
  28 import static org.junit.Assert.assertFalse;
  29 import static org.junit.Assert.assertTrue;
  30 import static org.junit.Assert.fail;
  31 
  32 import java.io.ByteArrayOutputStream;
  33 import java.io.IOException;
  34 import java.nio.ByteBuffer;
  35 import java.nio.channels.Channels;
  36 import java.nio.channels.WritableByteChannel;
  37 import java.util.Collection;
  38 import java.util.Collections;
  39 import java.util.Map;
  40 import java.util.Objects;
  41 import org.graalvm.graphio.GraphOutput;
  42 import org.graalvm.graphio.GraphStructure;
  43 import org.junit.Test;
  44 
  45 public final class GraphOutputTest {
  46 
  47     @Test
  48     @SuppressWarnings("static-method")
  49     public void testWritableByteChannel() throws IOException {
  50         ByteArrayOutputStream out = new ByteArrayOutputStream();
  51         WritableByteChannel channel = Channels.newChannel(out);
  52         ByteBuffer data = generateData(1 << 17);
  53         GraphOutput<?, ?> graphOutput = GraphOutput.newBuilder(new MockGraphStructure()).protocolVersion(6, 0).embedded(true).build(channel);
  54         try (GraphOutput<?, ?> closable = graphOutput) {
  55             assertTrue(closable.isOpen());
  56             closable.write(data);
  57         }
  58         assertFalse(graphOutput.isOpen());
  59         assertArrayEquals(data.array(), out.toByteArray());
  60     }
  61 
  62     @Test
  63     @SuppressWarnings("static-method")
  64     public void testWriteDuringPrint() throws IOException {
  65         ByteArrayOutputStream out = new ByteArrayOutputStream();
  66         WritableByteChannel channel = Channels.newChannel(out);
  67         class Action implements Runnable {
  68             GraphOutput<MockGraph, ?> out;
  69 
  70             @Override
  71             public void run() {
  72                 try {
  73                     ByteBuffer data = ByteBuffer.allocate(16);
  74                     data.limit(16);
  75                     out.write(data);
  76                 } catch (IOException ioe) {
  77                     throw new RuntimeException(ioe);
  78                 }
  79             }
  80         }
  81         Action action = new Action();
  82         try (GraphOutput<MockGraph, ?> graphOutput = GraphOutput.newBuilder(new MockGraphStructure(action)).protocolVersion(6, 0).build(channel)) {
  83             action.out = graphOutput;
  84             try {
  85                 graphOutput.print(new MockGraph(), Collections.emptyMap(), 0, "Mock Graph");
  86                 fail("Expected IllegalStateException");
  87             } catch (IllegalStateException ise) {
  88                 // expected exception
  89             }
  90         }
  91     }
  92 
  93     @Test
  94     @SuppressWarnings("static-method")
  95     public void testEmbeddedWritableByteChannel() throws IOException {
  96         ByteArrayOutputStream expected = new ByteArrayOutputStream();
  97         WritableByteChannel expectedChannel = Channels.newChannel(expected);
  98         Map<Object, Object> properties = Collections.singletonMap("version.id", 1);
  99         try (GraphOutput<MockGraph, ?> graphOutput = GraphOutput.newBuilder(new MockGraphStructure()).protocolVersion(6, 0).build(expectedChannel)) {
 100             graphOutput.print(new MockGraph(), properties, 1, "Graph 1");
 101             graphOutput.write(ByteBuffer.allocate(0));
 102             graphOutput.print(new MockGraph(), properties, 2, "Graph 1");
 103         }
 104         ByteArrayOutputStream embedded = new ByteArrayOutputStream();
 105         SharedWritableByteChannel embeddChannel = new SharedWritableByteChannel(Channels.newChannel(embedded));
 106         try {
 107             try (GraphOutput<MockGraph, ?> baseOutput = GraphOutput.newBuilder(new MockGraphStructure()).protocolVersion(6, 0).build(embeddChannel)) {
 108                 try (GraphOutput<MockGraph, ?> embeddedOutput = GraphOutput.newBuilder(new MockGraphStructure()).protocolVersion(6, 0).embedded(true).build((WritableByteChannel) baseOutput)) {
 109                     embeddedOutput.print(new MockGraph(), properties, 1, "Graph 1");
 110                     baseOutput.print(new MockGraph(), properties, 2, "Graph 1");
 111                 }
 112             }
 113         } finally {
 114             embeddChannel.realClose();
 115         }
 116         assertArrayEquals(expected.toByteArray(), embedded.toByteArray());
 117     }
 118 
 119     private static ByteBuffer generateData(int size) {
 120         ByteBuffer buffer = ByteBuffer.allocate(size);
 121         for (int i = 0; i < size; i++) {
 122             buffer.put(i, (byte) i);
 123         }
 124         buffer.limit(size);
 125         return buffer;
 126     }
 127 
 128     private static final class SharedWritableByteChannel implements WritableByteChannel {
 129 
 130         private final WritableByteChannel delegate;
 131 
 132         SharedWritableByteChannel(WritableByteChannel delegate) {
 133             Objects.requireNonNull(delegate, "Delegate must be non null.");
 134             this.delegate = delegate;
 135         }
 136 
 137         @Override
 138         public int write(ByteBuffer bb) throws IOException {
 139             return delegate.write(bb);
 140         }
 141 
 142         @Override
 143         public boolean isOpen() {
 144             return delegate.isOpen();
 145         }
 146 
 147         @Override
 148         public void close() throws IOException {
 149         }
 150 
 151         void realClose() throws IOException {
 152             delegate.close();
 153         }
 154     }
 155 
 156     private static final class MockGraphStructure implements GraphStructure<MockGraph, Void, Void, Void> {
 157 
 158         private final Runnable enterAction;
 159 
 160         MockGraphStructure() {
 161             this.enterAction = null;
 162         }
 163 
 164         MockGraphStructure(Runnable enterAction) {
 165             this.enterAction = enterAction;
 166         }
 167 
 168         @Override
 169         public MockGraph graph(MockGraph currentGraph, Object obj) {
 170             onEnter();
 171             return null;
 172         }
 173 
 174         @Override
 175         public Iterable<? extends Void> nodes(MockGraph graph) {
 176             onEnter();
 177             return Collections.emptySet();
 178         }
 179 
 180         @Override
 181         public int nodesCount(MockGraph graph) {
 182             onEnter();
 183             return 0;
 184         }
 185 
 186         @Override
 187         public int nodeId(Void node) {
 188             onEnter();
 189             return 0;
 190         }
 191 
 192         @Override
 193         public boolean nodeHasPredecessor(Void node) {
 194             onEnter();
 195             return false;
 196         }
 197 
 198         @Override
 199         public void nodeProperties(MockGraph graph, Void node, Map<String, ? super Object> properties) {
 200             onEnter();
 201         }
 202 
 203         @Override
 204         public Void node(Object obj) {
 205             onEnter();
 206             return null;
 207         }
 208 
 209         @Override
 210         public Void nodeClass(Object obj) {
 211             onEnter();
 212             return null;
 213         }
 214 
 215         @Override
 216         public Void classForNode(Void node) {
 217             onEnter();
 218             return null;
 219         }
 220 
 221         @Override
 222         public String nameTemplate(Void nodeClass) {
 223             onEnter();
 224             return null;
 225         }
 226 
 227         @Override
 228         public Object nodeClassType(Void nodeClass) {
 229             onEnter();
 230             return null;
 231         }
 232 
 233         @Override
 234         public Void portInputs(Void nodeClass) {
 235             onEnter();
 236             return null;
 237         }
 238 
 239         @Override
 240         public Void portOutputs(Void nodeClass) {
 241             onEnter();
 242             return null;
 243         }
 244 
 245         @Override
 246         public int portSize(Void port) {
 247             onEnter();
 248             return 0;
 249         }
 250 
 251         @Override
 252         public boolean edgeDirect(Void port, int index) {
 253             onEnter();
 254             return false;
 255         }
 256 
 257         @Override
 258         public String edgeName(Void port, int index) {
 259             onEnter();
 260             return null;
 261         }
 262 
 263         @Override
 264         public Object edgeType(Void port, int index) {
 265             onEnter();
 266             return null;
 267         }
 268 
 269         @Override
 270         public Collection<? extends Void> edgeNodes(MockGraph graph, Void node, Void port, int index) {
 271             onEnter();
 272             return null;
 273         }
 274 
 275         private void onEnter() {
 276             if (enterAction != null) {
 277                 enterAction.run();
 278             }
 279         }
 280     }
 281 
 282     private static final class MockGraph {
 283     }
 284 }