IVGCVSW-2051 Added unit tests in the Android NN Driver for the new
Mean layer

 * Added unit tests (in a new file test/1.1/Mean.cpp)
 * Refactored ArmnnDriverImpl to remove redundant tags in the log
   messages
 * Modified AddInputOperand to accept a quantized input tensor

Change-Id: Ie037ce426777daab28b0501124e1cc8686ad6184
diff --git a/test/1.1/Mean.cpp b/test/1.1/Mean.cpp
new file mode 100644
index 0000000..4ebb8cf
--- /dev/null
+++ b/test/1.1/Mean.cpp
@@ -0,0 +1,137 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "../DriverTestHelpers.hpp"
+#include "../TestTensor.hpp"
+
+#include <boost/array.hpp>
+#include <boost/test/data/test_case.hpp>
+
+BOOST_AUTO_TEST_SUITE(MeanTests)
+
+using namespace android::hardware;
+using namespace driverTestHelpers;
+using namespace armnn_driver;
+
+namespace
+{
+
+static const boost::array<armnn::Compute, 2> COMPUTE_DEVICES = {{ armnn::Compute::CpuRef, armnn::Compute::GpuAcc }};
+
+void MeanTestImpl(const TestTensor& input,
+                  const hidl_vec<uint32_t>& axisDimensions,
+                  const int32_t* axisValues,
+                  int32_t keepDims,
+                  const TestTensor& expectedOutput,
+                  bool fp16Enabled,
+                  armnn::Compute computeDevice)
+{
+    auto driver = std::make_unique<ArmnnDriver>(DriverOptions(computeDevice, fp16Enabled));
+
+    V1_1::Model model = {};
+    AddInputOperand (model, input.GetDimensions());
+    AddTensorOperand(model, axisDimensions, const_cast<int32_t*>(axisValues), OperandType::TENSOR_INT32);
+    AddIntOperand   (model, keepDims);
+    AddOutputOperand(model, expectedOutput.GetDimensions());
+
+    model.operations.resize(1);
+    model.operations[0].type               = V1_1::OperationType::MEAN;
+    model.operations[0].inputs             = hidl_vec<uint32_t>{ 0, 1, 2 };
+    model.operations[0].outputs            = hidl_vec<uint32_t>{ 3 };
+    model.relaxComputationFloat32toFloat16 = fp16Enabled;
+
+    android::sp<IPreparedModel> preparedModel = PrepareModel(model, *driver);
+
+    // The request's memory pools will follow the same order as the inputs
+    DataLocation inLoc    = {};
+    inLoc.poolIndex       = 0;
+    inLoc.offset          = 0;
+    inLoc.length          = input.GetNumElements() * sizeof(float);
+    RequestArgument inArg = {};
+    inArg.location        = inLoc;
+    inArg.dimensions      = input.GetDimensions();
+
+    // An additional memory pool is needed for the output
+    DataLocation outLoc    = {};
+    outLoc.poolIndex       = 1;
+    outLoc.offset          = 0;
+    outLoc.length          = expectedOutput.GetNumElements() * sizeof(float);
+    RequestArgument outArg = {};
+    outArg.location        = outLoc;
+    outArg.dimensions      = expectedOutput.GetDimensions();
+
+    // Make the request based on the arguments
+    Request request = {};
+    request.inputs  = hidl_vec<RequestArgument>{ inArg };
+    request.outputs = hidl_vec<RequestArgument>{ outArg };
+
+    // Set the input data
+    AddPoolAndSetData(input.GetNumElements(), request, input.GetData());
+
+    // Add memory for the output
+    android::sp<IMemory> outMemory = AddPoolAndGetData(expectedOutput.GetNumElements(), request);
+    const float* outputData = static_cast<const float*>(static_cast<void*>(outMemory->getPointer()));
+
+    ErrorStatus execStatus = Execute(preparedModel, request);
+    BOOST_TEST(execStatus == ErrorStatus::NONE);
+
+    const float* expectedOutputData = expectedOutput.GetData();
+    for (unsigned int i = 0; i < expectedOutput.GetNumElements(); i++)
+    {
+        BOOST_TEST(outputData[i] == expectedOutputData[i]);
+    }
+}
+
+} // anonymous namespace
+
+BOOST_DATA_TEST_CASE(MeanNoKeepDimsTest, COMPUTE_DEVICES)
+{
+    TestTensor input{ armnn::TensorShape{ 4, 3, 2 }, { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f,
+                                                       11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f,
+                                                       20.0f, 21.0f, 22.0f, 23.0f, 24.0f } };
+    hidl_vec<uint32_t> axisDimensions = { 2 };
+    int32_t axisValues[] = { 0, 1 };
+    int32_t keepDims = 0;
+    TestTensor expectedOutput{ armnn::TensorShape{ 2 }, { 12.0f, 13.0f } };
+
+    MeanTestImpl(input, axisDimensions, axisValues, keepDims, expectedOutput, false, sample);
+}
+
+BOOST_DATA_TEST_CASE(MeanKeepDimsTest, COMPUTE_DEVICES)
+{
+    TestTensor input{ armnn::TensorShape{ 1, 1, 3, 2 }, { 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f } };
+    hidl_vec<uint32_t> axisDimensions = { 1 };
+    int32_t axisValues[] = { 2 };
+    int32_t keepDims = 1;
+    TestTensor expectedOutput{ armnn::TensorShape{ 1, 1, 1, 2 }, {  2.0f, 2.0f } };
+
+    MeanTestImpl(input, axisDimensions, axisValues, keepDims, expectedOutput, false, sample);
+}
+
+BOOST_DATA_TEST_CASE(MeanFp16NoKeepDimsTest, COMPUTE_DEVICES)
+{
+    TestTensor input{ armnn::TensorShape{ 4, 3, 2 }, { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f,
+                                                       11.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0f, 17.0f, 18.0f, 19.0f,
+                                                       20.0f, 21.0f, 22.0f, 23.0f, 24.0f } };
+    hidl_vec<uint32_t> axisDimensions = { 2 };
+    int32_t axisValues[] = { 0, 1 };
+    int32_t keepDims = 0;
+    TestTensor expectedOutput{ armnn::TensorShape{ 2 }, { 12.0f, 13.0f } };
+
+    MeanTestImpl(input, axisDimensions, axisValues, keepDims, expectedOutput, true, sample);
+}
+
+BOOST_DATA_TEST_CASE(MeanFp16KeepDimsTest, COMPUTE_DEVICES)
+{
+    TestTensor input{ armnn::TensorShape{ 1, 1, 3, 2 }, { 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f } };
+    hidl_vec<uint32_t> axisDimensions = { 1 };
+    int32_t axisValues[] = { 2 };
+    int32_t keepDims = 1;
+    TestTensor expectedOutput{ armnn::TensorShape{ 1, 1, 1, 2 }, {  2.0f, 2.0f } };
+
+    MeanTestImpl(input, axisDimensions, axisValues, keepDims, expectedOutput, true, sample);
+}
+
+BOOST_AUTO_TEST_SUITE_END()