COMPMID-814: Add validate method to scale.

Change-Id: I5004c79ac7b10f988f25e14847f1ea2be01629da
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/131143
Tested-by: Jenkins <bsgcomp@arm.com>
Reviewed-by: Anthony Barbier <anthony.barbier@arm.com>
diff --git a/arm_compute/core/NEON/kernels/NEScaleKernel.h b/arm_compute/core/NEON/kernels/NEScaleKernel.h
index 0a3a952..575814b 100644
--- a/arm_compute/core/NEON/kernels/NEScaleKernel.h
+++ b/arm_compute/core/NEON/kernels/NEScaleKernel.h
@@ -67,6 +67,21 @@
      */
     void configure(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets, ITensor *output,
                    InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER);
+    /** Static function to check if given info will lead to a valid configuration of @ref NEScaleKernel
+     *
+     * @note dx, dy and offsets have the same dimensions (width and height) of the output tensor
+     *
+     * @param[in] input           Source tensor. Data types supported: U8/S16/F32.
+     * @param[in] dx              Pixel's distance between the X real coordinate and the smallest X following integer. Data type supported: F32
+     * @param[in] dy              Pixel's distance between the Y real coordinate and the smallest Y following integer. Data type supported: F32
+     * @param[in] offsets         Offset to access the pixel with NEAREST interpolation or the top-left pixel with BILINEAR interpolation in the input tensor. Data type supported: S32.
+     * @param[in] output          Destination tensor. Data types supported: Same as @p input. All but the lowest two dimensions must be the same size as in the input tensor, i.e. scaling is only performed within the XY-plane.
+     * @param[in] policy          Interpolation type to use
+     * @param[in] border_mode     Border mode policy
+     * @param[in] sampling_policy (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER
+     */
+    static Status validate(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy, const ITensorInfo *offsets, ITensorInfo *output,
+                           InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy = SamplingPolicy::CENTER);
 
     // Inherited methods overridden:
     void run(const Window &window, const ThreadInfo &info) override;
diff --git a/arm_compute/runtime/NEON/functions/NEScale.h b/arm_compute/runtime/NEON/functions/NEScale.h
index 1d96db3..9b5a12b 100644
--- a/arm_compute/runtime/NEON/functions/NEScale.h
+++ b/arm_compute/runtime/NEON/functions/NEScale.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017 ARM Limited.
+ * Copyright (c) 2016-2018 ARM Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -47,7 +47,7 @@
     NEScale();
     /** Initialize the function's source, destination, interpolation type and border_mode.
      *
-     * @param[in, out] input                 Source tensor. Data type supported: U8/F32. (Written to only for @p border_mode != UNDEFINED)
+     * @param[in, out] input                 Source tensor. Data type supported: U8/S16/F32. (Written to only for @p border_mode != UNDEFINED)
      * @param[out]     output                Destination tensor. Data type supported: Same as @p input. All but the lowest two dimensions must be the same size as in the input tensor, i.e. scaling is only performed within the XY-plane.
      * @param[in]      policy                The interpolation type.
      * @param[in]      border_mode           Strategy to use for borders.
@@ -56,6 +56,19 @@
      */
     void configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value = PixelValue(),
                    SamplingPolicy sampling_policy = SamplingPolicy::CENTER);
+    /** Static function to check if given info will lead to a valid configuration of @ref NEScale
+     *
+     * @param[in] input                 Source tensor. Data type supported: U8/S16/F32. (Written to only for @p border_mode != UNDEFINED)
+     * @param[in] output                Destination tensor. Data type supported: Same as @p input. All but the lowest two dimensions must be the same size as in the input tensor, i.e. scaling is only performed within the XY-plane.
+     * @param[in] policy                The interpolation type.
+     * @param[in] border_mode           Strategy to use for borders.
+     * @param[in] constant_border_value (Optional) Constant value to use for borders if border_mode is set to CONSTANT.
+     * @param[in] sampling_policy       (Optional) Sampling policy used by the interpolation. Defaults to @ref SamplingPolicy::CENTER
+     *
+     * @return a status
+     */
+    static Status validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy, BorderMode border_mode,
+                           PixelValue constant_border_value = PixelValue(), SamplingPolicy sampling_policy = SamplingPolicy::CENTER);
 
     // Inherited methods overridden:
     void run() override;
