/*
* This source file is part of RmlUi, the HTML/CSS Interface Middleware
*
* For the latest information, see http://github.com/mikke89/RmlUi
*
* Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
* Copyright (c) 2019 The RmlUi Team, and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "../Common/TestsShell.h"
#include
#include
#include
#include
#include
using namespace Rml;
namespace {
static const String document_rml = R"(
Test
Globals
{{ i0 }}
{{ i1 }}
{{ i2 }}
{{ i3 }}
{{ s0 }}
{{ s1 }}
{{ s2.val }}
{{ s3.val }}
{{ s4.val }}
{{ s5.val }}
Basic
{{ basic.a }}
{{ basic.b }}
{{ basic.c }}
{{ basic.d }}
{{ basic.e }}
{{ basic.f }}
Wrapped
{{ wrapped.a.val }}
{{ wrapped.b.val }}
{{ wrapped.c.val }}
{{ wrapped.d.val }}
{{ wrapped.e.val }}
Pointed
{{ pointed.a.val }}
{{ pointed.b.val }}
{{ pointed.c.val }}
Arrays
{{ it }}
{{ it }}
{{ it.val }}
{{ it.val }}
{{ it.val }}
)";
struct StringWrap
{
StringWrap(String val = "wrap_default") : val(val) {}
String val;
};
struct Globals
{
int i0 = 0;
int* i1 = new int(1);
UniquePtr i2 = MakeUnique(2);
SharedPtr i3 = MakeShared(3);
String s0 = "s0";
String* s1 = new String("s1");
StringWrap s2 = StringWrap("s2");
StringWrap* s3 = new StringWrap("s3");
UniquePtr s4 = MakeUnique("s4");
SharedPtr s5 = MakeShared("s5");
// Invalid
const int x0 = 100; // Invalid: const variable
const int* x1 = new int(101); // Invalid: const pointer
UniquePtr x2 = MakeUnique(102); // Invalid: const pointer
const StringWrap* x3 = new StringWrap("x2"); // Invalid: const pointer
UniquePtr x4 = MakeUnique("x3"); // Invalid: const pointer
} globals;
struct Basic
{
int a = 1;
int* b = new int(2);
int GetC() {
static int v = 5;
return v;
}
int& GetD() {
static int v = 5;
return v;
}
int* GetE() {
static int v = 6;
return &v;
}
UniquePtr GetF() {
return MakeUnique(7);
}
// Invalid: const member
const int x0 = 2;
// Invalid: const pointer
const int* x1 = new int(3);
// Invalid: const qualified member function
int GetX2() const {
return 4;
}
// Invalid: const reference return
const int& GetX3() {
static int g = 7;
return g;
}
// Invalid: const pointer return
const int* GetX4() {
static int h = 8;
return &h;
}
// Invalid: Illegal signature
int GetX5(int) {
return 9;
}
// Invalid: Const qualified return type
const int GetX6() {
return 9;
}
};
struct Wrapped
{
StringWrap a = { "a" };
StringWrap* b = new StringWrap("b");
UniquePtr c = MakeUnique("c");
StringWrap& GetD() {
static StringWrap v = { "e" };
return v;
}
StringWrap* GetE() {
static StringWrap v = { "f" };
return &v;
}
// Invalid: const pointer
const StringWrap* x0 = new StringWrap("x0");
// Invalid (run-time): Returning non-scalar variable by value.
StringWrap GetX1() {
return { "x1" };
}
// Invalid (run-time): Returning non-scalar variable by value.
UniquePtr GetX2() {
return MakeUnique("x2");
}
};
using StringWrapPtr = UniquePtr;
struct Pointed
{
StringWrapPtr a = MakeUnique("a");
StringWrapPtr& GetB() {
static StringWrapPtr v = MakeUnique("b");
return v;
}
StringWrapPtr* GetC() {
static StringWrapPtr v = MakeUnique("c");
return &v;
}
// Invalid: We disallow recursive pointer types (pointer to pointer)
StringWrapPtr* x0 = new StringWrapPtr(new StringWrap("x0"));
// Invalid (run-time error): Only scalar data members can be returned by value
StringWrapPtr GetX1() {
return MakeUnique("x1");
}
};
struct Arrays
{
Vector a = { 10, 11, 12 };
Vector b = { new int(20), new int(21), new int(22) };
Vector c = { StringWrap("c1"), StringWrap("c2"), StringWrap("c3") };
Vector d = { new StringWrap("d1"), new StringWrap("d2"), new StringWrap("d3") };
Vector e;
// Invalid: const pointer
Vector x0 = { new int(30), new int(31), new int(32) };
// Invalid: const pointer
Vector> x1;
Arrays() {
e.emplace_back(MakeUnique("e1"));
e.emplace_back(MakeUnique("e2"));
e.emplace_back(MakeUnique("e3"));
x1.emplace_back(MakeUnique("x1_1"));
x1.emplace_back(MakeUnique("x1_2"));
x1.emplace_back(MakeUnique("x1_3"));
}
};
DataModelHandle model_handle;
bool InitializeDataBindings(Context* context)
{
Rml::DataModelConstructor constructor = context->CreateDataModel("basics");
if (!constructor)
return false;
if (auto handle = constructor.RegisterStruct())
{
handle.RegisterMember("val", &StringWrap::val);
}
{
// Globals
constructor.Bind("i0", &globals.i0);
constructor.Bind("i1", &globals.i1);
constructor.Bind("i2", &globals.i2);
constructor.Bind("i3", &globals.i3);
constructor.Bind("s0", &globals.s0);
constructor.Bind("s1", &globals.s1);
constructor.Bind("s2", &globals.s2);
constructor.Bind("s3", &globals.s3);
constructor.Bind("s4", &globals.s4);
constructor.Bind("s5", &globals.s5);
// Invalid: Each of the following should give a compile-time failure.
//constructor.Bind("x0", &globals.x0);
//constructor.Bind("x1", &globals.x1);
//constructor.Bind("x2", &globals.x2);
//constructor.Bind("x3", &globals.x3);
//constructor.Bind("x4", &globals.x4);
}
if (auto handle = constructor.RegisterStruct())
{
handle.RegisterMember("a", &Basic::a);
handle.RegisterMember("b", &Basic::b);
handle.RegisterMember("c", &Basic::GetC);
handle.RegisterMember("d", &Basic::GetD);
handle.RegisterMember("e", &Basic::GetE);
handle.RegisterMember("f", &Basic::GetF);
//handle.RegisterMember("x0", &Basic::x0);
//handle.RegisterMember("x1", &Basic::x1);
//handle.RegisterMember("x2", &Basic::GetX2);
//handle.RegisterMember("x3", &Basic::GetX3);
//handle.RegisterMember("x4", &Basic::GetX4);
//handle.RegisterMember("x6", &Basic::GetX6);
}
constructor.Bind("basic", new Basic);
if (auto handle = constructor.RegisterStruct())
{
handle.RegisterMember("a", &Wrapped::a);
handle.RegisterMember("b", &Wrapped::b);
handle.RegisterMember("c", &Wrapped::c);
handle.RegisterMember("d", &Wrapped::GetD);
handle.RegisterMember("e", &Wrapped::GetE);
//handle.RegisterMember("x0", &Wrapped::x0);
//handle.RegisterMember("x1", &Wrapped::GetX1);
//handle.RegisterMember("x2", &Wrapped::GetX2);
}
constructor.Bind("wrapped", new Wrapped);
if (auto handle = constructor.RegisterStruct())
{
handle.RegisterMember("a", &Pointed::a);
handle.RegisterMember("b", &Pointed::GetB);
handle.RegisterMember("c", &Pointed::GetC);
//handle.RegisterMember("x0", &Pointed::x0);
//handle.RegisterMember("x1", &Pointed::GetX1);
}
constructor.Bind("pointed", new Pointed);
constructor.RegisterArray();
constructor.RegisterArray();
constructor.RegisterArray();
constructor.RegisterArray();
constructor.RegisterArray();
//constructor.RegisterArray();
//constructor.RegisterArray();
if (auto handle = constructor.RegisterStruct())
{
handle.RegisterMember("a", &Arrays::a);
handle.RegisterMember("b", &Arrays::b);
handle.RegisterMember("c", &Arrays::c);
handle.RegisterMember("d", &Arrays::d);
handle.RegisterMember("e", &Arrays::e);
//handle.RegisterMember("x0", &Arrays::x0);
//handle.RegisterMember("x1", &Arrays::x1);
}
constructor.Bind("arrays", new Arrays);
model_handle = constructor.GetModelHandle();
return true;
}
} // Anonymous namespace
TEST_CASE("databinding")
{
Context* context = TestsShell::GetContext();
REQUIRE(context);
REQUIRE(InitializeDataBindings(context));
ElementDocument* document = context->LoadDocumentFromMemory(document_rml);
REQUIRE(document);
document->Show();
context->Update();
context->Render();
TestsShell::RenderLoop();
document->Close();
TestsShell::ShutdownShell();
}