From 3095de8e4e6596d80509c06139517cc31790ea2f Mon Sep 17 00:00:00 2001 From: Jaeyun Jung Date: Sun, 22 Sep 2019 18:19:56 +0900 Subject: [PATCH] [Android/Test] update testcases 1. update testcases for each java class 2. add flag to generate coverage report Signed-off-by: Jaeyun Jung --- api/android/api/build.gradle | 3 + .../java/org/nnsuite/nnstreamer/APITestCommon.java | 20 + .../nnsuite/nnstreamer/APITestCustomFilter.java | 250 ++++++++++ .../org/nnsuite/nnstreamer/APITestPipeline.java | 548 +++++++++++++++++++++ .../org/nnsuite/nnstreamer/APITestSingleShot.java | 237 +++++++++ .../org/nnsuite/nnstreamer/APITestTensorsData.java | 282 +++++++++++ .../org/nnsuite/nnstreamer/APITestTensorsInfo.java | 192 ++++++++ .../java/org/nnsuite/nnstreamer/CustomFilter.java | 6 +- 8 files changed, 1535 insertions(+), 3 deletions(-) create mode 100644 api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCustomFilter.java create mode 100644 api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestPipeline.java create mode 100644 api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestSingleShot.java create mode 100644 api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsData.java create mode 100644 api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsInfo.java diff --git a/api/android/api/build.gradle b/api/android/api/build.gradle index c2c083b..0436257 100644 --- a/api/android/api/build.gradle +++ b/api/android/api/build.gradle @@ -45,6 +45,9 @@ android { } } buildTypes { + debug { + testCoverageEnabled true + } release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' diff --git a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCommon.java b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCommon.java index a208db9..21de8f3 100644 --- a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCommon.java +++ b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCommon.java @@ -9,6 +9,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import static org.junit.Assert.*; @@ -52,6 +54,24 @@ public class APITestCommon { return model; } + /** + * Verifies the byte buffer is direct buffer with native order. + * + * @param buffer The byte buffer + * @param expected The expected capacity + * + * @return True if the byte buffer is valid. + */ + public static boolean isValidBuffer(ByteBuffer buffer, int expected) { + if (buffer != null && buffer.isDirect() && buffer.order() == ByteOrder.nativeOrder()) { + int capacity = buffer.capacity(); + + return (capacity == expected); + } + + return false; + } + @Test public void useAppContext() { Context context = InstrumentationRegistry.getTargetContext(); diff --git a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCustomFilter.java b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCustomFilter.java new file mode 100644 index 0000000..6e2666c --- /dev/null +++ b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestCustomFilter.java @@ -0,0 +1,250 @@ +package org.nnsuite.nnstreamer; + +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; + +import static org.junit.Assert.*; + +/** + * Testcases for CustomFilter. + */ +@RunWith(AndroidJUnit4.class) +public class APITestCustomFilter { + private int mReceived = 0; + private boolean mInvalidState = false; + private boolean mRegistered = false; + private CustomFilter mCustomPassthrough; + private CustomFilter mCustomConvert; + private CustomFilter mCustomAdd; + + private void registerCustomFilters() { + try { + /* register custom-filter (passthrough) */ + mCustomPassthrough = CustomFilter.registerCustomFilter("custom-passthrough", + new CustomFilter.CustomFilterCallback() { + @Override + public TensorsInfo getOutputInfo(TensorsInfo inInfo) { + return inInfo; + } + + @Override + public TensorsData invoke(TensorsData inData, TensorsInfo inInfo, TensorsInfo outInfo) { + return inData; + } + }); + + /* register custom-filter (convert data type to float) */ + mCustomConvert = CustomFilter.registerCustomFilter("custom-convert", + new CustomFilter.CustomFilterCallback() { + @Override + public TensorsInfo getOutputInfo(TensorsInfo inInfo) { + inInfo.setTensorType(0, NNStreamer.TENSOR_TYPE_FLOAT32); + return inInfo; + } + + @Override + public TensorsData invoke(TensorsData inData, TensorsInfo inInfo, TensorsInfo outInfo) { + ByteBuffer input = inData.getTensorData(0); + ByteBuffer output = TensorsData.allocateByteBuffer(4 * 10); + + for (int i = 0; i < 10; i++) { + float value = (float) input.getInt(i * 4); + output.putFloat(i * 4, value); + } + + TensorsData out = new TensorsData(); + out.addTensorData(output); + + return out; + } + }); + + /* register custom-filter (add constant) */ + mCustomAdd = CustomFilter.registerCustomFilter("custom-add", + new CustomFilter.CustomFilterCallback() { + @Override + public TensorsInfo getOutputInfo(TensorsInfo inInfo) { + return inInfo; + } + + @Override + public TensorsData invoke(TensorsData inData, TensorsInfo inInfo, TensorsInfo outInfo) { + ByteBuffer input = inData.getTensorData(0); + ByteBuffer output = TensorsData.allocateByteBuffer(4 * 10); + + for (int i = 0; i < 10; i++) { + float value = input.getFloat(i * 4); + + /* add constant */ + value += 1.5f; + output.putFloat(i * 4, value); + } + + TensorsData out = new TensorsData(); + out.addTensorData(output); + + return out; + } + }); + + mRegistered = true; + } catch (Exception e) { + /* failed to register custom-filters */ + fail(); + } + } + + @Before + public void setUp() { + APITestCommon.initNNStreamer(); + + mReceived = 0; + mInvalidState = false; + + if (!mRegistered) { + registerCustomFilters(); + } + } + + @After + public void tearDown() { + if (mRegistered) { + mCustomPassthrough.close(); + mCustomConvert.close(); + mCustomAdd.close(); + } + } + + @Test + public void testGetName() { + try { + assertEquals("custom-passthrough", mCustomPassthrough.getName()); + assertEquals("custom-convert", mCustomConvert.getName()); + assertEquals("custom-add", mCustomAdd.getName()); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testCustomFilters() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)10:1:1:1,type=(string)int32,framerate=(fraction)0/1 ! " + + "tensor_filter framework=" + mCustomPassthrough.getName() + " ! " + + "tensor_filter framework=" + mCustomConvert.getName() + " ! " + + "tensor_filter framework=" + mCustomAdd.getName() + " ! " + + "tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* register sink callback */ + pipe.setSinkCallback("sinkx", new Pipeline.NewDataCallback() { + @Override + public void onNewDataReceived(TensorsData data, TensorsInfo info) { + if (data == null || data.getTensorsCount() != 1 || + info == null || info.getTensorsCount() != 1) { + mInvalidState = true; + } else { + ByteBuffer output = data.getTensorData(0); + + for (int i = 0; i < 10; i++) { + float expected = i + 1.5f; + + if (expected != output.getFloat(i * 4)) { + mInvalidState = true; + } + } + } + + mReceived++; + } + }); + + /* start pipeline */ + pipe.start(); + + /* push input buffer */ + for (int i = 0; i < 15; i++) { + ByteBuffer input = TensorsData.allocateByteBuffer(4 * 10); + + for (int j = 0; j < 10; j++) { + input.putInt(j * 4, j); + } + + TensorsData in = new TensorsData(); + in.addTensorData(input); + + pipe.inputData("srcx", in); + Thread.sleep(50); + } + + /* sleep 300 to pass all input buffers to sink */ + Thread.sleep(300); + + /* check received data from sink */ + assertFalse(mInvalidState); + assertEquals(15, mReceived); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testRegisterNullName() { + try { + CustomFilter.registerCustomFilter(null, + new CustomFilter.CustomFilterCallback() { + @Override + public TensorsInfo getOutputInfo(TensorsInfo inInfo) { + return inInfo; + } + + @Override + public TensorsData invoke(TensorsData inData, TensorsInfo inInfo, TensorsInfo outInfo) { + return inData; + } + }); + + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testRegisterNullCallback() { + try { + CustomFilter.registerCustomFilter("custom-invalid-cb", null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testRegisterDuplicatedName() { + try { + CustomFilter.registerCustomFilter(mCustomPassthrough.getName(), + new CustomFilter.CustomFilterCallback() { + @Override + public TensorsInfo getOutputInfo(TensorsInfo inInfo) { + return inInfo; + } + + @Override + public TensorsData invoke(TensorsData inData, TensorsInfo inInfo, TensorsInfo outInfo) { + return inData; + } + }); + + fail(); + } catch (Exception e) { + /* expected */ + } + } +} diff --git a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestPipeline.java b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestPipeline.java new file mode 100644 index 0000000..f69620a --- /dev/null +++ b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestPipeline.java @@ -0,0 +1,548 @@ +package org.nnsuite.nnstreamer; + +import android.Manifest; +import android.support.test.rule.GrantPermissionRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import static org.junit.Assert.*; + +/** + * Testcases for Pipeline. + */ +@RunWith(AndroidJUnit4.class) +public class APITestPipeline { + private int mReceived = 0; + private boolean mInvalidState = false; + private int mPipelineState = NNStreamer.PIPELINE_STATE_NULL; + + private Pipeline.NewDataCallback mSinkCb = new Pipeline.NewDataCallback() { + @Override + public void onNewDataReceived(TensorsData data, TensorsInfo info) { + /* validate received data (unit8 2:10:10:1) */ + if (data == null || data.getTensorsCount() != 1 || + data.getTensorData(0).capacity() != 200 || + info == null || info.getTensorsCount() != 1 || + info.getTensorName(0) != null || + info.getTensorType(0) != NNStreamer.TENSOR_TYPE_UINT8 || + !Arrays.equals(info.getTensorDimension(0), new int[]{2,10,10,1})) { + /* received data is invalid */ + mInvalidState = true; + } + + mReceived++; + } + }; + + @Rule + public GrantPermissionRule mPermissionRule = + GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE); + + @Before + public void setUp() { + APITestCommon.initNNStreamer(); + + mReceived = 0; + mInvalidState = false; + mPipelineState = NNStreamer.PIPELINE_STATE_NULL; + } + + @Test + public void testConstructInvalidElement() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "invalidelement ! tensor_converter ! tensor_sink"; + + try { + new Pipeline(desc); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testConstructNullDescription() { + try { + new Pipeline(null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testConstructNullStateCb() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "tensor_converter ! tensor_sink"; + + try (Pipeline pipe = new Pipeline(desc, null)) { + Thread.sleep(100); + assertEquals(NNStreamer.PIPELINE_STATE_PAUSED, pipe.getState()); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testConstructWithStateCb() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "tensor_converter ! tensor_sink"; + + /* pipeline state callback */ + Pipeline.StateChangeCallback stateCb = new Pipeline.StateChangeCallback() { + @Override + public void onStateChanged(int state) { + mPipelineState = state; + } + }; + + try (Pipeline pipe = new Pipeline(desc, stateCb)) { + Thread.sleep(100); + assertEquals(NNStreamer.PIPELINE_STATE_PAUSED, mPipelineState); + + /* start pipeline */ + pipe.start(); + Thread.sleep(300); + + assertEquals(NNStreamer.PIPELINE_STATE_PLAYING, mPipelineState); + + /* stop pipeline */ + pipe.stop(); + Thread.sleep(300); + + assertEquals(NNStreamer.PIPELINE_STATE_PAUSED, mPipelineState); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetState() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "tensor_converter ! tensor_sink"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* start pipeline */ + pipe.start(); + Thread.sleep(300); + + assertEquals(NNStreamer.PIPELINE_STATE_PLAYING, pipe.getState()); + + /* stop pipeline */ + pipe.stop(); + Thread.sleep(300); + + assertEquals(NNStreamer.PIPELINE_STATE_PAUSED, pipe.getState()); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testSetNullDataCb() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "tensor_converter ! tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + pipe.setSinkCallback("sinkx", null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSetDataCbInvalidName() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "tensor_converter ! tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + pipe.setSinkCallback("invalid_sink", mSinkCb); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSetDataCbNullName() { + String desc = "videotestsrc ! videoconvert ! video/x-raw,format=RGB ! " + + "tensor_converter ! tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + pipe.setSinkCallback(null, mSinkCb); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testRemoveDataCb() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* register sink callback */ + pipe.setSinkCallback("sinkx", mSinkCb); + + /* start pipeline */ + pipe.start(); + + /* push input buffer */ + for (int i = 0; i < 10; i++) { + /* dummy input */ + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(200)); + + pipe.inputData("srcx", in); + Thread.sleep(50); + } + + /* pause pipeline and unregister sink callback */ + Thread.sleep(100); + pipe.stop(); + + pipe.setSinkCallback("sinkx", null); + Thread.sleep(100); + + /* start pipeline again */ + pipe.start(); + + /* push input buffer again */ + for (int i = 0; i < 10; i++) { + /* dummy input */ + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(200)); + + pipe.inputData("srcx", in); + Thread.sleep(50); + } + + /* check received data from sink */ + assertFalse(mInvalidState); + assertEquals(10, mReceived); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testRunModel() { + File model = APITestCommon.getTestModel(); + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)3:224:224:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tensor_filter framework=tensorflow-lite model=" + model.getAbsolutePath() + " ! " + + "tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* register sink callback */ + pipe.setSinkCallback("sinkx", new Pipeline.NewDataCallback() { + @Override + public void onNewDataReceived(TensorsData data, TensorsInfo info) { + if (data == null || data.getTensorsCount() != 1 || + info == null || info.getTensorsCount() != 1) { + mInvalidState = true; + } else { + ByteBuffer output = data.getTensorData(0); + + if (!APITestCommon.isValidBuffer(output, 1001)) { + mInvalidState = true; + } + } + + mReceived++; + } + }); + + /* start pipeline */ + pipe.start(); + + /* push input buffer */ + for (int i = 0; i < 15; i++) { + /* dummy input */ + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(3 * 224 * 224)); + + pipe.inputData("srcx", in); + Thread.sleep(100); + } + + /* sleep 500 to invoke */ + Thread.sleep(500); + + /* check received data from sink */ + assertFalse(mInvalidState); + assertTrue(mReceived > 0); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testInputInvalidName() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* start pipeline */ + pipe.start(); + + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(200)); + + pipe.inputData("invalid_src", in); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInputNullName() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* start pipeline */ + pipe.start(); + + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(200)); + + pipe.inputData(null, in); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInputNullData() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* start pipeline */ + pipe.start(); + + pipe.inputData("srcx", null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSelectSwitch() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "output-selector name=outs " + + "outs.src_0 ! tensor_sink name=sinkx async=false " + + "outs.src_1 ! tensor_sink async=false"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* register sink callback */ + pipe.setSinkCallback("sinkx", mSinkCb); + + /* start pipeline */ + pipe.start(); + + /* push input buffer */ + for (int i = 0; i < 15; i++) { + /* dummy input */ + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(200)); + + pipe.inputData("srcx", in); + Thread.sleep(50); + + if (i == 9) { + /* select pad */ + pipe.selectSwitchPad("outs", "src_1"); + } + } + + /* sleep 300 to pass all input buffers to sink */ + Thread.sleep(300); + + /* check received data from sink */ + assertFalse(mInvalidState); + assertEquals(10, mReceived); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetSwitchPad() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "output-selector name=outs " + + "outs.src_0 ! tensor_sink name=sinkx async=false " + + "outs.src_1 ! tensor_sink async=false"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* start pipeline */ + pipe.start(); + + /* get pad list of output-selector */ + String[] pads = pipe.getSwitchPads("outs"); + + assertEquals(2, pads.length); + assertEquals("src_0", pads[0]); + assertEquals("src_1", pads[1]); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetSwitchInvalidName() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "output-selector name=outs " + + "outs.src_0 ! tensor_sink name=sinkx async=false " + + "outs.src_1 ! tensor_sink async=false"; + + Pipeline pipe = new Pipeline(desc); + + /* start pipeline */ + pipe.start(); + + try { + /* get pad list with invalid switch name */ + pipe.getSwitchPads("invalid_outs"); + fail(); + } catch (Exception e) { + /* expected */ + } + + pipe.close(); + } + + @Test + public void testGetSwitchNullName() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "output-selector name=outs " + + "outs.src_0 ! tensor_sink name=sinkx async=false " + + "outs.src_1 ! tensor_sink async=false"; + + Pipeline pipe = new Pipeline(desc); + + /* start pipeline */ + pipe.start(); + + try { + /* get pad list with null param */ + pipe.getSwitchPads(null); + fail(); + } catch (Exception e) { + /* expected */ + } + + pipe.close(); + } + + @Test + public void testSelectInvalidPad() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "output-selector name=outs " + + "outs.src_0 ! tensor_sink name=sinkx async=false " + + "outs.src_1 ! tensor_sink async=false"; + + Pipeline pipe = new Pipeline(desc); + + /* start pipeline */ + pipe.start(); + + try { + /* select invalid pad name */ + pipe.selectSwitchPad("outs", "invalid_src"); + fail(); + } catch (Exception e) { + /* expected */ + } + + pipe.close(); + } + + @Test + public void testControlValve() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tee name=t " + + "t. ! queue ! tensor_sink " + + "t. ! queue ! valve name=valvex ! tensor_sink name=sinkx"; + + try (Pipeline pipe = new Pipeline(desc)) { + /* register sink callback */ + pipe.setSinkCallback("sinkx", mSinkCb); + + /* start pipeline */ + pipe.start(); + + /* push input buffer */ + for (int i = 0; i < 15; i++) { + /* dummy input */ + TensorsData in = new TensorsData(); + in.addTensorData(TensorsData.allocateByteBuffer(200)); + + pipe.inputData("srcx", in); + Thread.sleep(50); + + if (i == 9) { + /* close valve */ + pipe.controlValve("valvex", false); + } + } + + /* sleep 300 to pass all input buffers to sink */ + Thread.sleep(300); + + /* check received data from sink */ + assertFalse(mInvalidState); + assertEquals(10, mReceived); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testControlInvalidValve() { + String desc = "appsrc name=srcx ! " + + "other/tensor,dimension=(string)2:10:10:1,type=(string)uint8,framerate=(fraction)0/1 ! " + + "tee name=t " + + "t. ! queue ! tensor_sink " + + "t. ! queue ! valve name=valvex ! tensor_sink name=sinkx"; + + Pipeline pipe = new Pipeline(desc); + + /* start pipeline */ + pipe.start(); + + try { + /* control valve with invalid name */ + pipe.controlValve("invalid_valve", false); + fail(); + } catch (Exception e) { + /* expected */ + } + + pipe.close(); + } +} diff --git a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestSingleShot.java b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestSingleShot.java new file mode 100644 index 0000000..04b6d61 --- /dev/null +++ b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestSingleShot.java @@ -0,0 +1,237 @@ +package org.nnsuite.nnstreamer; + +import android.Manifest; +import android.os.Environment; +import android.support.test.rule.GrantPermissionRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; + +import static org.junit.Assert.*; + +/** + * Testcases for SingleShot. + */ +@RunWith(AndroidJUnit4.class) +public class APITestSingleShot { + private SingleShot mSingle; + + @Rule + public GrantPermissionRule mPermissionRule = + GrantPermissionRule.grant(Manifest.permission.READ_EXTERNAL_STORAGE); + + @Before + public void setUp() { + APITestCommon.initNNStreamer(); + + try { + mSingle = new SingleShot(APITestCommon.getTestModel()); + } catch (Exception e) { + fail(); + } + } + + @After + public void tearDown() { + mSingle.close(); + } + + @Test + public void testGetInputInfo() { + try { + TensorsInfo info = mSingle.getInputInfo(); + + /* input: uint8 3:224:224:1 */ + assertEquals(1, info.getTensorsCount()); + assertEquals(NNStreamer.TENSOR_TYPE_UINT8, info.getTensorType(0)); + assertArrayEquals(new int[]{3,224,224,1}, info.getTensorDimension(0)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetOutputInfo() { + try { + TensorsInfo info = mSingle.getOutputInfo(); + + /* output: uint8 1001:1:1:1 */ + assertEquals(1, info.getTensorsCount()); + assertEquals(NNStreamer.TENSOR_TYPE_UINT8, info.getTensorType(0)); + assertArrayEquals(new int[]{1001,1,1,1}, info.getTensorDimension(0)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testInvoke() { + try { + TensorsInfo info = mSingle.getInputInfo(); + + /* single-shot invoke */ + for (int i = 0; i < 5; i++) { + /* dummy input */ + TensorsData in = TensorsData.allocate(info); + TensorsData out = mSingle.invoke(in); + + /* output: uint8 1001:1:1:1 */ + assertEquals(1, out.getTensorsCount()); + assertEquals(1001, out.getTensorData(0).capacity()); + + Thread.sleep(50); + } + } catch (Exception e) { + fail(); + } + } + + @Test + public void testInvokeTimeout() { + TensorsInfo info = mSingle.getInputInfo(); + + /* timeout 5ms */ + mSingle.setTimeout(5); + + for (int i = 0; i < 5; i++) { + /* dummy input */ + TensorsData in = TensorsData.allocate(info); + + try { + mSingle.invoke(in); + fail(); + } catch (Exception e) { + /* expected */ + } + } + } + + @Test + public void testNullFile() { + try { + new SingleShot(null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvalidFile() { + String root = Environment.getExternalStorageDirectory().getAbsolutePath(); + File model = new File(root + "/invalid_path/invalid.tflite"); + + try { + new SingleShot(model); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvalidInputType() { + /* input: uint8 3:224:224:1 */ + TensorsInfo info = new TensorsInfo(); + info.addTensorInfo(NNStreamer.TENSOR_TYPE_UINT16, new int[]{3,224,224,1}); + + try { + new SingleShot(APITestCommon.getTestModel(), info, null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvalidInputDimension() { + /* input: uint8 3:224:224:1 */ + TensorsInfo info = new TensorsInfo(); + info.addTensorInfo(NNStreamer.TENSOR_TYPE_UINT8, new int[]{2,224,224}); + + try { + new SingleShot(APITestCommon.getTestModel(), info, null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvalidOutputType() { + /* output: uint8 1001:1:1:1 */ + TensorsInfo info = new TensorsInfo(); + info.addTensorInfo(NNStreamer.TENSOR_TYPE_INT16, new int[]{1001,1,1,1}); + + try { + new SingleShot(APITestCommon.getTestModel(), null, info); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvalidOutputDimension() { + /* output: uint8 1001:1:1:1 */ + TensorsInfo info = new TensorsInfo(); + info.addTensorInfo(NNStreamer.TENSOR_TYPE_UINT8, new int[]{1001,2,1,1}); + + try { + new SingleShot(APITestCommon.getTestModel(), null, info); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvokeNullData() { + try { + mSingle.invoke(null); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testInvokeInvalidData() { + /* input data size: 3 * 224 * 224 */ + TensorsData data = new TensorsData(); + data.addTensorData(TensorsData.allocateByteBuffer(100)); + + try { + mSingle.invoke(data); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSetZeroTimeout() { + try { + mSingle.setTimeout(0); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSetInvalidTimeout() { + try { + mSingle.setTimeout(-1); + fail(); + } catch (Exception e) { + /* expected */ + } + } +} diff --git a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsData.java b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsData.java new file mode 100644 index 0000000..4ce939d --- /dev/null +++ b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsData.java @@ -0,0 +1,282 @@ +package org.nnsuite.nnstreamer; + +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import static org.junit.Assert.*; + +/** + * Testcases for TensorsData. + */ +@RunWith(AndroidJUnit4.class) +public class APITestTensorsData { + private TensorsData mData; + + @Before + public void setUp() { + APITestCommon.initNNStreamer(); + mData = new TensorsData(); + } + + @After + public void tearDown() { + mData.close(); + } + + @Test + public void testAllocateByteBuffer() { + try { + ByteBuffer buffer = TensorsData.allocateByteBuffer(300); + + assertTrue(APITestCommon.isValidBuffer(buffer, 300)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testAllocate() { + try { + TensorsInfo info = new TensorsInfo(); + + info.addTensorInfo(NNStreamer.TENSOR_TYPE_INT16, new int[]{2}); + info.addTensorInfo(NNStreamer.TENSOR_TYPE_UINT16, new int[]{2,2}); + info.addTensorInfo(NNStreamer.TENSOR_TYPE_UINT32, new int[]{2,2,2}); + + mData = TensorsData.allocate(info); + + /* index 0: 2:1:1:1 int16 */ + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(0), 4)); + + /* index 1: 2:2:1:1 uint16 */ + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(1), 8)); + + /* index 0: 2:2:2:1 uint32 */ + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(2), 32)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testAddData() { + try { + Object buffer = ByteBuffer.allocateDirect(100).order(ByteOrder.nativeOrder()); + + mData.addTensorData(buffer); + assertEquals(1, mData.getTensorsCount()); + + mData.addTensorData(new byte[200]); + assertEquals(2, mData.getTensorsCount()); + + mData.addTensorData(TensorsData.allocateByteBuffer(300)); + assertEquals(3, mData.getTensorsCount()); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetData() { + try { + testAddData(); + + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(0), 100)); + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(1), 200)); + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(2), 300)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testSetData() { + try { + testAddData(); + + ByteBuffer buffer = TensorsData.allocateByteBuffer(500); + mData.setTensorData(1, buffer); + + assertEquals(3, mData.getTensorsCount()); + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(0), 100)); + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(1), 500)); + assertTrue(APITestCommon.isValidBuffer(mData.getTensorData(2), 300)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testAllocateNullInfo() { + try { + TensorsData.allocate(null); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testAddNullByteBuffer() { + try { + ByteBuffer buffer = null; + + mData.addTensorData(buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testAddInvalidType() { + try { + Object buffer = new int[8]; + + mData.addTensorData(buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testAddInvalidByteBuffer() { + try { + /* big-endian byte order */ + Object buffer = ByteBuffer.allocateDirect(100); + + mData.addTensorData(buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testAddNonDirectBuffer() { + try { + /* non-direct byte buffer */ + Object buffer = ByteBuffer.allocate(100); + + mData.addTensorData(buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testAddNullObject() { + try { + Object buffer = null; + + mData.addTensorData(buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testAddNullByteArray() { + try { + byte[] buffer = null; + + mData.addTensorData(buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mData.getTensorsCount()); + } + + @Test + public void testGetInvalidIndex() { + try { + mData.getTensorData(0); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSetInvalidIndex() { + try { + ByteBuffer buffer = TensorsData.allocateByteBuffer(500); + + mData.setTensorData(1, buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testSetInvalidByteBuffer() { + testAddData(); + + try { + /* non-direct byte buffer */ + ByteBuffer buffer = ByteBuffer.allocate(100); + + mData.setTensorData(1, buffer); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testAllocateInvalidSize() { + try { + TensorsData.allocateByteBuffer(-1); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testAllocateZeroSize() { + try { + TensorsData.allocateByteBuffer(0); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testAddMaxData() { + try { + for (int i = 0; i <= NNStreamer.TENSOR_SIZE_LIMIT; i++) { + mData.addTensorData(TensorsData.allocateByteBuffer(10)); + } + fail(); + } catch (Exception e) { + /* expected */ + } + } +} diff --git a/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsInfo.java b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsInfo.java new file mode 100644 index 0000000..0d43cdf --- /dev/null +++ b/api/android/api/src/androidTest/java/org/nnsuite/nnstreamer/APITestTensorsInfo.java @@ -0,0 +1,192 @@ +package org.nnsuite.nnstreamer; + +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Testcases for TensorsInfo. + */ +@RunWith(AndroidJUnit4.class) +public class APITestTensorsInfo { + private TensorsInfo mInfo; + + @Before + public void setUp() { + APITestCommon.initNNStreamer(); + mInfo = new TensorsInfo(); + } + + @After + public void tearDown() { + mInfo.close(); + } + + @Test + public void testAddInfo() { + try { + mInfo.addTensorInfo("name1", NNStreamer.TENSOR_TYPE_INT8, new int[]{1}); + assertEquals(1, mInfo.getTensorsCount()); + + mInfo.addTensorInfo("name2", NNStreamer.TENSOR_TYPE_UINT8, new int[]{2,2}); + assertEquals(2, mInfo.getTensorsCount()); + + mInfo.addTensorInfo(NNStreamer.TENSOR_TYPE_FLOAT32, new int[]{3,3,3}); + assertEquals(3, mInfo.getTensorsCount()); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetInfo() { + try { + testAddInfo(); + + assertEquals("name1", mInfo.getTensorName(0)); + assertEquals(NNStreamer.TENSOR_TYPE_INT8, mInfo.getTensorType(0)); + assertArrayEquals(new int[]{1,1,1,1}, mInfo.getTensorDimension(0)); + + assertEquals("name2", mInfo.getTensorName(1)); + assertEquals(NNStreamer.TENSOR_TYPE_UINT8, mInfo.getTensorType(1)); + assertArrayEquals(new int[]{2,2,1,1}, mInfo.getTensorDimension(1)); + + assertNull(mInfo.getTensorName(2)); + assertEquals(NNStreamer.TENSOR_TYPE_FLOAT32, mInfo.getTensorType(2)); + assertArrayEquals(new int[]{3,3,3,1}, mInfo.getTensorDimension(2)); + + assertEquals(3, mInfo.getTensorsCount()); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testGetSize() { + try { + testAddInfo(); + + /* index 0: 1:1:1:1 int8 */ + assertEquals(1, mInfo.getTensorSize(0)); + + /* index 1: 2:2:1:1 uint8 */ + assertEquals(4, mInfo.getTensorSize(1)); + + /* index 2: 3:3:3:1 float32 */ + assertEquals(108, mInfo.getTensorSize(2)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testUpdateInfo() { + try { + testAddInfo(); + + mInfo.setTensorName(2, "name3"); + assertEquals("name1", mInfo.getTensorName(0)); + assertEquals("name2", mInfo.getTensorName(1)); + assertEquals("name3", mInfo.getTensorName(2)); + + mInfo.setTensorType(2, NNStreamer.TENSOR_TYPE_INT64); + assertEquals(NNStreamer.TENSOR_TYPE_INT8, mInfo.getTensorType(0)); + assertEquals(NNStreamer.TENSOR_TYPE_UINT8, mInfo.getTensorType(1)); + assertEquals(NNStreamer.TENSOR_TYPE_INT64, mInfo.getTensorType(2)); + + mInfo.setTensorDimension(2, new int[]{2,3}); + assertArrayEquals(new int[]{1,1,1,1}, mInfo.getTensorDimension(0)); + assertArrayEquals(new int[]{2,2,1,1}, mInfo.getTensorDimension(1)); + assertArrayEquals(new int[]{2,3,1,1}, mInfo.getTensorDimension(2)); + } catch (Exception e) { + fail(); + } + } + + @Test + public void testAddInvalidType() { + try { + mInfo.addTensorInfo(100, new int[]{2,2,2,2}); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mInfo.getTensorsCount()); + } + + @Test + public void testAddUnknownType() { + try { + mInfo.addTensorInfo(NNStreamer.TENSOR_TYPE_UNKNOWN, new int[]{2,2,2,2}); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mInfo.getTensorsCount()); + } + + @Test + public void testAddInvalidRank() { + try { + mInfo.addTensorInfo(NNStreamer.TENSOR_TYPE_INT32, new int[]{2,2,2,2,2}); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mInfo.getTensorsCount()); + } + + @Test + public void testAddInvalidDimension() { + try { + mInfo.addTensorInfo(NNStreamer.TENSOR_TYPE_INT32, new int[]{1,1,0}); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mInfo.getTensorsCount()); + } + + @Test + public void testAddNullDimension() { + try { + mInfo.addTensorInfo(NNStreamer.TENSOR_TYPE_UINT8, null); + fail(); + } catch (Exception e) { + /* expected */ + } + + assertEquals(0, mInfo.getTensorsCount()); + } + + @Test + public void testGetInvalidIndex() { + try { + mInfo.getTensorType(0); + fail(); + } catch (Exception e) { + /* expected */ + } + } + + @Test + public void testAddMaxInfo() { + try { + for (int i = 0; i <= NNStreamer.TENSOR_SIZE_LIMIT; i++) { + mInfo.addTensorInfo(NNStreamer.TENSOR_TYPE_FLOAT32, new int[]{2,2,2,2}); + } + fail(); + } catch (Exception e) { + /* expected */ + } + } +} diff --git a/api/android/api/src/main/java/org/nnsuite/nnstreamer/CustomFilter.java b/api/android/api/src/main/java/org/nnsuite/nnstreamer/CustomFilter.java index a6287ea..c4aef02 100644 --- a/api/android/api/src/main/java/org/nnsuite/nnstreamer/CustomFilter.java +++ b/api/android/api/src/main/java/org/nnsuite/nnstreamer/CustomFilter.java @@ -107,13 +107,13 @@ public class CustomFilter implements AutoCloseable { throw new IllegalArgumentException("The param callback is null"); } - mName = name; - mCallback = callback; - mHandle = nativeInitialize(name); if (mHandle == 0) { throw new IllegalStateException("Failed to initialize custom-filter " + name); } + + mName = name; + mCallback = callback; } /** -- 2.7.4