diff --git a/src/core/NEON/kernels/NEScaleKernel.cpp b/src/core/NEON/kernels/NEScaleKernel.cpp
index 311c807..3f57ffb 100644
--- a/src/core/NEON/kernels/NEScaleKernel.cpp
+++ b/src/core/NEON/kernels/NEScaleKernel.cpp
@@ -42,52 +42,122 @@
 {
 namespace
 {
-Window configure_nchw(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets, ITensor *output,
-                      InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size)
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy,
+                          const ITensorInfo *offsets, ITensorInfo *output, InterpolationPolicy policy,
+                          BorderMode border_mode, SamplingPolicy sampling_policy)
 {
+    ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32);
+    ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(output);
+    ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
+    ARM_COMPUTE_RETURN_ERROR_ON(output == input);
+    ARM_COMPUTE_RETURN_ERROR_ON(sampling_policy != SamplingPolicy::CENTER);
+    ARM_COMPUTE_UNUSED(border_mode);
+
+    const DataLayout data_layout = input->data_layout();
+    ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH)) == 0);
+    ARM_COMPUTE_RETURN_ERROR_ON(output->dimension(get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT)) == 0);
+
+    if(policy == InterpolationPolicy::NEAREST_NEIGHBOR)
+    {
+        ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32);
+    }
+
+    if(policy == InterpolationPolicy::BILINEAR)
+    {
+        ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32);
+        ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dx, 1, DataType::F32);
+        ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dy, 1, DataType::F32);
+    }
+
+    if(policy == InterpolationPolicy::AREA)
+    {
+        ARM_COMPUTE_RETURN_ERROR_ON(data_layout != DataLayout::NCHW);
+    }
+
+    return Status{};
+}
+
+std::pair<Status, Window> validate_and_configure_window_nchw(ITensorInfo *input, ITensorInfo *dx, ITensorInfo *dy, ITensorInfo *offsets, ITensorInfo *output,
+                                                             InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size)
+{
+    bool   window_changed{ false };
+    Window win{};
+
     constexpr unsigned int num_elems_processed_per_iteration = 16;
 
     // Configure kernel window
-    Window win = calculate_max_window(*output->info(), Steps(num_elems_processed_per_iteration));
+    win = calculate_max_window(*output, Steps(num_elems_processed_per_iteration));
 
-    const ValidRegion &input_valid_region = input->info()->valid_region();
+    const ValidRegion &input_valid_region = input->valid_region();
+
+    if(offsets != nullptr)
+    {
+        AccessWindowHorizontal offsets_access(offsets, 0, num_elems_processed_per_iteration);
+        window_changed = window_changed || update_window_and_padding(win, offsets_access);
+    }
+    if(dx != nullptr && dy != nullptr)
+    {
+        AccessWindowHorizontal dx_access(dx, 0, num_elems_processed_per_iteration);
+        AccessWindowHorizontal dy_access(dy, 0, num_elems_processed_per_iteration);
+        window_changed = window_changed || update_window_and_padding(win, dx_access, dy_access);
+    }
 
     // Reads can occur within the valid region of the input
-    AccessWindowStatic input_access(input->info(), input_valid_region.anchor[0] - border_size.left,
+    AccessWindowStatic input_access(input, input_valid_region.anchor[0] - border_size.left,
                                     input_valid_region.anchor[1] - border_size.top,
                                     input_valid_region.anchor[0] + input_valid_region.shape[0] + border_size.right,
                                     input_valid_region.anchor[1] + input_valid_region.shape[1] + border_size.bottom);
-    AccessWindowHorizontal offsets_access(offsets == nullptr ? nullptr : offsets->info(), 0,
-                                          num_elems_processed_per_iteration);
-    AccessWindowHorizontal dx_access(dx == nullptr ? nullptr : dx->info(), 0, num_elems_processed_per_iteration);
-    AccessWindowHorizontal dy_access(dy == nullptr ? nullptr : dy->info(), 0, num_elems_processed_per_iteration);
-    AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
-
-    update_window_and_padding(win, input_access, offsets_access, dx_access, dy_access, output_access);
-
-    output_access.set_valid_region(win, calculate_valid_region_scale(*(input->info()), output->info()->tensor_shape(),
+    AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
+    window_changed = window_changed || update_window_and_padding(win, input_access, output_access);
+    output_access.set_valid_region(win, calculate_valid_region_scale(*input, output->tensor_shape(),
                                                                      policy, sampling_policy, border_undefined));
 
-    return win;
+    Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+    return std::make_pair(err, win);
 }
-Window configure_nhwc(const ITensor *input, ITensor *output,
-                      InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size)
+
+std::pair<Status, Window> validate_and_configure_window_nhwc(ITensorInfo *input, ITensorInfo *output,
+                                                             InterpolationPolicy policy, bool border_undefined,
+                                                             SamplingPolicy sampling_policy, BorderSize border_size)
 {
-    unsigned int num_elems_processed_per_iteration = (policy == InterpolationPolicy::NEAREST_NEIGHBOR) ? 16 / input->info()->element_size() : 1;
+    bool   window_changed{ false };
+    Window win{};
+
+    const unsigned int num_elems_processed_per_iteration = (policy == InterpolationPolicy::NEAREST_NEIGHBOR) ? 16 / input->element_size() : 1;
 
     // Configure kernel window
-    Window win = calculate_max_window(*output->info(), Steps(num_elems_processed_per_iteration));
+    win = calculate_max_window(*output, Steps(num_elems_processed_per_iteration));
 
-    AccessWindowStatic input_access(input->info(), 0, -border_size.top,
-                                    ceil_to_multiple(input->info()->tensor_shape()[0], num_elems_processed_per_iteration),
-                                    input->info()->tensor_shape()[1]);
-    AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
+    AccessWindowStatic input_access(input, 0, -border_size.top,
+                                    ceil_to_multiple(input->tensor_shape()[0], num_elems_processed_per_iteration),
+                                    input->tensor_shape()[1]);
+    AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
 
-    update_window_and_padding(win, input_access, output_access);
-    output->info()->set_valid_region(calculate_valid_region_scale(*(input->info()), output->info()->tensor_shape(),
-                                                                  policy, sampling_policy, border_undefined));
+    window_changed = update_window_and_padding(win, input_access, output_access);
+    output->set_valid_region(calculate_valid_region_scale(*input, output->tensor_shape(),
+                                                          policy, sampling_policy, border_undefined));
 
-    return win;
+    Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+    return std::make_pair(err, win);
+}
+
+std::pair<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *dx, ITensorInfo *dy, ITensorInfo *offsets, ITensorInfo *output,
+                                                        InterpolationPolicy policy, bool border_undefined, SamplingPolicy sampling_policy, BorderSize border_size)
+{
+    std::pair<Status, Window> win_config;
+    switch(input->data_layout())
+    {
+        case DataLayout::NCHW:
+            win_config = validate_and_configure_window_nchw(input, dx, dy, offsets, output, policy, border_undefined, sampling_policy, border_size);
+            break;
+        case DataLayout::NHWC:
+            win_config = validate_and_configure_window_nhwc(input, output, policy, border_undefined, sampling_policy, border_size);
+            break;
+        default:
+            win_config = std::make_pair(ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Unsupported data layout!"), Window{});
+    }
+
+    return win_config;
 }
 
 template <typename T>
@@ -197,33 +267,21 @@
 void NEScaleKernel::configure(const ITensor *input, const ITensor *dx, const ITensor *dy, const ITensor *offsets,
                               ITensor *output, InterpolationPolicy policy, BorderMode border_mode, SamplingPolicy sampling_policy)
 {
-    ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32);
-    ARM_COMPUTE_ERROR_ON_NULLPTR(output);
-    ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
-    ARM_COMPUTE_ERROR_ON(output == input);
-    ARM_COMPUTE_ERROR_ON(sampling_policy != SamplingPolicy::CENTER);
-    ARM_COMPUTE_UNUSED(sampling_policy);
+    ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
 
-    if(policy == InterpolationPolicy::NEAREST_NEIGHBOR)
-    {
-        ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32);
-    }
-
-    if(policy == InterpolationPolicy::BILINEAR)
-    {
-        ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(offsets, 1, DataType::S32);
-        ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dx, 1, DataType::F32);
-        ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(dy, 1, DataType::F32);
-    }
+    // Perform validation step
+    ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(),
+                                                  dx != nullptr ? dx->info() : nullptr,
+                                                  dy != nullptr ? dy->info() : nullptr,
+                                                  offsets != nullptr ? offsets->info() : nullptr,
+                                                  output->info(),
+                                                  policy, border_mode, sampling_policy));
 
     // Get data layout and width/height indices
     const DataLayout data_layout = input->info()->data_layout();
     const int        idx_width   = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
     const int        idx_height  = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
 
