[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/livecode/livecode/develop/libfoundation/test/test_foreign.cpp [Back]  [Original]

/* Copyright (C) 2017 LiveCode Ltd.
 
 This file is part of LiveCode.
 
 LiveCode is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License v3 as published by the Free
 Software Foundation.
 
 LiveCode is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 along with LiveCode.  If not see .  */

#include "gtest/gtest.h"

#include "foundation.h"
#include "foundation-auto.h"

#include 
#include 

typedef MCAutoValueRefBase MCAutoForeignValueRef;

template
void check_creation(MCTypeInfoRef p_type_info, T p_value)
{
    MCAutoForeignValueRef t_boxed_value;
    EXPECT_TRUE(MCForeignValueCreate(p_type_info, &p_value, &t_boxed_value));
    EXPECT_EQ(*static_cast(MCForeignValueGetContentsPtr(*t_boxed_value)), p_value);
}

template
void check_equality(MCTypeInfoRef p_type_info, T p_left, T p_right, bool p_expected)
{
    MCAutoForeignValueRef t_left_box, t_right_box;
    EXPECT_TRUE(MCForeignValueCreate(p_type_info, &p_left, &t_left_box));
    EXPECT_TRUE(MCForeignValueCreate(p_type_info, &p_right, &t_right_box));
    EXPECT_EQ(MCValueIsEqualTo(*t_left_box, *t_right_box), p_expected);
}

template
void check_hash(MCTypeInfoRef p_type_info, T p_value, hash_t (*p_hash_func)(U p_value))
{
    MCAutoForeignValueRef t_boxed_value;
    EXPECT_TRUE(MCForeignValueCreate(p_type_info, &p_value, &t_boxed_value));
    EXPECT_EQ(MCValueHash(*t_boxed_value), p_hash_func(p_value));
}

template
void check_describe(MCTypeInfoRef p_type_info, T p_value, const char *p_format_str)
{
    char t_format[256];
    sprintf(t_format, p_format_str, p_value);
    MCAutoForeignValueRef t_boxed_value;
    EXPECT_TRUE(MCForeignValueCreate(p_type_info, &p_value, &t_boxed_value));
    MCAutoStringRef t_description;
    EXPECT_TRUE(MCValueCopyDescription(*t_boxed_value, &t_description));
    if (t_description.IsSet())
        EXPECT_STREQ(MCStringGetCString(*t_description), t_format);
}
    
template
void check_export(MCTypeInfoRef p_type_info, bool (*p_bridge)(W, U&), T p_value)
{
    MCAutoValueRefBase t_bridge_value;
    EXPECT_TRUE(p_bridge(p_value, &t_bridge_value));
    MCAutoForeignValueRef t_boxed_value;
    EXPECT_TRUE(MCForeignValueExport(p_type_info, *t_bridge_value, &t_boxed_value));
    if (t_boxed_value.IsSet())
        EXPECT_EQ(*static_cast(MCForeignValueGetContentsPtr(*t_boxed_value)), p_value);
}

void check_integral_export_overflow(MCTypeInfoRef p_type_info, MCTypeInfoRef p_err_type_info, int64_t p_value)
{
    MCAutoNumberRef t_bridge_value;
    EXPECT_TRUE(MCNumberCreateWithReal(p_value, &t_bridge_value));
    MCAutoForeignValueRef t_boxed_value;
    EXPECT_FALSE(MCForeignValueExport(p_type_info, *t_bridge_value, &t_boxed_value));
    if (!t_boxed_value.IsSet())
    {
        MCAutoErrorRef t_error;
        EXPECT_TRUE(MCErrorCatch(&t_error));
        EXPECT_EQ(MCValueGetTypeInfo(*t_error), p_err_type_info);
    }
}

template
void check_export_raw(MCTypeInfoRef p_type_info, bool (*p_bridge)(W, U&), T p_value)
{
    MCAutoValueRefBase t_bridge_value;
    EXPECT_TRUE(p_bridge(p_value, &t_bridge_value));
    const MCForeignTypeDescriptor *t_desc = MCForeignTypeInfoGetDescriptor(p_type_info);
    EXPECT_TRUE(t_desc->doexport != nullptr);
    T t_exported_value;
    EXPECT_TRUE(t_desc->doexport(t_desc, *t_bridge_value, false, &t_exported_value));
    EXPECT_EQ(t_exported_value, p_value);
}

template
void check_integral_raw_export_overflow(MCTypeInfoRef p_type_info, MCTypeInfoRef p_err_type_info, int64_t p_value)
{
    MCAutoNumberRef t_bridge_value;
    EXPECT_TRUE(MCNumberCreateWithReal(p_value, &t_bridge_value));
    const MCForeignTypeDescriptor *t_desc = MCForeignTypeInfoGetDescriptor(p_type_info);
    EXPECT_TRUE(t_desc->doexport != nullptr);
    MCAutoForeignValueRef t_boxed_value;
    T t_exported_value = 0;
    EXPECT_FALSE(t_desc->doexport(t_desc, *t_bridge_value, false, &t_exported_value));
    if (t_exported_value != 0)
    {
        MCAutoErrorRef t_error;
        EXPECT_TRUE(MCErrorCatch(&t_error));
        EXPECT_EQ(MCValueGetTypeInfo(*t_error), p_err_type_info);
    }
}

template
void check_import_raw(MCTypeInfoRef p_type_info, bool (*p_bridge)(W, U&), T p_value)
{
    MCAutoValueRefBase t_bridge_value;
    EXPECT_TRUE(p_bridge(p_value, &t_bridge_value));
    const MCForeignTypeDescriptor *t_desc = MCForeignTypeInfoGetDescriptor(p_type_info);
    EXPECT_TRUE(t_desc->doimport != nullptr);
    MCAutoValueRef t_imported_value;
    EXPECT_TRUE(t_desc->doimport(t_desc, &p_value, false, &t_imported_value));
    if (t_imported_value.IsSet())
        EXPECT_TRUE(MCValueIsEqualTo(*t_imported_value, *t_bridge_value));
}

template
void check_integral_raw_import_overflow(MCTypeInfoRef p_type_info, MCTypeInfoRef p_err_type_info, T p_value)
{
    const MCForeignTypeDescriptor *t_desc = MCForeignTypeInfoGetDescriptor(p_type_info);
    EXPECT_TRUE(t_desc->doimport != nullptr);
    MCAutoValueRef t_imported_value;
    EXPECT_FALSE(t_desc->doimport(t_desc, &p_value, false, &t_imported_value));
    if (!t_imported_value.IsSet())
    {
        MCAutoErrorRef t_error;
        EXPECT_TRUE(MCErrorCatch(&t_error));
        EXPECT_EQ(MCValueGetTypeInfo(*t_error), p_err_type_info);
    }
}

/* Bool Type Tests */

static void
test_bool_type(MCTypeInfoRef p_type, const char *p_false, const char *p_true)
{
    /* Check Copy */
    check_creation(p_type, false);
    check_creation(p_type, true);

    /* Check Equality */
    check_equality(p_type, false, false, true);
    check_equality(p_type, true, true, true);
    check_equality(p_type, false, true, false);
    check_equality(p_type, true, false, false);

    /* Check Hash */
    check_hash(p_type, false, MCHashBool);
    check_hash(p_type, true, MCHashBool);

    /* Check describe */
    check_describe(p_type, false,p_false);
    check_describe(p_type, true, p_true);
    
    /* Check export (via api) - from Boolean */
    check_export(p_type, MCBooleanCreateWithBool, false);
    check_export(p_type, MCBooleanCreateWithBool, true);
    
    /* Check export (direct) - from Boolean */
    check_export_raw(p_type, MCBooleanCreateWithBool, false);
    check_export_raw(p_type, MCBooleanCreateWithBool, true);
    
    /* Check import (direct) - to Boolean */
    check_import_raw(p_type, MCBooleanCreateWithBool, false);
    check_import_raw(p_type, MCBooleanCreateWithBool, true);
}

TEST(foreign, Bool)
{
    test_bool_type(kMCBoolTypeInfo, "", "");
}

TEST(foreign, CBool)
{
    test_bool_type(kMCCBoolTypeInfo, "", "");
}

/* Pointer Type Tests */

TEST(foreign, Pointer)
{
    const MCForeignTypeDescriptor *t_desc = MCForeignTypeInfoGetDescriptor(kMCPointerTypeInfo);
    
    /* Check Copy */
    check_creation(kMCPointerTypeInfo, nullptr);
    check_creation(kMCPointerTypeInfo, &kMCPointerTypeInfo);

    /* Check Equality */
    check_equality(kMCPointerTypeInfo, nullptr, nullptr, true);
    check_equality(kMCPointerTypeInfo, &kMCPointerTypeInfo, &kMCPointerTypeInfo, true);
    check_equality(kMCPointerTypeInfo, nullptr, &kMCPointerTypeInfo, false);
    check_equality(kMCPointerTypeInfo, &kMCPointerTypeInfo, nullptr, false);

    /* Check Hash */
    check_hash(kMCPointerTypeInfo, nullptr, MCHashPointer);
    check_hash(kMCPointerTypeInfo, &kMCPointerTypeInfo, MCHashPointer);

    /* Check describe */
    check_describe(kMCPointerTypeInfo, nullptr, "");
    check_describe(kMCPointerTypeInfo, &kMCPointerTypeInfo, "");
    
    /* Check initialize */
    ASSERT_NE(t_desc->initialize, nullptr);
    if (t_desc->initialize != nullptr)
    {
        void *t_test = &kMCPointerTypeInfo;
        ASSERT_TRUE(t_desc->initialize(&t_test));
        ASSERT_EQ(t_test, nullptr);
    }
    
    /* Check defined */
    ASSERT_NE(t_desc->defined, nullptr);
    if (t_desc->defined != nullptr)
    {
        void *t_test_null = nullptr;
        ASSERT_FALSE(t_desc->defined(&t_test_null));
        ASSERT_TRUE(t_desc->defined(&kMCPointerTypeInfo));
    }
}

/* Real Type Tests */

template
void test_numeric(MCTypeInfoRef p_type_info, T x, T y, hash_t (*p_hash)(W value), const char *p_format_str, bool (*p_bridge)(W value, U& r_bridged_value))
{
    check_creation(p_type_info, x);
    check_creation(p_type_info, y);
    
    /* Check Equality */
    check_equality(p_type_info, x, x, true);
    check_equality(p_type_info, y, y, true);
    check_equality(p_type_info, x, y, false);
    check_equality(p_type_info, y, x, false);

    /* Check Hash */
    check_hash(p_type_info, x, p_hash);
    check_hash(p_type_info, y, p_hash);

    /* Check describe */
    check_describe(p_type_info, x, p_format_str);
    check_describe(p_type_info, y, p_format_str);
    
    /* Check export (via api) */
    check_export(p_type_info, p_bridge, x);
    check_export(p_type_info, p_bridge, y);
    
    /* Check export (direct) */
    check_export_raw(p_type_info, p_bridge, x);
    check_export_raw(p_type_info, p_bridge, y);
    
    /* Check import (direct) */
    check_import_raw(p_type_info, p_bridge, x);
    check_import_raw(p_type_info, p_bridge, y);
}

TEST(foreign, Float)
{
    test_numeric(kMCFloatTypeInfo, FLT_MIN, FLT_MAX, MCHashDouble, "", MCNumberCreateWithReal);
}

TEST(foreign, Double)
{
    test_numeric(kMCDoubleTypeInfo, DBL_MIN, DBL_MAX, MCHashDouble, "", MCNumberCreateWithReal);
}

TEST(foreign, NaturalFloat)
{
#ifdef __32_BIT__
    test_numeric(kMCNaturalFloatTypeInfo, FLT_MIN, FLT_MAX, MCHashDouble, "", MCNumberCreateWithReal);
#else
    test_numeric(kMCNaturalFloatTypeInfo, DBL_MIN, DBL_MAX, MCHashDouble, "", MCNumberCreateWithReal);
#endif
}

/* Integral Type Tests */

template
hash_t __hash_int(T p_value)
{
    if (std::is_signed::value)
        return MCHashInt64(p_value);
    return MCHashUInt64(p_value);
}

template
bool __bridge_int(T p_value, MCNumberRef& r_number)
{
    if (sizeof(T) > sizeof(integer_t))
    {
        return MCNumberCreateWithReal(p_value, r_number);
    }

    if (std::is_signed::value)
    {
        return MCNumberCreateWithInteger(p_value, r_number);
    }
    
    return MCNumberCreateWithUnsignedInteger(p_value, r_number);
}

#define TEST_INTEGRAL(name, type, format) \
    TEST(foreign, name) \
    { \
        test_integral(kMC##name##TypeInfo, ""); \
    }

#define INT_NUMBER_MIN -(1LL 

Web Proxy Viewer  |  New URL  |  Original Page