// Copyright (C) 2018 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <gtest/gtest.h>
#include <inference_engine/shape_infer/built-in/ie_built_in_holder.hpp>
#include <xml_net_builder.hpp>
#include <inference_engine/cnn_network_impl.hpp>
#include <inference_engine/shape_infer/ie_reshaper.hpp>
#include <cpp/ie_cnn_net_reader.h>
#include <test_model_path.hpp>
#include <inference_engine/debug.h>
#include "built_in_shape_infer_general_test.hpp"

using namespace InferenceEngine;
using namespace InferenceEngine::details;
using namespace ShapeInfer;

TEST_P(BuiltInShapeInferImplTest, impl) {
    auto impl = getShapeInferImpl(type);
    ASSERT_NE(nullptr, impl);
    ASSERT_NO_THROW(sts = impl->inferShapes(newInOutShapes.inDims, layerParams.data, blobs, outShapes, &resp));

    if (canInfer) {
        ASSERT_EQ(int(OK), sts) << resp.msg;
        ASSERT_EQ(newInOutShapes.outDims, outShapes);
    } else {
        ASSERT_EQ(GENERAL_ERROR, sts) << resp.msg;
    }
}

TEST_P(BuiltInShapeInferImplTest, reshaper) {
    auto cnnNetworkImplPtr = buildSingleLayerNetwork<3>(type, inOutShapes, &layerParams.data, layerDataName);
    auto reshaper = std::make_shared<Reshaper>(*cnnNetworkImplPtr);
    auto inputShapes = setInputShapes(*cnnNetworkImplPtr.get(), newInOutShapes.inDims);

    if (canInfer) {
        reshaper->run(inputShapes);
        checkNetworkInOut(*cnnNetworkImplPtr, newInOutShapes);
    } else {
        ASSERT_THROW(reshaper->run(inputShapes), InferenceEngine::details::InferenceEngineException);
    }
}

//TODO: use static variables for dimensions and parameters!!
//TODO: think about shorter instantiation

INSTANTIATE_TEST_CASE_P(
        BuiltInEqualImpls, BuiltInShapeInferImplTest,
        ::testing::Combine(
                ::testing::Values(LayerType("SoftMax"), LayerType("ELU"), LayerType("TanH"), LayerType("Sigmoid"),
                                  LayerType("Logistic"),
                                  LayerType("Normalize"), LayerType("Copy"), LayerType("Eltwise"),
                                  LayerType("ScaleShift"), LayerType("PowerFile"),
                                  LayerType("GRN"), LayerType("MVN")),
                ::testing::Values(InOutShapes({{{1, 1, 1, 1}},
                                               {{1, 1, 1, 1}}})),
                ::testing::Values(NewInOutShapes({{{1, 3, 228, 228}},
                                                  {{1, 3, 228, 228}}})),
                ::testing::Values(MapParams(MapStrStr())),
                ::testing::Values(LayerDataName("data")),
                ::testing::Values(CanInfer(true)))
);