-    ARM_COMPUTE_ERROR_ON(output->info()->dimension(idx_width) == 0);
-    ARM_COMPUTE_ERROR_ON(output->info()->dimension(idx_height) == 0);
-
     _input       = input;
     _output      = output;
     _offsets     = offsets;
@@ -259,16 +317,11 @@
         }
         case InterpolationPolicy::BILINEAR:
         {
-            ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_dx, 1, DataType::F32);
-            ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_dy, 1, DataType::F32);
-
             _func = (data_layout == DataLayout::NCHW) ? &NEScaleKernel::scale_bilinear_nchw : &NEScaleKernel::scale_nhwc;
             break;
         }
         case InterpolationPolicy::AREA:
         {
-            ARM_COMPUTE_ERROR_ON(data_layout != DataLayout::NCHW);
-
             _func = &NEScaleKernel::scale_area_nchw;
             break;
         }
@@ -277,19 +330,14 @@
     }
 
     // Configure window
-    Window win{};
-    switch(data_layout)
-    {
-        case DataLayout::NCHW:
-            win = configure_nchw(input, dx, dy, offsets, output, policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size());
-            break;
-        case DataLayout::NHWC:
-            win = configure_nhwc(input, output, policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size());
-            break;
-        default:
-            ARM_COMPUTE_ERROR("Unsupported data layout");
-    }
-    INEKernel::configure(win);
+    std::pair<Status, Window> win_config = validate_and_configure_window(input->info(),
+                                                                         dx != nullptr ? dx->info() : nullptr,
+                                                                         dy != nullptr ? dy->info() : nullptr,
+                                                                         offsets != nullptr ? offsets->info() : nullptr,
+                                                                         output->info(),
+                                                                         policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size());
+    ARM_COMPUTE_ERROR_THROW_ON(win_config.first);
+    INEKernel::configure(win_config.second);
 }
 
 void NEScaleKernel::scale_nearest_nchw(const Window &window)
