// Copyright (c) 2014 Tom Zhou<iwebpp@gmail.com> package com.iwebpp.node.tests; import java.nio.ByteBuffer; import java.nio.charset.Charset; import android.util.Log; import com.iwebpp.node.EventEmitter.Listener; import com.iwebpp.node.NodeContext; import com.iwebpp.node.NodeContext.IntervalListener; import com.iwebpp.node.Util; import com.iwebpp.node.stream.Duplex; import com.iwebpp.node.stream.Readable; import com.iwebpp.node.stream.Readable2; import com.iwebpp.node.stream.Transform; import com.iwebpp.node.stream.Writable; import com.iwebpp.node.stream.Writable2; import com.iwebpp.node.stream.Writable.WriteCB; import junit.framework.TestCase; public final class StreamTest extends TestCase { private static final String TAG = "StreamTest"; private NodeContext context; private static String burst; static { burst = "你好"; for (int i = 0; i < 6; i++) burst += i; } public StreamTest() { this.context = new NodeContext(); } private class Counting extends Readable2 { private int _max = 10; private int _index = 1; Counting() { super(context, new Readable2.Options(16, "utf8", false, "utf8", true)); // TODO Auto-generated constructor stub _index = 1; } @Override public void _read(int size) throws Exception { int i = this._index++; if (i > this._max) this.push(null, null); else { for (int c = 0; c < 3; c ++) { String str = burst + "@大家好" + i+"/"+c+"$"; ByteBuffer buf = ByteBuffer.wrap(str.getBytes("utf8")); this.push(buf, null); ///this.push(str, "utf8"); } } } } private class DummyWritable extends Writable2 { public DummyWritable() { super(context, new Options(-1, true, "utf8", false, true)); // TODO Auto-generated constructor stub } @Override public void _write(Object chunk, String encoding, WriteCB cb) throws Exception { if (Util.isString(chunk)) { Log.d(TAG, "DummyWritable: encdoing "+encoding+":"+chunk.toString()); if (cb != null) cb.writeDone(null); } else { Log.d(TAG, "DummyWritable: binary data "+chunk.toString()); if (cb != null) cb.writeDone(null); // decode chunk to string String result = Charset.forName("utf8").newDecoder().decode((ByteBuffer)chunk).toString(); Log.d(TAG, "DummyWritable: decoded string "+result); } } } private class DummyDuplex extends Duplex { private int _max = 20; private int _index = 1; public DummyDuplex() { super(context, new Duplex.Options( new Readable2.Options(-1, "utf8", false, "utf8", true), new Writable2.Options(-1, true, "utf8", false, true), true)); // TODO Auto-generated constructor stub _index = 1; } @Override public void _read(int size) throws Exception { int i = this._index++; if (i > this._max) this.push(null, null); else { for (int c = 0; c < 3; c ++) { String str = burst + "@大家好" + i+"/"+c+"$"; ByteBuffer buf = ByteBuffer.wrap(str.getBytes("utf8")); if (!this.push(buf, null)) break; ///if (!this.push(str, "utf8")) break; Log.d(TAG, "DummyDuplex: _read "+str); } } } @Override public void _write(Object chunk, String encoding, WriteCB cb) throws Exception { if (Util.isString(chunk)) { Log.d(TAG, "DummyDuplex: encdoing "+encoding+":"+chunk.toString()); if (cb != null) cb.writeDone(null); } else { Log.d(TAG, "DummyDuplex: binary data "+chunk.toString()); if (cb != null) cb.writeDone(null); // decode chunk to string String result = Charset.forName("utf8").newDecoder().decode((ByteBuffer)chunk).toString(); Log.d(TAG, "DummyDuplex: decoded string "+result); } } } private class DoubleTransform extends Transform { protected DoubleTransform() { super(context, new Duplex.Options( new Readable2.Options(-1, "", false, "utf8", true), new Writable2.Options(-1, false, "utf8", false, true), true)); // TODO Auto-generated constructor stub } @Override protected void _transform(Object chunk, String encoding, afterTransformCallback cb) throws Exception { if (Util.isBuffer(chunk)) { ByteBuffer ori = (ByteBuffer)chunk; ByteBuffer dbl = ByteBuffer.allocate(ori.capacity()*2); dbl.put(ori); ori.flip();dbl.put(ori); ori.flip();dbl.flip(); this.push(dbl, encoding); cb.afterTransform(null, null); } else if (Util.isString(chunk)) { String ori = (String)chunk; String dbl = ori + ori; this.push(dbl, encoding); cb.afterTransform(null, null); } else { cb.afterTransform("invalid data "+chunk, null); } } @Override protected void _flush(flushCallback cb) throws Exception { cb.onFlush(null); } } public void testTransform() { final DoubleTransform ts = new DoubleTransform(); try { ts.on("readable", new Listener(){ @Override public void onEvent(Object data) throws Exception { Object chunk; while (null != (chunk = ts.read(-1))) { Log.d(TAG, "\n\n\ntestTransform: "+Util.chunkToString(chunk, "utf8")); } } }); context.setInterval(new IntervalListener(){ @Override public void onInterval() throws Exception { ts.write("double string", "utf-8", null); } }, 2000); } catch (Exception e) { e.printStackTrace(); } } public void testRead_less() { final Readable rs = new Counting(); try { rs.on("readable", new Listener(){ @Override public void onEvent(Object data) throws Exception { Object chunk; Log.d(TAG, "testRead_less: start..."); ///chunk = rs.read(3); while (null != (chunk = rs.read(3))) { Log.d(TAG, "testRead_less:"+Util.chunkToString(chunk, "utf8")); } Log.d(TAG, "testRead_less: ...end"); } }); } catch (Exception e) { e.printStackTrace(); } } public void testRead_more() { final Readable rs = new Counting(); try { rs.on("readable", new Listener(){ @Override public void onEvent(Object data) throws Exception { Object chunk; Log.d(TAG, "testRead_more: start..."); ///chunk = rs.read(33); while (null != (chunk = rs.read(28))) { Log.d(TAG, "testRead_more: "+Util.chunkToString(chunk, "utf8")); } Log.d(TAG, "testRead_more: ...end"); } }); } catch (Exception e) { e.printStackTrace(); } } public void testRead_forever() { final Readable rs = new Counting(); try { rs.on("readable", new Listener(){ @Override public void onEvent(Object data) throws Exception { Object chunk; Log.d(TAG, "testRead_forever: start..."); while (null != (chunk = rs.read(-1))) { Log.d(TAG, "testRead_forever: "+Util.chunkToString(chunk, "utf8")); } Log.d(TAG, "testRead_forever: ...end"); } }); } catch (Exception e) { e.printStackTrace(); } } public void testPipe() { final Readable rs = new Counting(); final Writable ws = new DummyWritable(); try { ws.on("pipe", new Listener () { @Override public void onEvent(Object src) throws Exception { Log.d(TAG, "testPipe: something is piping into the writer"); assert(rs.equals(src)); } }); ws.on("unpipe", new Listener () { @Override public void onEvent(Object src) throws Exception { Log.d(TAG, "testPipe: something has stopped piping into the writer"); assert(rs.equals(src)); } }); rs.pipe(ws, true); rs.unpipe(ws); } catch (Exception e) { e.printStackTrace(); } } public void testDuplex() { final Duplex du = new DummyDuplex(); try { du.pipe(du, true); } catch (Exception e) { e.printStackTrace(); } } public void testFinish() { final Writable ws = new DummyWritable(); try { ws.on("finish", new Listener() { @Override public void onEvent(Object src) throws Exception { Log.d(TAG, "testFinish: all writes are now complete."); } }); for (int i = 0; i < 100; i ++) { ws.write("hello, #" + i + "!\n", null, new WriteCB() { @Override public void writeDone(String error) throws Exception { Log.d(TAG, "testFinish: write done"); } }); } ws.end("this is the end\n", null, null); } catch (Exception e) { e.printStackTrace(); } } }