/* * 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(); }