@@ -663,8 +711,6 @@
 
 void NEScaleKernel::scale_nhwc(const Window &window)
 {
-    ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(_input, 1, DataType::U8, DataType::S16, DataType::F32);
-
     // Get data layout and width/height indices
     const DataLayout data_layout  = _input->info()->data_layout();
     const int        idx_channels = get_data_layout_dimension_index(data_layout, DataLayoutDimension::CHANNEL);
@@ -732,6 +778,28 @@
     }
 }
 
+Status NEScaleKernel::validate(const ITensorInfo *input, const ITensorInfo *dx, const ITensorInfo *dy,
+                               const ITensorInfo *offsets, ITensorInfo *output, InterpolationPolicy policy,
+                               BorderMode border_mode, SamplingPolicy sampling_policy)
+{
+    BorderSize border_size(1);
+    if(input->data_layout() == DataLayout::NHWC)
+    {
+        border_size = (border_mode == BorderMode::CONSTANT && policy == InterpolationPolicy::BILINEAR) ? BorderSize(1, 0, 0, 0) : BorderSize(0);
+    }
+
+    ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, dx, dy, offsets, output, policy, border_mode, sampling_policy));
+    ARM_COMPUTE_RETURN_ON_ERROR(validate_and_configure_window(input->clone().get(),
+                                                              dx != nullptr ? dx->clone().get() : nullptr,
+                                                              dy != nullptr ? dy->clone().get() : nullptr,
+                                                              offsets != nullptr ? offsets->clone().get() : nullptr,
+                                                              output->clone().get(),
+                                                              policy, border_mode == BorderMode::UNDEFINED, sampling_policy, border_size)
+                                .first);
+
+    return Status{};
+}
+
 void NEScaleKernel::run(const Window &window, const ThreadInfo &info)
 {
     ARM_COMPUTE_UNUSED(info);
diff --git a/src/runtime/NEON/functions/NEScale.cpp b/src/runtime/NEON/functions/NEScale.cpp
index 43ef619..9407273 100644
--- a/src/runtime/NEON/functions/NEScale.cpp
+++ b/src/runtime/NEON/functions/NEScale.cpp
@@ -45,7 +45,6 @@
 void precompute_dx_dy_offsets(ITensor *dx, ITensor *dy, ITensor *offsets, float wr, float hr, size_t input_element_size, SamplingPolicy sampling_policy)
 {
     ARM_COMPUTE_ERROR_ON(nullptr == offsets);
-    ARM_COMPUTE_ERROR_ON(sampling_policy != SamplingPolicy::CENTER);
     ARM_COMPUTE_UNUSED(sampling_policy);
 
     Window win;
@@ -99,8 +98,8 @@
 
 void NEScale::configure(ITensor *input, ITensor *output, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy)
 {
-    ARM_COMPUTE_ERROR_ON(nullptr == input);
-    ARM_COMPUTE_ERROR_ON(nullptr == output);
+    ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
+    ARM_COMPUTE_ERROR_THROW_ON(NEScale::validate(input->info(), output->info(), policy, border_mode, constant_border_value, sampling_policy));
 
     // Get data layout and width/height indices
     const DataLayout data_layout = input->info()->data_layout();
@@ -171,6 +170,48 @@
     _border_handler.configure(input, _scale_kernel.border_size(), border_mode, PixelValue(constant_border_value));
 }
 
+Status NEScale::validate(const ITensorInfo *input, const ITensorInfo *output, InterpolationPolicy policy,
+                         BorderMode border_mode, PixelValue constant_border_value, SamplingPolicy sampling_policy)
+{
+    ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
+    ARM_COMPUTE_RETURN_ERROR_ON(sampling_policy != SamplingPolicy::CENTER);
+    ARM_COMPUTE_UNUSED(border_mode, constant_border_value);
+
+    ITensorInfo *offsets = nullptr;
+    ITensorInfo *dx      = nullptr;
+    ITensorInfo *dy      = nullptr;
+
+    // Get data layout and width/height indices
+    const DataLayout data_layout = input->data_layout();
+    const int        idx_width   = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
+    const int        idx_height  = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
+
+    // Get the tensor shape of auxilary buffers
+    const TensorShape shape(output->dimension(idx_width), output->dimension(idx_height));
+
+    TensorInfo tensor_info_offsets(shape, Format::S32);
+    TensorInfo tensor_info_dx(shape, Format::F32);
+    TensorInfo tensor_info_dy(shape, Format::F32);
+
+    switch(policy)
+    {
+        case InterpolationPolicy::NEAREST_NEIGHBOR:
+            offsets = &tensor_info_offsets;
+            break;
+        case InterpolationPolicy::BILINEAR:
+            offsets = &tensor_info_offsets;
+            dx      = &tensor_info_dx;
+            dy      = &tensor_info_dy;
+            break;
+        default:
+            break;
+    }
+
+    ARM_COMPUTE_RETURN_ON_ERROR(NEScaleKernel::validate(input->clone().get(), dx, dy, offsets, output->clone().get(),
+                                                        policy, border_mode, sampling_policy));
+    return Status{};
+}
+
 void NEScale::run()
 {
     NEScheduler::get().schedule(&_border_handler, Window::DimZ);
diff --git a/tests/validation/NEON/Scale.cpp b/tests/validation/NEON/Scale.cpp
index b21affd..8940259 100644
--- a/tests/validation/NEON/Scale.cpp
+++ b/tests/validation/NEON/Scale.cpp
@@ -74,6 +74,57 @@
 TEST_SUITE(NEON)
 TEST_SUITE(Scale)
 
+// *INDENT-OFF*
+// clang-format off
+DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(zip(zip(
+        framework::dataset::make("InputInfo", { TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::U8, 0),  // Mismatching data type
+                                                TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32, 0), // Unsupported sampling point
+                                                TensorInfo(TensorShape(4U, 27U, 13U), 1, DataType::F32, 0), // Invalid policy
+                                                TensorInfo(TensorShape(27U, 13U, 2U), 1, DataType::F32, 0), // Insufficient padding
+                                                TensorInfo(TensorShape(4U, 27U, 13U), 1, DataType::F32, 0),
+                                              }),
+        framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32, 0),
+                                                TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32, 0),
+                                                TensorInfo(TensorShape(4U, 132U, 25U), 1, DataType::F32, 0),
+                                                TensorInfo(TensorShape(132U, 25U, 2U), 1, DataType::F32, 0),
+                                                TensorInfo(TensorShape(4U, 132U, 25U), 1, DataType::F32, 0),
+                                              })),
+        framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR,
+                                                          InterpolationPolicy::NEAREST_NEIGHBOR,
+                                                          InterpolationPolicy::AREA,
+                                                          InterpolationPolicy::AREA,
+                                                          InterpolationPolicy::NEAREST_NEIGHBOR,
+                                                        })),
+        framework::dataset::make("BorderMode",  { BorderMode::UNDEFINED,
+                                                  BorderMode::UNDEFINED,
+                                                  BorderMode::UNDEFINED,
+                                                  BorderMode::UNDEFINED,
+                                                  BorderMode::REPLICATE,
+                                                })),
+        framework::dataset::make("SamplingPolicy",  { SamplingPolicy::CENTER,
+                                                      SamplingPolicy::TOP_LEFT,
+                                                      SamplingPolicy::CENTER,
+                                                      SamplingPolicy::CENTER,
+                                                      SamplingPolicy::CENTER,
+                                                    })),
+        framework::dataset::make("DataLayout",  { DataLayout::NCHW,
+                                                  DataLayout::NCHW,
+                                                  DataLayout::NHWC,
+                                                  DataLayout::NCHW,
+                                                  DataLayout::NHWC,
+                                                })),
+        framework::dataset::make("Expected", { false, false, false, false ,true })),
+        input_info, output_info, policy,border_mode, sampling_policy, data_layout, expected)
+{
+    const PixelValue constant_border(5);
+    Status status = NEScale::validate(&input_info.clone()->set_is_resizable(false).set_data_layout(data_layout),
+                                           &output_info.clone()->set_is_resizable(false).set_data_layout(data_layout),
+                                           policy, border_mode, constant_border, sampling_policy);
+    ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
+}
+// clang-format on
+// *INDENT-ON*
+
 DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, combine(combine(combine(combine(combine(concat(datasets::SmallShapes(), datasets::LargeShapes()), ScaleDataTypes), ScaleDataLayouts),
                                                                                    framework::dataset::make("InterpolationPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR, InterpolationPolicy::BILINEAR })),
                                                                            datasets::BorderModes()),