INSTANTIATE_TEST_CASE_P(
        BuiltInGeneralImpls, BuiltInShapeInferImplTest,
        ::testing::Values(
                ::testing::make_tuple(LayerType("LRN"),
                                      InOutShapes({{{1, 1, 1, 1}},
                                                   {{1, 1, 1, 1}}}),
                                      NewInOutShapes({{{1, 3, 228, 228}},
                                                      {{1, 3, 228, 228}}}),
                                      MapParams(MapStrStr({{"alpha",      "9.9999997e-05"},
                                                           {"beta",       "0.75"},
                                                           {"local-size", "5"},
                                                           {"region",     "across"}})),
                                      LayerDataName("norm_data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("ReLU"),
                                      InOutShapes({{{1, 1, 1, 1}},
                                                   {{1, 1, 1, 1}}}),
                                      NewInOutShapes({{{1, 3, 228, 228}},
                                                      {{1, 3, 228, 228}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"negative_slope", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Power"),
                                      InOutShapes({{{1, 1, 1, 1}},
                                                   {{1, 1, 1, 1}}}),
                                      NewInOutShapes({{{1, 3, 228, 228}},
                                                      {{1, 3, 228, 228}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"shift", "1"},
                                                                                             {"power", "1"},
                                                                                             {"scale", "1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Clamp"),
                                      InOutShapes({{{1, 1, 1, 1}},
                                                   {{1, 1, 1, 1}}}),
                                      NewInOutShapes({{{1, 3, 228, 228}},
                                                      {{1, 3, 228, 228}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"min", "1"},
                                                                                             {"max", "2"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("BatchNormalization"),
                                      InOutShapes({{{1, 1, 1, 1}},
                                                   {{1, 1, 1, 1}}}),
                                      NewInOutShapes({{{1, 3, 228, 228}},
                                                      {{1, 3, 228, 228}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"epsilon", "1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("InnerProduct"),
                                      InOutShapes({{{1, 3, 228, 228}},
                                                   {{1, 1000}}}),
                                      NewInOutShapes({{{1, 3, 228, 228}},
                                                      {{1, 1000}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"out-size", "1000"}})),
                                      LayerDataName("fc_data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("FullyConnected"),
                                      InOutShapes({{{1, 3}},
                                                   {{1, 1000}}}),
                                      NewInOutShapes({{{BATCH, 3}},
                                                      {{BATCH, 1000}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"out-size", "1000"}})),
                                      LayerDataName("fc_data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Permute"),
                                      InOutShapes({{{2, 3, 4, 5}},
                                                   {{4, 3, 5, 2}}}),
                                      NewInOutShapes({{{10, 3, 4, 5}},
                                                      {{4,  3, 5, 10}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"order", "2,1,3,0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Reshape"),
                                      InOutShapes({{{1, 34452}},
                                                   {{2, 5742, 6}}}),
                                      NewInOutShapes({{{2, 34458}},
                                                      {{2, 5743, 6}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"dim", "0,-1,6"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Reshape"),
                                      InOutShapes({{{1, 1, 300, 4}},
                                                   {{300, 4}}}),
                                      NewInOutShapes({{{1, 1, 500, 4}},
                                                      {{500, 4}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"dim", "-1,4"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Flatten"),
                                      InOutShapes({{{2, 1, 4, 5}},
                                                   {{40}}}),
                                      NewInOutShapes({{{4, 1, 4, 5}},
                                                      {{80}}}),
                                      MapParams(MapParams(MapStrStr())),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("PriorBoxClustered"),
                                      InOutShapes({{{2, 1, 4, 5}},
                                                   {{1, 2, 400}}}),
                                      NewInOutShapes({{{4, 1, 5, 5}},
                                                      {{1, 2, 500}}}),
                                      MapParams(MapStrStr(
                                              std::map<std::string, std::string>{{"width",  "86.000000,13.000000,57.000000,39.000000,68.000000"},
                                                                                 {"clip",   "0"},
                                                                                 {"flip",   "1"},
                                                                                 {"offset", "0.5"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("PriorBox"),
                                      InOutShapes({{{1, 256, 1, 1}, {1, 3, 300, 300}},
                                                   {{1, 2,   16}}}),
                                      NewInOutShapes({{{2, 256, 1, 1}, {2, 3, 300, 300}},
                                                      {{1, 2,   16}}}),
                                      MapParams(MapStrStr(
                                              std::map<std::string, std::string>{{"min_size",     "264"},
                                                                                 {"max_size",     "315"},
                                                                                 {"clip",         "0"},
                                                                                 {"flip",         "1"},
                                                                                 {"aspect_ratio", "2"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("PriorBox"),
                                      InOutShapes({{{2, 512, 32, 32}, {2, 3, 512, 512}},
                                                   {{1, 2,   16384}}}),
                                      NewInOutShapes({{{2, 512, 32, 32}, {2, 3, 512, 512}},
                                                   {{1, 2,   16384}}}),
                                      MapParams(MapStrStr(
                                          std::map<std::string, std::string>{{"min_size",     "35.84,52.46464"},
                                                                             {"max_size",     ""},
                                                                             {"clip",         "0"},
                                                                             {"step",         "16"},
                                                                             {"flip",         "0"},
                                                                             {"offset",       "0.5"},
                                                                             {"aspect_ratio", "1.0,2.0,0.5"},
                                                                             {"scale_all_sizes", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("PriorBox"),
                                      InOutShapes({{{2, 512, 32, 32}, {2, 3, 512, 512}},
                                                   {{1, 2,   32768}}}),
                                      NewInOutShapes({{{2, 512, 32, 32}, {2, 3, 512, 512}},
                                                      {{1, 2,   28672}}}),
                                      MapParams(MapStrStr(
                                          std::map<std::string, std::string>{{"min_size",     "35.84,52.46464"},
                                                                             {"max_size",     ""},
                                                                             {"clip",         "0"},
                                                                             {"step",         "16"},
                                                                             {"offset",       "0.5"},
                                                                             {"flip",         "1"},
                                                                             {"aspect_ratio", "1.0,2.0,0.5"},
                                                                             {"scale_all_sizes", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("DetectionOutput"),
                                      InOutShapes({{{2, 1, 4,   5}},
                                                   {{2, 1, 200, 7}}}),
                                      NewInOutShapes({{{4, 1, 5,   5}},
                                                      {{1, 1, 800, 7}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"keep_top_k",    "200"},
                                                                                             {"num_classes",   "21"},
                                                                                             {"nms_threshold", "0.44999998807907104"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Interp"),
                                      InOutShapes({{{2, 2, 33,   65}},
                                                   {{2, 2, 257, 513}}}),
                                      NewInOutShapes({{{2, 2, 33,   65}},
                                                      {{2, 2, 257, 513}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"align_corners", "1"},
                                                                                             {"height", "257"},
                                                                                             {"pad_beg", "0"},
                                                                                             {"pad_end", "0"},
                                                                                             {"width", "513"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Interp"),
                                      InOutShapes({{{2, 2, 33,   65}},
                                                   {{2, 2, 66, 513}}}),
                                      NewInOutShapes({{{2, 2, 33,   65}},
                                                      {{2, 2, 66, 513}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"align_corners", "1"},
                                                                                             {"factor", "2"},
                                                                                             {"width", "513"},
                                                                                             {"pad_beg", "0"},
                                                                                             {"pad_end", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Interp"),
                                      InOutShapes({{{2, 2, 33,   65}},
                                                   {{2, 2, 257, 130}}}),
                                      NewInOutShapes({{{2, 2, 33,   65}},
                                                      {{2, 2, 257, 130}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"align_corners", "1"},
                                                                                             {"factor", "2"},
                                                                                             {"height", "257"},
                                                                                             {"pad_beg", "0"},
                                                                                             {"pad_end", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Interp"),
                                      InOutShapes({{{2, 2, 33,   65}},
                                                   {{2, 2, 257, 130}}}),
                                      NewInOutShapes({{{2, 2, 33,   65}},
                                                      {{2, 2, 257, 130}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"align_corners", "1"},
                                                                                             {"width", "513"},
                                                                                             {"pad_beg", "0"},
                                                                                             {"pad_end", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(false)),
                ::testing::make_tuple(LayerType("ROIPooling"),
                                      InOutShapes({{{2,   3, 4, 5}, {150, 5}},
                                                   {{150, 3, 6, 6}}}),
                                      NewInOutShapes({{{4,   1, 5, 5}, {150, 5}},
                                                      {{150, 1, 6, 6}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"pooled_h",      "6"},
                                                                                             {"pooled_w",      "6"},
                                                                                             {"spatial_scale", "0.062500"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Upsampling"),
                                      InOutShapes({{{1, 3, 4, 5}},
                                                   {{1, 3, 8, 10}}}),
                                      NewInOutShapes({{{2, 1, 5,  5}},
                                                      {{2, 1, 10, 10}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"scale", "2"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("PSROIPooling"),
                                      InOutShapes({{{1,   3, 4, 5}, {150, 5}},
                                                   {{150, 2, 6, 6}}}),
                                      NewInOutShapes({{{2,   1, 5, 5}, {200, 5}},
                                                      {{200, 2, 6, 6}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"output_dim", "2"},
                                                                                             {"group_size", "6"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("SimplerNMS"),
                                      InOutShapes({{{1,   3, 4, 5}, {1, 3, 4, 5}, {1, 3}},
                                                   {{150, 5}}}),
                                      NewInOutShapes({{{2,   1, 5, 5}, {2, 1, 5, 5}, {1, 3}},
                                                      {{150, 5}}}),
                                      MapParams(
                                              MapStrStr(std::map<std::string, std::string>{{"post_nms_topn", "150"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Concat"),
                                      InOutShapes({{{1, 3, 5, 5}, {1, 2, 5, 5}},
                                                   {{1, 5, 5, 5}}}),
                                      NewInOutShapes({{{2, 1, 5, 5}, {2, 1, 5, 5}},
                                                      {{2, 2, 5, 5}}}),
                                      MapParams(
                                              MapStrStr(std::map<std::string, std::string>{{"post_nms_topn", "150"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Crop"),
                                      InOutShapes({{{1, 3, 5, 5}, {7, 7, 2, 3}},
                                                   {{1, 5, 2, 3}}}),
                                      NewInOutShapes({{{2, 1, 5, 6}, {7, 7, 2, 3}},
                                                      {{2, 1, 2, 3}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",   "2,3"},
                                                                                             {"offset", "2,1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Crop"),
                                      InOutShapes({{{1, 3, 5, 5}},
                                                   {{1, 5, 2, 3}}}),
                                      NewInOutShapes({{{2, 1, 5, 6}},
                                                      {{2, 1, 2, 1}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",   "2,3"},
                                                                                             {"offset", "2,1"},
                                                                                             {"dim",    "2,1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                // offset is too big
                ::testing::make_tuple(LayerType("Crop"),
                                      InOutShapes({{{1, 3, 5, 5}},
                                                   {{1, 5, 2, 3}}}),
                                      NewInOutShapes({{{2, 1, 5, 4}},
                                                      {{2, 1, 2, 1}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",   "2,3"},
                                                                                             {"offset", "3,4"},
                                                                                             {"dim",    "2,1"}})),
                                      LayerDataName("data"),
                                      CanInfer(false)),
                ::testing::make_tuple(LayerType("Crop"),
                                      InOutShapes({{{1, 3, 5, 5}},
                                                   {{1, 5, 2, 3}}}),
                                      NewInOutShapes({{{2, 1, 5, 6}},
                                                      {{2, 1, 1, 4}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",       "2,3"},
                                                                                             {"crop_begin", "2,1"},
                                                                                             {"crop_end",   "2,1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Tile"),
                                      InOutShapes({{{1, 3, 5, 5}},
                                                   {{1, 9, 5, 5}}}),
                                      NewInOutShapes({{{2, 1, 5, 6}},
                                                      {{2, 3, 5, 6}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",  "1"},
                                                                                             {"tiles", "3"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Split"),
                                      InOutShapes({{{1, 4, 5, 5}},
                                                   {{1, 2, 5, 5}, {1, 2, 5, 5}}}),
                                      NewInOutShapes({{{2, 4, 5, 6}},
                                                      {{2, 2, 5, 6}, {2, 2, 5, 6}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",      "1"},
                                                                                             {"out_sizes", "2,2"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Slice"),
                                      InOutShapes({{{1, 6, 5, 5}},
                                                   {{1, 2, 5, 5}, {1, 4, 5, 5}}}),
                                      NewInOutShapes({{{2, 6, 5, 6}},
                                                      {{2, 2, 5, 6}, {2, 4, 5, 6}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis",      "1"},
                                                                                             {"out_sizes", "2,4"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("CTCGreedyDecoder"),
                                      InOutShapes({{{88, 1,  48, 1}},
                                                   {{1,  88, 1,  1}}}),
                                      NewInOutShapes({{{88, 2,  48, 1}},
                                                      {{2,  88, 1,  1}}}),
                                      MapParams(MapStrStr()),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Proposal"),
                                      InOutShapes({{{1,   12, 34, 62}, {1, 24, 34, 62}, {1, 6}},
                                                   {{200, 5}}}),
                                      NewInOutShapes({{{2,   1, 5, 5}, {2, 1, 5, 5}, {1, 6}},
                                                      {{400, 5}}}),
                                      MapParams(
                                              MapStrStr(std::map<std::string, std::string>{{"post_nms_topn", "200"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("ReorgYolo"),
                                      InOutShapes({{{1, 64,  26, 26}},
                                                   {{1, 256, 13, 13}}}),
                                      NewInOutShapes({{{2, 8,  6, 6}},
                                                      {{2, 32, 3, 3}}}),
                                      MapParams(
                                              MapStrStr(std::map<std::string, std::string>{{"stride", "2"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("RegionYolo"),
                                      InOutShapes({{{1, 125, 13, 13}},
                                                   {{1, 21125}}}),
                                      NewInOutShapes({{{20, 125, 16, 13}},
                                                      {{20, 26000}}}),
                                      MapParams(MapStrStr()),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("ArgMax"),
                                      InOutShapes({{{1, 3, 1025, 2049}},
                                                   {{1, 3, 1025, 100}}}),
                                      NewInOutShapes({{{20, 3, 1025, 2049}},
                                                      {{20, 3, 1025, 100}}}),
                                      MapParams(MapStrStr({{"out_max_val", "1"},
                                                           {"top_k",       "100"},
                                                           {"axis",        "-1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("ArgMax"),
                                      InOutShapes({{{1, 3, 1025, 2049}},
                                                   {{1, 3, 100,  2049}}}),
                                      NewInOutShapes({{{20, 3, 1025, 2049}},
                                                      {{20, 3, 100,  2049}}}),
                                      MapParams(MapStrStr({{"out_max_val", "1"},
                                                           {"top_k",       "100"},
                                                           {"axis",        "2"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("ArgMax"),
                                      InOutShapes({{{1, 3}},
                                                   {{1, 2, 100}}}),
                                      NewInOutShapes({{{20, 3}},
                                                      {{20, 2, 100}}}),
                                      MapParams(MapStrStr({{"out_max_val", "1"},
                                                           {"top_k",       "100"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("ArgMax"),
                                      InOutShapes({{{1, 3}},
                                                   {{1, 1, 100}}}),
                                      NewInOutShapes({{{20, 3}},
                                                      {{20, 1, 100}}}),
                                      MapParams(MapStrStr({{"out_max_val", "0"},
                                                           {"top_k",       "100"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{15, 10}, {10, 20}, {15, 20}},
                                                   {{15, 20}}}),
                                      NewInOutShapes({{{20, 15}, {15, 25}, {20, 25}},
                                                      {{20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{15, 10}, {10, 20}, {15, 20}},
                                                   {{15, 20}}}),
                                      NewInOutShapes({{{20, 15}, {10, 25}, {20, 25}},
                                                      {{20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(false)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{15, 10}, {10, 20}, {15, 20}},
                                                   {{15, 20}}}),
                                      NewInOutShapes({{{20, 15}, {15, 25}, {15, 25}},
                                                      {{20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(false)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{15, 10}, {10, 20}},
                                                   {{15, 20}}}),
                                      NewInOutShapes({{{20, 15}, {15, 25}},
                                                      {{20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{15, 10}, {10, 20}},
                                                   {{15, 20}}}),
                                      NewInOutShapes({{{20, 15}, {10, 25}},
                                                      {{20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(false)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{3, 3, 15, 10}, {3, 3, 10, 20}, {3, 3, 15, 20}},
                                                   {{3, 3, 15, 20}}}),
                                      NewInOutShapes({{{4, 1, 20, 15}, {4, 1, 15, 25}, {4, 1, 20, 25}},
                                                      {{4, 1, 20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Gemm"),
                                      InOutShapes({{{3, 3, 15, 10}, {3, 1, 10, 20}, {3, 1, 15, 20}},
                                                   {{3, 3, 15, 20}}}),
                                      NewInOutShapes({{{4, 2, 20, 15}, {4, 2, 15, 25}, {4, 1, 20, 25}},
                                                      {{4, 2, 20, 25}}}),
                                      MapParams(MapStrStr({{"alpha",       "1"},
                                                           {"beta",        "1"},
                                                           {"transpose_a", "false"},
                                                           {"transpose_b", "false"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Pad"),
                                      InOutShapes({{{3, 3, 15, 10}},
                                                   {{9, 11, 25, 22}}}),
                                      NewInOutShapes({{{4, 2, 20, 15}},
                                                      {{10, 10, 30, 27}}}),
                                      MapParams(MapStrStr({{"pads_begin",  "1,2,3,4"},
                                                           {"pads_end",    "5,6,7,8"},
                                                           {"pad_mode",    "edge"},
                                                           {"pad_value",   "1.0f"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Pad"),
                                      InOutShapes({{{10, 10, 15, 10}},
                                                   {{16, 18, 25, 22}}}),
                                      NewInOutShapes({{{20, 30, 40, 50}},
                                                      {{26, 38, 40, 50}}}),
                                      MapParams(MapStrStr({{"pads_begin",  "1,2,0,0"},
                                                           {"pads_end",    "5,6,0,0"},
                                                           {"pad_mode",    "reflect"},
                                                           {"pad_value",   "1.0f"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Pad"),
                                      InOutShapes({{{10, 10, 15, 10}},
                                                   {{16, 18, 25, 22}}}),
                                      NewInOutShapes({{{4, 2, 20, 15}},
                                                      {{10, 10, 30, 27}}}),
                                      MapParams(MapStrStr({{"pads_begin",  "1,2,3,4"},
                                                           {"pads_end",    "5,6,7,8"},
                                                           {"pad_mode",    "reflect"},
                                                           {"pad_value",   "1.0f"}})),
                                      LayerDataName("data"),
                                      CanInfer(false))
        )
);

INSTANTIATE_TEST_CASE_P(
        BuiltInGeneralImpls2, BuiltInShapeInferImplTest,
        ::testing::Values(
                ::testing::make_tuple(LayerType("Gather"),
                                      InOutShapes({{{7, 16}, {1, 25}},
                                                   {{1, 25, 16}}}),
                                      NewInOutShapes({{{7, 16}, {12, 25}},
                                                      {{12, 25, 16}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis", "0"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Gather"),
                                      InOutShapes({{{7, 16}, {1, 25}},
                                                   {{7, 1, 25}}}),
                                      NewInOutShapes({{{7, 16}, {12, 25}},
                                                      {{7, 12, 25}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis", "1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Gather"),
                                      InOutShapes({{{7, 16}, {1, 25}},
                                                   {{7, 1, 25}}}),
                                      NewInOutShapes({{{7, 16}, {12, 25}},
                                                      {{7, 12, 25}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"axis", "-1"}})),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Reshape"),
                                      InOutShapes({{{1, 2}},
                                                   {{1, 1}}}),
                                      NewInOutShapes({{{1, 2}},
                                                      {{1, 1}}}),
                                      MapParams(MapStrStr(std::map<std::string, std::string>{{"dim", "1,1"}})),  // dim doesn't match input
                                      LayerDataName("data"),
                                      CanInfer(false)),
                ::testing::make_tuple(LayerType("Flatten"),
                                      InOutShapes({{{2, 1, 4, 5}},
                                                   {{40}}}),
                                      NewInOutShapes({{{4, 1, 4, 5}},
                                                      {{80}}}),
                                      MapParams(MapParams(MapStrStr(std::map<std::string, std::string>{{"axis", "0"},
                                                                                                       {"end_axis", "-1"}}))),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Flatten"),
                                      InOutShapes({{{2, 2, 4, 5}},
                                                   {{2, 8, 5}}}),
                                      NewInOutShapes({{{4, 2, 4, 5}},
                                                      {{4, 8, 5}}}),
                                      MapParams(MapParams(MapStrStr(std::map<std::string, std::string>{{"axis", "1"},
                                                                                                       {"end_axis", "2"}}))),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Flatten"),
                                      InOutShapes({{{2, 2, 4, 5}},
                                                   {{2, 40}}}),
                                      NewInOutShapes({{{4, 2, 4, 5}},
                                                      {{4, 40}}}),
                                      MapParams(MapParams(MapStrStr(std::map<std::string, std::string>{{"axis", "1"}}))),
                                      LayerDataName("data"),
                                      CanInfer(true)),
                ::testing::make_tuple(LayerType("Flatten"),
                                      InOutShapes({{{2, 2, 4, 5}},
                                                   {{4, 4, 5}}}),
                                      NewInOutShapes({{{4, 2, 4, 5}},
                                                      {{8, 4, 5}}}),
                                      MapParams(MapParams(MapStrStr(std::map<std::string, std::string>{{"end_axis", "1"}}))),
                                      LayerDataName("data"),
                                      CanInfer(true))
        )
);

class LayerValidatorNegativeTests : public BuiltInShapeInferImplTest {
};

TEST_P(LayerValidatorNegativeTests, reshaper) {
    ASSERT_THROW(buildSingleLayerNetwork<3>(type, inOutShapes, &layerParams.data, layerDataName),
                 InferenceEngine::details::InferenceEngineException);
}

// TODO: test using MR!1690
INSTANTIATE_TEST_CASE_P(
        Reshape, LayerValidatorNegativeTests,
        ::testing::Combine(
                ::testing::Values(LayerType("Reshape")),
                ::testing::Values(InOutShapes({{{1,   1, 300, 4}},
                                               {{300, 4}}})),
                ::testing::Values(NewInOutShapes({{{1,   1, 500, 4}},
                                                  {{500, 4}}})),
                ::testing::Values(
                        MapParams(MapStrStr(
                                std::map<std::string, std::string>{{"dim", "0,-2,6"}})),  // can't be less the -1
                        MapParams(MapStrStr(
                                std::map<std::string, std::string>{{"dim", "0,-1,-1"}}))),  // single -1 is expected
                ::testing::Values(LayerDataName("data")),
                ::testing::Values(CanInfer())
        )
);
