TEST( gpu_device_load_and_unload, callbacks_test )
{
    // Run in a loop: load, validate,work_item, unload
    for( int i = 0; i < 2; ++i )
    {
        // nn_device_load
        EXPECT_LT( nn_device_load( nullptr ), 0 );  // no error on invalid pointer

        nn_device_description_t dd;
        const auto              invalid_first = static_cast< decltype( dd.version_first ) >( -1 );
        const auto              invalid_last  = static_cast< decltype( dd.version_first ) >( -2 );
        dd.version_first = invalid_first;
        dd.version_last  = invalid_last;

        EXPECT_EQ( 0, nn_device_load( &dd ) );      // non-zero return code on valid call
        EXPECT_NE( invalid_first, dd.version_first ); // nn_device_description_t::version_first is incorrect
        EXPECT_NE( invalid_last, dd.version_last ); // nn_device_description_t::version_last is incorrect
        EXPECT_LE( dd.version_first, dd.version_last ); // nn_device_description_t::version_first is greater than
                                                        // ::version_last

        // nn_device_interface_open & close
        {
            uint8_t buffer[4096];

            // nn_device_interface_open parameter validation
            EXPECT_GT( 0, nn_device_interface_open( invalid_last, buffer ) ); // no error on invalid
                                                                                            // version
            EXPECT_GT( 0, nn_device_interface_open( dd.version_first, nullptr) ); // no error on invalid
                                                                                                 // buffer
            // nn_device_interface_close parameter validation
            EXPECT_GT( 0, nn_device_interface_close( nullptr ) );                           // no error on invalid
                                                                                            // interface pointer
        }

        { // interface version 0
            const uint16_t          interface_version = 0;
            nn_device_interface_0_t di;
            if( ( interface_version >= dd.version_first ) && ( interface_version <= dd.version_last ) )
            {
                EXPECT_EQ( 0, nn_device_interface_open( interface_version, &di ) );
                EXPECT_EQ( interface_version, di.version );     // returned version matches requested
                EXPECT_NE( nullptr, di.device );                // non-null device returned
                EXPECT_NE( nullptr, di.workflow_item_validate_function ); // non-null function pointer returned
                EXPECT_NE( nullptr, di.workflow_item_delete_function ); // non-null function pointer returned
                EXPECT_NE( nullptr, di.parameter_set_function ); // non-null function pointer returned
                EXPECT_NE( nullptr, di.parameter_get_function ); // non-null function pointer returned
            }

            EXPECT_EQ( true, run_convolve_test( di, 1, 1, 2, 2, 1, 1, 1, 1, 1, NN_ACTIVATION_FUNCTION_NONE ) );
            EXPECT_EQ( 0, nn_device_interface_close( &di ) ); // successful close of interface
        }


        // nn_device_unload
        EXPECT_EQ( 0, nn_device_unload() ); // successful unload
    }
}
TEST( cpu_int16_device_load_and_unload, callbacks_test )
{
    // nn_device_load
    EXPECT_LT(nn_device_load(nullptr), 0);          // no error on invalid pointer

    nn_device_description_t dd;
    const auto invalid_first = static_cast<decltype(dd.version_first)>(-1);
    const auto invalid_last = static_cast<decltype(dd.version_first)>(-2);
    dd.version_first = invalid_first;
    dd.version_last = invalid_last;

    EXPECT_EQ(0, nn_device_load(&dd));              // non-zero return code on valid call
    EXPECT_NE(invalid_first, dd.version_first);     // nn_device_description_t::version_first is incorrect
    EXPECT_NE(invalid_last, dd.version_last);       // nn_device_description_t::version_last is incorrect
    EXPECT_LE(dd.version_first, dd.version_last);   // nn_device_description_t::version_first is greater than ::version_last

    // nn_device_interface_open & close
    {
        uint8_t buffer[4096];

        // nn_device_interface_open parameter validation
        EXPECT_GT(0, nn_device_interface_open(invalid_last, buffer));         // no error on invalid version
        EXPECT_GT(0, nn_device_interface_open(dd.version_first, nullptr));    // no error on invalid buffer

        // nn_device_interface_close parameter validation
        EXPECT_GT(0, nn_device_interface_close(nullptr));                                   // no error on invalid interface pointer
    }

    { // interface version 0
        const uint16_t interface_version = 0;
        nn_device_interface_0_t di;
        if(interface_version>=dd.version_first && interface_version<=dd.version_last) {
            EXPECT_EQ(0, nn_device_interface_open(interface_version, &di));
            EXPECT_EQ(interface_version, di.version);                   // returned version matches requested
            EXPECT_NE(nullptr, di.device);                              // non-null device returned
            EXPECT_NE(nullptr, di.workflow_create_function);            // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_delete_function);            // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_metrics_query_function);     // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_metrics_delete_function);    // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_compile_function);           // non-null function pointer returned
            EXPECT_NE(nullptr, di.workload_execute_function);           // non-null function pointer returned
            EXPECT_NE(nullptr, di.workload_delete_function);            // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_item_create_function);       // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_item_validate_function);     // non-null function pointer returned
            EXPECT_NE(nullptr, di.workflow_item_delete_function);       // non-null function pointer returned
            EXPECT_NE(nullptr, di.parameter_get_function);              // non-null function pointer returned
            EXPECT_NE(nullptr, di.parameter_set_function);              // non-null function pointer returned
            EXPECT_NE(nullptr, di.translate_api_status_function);       // non-null function pointer returned
            EXPECT_EQ(0, nn_device_interface_close(&di));               // successful close of interface
        }
    }

    // nn_device_unload
    EXPECT_EQ(0, nn_device_unload()); // successful unload
}
static bool ult_nn_fc_interface_run(nn_workload_item* work_item)
{
    bool retvalue = true;

    // Use optimized routine.
    nn_device_description_t device_description;
    nn_device_interface_0_t device_interface_0;

    nn_device_load(&device_description);
    nn_device_interface_open(0, &device_interface_0);

    int16_fixedpoint::run_multithreaded_fully_connected_fixedpoint_work_item(work_item, reinterpret_cast<nn_device_internal*>(device_interface_0.device));

    nn_device_interface_close(&device_interface_0);
    nn_device_unload();
    return retvalue;
}
TEST( gpu_device_interface_0, start_work_item_test )
{

    // 1. Initialize and check if interface 0 is supported
    nn_device_description_t dd;
    const auto              invalid_first = static_cast< decltype( dd.version_first ) >( -1 );
    const auto              invalid_last  = static_cast< decltype( dd.version_first ) >( -2 );
    dd.version_first = invalid_first;
    dd.version_last  = invalid_last;


    EXPECT_EQ( 0, nn_device_load( &dd ) );              // non-zero return code on valid call

    EXPECT_NE( invalid_first, dd.version_first );     // nn_device_description_t::version_first is incorrect
    EXPECT_EQ( 0, dd.version_first );                 // First supported interface version should be 0

    // 2. Get interface 0
    const uint16_t          interface_version = 0;
    nn_device_interface_0_t di;
    if( ( interface_version >= dd.version_first ) && ( interface_version <= dd.version_last ) )
    {
        EXPECT_EQ( 0, nn_device_interface_open( interface_version, &di) );
        EXPECT_EQ( interface_version, di.version );           // returned version matches requested
        EXPECT_NE( nullptr, di.device );                      // non-null device returned
        EXPECT_NE( nullptr, di.workflow_item_validate_function ); // non-null function pointer returned
        EXPECT_NE( nullptr, di.workflow_item_delete_function );   // non-null function pointer returned
        EXPECT_NE( nullptr, di.parameter_set_function );      // non-null function pointer returned
        EXPECT_NE( nullptr, di.parameter_get_function );      // non-null function pointer returned
    //assert(0);//TODO: Add other interface functions  just above
    }

    EXPECT_EQ( NN_API_STATUS_ERROR_INVALID_POINTER, di.workflow_item_validate_function( di.device, nullptr ) );    // test invalid pointer case

    EXPECT_EQ( true, run_softmax_test( di,   // interface
                                       10,  // length of input to be  processed (softmax normalize)
                                       3) );

    EXPECT_EQ( 0, nn_device_interface_close( &di ) );       // successful close of interface
    //// nn_device_unload
    EXPECT_EQ( 0, nn_device_unload() ); // successful unload
}