<commit_before>// Copyright (c) 2017 offa
//
// 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 "danek/internal/ConfigScope.h"
#include <gmock/gmock.h>

using namespace danek;
using namespace testing;

class ConfigScopeTest : public testing::Test
{
};

TEST_F(ConfigScopeTest, initRootElement)
{
    ConfigScope s{nullptr, "\0"};
    EXPECT_THAT(s.scopedName(), StrEq(""));
    EXPECT_THAT(s.parentScope(), Eq(nullptr));
}

TEST_F(ConfigScopeTest, initRootElementThrowsIfNameIsPassed)
{
    EXPECT_THROW(ConfigScope(nullptr, "invalid"), std::invalid_argument);
}

TEST_F(ConfigScopeTest, initNodeElement)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope node{&root, "abc"};
    EXPECT_THAT(node.scopedName(), StrEq("abc"));
    EXPECT_THAT(node.parentScope(), Eq(&root));
}

TEST_F(ConfigScopeTest, initNodeElementAddsScopeOfParentElement)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope parent{&root, "xyz"};
    ConfigScope node{&parent, "abc"};
    EXPECT_THAT(node.scopedName(), StrEq("xyz.abc"));
    EXPECT_THAT(node.parentScope(), Eq(&parent));
}

TEST_F(ConfigScopeTest, rootScope)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope parent{&root, "xyz"};
    ConfigScope node{&parent, "abc"};
    EXPECT_THAT(parent.rootScope(), Eq(&root));
    EXPECT_THAT(node.rootScope(), Eq(&root));
}

TEST_F(ConfigScopeTest, rootScopeOnRootElement)
{
    ConfigScope root{nullptr, "\0"};
    EXPECT_THAT(root.rootScope(), Eq(&root));
}

TEST_F(ConfigScopeTest, findItemIfEmpty)
{
    ConfigScope root{nullptr, "\0"};
    const auto item = root.findItem("x");
    EXPECT_THAT(item, Eq(nullptr));
}

TEST_F(ConfigScopeTest, findItemIfFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto item = root.findItem("n2");
    EXPECT_THAT(item->name(), StrEq("n2"));
    EXPECT_THAT(item->stringVal(), StrEq("456"));
    EXPECT_THAT(item->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, findItemIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto item = root.findItem("not-found");
    EXPECT_THAT(item, Eq(nullptr));
}

TEST_F(ConfigScopeTest, addStringItemAddsNewElement)
{
    ConfigScope root{nullptr, "\0"};
    const auto result = root.addOrReplaceString("e1", "123");

    EXPECT_TRUE(result);
    const auto found = root.findItem("e1");
    EXPECT_THAT(found->name(), StrEq("e1"));
    EXPECT_THAT(found->stringVal(), StrEq("123"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, addStringItemReplacesExistingItemOfSameName)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("e", "123");
    const auto result = root.addOrReplaceString("e", "new-value");

    EXPECT_TRUE(result);
    const auto found = root.findItem("e");
    EXPECT_THAT(found->name(), StrEq("e"));
    EXPECT_THAT(found->stringVal(), StrEq("new-value"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, addStringItemDoesNothingIfExistingScopeOfSameName)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;
    root.ensureScopeExists("scope-name", ptr);

    const auto result = root.addOrReplaceString("scope-name", "value");
    EXPECT_FALSE(result);
}

TEST_F(ConfigScopeTest, addListItemAddsNewElement)
{
    const std::vector<std::string> v = {"a", "b"};
    ConfigScope root{nullptr, "\0"};
    const auto result = root.addOrReplaceList("el", StringVector{v});

    EXPECT_TRUE(result);
    const auto found = root.findItem("el");
    EXPECT_THAT(found->name(), StrEq("el"));
    EXPECT_THAT(found->listVal(), ElementsAre("a", "b"));
    EXPECT_THAT(found->type(), Eq(ConfType::List));
}

TEST_F(ConfigScopeTest, addListItemReplacesExistingItemOfSameName)
{
    const std::vector<std::string> old = {"1", "2"};
    const std::vector<std::string> v = {"4", "5"};
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceList("el", StringVector{old});
    const auto result = root.addOrReplaceList("el", StringVector{v});

    EXPECT_TRUE(result);
    const auto found = root.findItem("el");
    EXPECT_THAT(found->name(), StrEq("el"));
    EXPECT_THAT(found->listVal(), ElementsAre("4", "5"));
    EXPECT_THAT(found->type(), Eq(ConfType::List));
}

TEST_F(ConfigScopeTest, addListItemDoesNothingIfExistingScopeOfSameName)
{
    const std::vector<std::string> v = {"4", "5"};
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;
    root.ensureScopeExists("scope-name", ptr);

    const auto result = root.addOrReplaceList("scope-name", StringVector{v});
    EXPECT_FALSE(result);
}

TEST_F(ConfigScopeTest, addItemReplacesElementOfSameName)
{
    const std::vector<std::string> v = {"4", "5"};
    ConfigScope root{nullptr, "\0"};

    EXPECT_TRUE(root.addOrReplaceList("name", StringVector{v}));
    EXPECT_TRUE(root.addOrReplaceString("name", "abc"));

    const auto found = root.findItem("name");
    EXPECT_THAT(found->name(), StrEq("name"));
    EXPECT_THAT(found->stringVal(), StrEq("abc"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, addScopeAddsNewScopeElement)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;

    const auto result = root.ensureScopeExists("scope-name", ptr);
    EXPECT_TRUE(result);
    const auto found = root.findItem("scope-name");
    EXPECT_THAT(found->name(), StrEq("scope-name"));
    EXPECT_THAT(found->type(), Eq(ConfType::Scope));
}

TEST_F(ConfigScopeTest, addScopeDoesNothingIfExisting)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;

    root.ensureScopeExists("scope-name", ptr);
    const auto result = root.ensureScopeExists("scope-name", ptr);
    EXPECT_TRUE(result);
    const auto found = root.findItem("scope-name");
    EXPECT_THAT(found->name(), StrEq("scope-name"));
    EXPECT_THAT(found->type(), Eq(ConfType::Scope));
}

TEST_F(ConfigScopeTest, addScopeDoesNothingIfExistingElementOfSameName)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;

    root.addOrReplaceString("item-name", "123");
    root.ensureScopeExists("item-name", ptr);
    const auto result = root.ensureScopeExists("item-name", ptr);
    EXPECT_FALSE(result);
    const auto found = root.findItem("item-name");
    EXPECT_THAT(found->name(), StrEq("item-name"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, removeItemRemovesItem)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");
    root.addOrReplaceString("n3", "789");
    const auto result = root.removeItem("n2");

    EXPECT_TRUE(result);
    EXPECT_FALSE(root.is_in_table("n2"));
}

TEST_F(ConfigScopeTest, removeItemDoesNothingIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");
    const auto result = root.removeItem("n3");

    EXPECT_FALSE(result);
    EXPECT_TRUE(root.is_in_table("n1"));
    EXPECT_TRUE(root.is_in_table("n2"));
}

TEST_F(ConfigScopeTest, isInTableIfFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto result = root.is_in_table("n2");
    EXPECT_TRUE(result);
}

TEST_F(ConfigScopeTest, isInTableIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto result = root.is_in_table("n3");
    EXPECT_FALSE(result);
}

TEST_F(ConfigScopeTest, findEntryIfEmpty)
{
    ConfigScope root{nullptr, "\0"};
    int index = 0;
    const auto entry = root.findEntry("x", index);
    EXPECT_THAT(entry, Eq(nullptr));
}

TEST_F(ConfigScopeTest, findEntryIfFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "aa");
    root.addOrReplaceString("n2", "bb");
    root.addOrReplaceString("n3", "cc");

    int index = 0;
    const auto entry = root.findEntry("n3", index);
    EXPECT_THAT(entry->name(), StrEq("n3"));
    EXPECT_THAT(entry->item()->stringVal(), StrEq("cc"));
    EXPECT_THAT(entry->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, findEntryIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");
    root.addOrReplaceString("n3", "789");

    int index = 0;
    const auto item = root.findEntry("not-found", index);
    EXPECT_THAT(item, Eq(nullptr));
}

TEST_F(ConfigScopeTest, listFullyScopedNames)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "1");
    root.addOrReplaceString("n2", "2");

    StringVector v;
    root.listFullyScopedNames(ConfType::String, false, v);
    EXPECT_THAT(v.get(), UnorderedElementsAre("n1", "n2"));
}

TEST_F(ConfigScopeTest, listFullyScopedNamesOfMixedType)
{
    const std::vector<std::string> elements = {"a", "b"};
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "1");
    root.addOrReplaceString("n2", "2");
    root.addOrReplaceList("n3", StringVector{elements});

    StringVector v;
    root.listFullyScopedNames(ConfType::Variables, false, v);
    EXPECT_THAT(v.get(), UnorderedElementsAre("n1", "n2", "n3"));
}

TEST_F(ConfigScopeTest, listFullyScopedNamesFiltersElements)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "1");
    root.addOrReplaceString("n2", "2");

    StringVector v;
    root.listFullyScopedNames(ConfType::List, false, v);
    EXPECT_THAT(v.get(), IsEmpty());
}

TEST_F(ConfigScopeTest, listFullyScopedNamesWithScope)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope0{&root, "s0"};
    ConfigScope* ptr0 = &scope0;
    ConfigScope scope1{&root, "s1"};
    ConfigScope* ptr1 = &scope1;

    root.ensureScopeExists("sn-0", ptr0);
    root.ensureScopeExists("sn-1", ptr1);

    StringVector v;
    root.listFullyScopedNames(ConfType::ScopesAndVars, false, v);

    EXPECT_THAT(v.get(), UnorderedElementsAre("sn-0", "sn-1"));
}
<commit_msg>Test extended.<commit_after>// Copyright (c) 2017 offa
//
// 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 "danek/internal/ConfigScope.h"
#include <gmock/gmock.h>

using namespace danek;
using namespace testing;

class ConfigScopeTest : public testing::Test
{
};

TEST_F(ConfigScopeTest, initRootElement)
{
    ConfigScope s{nullptr, "\0"};
    EXPECT_THAT(s.scopedName(), StrEq(""));
    EXPECT_THAT(s.parentScope(), Eq(nullptr));
}

TEST_F(ConfigScopeTest, initRootElementThrowsIfNameIsPassed)
{
    EXPECT_THROW(ConfigScope(nullptr, "invalid"), std::invalid_argument);
}

TEST_F(ConfigScopeTest, initNodeElement)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope node{&root, "abc"};
    EXPECT_THAT(node.scopedName(), StrEq("abc"));
    EXPECT_THAT(node.parentScope(), Eq(&root));
}

TEST_F(ConfigScopeTest, initNodeElementAddsScopeOfParentElement)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope parent{&root, "xyz"};
    ConfigScope node{&parent, "abc"};
    EXPECT_THAT(node.scopedName(), StrEq("xyz.abc"));
    EXPECT_THAT(node.parentScope(), Eq(&parent));
}

TEST_F(ConfigScopeTest, rootScope)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope parent{&root, "xyz"};
    ConfigScope node{&parent, "abc"};
    ConfigScope node2{&parent, "def"};
    ConfigScope node3{&node2, "ghi"};
    EXPECT_THAT(parent.rootScope(), Eq(&root));
    EXPECT_THAT(node.rootScope(), Eq(&root));
    EXPECT_THAT(node2.rootScope(), Eq(&root));
    EXPECT_THAT(node3.rootScope(), Eq(&root));
}

TEST_F(ConfigScopeTest, rootScopeOnRootElement)
{
    ConfigScope root{nullptr, "\0"};
    EXPECT_THAT(root.rootScope(), Eq(&root));
}

TEST_F(ConfigScopeTest, findItemIfEmpty)
{
    ConfigScope root{nullptr, "\0"};
    const auto item = root.findItem("x");
    EXPECT_THAT(item, Eq(nullptr));
}

TEST_F(ConfigScopeTest, findItemIfFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto item = root.findItem("n2");
    EXPECT_THAT(item->name(), StrEq("n2"));
    EXPECT_THAT(item->stringVal(), StrEq("456"));
    EXPECT_THAT(item->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, findItemIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto item = root.findItem("not-found");
    EXPECT_THAT(item, Eq(nullptr));
}

TEST_F(ConfigScopeTest, addStringItemAddsNewElement)
{
    ConfigScope root{nullptr, "\0"};
    const auto result = root.addOrReplaceString("e1", "123");

    EXPECT_TRUE(result);
    const auto found = root.findItem("e1");
    EXPECT_THAT(found->name(), StrEq("e1"));
    EXPECT_THAT(found->stringVal(), StrEq("123"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, addStringItemReplacesExistingItemOfSameName)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("e", "123");
    const auto result = root.addOrReplaceString("e", "new-value");

    EXPECT_TRUE(result);
    const auto found = root.findItem("e");
    EXPECT_THAT(found->name(), StrEq("e"));
    EXPECT_THAT(found->stringVal(), StrEq("new-value"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, addStringItemDoesNothingIfExistingScopeOfSameName)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;
    root.ensureScopeExists("scope-name", ptr);

    const auto result = root.addOrReplaceString("scope-name", "value");
    EXPECT_FALSE(result);
}

TEST_F(ConfigScopeTest, addListItemAddsNewElement)
{
    const std::vector<std::string> v = {"a", "b"};
    ConfigScope root{nullptr, "\0"};
    const auto result = root.addOrReplaceList("el", StringVector{v});

    EXPECT_TRUE(result);
    const auto found = root.findItem("el");
    EXPECT_THAT(found->name(), StrEq("el"));
    EXPECT_THAT(found->listVal(), ElementsAre("a", "b"));
    EXPECT_THAT(found->type(), Eq(ConfType::List));
}

TEST_F(ConfigScopeTest, addListItemReplacesExistingItemOfSameName)
{
    const std::vector<std::string> old = {"1", "2"};
    const std::vector<std::string> v = {"4", "5"};
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceList("el", StringVector{old});
    const auto result = root.addOrReplaceList("el", StringVector{v});

    EXPECT_TRUE(result);
    const auto found = root.findItem("el");
    EXPECT_THAT(found->name(), StrEq("el"));
    EXPECT_THAT(found->listVal(), ElementsAre("4", "5"));
    EXPECT_THAT(found->type(), Eq(ConfType::List));
}

TEST_F(ConfigScopeTest, addListItemDoesNothingIfExistingScopeOfSameName)
{
    const std::vector<std::string> v = {"4", "5"};
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;
    root.ensureScopeExists("scope-name", ptr);

    const auto result = root.addOrReplaceList("scope-name", StringVector{v});
    EXPECT_FALSE(result);
}

TEST_F(ConfigScopeTest, addItemReplacesElementOfSameName)
{
    const std::vector<std::string> v = {"4", "5"};
    ConfigScope root{nullptr, "\0"};

    EXPECT_TRUE(root.addOrReplaceList("name", StringVector{v}));
    EXPECT_TRUE(root.addOrReplaceString("name", "abc"));

    const auto found = root.findItem("name");
    EXPECT_THAT(found->name(), StrEq("name"));
    EXPECT_THAT(found->stringVal(), StrEq("abc"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, addScopeAddsNewScopeElement)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;

    const auto result = root.ensureScopeExists("scope-name", ptr);
    EXPECT_TRUE(result);
    const auto found = root.findItem("scope-name");
    EXPECT_THAT(found->name(), StrEq("scope-name"));
    EXPECT_THAT(found->type(), Eq(ConfType::Scope));
}

TEST_F(ConfigScopeTest, addScopeDoesNothingIfExisting)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;

    root.ensureScopeExists("scope-name", ptr);
    const auto result = root.ensureScopeExists("scope-name", ptr);
    EXPECT_TRUE(result);
    const auto found = root.findItem("scope-name");
    EXPECT_THAT(found->name(), StrEq("scope-name"));
    EXPECT_THAT(found->type(), Eq(ConfType::Scope));
}

TEST_F(ConfigScopeTest, addScopeDoesNothingIfExistingElementOfSameName)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope{&root, "xy"};
    ConfigScope* ptr = &scope;

    root.addOrReplaceString("item-name", "123");
    root.ensureScopeExists("item-name", ptr);
    const auto result = root.ensureScopeExists("item-name", ptr);
    EXPECT_FALSE(result);
    const auto found = root.findItem("item-name");
    EXPECT_THAT(found->name(), StrEq("item-name"));
    EXPECT_THAT(found->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, removeItemRemovesItem)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");
    root.addOrReplaceString("n3", "789");
    const auto result = root.removeItem("n2");

    EXPECT_TRUE(result);
    EXPECT_FALSE(root.is_in_table("n2"));
}

TEST_F(ConfigScopeTest, removeItemDoesNothingIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");
    const auto result = root.removeItem("n3");

    EXPECT_FALSE(result);
    EXPECT_TRUE(root.is_in_table("n1"));
    EXPECT_TRUE(root.is_in_table("n2"));
}

TEST_F(ConfigScopeTest, isInTableIfFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto result = root.is_in_table("n2");
    EXPECT_TRUE(result);
}

TEST_F(ConfigScopeTest, isInTableIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");

    const auto result = root.is_in_table("n3");
    EXPECT_FALSE(result);
}

TEST_F(ConfigScopeTest, findEntryIfEmpty)
{
    ConfigScope root{nullptr, "\0"};
    int index = 0;
    const auto entry = root.findEntry("x", index);
    EXPECT_THAT(entry, Eq(nullptr));
}

TEST_F(ConfigScopeTest, findEntryIfFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "aa");
    root.addOrReplaceString("n2", "bb");
    root.addOrReplaceString("n3", "cc");

    int index = 0;
    const auto entry = root.findEntry("n3", index);
    EXPECT_THAT(entry->name(), StrEq("n3"));
    EXPECT_THAT(entry->item()->stringVal(), StrEq("cc"));
    EXPECT_THAT(entry->type(), Eq(ConfType::String));
}

TEST_F(ConfigScopeTest, findEntryIfNotFound)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "123");
    root.addOrReplaceString("n2", "456");
    root.addOrReplaceString("n3", "789");

    int index = 0;
    const auto item = root.findEntry("not-found", index);
    EXPECT_THAT(item, Eq(nullptr));
}

TEST_F(ConfigScopeTest, listFullyScopedNames)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "1");
    root.addOrReplaceString("n2", "2");

    StringVector v;
    root.listFullyScopedNames(ConfType::String, false, v);
    EXPECT_THAT(v.get(), UnorderedElementsAre("n1", "n2"));
}

TEST_F(ConfigScopeTest, listFullyScopedNamesOfMixedType)
{
    const std::vector<std::string> elements = {"a", "b"};
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "1");
    root.addOrReplaceString("n2", "2");
    root.addOrReplaceList("n3", StringVector{elements});

    StringVector v;
    root.listFullyScopedNames(ConfType::Variables, false, v);
    EXPECT_THAT(v.get(), UnorderedElementsAre("n1", "n2", "n3"));
}

TEST_F(ConfigScopeTest, listFullyScopedNamesFiltersElements)
{
    ConfigScope root{nullptr, "\0"};
    root.addOrReplaceString("n1", "1");
    root.addOrReplaceString("n2", "2");

    StringVector v;
    root.listFullyScopedNames(ConfType::List, false, v);
    EXPECT_THAT(v.get(), IsEmpty());
}

TEST_F(ConfigScopeTest, listFullyScopedNamesWithScope)
{
    ConfigScope root{nullptr, "\0"};
    ConfigScope scope0{&root, "s0"};
    ConfigScope* ptr0 = &scope0;
    ConfigScope scope1{&root, "s1"};
    ConfigScope* ptr1 = &scope1;

    root.ensureScopeExists("sn-0", ptr0);
    root.ensureScopeExists("sn-1", ptr1);

    StringVector v;
    root.listFullyScopedNames(ConfType::ScopesAndVars, false, v);

    EXPECT_THAT(v.get(), UnorderedElementsAre("sn-0", "sn-1"));
}
<|endoftext|>


<commit_before>#include "catch/catch.hpp"

#include "QWebService.h"
#include <QHostAddress>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QUrl>
#include <string>
#include <QWebServiceConfig.h>
#include "router/QWebRequest.h"
#include "router/QWebResponse.h"

SCENARIO( "A simple service is configured and used", "[QWebRouter]" ) {

    GIVEN( "A network manager" )
    {
        QNetworkAccessManager manager;

        auto response = [](QSharedPointer<QWebRequest> req, QSharedPointer<QWebResponse> resp)
        {
            REQUIRE(req);
            REQUIRE(resp);
        };

        QSharedPointer<QWebService> service = QSharedPointer<QWebService> (QWebServiceConfig()
                .get ("hello", response)
                .build());

        service->startService(QHostAddress::LocalHost, 8080);

        REQUIRE(service);

        WHEN( "We try to call the path hello" )
        {
            //Set up the networking request
            QNetworkRequest request(QUrl("http://localhost:8080/hello"));

            //Post the request
            QNetworkReply* reply = manager.get(request);

            //Spin until we get the reply
            QEventLoop eLoop;
            QObject::connect(&manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
            eLoop.exec();

            REQUIRE(reply);
        }
    }
}
<commit_msg>Updated test case to send a response, refactored the QEventLoop wait to a spin function<commit_after>#include "catch/catch.hpp"

#include "QWebService.h"
#include <QHostAddress>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QJsonObject>
#include <QUrl>
#include <string>
#include <QWebServiceConfig.h>
#include "router/QWebRequest.h"
#include "router/QWebResponse.h"

void spin(const QNetworkAccessManager& manager)
{
    //Spin until we get the reply
    QEventLoop eLoop;
    QObject::connect(&manager, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT(quit()));
    eLoop.exec();
}

SCENARIO( "A simple service is configured and used", "[QWebService]" ) {

    GIVEN( "A network manager" )
    {
        QNetworkAccessManager manager;

        auto response = [](QSharedPointer<QWebRequest> req, QSharedPointer<QWebResponse> resp)
        {
            REQUIRE(req);
            REQUIRE(resp);
            QJsonObject result;
            result.insert(QString("hello"),QString("world"));
            resp->setStatusCode(QWebResponse::StatusCode::STATUS_OK);
            resp->writeJson(QJsonDocument(result));
        };

        QSharedPointer<QWebService> service = QSharedPointer<QWebService> (QWebServiceConfig()
                .get ("hello", response)
                .build());

        service->startService(QHostAddress::LocalHost, 8080);

        REQUIRE(service);

        WHEN( "We try to call the path hello" )
        {
            //Set up the networking request
            QNetworkRequest request(QUrl("http://localhost:8080/hello"));

            //Post the request
            QNetworkReply* reply = manager.get(request);

            spin(manager);

            REQUIRE(reply);
        }
    }
}
<|endoftext|>


<commit_before>#ifndef ANIMATED_HPP_
#define ANIMATED_HPP_

#include "./transition.hpp"

template <typename T>
class Animated
{
public:
    Animated(const T &value):
        m_value(value),
        m_transition(nullptr)
    {}

    ~Animated()
    {
        if (m_transition != nullptr) {
            delete m_transition;
            m_transition = nullptr;
        }
    }

    T getValue() const
    {
        return value;
    }

    void setTransition(Transition<T> *transition)
    {
        if (m_transition != nullptr) {
            delete m_transition;
            m_transition = nullptr;
        }

        m_transition = transition;
    }

    void tick(sf::Int32 deltaTime)
    {
        if (m_transition != nullptr) {
            if (!m_transition.isFinished()) {
                m_value = m_transition->nextState(deltaTime);
            } else {
                delete m_transition;
                m_transition = nullptr;
            }
        }
    }

private:

private:
    T m_value;
    Transition<T> *m_transition;
};

#endif  // ANIMATED_HPP_
<commit_msg>Do not allow to copy animated value (#3)<commit_after>#ifndef ANIMATED_HPP_
#define ANIMATED_HPP_

#include "./transition.hpp"

template <typename T>
class Animated
{
public:
    Animated(const Animated&) = delete;

    Animated(const T &value):
        m_value(value),
        m_transition(nullptr)
    {}

    ~Animated()
    {
        if (m_transition != nullptr) {
            delete m_transition;
            m_transition = nullptr;
        }
    }

    T getValue() const
    {
        return value;
    }

    void setTransition(Transition<T> *transition)
    {
        if (m_transition != nullptr) {
            delete m_transition;
            m_transition = nullptr;
        }

        m_transition = transition;
    }

    void tick(sf::Int32 deltaTime)
    {
        if (m_transition != nullptr) {
            if (!m_transition.isFinished()) {
                m_value = m_transition->nextState(deltaTime);
            } else {
                delete m_transition;
                m_transition = nullptr;
            }
        }
    }

private:
    T m_value;
    Transition<T> *m_transition;
};

#endif  // ANIMATED_HPP_
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the MoleQueue project.

  Copyright 2011 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "sshcommand.h"
#include "terminalprocess.h"
#include <QtCore/QProcessEnvironment>
#include <QtCore/QDir>
#include <QtCore/QDebug>

namespace MoleQueue {

SshCommand::SshCommand(QObject *parentObject) : SshConnection(parentObject),
  m_sshCommand("ssh"),
  m_scpCommand("scp"),
  m_exitCode(-1),
  m_process(0),
  m_isComplete(true)
{
}

SshCommand::~SshCommand()
{
  delete m_process;
  m_process = 0;
}

QString SshCommand::output() const
{
  return isComplete() ? m_output : QString();
}

int SshCommand::exitCode() const
{
  return isComplete() ? m_exitCode : -1;
}

bool SshCommand::waitForCompletion(int msecs)
{
  if (!m_process)
    return false;

  if (m_process->state() == QProcess::Starting)
    m_process->waitForStarted(msecs);

  if (m_isComplete)
    return true;

  return m_process->waitForFinished(msecs);
}

bool SshCommand::isComplete() const
{
  return m_isComplete;
}

bool SshCommand::execute(const QString &command)
{
  if (!isValid())
    return false;

  QStringList args = this->sshArgs();
  args << this->remoteSpec() << command;

  this->sendRequest(m_sshCommand, args);

  return true;
}

bool SshCommand::copyTo(const QString &localFile, const QString &remoteFile)
{
  if (!isValid())
    return false;

  QStringList args = scpArgs();
  QString remoteFileSpec = this->remoteSpec() + ":" + remoteFile;
  args << localFile << remoteFileSpec;

  this->sendRequest(m_scpCommand, args);

  return true;
}

bool SshCommand::copyFrom(const QString &remoteFile, const QString &localFile)
{
  if (!isValid())
    return false;

  QStringList args = scpArgs();
  QString remoteFileSpec = this->remoteSpec() + ":" + remoteFile;
  args << remoteFileSpec << localFile;

  this->sendRequest(m_scpCommand, args);

  return true;
}

bool SshCommand::copyDirTo(const QString &localDir, const QString &remoteDir)
{
  if (!isValid())
    return false;

  QStringList args = scpArgs();
  QString remoteDirSpec = this->remoteSpec() + ":" + remoteDir;
  args << "-r" << localDir << remoteDirSpec;

  this->sendRequest(m_scpCommand, args);

  return true;
}

bool SshCommand::copyDirFrom(const QString &remoteDir, const QString &localDir)
{
  if (!isValid())
    return false;

  QDir local(localDir);
  if (!local.exists())
    local.mkpath(localDir); /// @todo Check for failure of mkpath

  QStringList args = scpArgs();
  QString remoteDirSpec = this->remoteSpec() + ":" + remoteDir;
  args << "-r" << remoteDirSpec << localDir;

  this->sendRequest(m_scpCommand, args);

  return true;
}

void SshCommand::processStarted()
{
  m_process->closeWriteChannel();
  emit requestSent();
}

void SshCommand::processFinished()
{
  m_output = m_process->readAll();
  m_exitCode = m_process->exitCode();
  m_process->close();

  qDebug() << "SshCommand exit:" << m_exitCode << "output:\n" << m_output;

  m_isComplete = true;
  emit requestComplete();
}

void SshCommand::sendRequest(const QString &command, const QStringList &args)
{
  if (!m_process)
    this->initializeProcess();

  m_isComplete = false;

  qDebug() << "SshCommand sending request:" << command << args.join(" ");

  m_process->start(command, args);
}

void SshCommand::initializeProcess()
{
  // Initialize the environment for the process, set merged channels.
  if (!m_process)
    m_process = new TerminalProcess(this);
  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
  QProcessEnvironment sshEnv;
  if (env.contains("DISPLAY"))
    sshEnv.insert("DISPLAY", env.value("DISPLAY"));
  if (env.contains("EDITOR"))
    sshEnv.insert("EDITOR", env.value("EDITOR"));
  if (env.contains("SSH_AUTH_SOCK"))
    sshEnv.insert("SSH_AUTH_SOCK", env.value("SSH_AUTH_SOCK"));
  sshEnv.insert("SSH_ASKPASS", "/usr/bin/pinentry-qt4");
  m_process->setProcessEnvironment(sshEnv);
  m_process->setProcessChannelMode(QProcess::MergedChannels);

  connect(m_process, SIGNAL(started()), this, SLOT(processStarted()));
  connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
          this, SLOT(processFinished()));
}

QStringList SshCommand::sshArgs()
{
  QStringList args;
  if (!m_identityFile.isEmpty())
    args << "-i" << m_identityFile;
  if (m_portNumber >= 0)
    args << "-p" << QString::number(m_portNumber);
  return args;
}

QStringList SshCommand::scpArgs()
{
  QStringList args;
  if (!m_identityFile.isEmpty())
    args << "-i" << m_identityFile;
  if (m_portNumber >= 0)
    args << "-P" << QString::number(m_portNumber);
  return args;
}

QString SshCommand::remoteSpec()
{
  return m_userName.isEmpty() ? m_hostName : m_userName + "@" + m_hostName;
}

} // End namespace
<commit_msg>Suppress login banners when connecting through ssh/scp.<commit_after>/******************************************************************************

  This source file is part of the MoleQueue project.

  Copyright 2011 Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

******************************************************************************/

#include "sshcommand.h"
#include "terminalprocess.h"
#include <QtCore/QProcessEnvironment>
#include <QtCore/QDir>
#include <QtCore/QDebug>

namespace MoleQueue {

SshCommand::SshCommand(QObject *parentObject) : SshConnection(parentObject),
  m_sshCommand("ssh"),
  m_scpCommand("scp"),
  m_exitCode(-1),
  m_process(0),
  m_isComplete(true)
{
}

SshCommand::~SshCommand()
{
  delete m_process;
  m_process = 0;
}

QString SshCommand::output() const
{
  return isComplete() ? m_output : QString();
}

int SshCommand::exitCode() const
{
  return isComplete() ? m_exitCode : -1;
}

bool SshCommand::waitForCompletion(int msecs)
{
  if (!m_process)
    return false;

  if (m_process->state() == QProcess::Starting)
    m_process->waitForStarted(msecs);

  if (m_isComplete)
    return true;

  return m_process->waitForFinished(msecs);
}

bool SshCommand::isComplete() const
{
  return m_isComplete;
}

bool SshCommand::execute(const QString &command)
{
  if (!isValid())
    return false;

  QStringList args = this->sshArgs();
  args << this->remoteSpec() << command;

  this->sendRequest(m_sshCommand, args);

  return true;
}

bool SshCommand::copyTo(const QString &localFile, const QString &remoteFile)
{
  if (!isValid())
    return false;

  QStringList args = scpArgs();
  QString remoteFileSpec = this->remoteSpec() + ":" + remoteFile;
  args << localFile << remoteFileSpec;

  this->sendRequest(m_scpCommand, args);

  return true;
}

bool SshCommand::copyFrom(const QString &remoteFile, const QString &localFile)
{
  if (!isValid())
    return false;

  QStringList args = scpArgs();
  QString remoteFileSpec = this->remoteSpec() + ":" + remoteFile;
  args << remoteFileSpec << localFile;

  this->sendRequest(m_scpCommand, args);

  return true;
}

bool SshCommand::copyDirTo(const QString &localDir, const QString &remoteDir)
{
  if (!isValid())
    return false;

  QStringList args = scpArgs();
  QString remoteDirSpec = this->remoteSpec() + ":" + remoteDir;
  args << "-r" << localDir << remoteDirSpec;

  this->sendRequest(m_scpCommand, args);

  return true;
}

bool SshCommand::copyDirFrom(const QString &remoteDir, const QString &localDir)
{
  if (!isValid())
    return false;

  QDir local(localDir);
  if (!local.exists())
    local.mkpath(localDir); /// @todo Check for failure of mkpath

  QStringList args = scpArgs();
  QString remoteDirSpec = this->remoteSpec() + ":" + remoteDir;
  args << "-r" << remoteDirSpec << localDir;

  this->sendRequest(m_scpCommand, args);

  return true;
}

void SshCommand::processStarted()
{
  m_process->closeWriteChannel();
  emit requestSent();
}

void SshCommand::processFinished()
{
  m_output = m_process->readAll();
  m_exitCode = m_process->exitCode();
  m_process->close();

  qDebug() << "SshCommand exit:" << m_exitCode << "output:\n" << m_output;

  m_isComplete = true;
  emit requestComplete();
}

void SshCommand::sendRequest(const QString &command, const QStringList &args)
{
  if (!m_process)
    this->initializeProcess();

  m_isComplete = false;

  qDebug() << "SshCommand sending request:" << command << args.join(" ");

  m_process->start(command, args);
}

void SshCommand::initializeProcess()
{
  // Initialize the environment for the process, set merged channels.
  if (!m_process)
    m_process = new TerminalProcess(this);
  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
  QProcessEnvironment sshEnv;
  if (env.contains("DISPLAY"))
    sshEnv.insert("DISPLAY", env.value("DISPLAY"));
  if (env.contains("EDITOR"))
    sshEnv.insert("EDITOR", env.value("EDITOR"));
  if (env.contains("SSH_AUTH_SOCK"))
    sshEnv.insert("SSH_AUTH_SOCK", env.value("SSH_AUTH_SOCK"));
  sshEnv.insert("SSH_ASKPASS", "/usr/bin/pinentry-qt4");
  m_process->setProcessEnvironment(sshEnv);
  m_process->setProcessChannelMode(QProcess::MergedChannels);

  connect(m_process, SIGNAL(started()), this, SLOT(processStarted()));
  connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
          this, SLOT(processFinished()));
}

QStringList SshCommand::sshArgs()
{
  QStringList args;
  // Suppress login banners
  args << "-q";
  if (!m_identityFile.isEmpty())
    args << "-i" << m_identityFile;
  if (m_portNumber >= 0)
    args << "-p" << QString::number(m_portNumber);
  return args;
}

QStringList SshCommand::scpArgs()
{
  QStringList args;
  // Suppress login banners
  args << "-q";
  if (!m_identityFile.isEmpty())
    args << "-i" << m_identityFile;
  if (m_portNumber >= 0)
    args << "-P" << QString::number(m_portNumber);
  return args;
}

QString SshCommand::remoteSpec()
{
  return m_userName.isEmpty() ? m_hostName : m_userName + "@" + m_hostName;
}

} // End namespace
<|endoftext|>


<commit_before>#include "hooks_py.h"
#include "simulator.h"
#include "clock_skew_minimization_object.h"
#include "stats.h"
#include "magic_server.h"

//////////
// get(): retrieve a stats value
//////////

static PyObject *
getStatsValue(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL;
   long int index = -1;

   if (!PyArg_ParseTuple(args, "sls", &objectName, &index, &metricName))
      return NULL;

   StatsMetricBase *metric = Sim()->getStatsManager()->getMetricObject(objectName, index, metricName);

   if (!metric) {
      PyErr_SetString(PyExc_ValueError, "Stats metric not found");
      return NULL;
   }

   return PyLong_FromUnsignedLongLong(metric->recordMetric());
}

//////////
// getter(): return a statsGetterObject Python object which, when called, returns a stats value
//////////

typedef struct {
   PyObject_HEAD
   StatsMetricBase *metric;
} statsGetterObject;

static PyObject *
statsGetterGet(PyObject *self, PyObject *args, PyObject *kw)
{
   statsGetterObject *getter = (statsGetterObject *)self;
   StatsMetricBase *metric = getter->metric;
   return PyLong_FromUnsignedLongLong(metric->recordMetric());
}

static PyTypeObject statsGetterType = {
   PyObject_HEAD_INIT(NULL)
   0,                         /*ob_size*/
   "statsGetter",             /*tp_name*/
   sizeof(statsGetterObject), /*tp_basicsize*/
   0,                         /*tp_itemsize*/
   0,                         /*tp_dealloc*/
   0,                         /*tp_print*/
   0,                         /*tp_getattr*/
   0,                         /*tp_setattr*/
   0,                         /*tp_compare*/
   0,                         /*tp_repr*/
   0,                         /*tp_as_number*/
   0,                         /*tp_as_sequence*/
   0,                         /*tp_as_mapping*/
   0,                         /*tp_hash */
   statsGetterGet,            /*tp_call*/
   0,                         /*tp_str*/
   0,                         /*tp_getattro*/
   0,                         /*tp_setattro*/
   0,                         /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT,        /*tp_flags*/
   "Stats getter objects",    /*tp_doc*/
   0,                         /*tp_traverse*/
   0,                         /*tp_clear*/
   0,                         /*tp_richcompare*/
   0,                         /*tp_weaklistoffset*/
   0,                         /*tp_iter*/
   0,                         /*tp_iternext*/
   0,                         /*tp_methods*/
   0,                         /*tp_members*/
   0,                         /*tp_getset*/
   0,                         /*tp_base*/
   0,                         /*tp_dict*/
   0,                         /*tp_descr_get*/
   0,                         /*tp_descr_set*/
   0,                         /*tp_dictoffset*/
   0,                         /*tp_init*/
   0,                         /*tp_alloc*/
   0,                         /*tp_new*/
   0,                         /*tp_free*/
   0,                         /*tp_is_gc*/
   0,                         /*tp_bases*/
   0,                         /*tp_mro*/
   0,                         /*tp_cache*/
   0,                         /*tp_subclasses*/
   0,                         /*tp_weaklist*/
   0,                         /*tp_del*/
   0,                         /*tp_version_tag*/
};

static PyObject *
getStatsGetter(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL;
   long int index = -1;

   if (!PyArg_ParseTuple(args, "sls", &objectName, &index, &metricName))
      return NULL;

   StatsMetricBase *metric = Sim()->getStatsManager()->getMetricObject(objectName, index, metricName);

   if (!metric) {
      PyErr_SetString(PyExc_ValueError, "Stats metric not found");
      return NULL;
   }

   statsGetterObject *pGetter = PyObject_New(statsGetterObject, &statsGetterType);
   pGetter->metric = metric;

   return (PyObject *)pGetter;
}

//////////
// write(): write the current set of statistics out to sim.stats or our own file
//////////

static PyObject *
writeStats(PyObject *self, PyObject *args)
{
   const char *prefix = NULL;

   if (!PyArg_ParseTuple(args, "s", &prefix))
      return NULL;

   Sim()->getStatsManager()->recordStats(prefix);

   Py_RETURN_NONE;
}

//////////
// register(): register a callback function that returns a statistics value
//////////

static UInt64 statsCallback(String objectName, UInt32 index, String metricName, UInt64 _pFunc)
{
   PyObject *pFunc = (PyObject*)_pFunc;
   PyObject *pResult = HooksPy::callPythonFunction(pFunc, Py_BuildValue("(sls)", objectName.c_str(), index, metricName.c_str()));

   if (!PyLong_Check(pResult)) {
      fprintf(stderr, "Stats callback: return value must be (convertable into) 64-bit unsigned integer\n");
      Py_XDECREF(pResult);
      return 0;
   }

   UInt64 val = PyLong_AsLongLong(pResult);
   Py_XDECREF(pResult);

   return val;
}

static PyObject *
registerStats(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL;
   long int index = -1;
   PyObject *pFunc = NULL;

   if (!PyArg_ParseTuple(args, "slsO", &objectName, &index, &metricName, &pFunc))
      return NULL;

   if (!PyCallable_Check(pFunc)) {
      PyErr_SetString(PyExc_TypeError, "Fourth argument must be callable");
      return NULL;
   }
   Py_INCREF(pFunc);

   Sim()->getStatsManager()->registerMetric(new StatsMetricCallback(objectName, index, metricName, (StatsCallback)statsCallback, (UInt64)pFunc));

   Py_RETURN_NONE;
}

//////////
// marker(): record a marker
//////////

static PyObject *
writeMarker(PyObject *self, PyObject *args)
{
   UInt64 core_id = INVALID_CORE_ID, thread_id = INVALID_THREAD_ID, arg0 = 0, arg1 = 0;
   const char *description = NULL;

   if (!PyArg_ParseTuple(args, "llll|z", &core_id, &thread_id, &arg0, &arg1, &description))
      return NULL;

   Sim()->getStatsManager()->logMarker(Sim()->getClockSkewMinimizationServer()->getGlobalTime(), core_id, thread_id, arg0, arg1, description);

   Py_RETURN_NONE;
}

//////////
// time(): Return current global time in femtoseconds
//////////

static PyObject *
getTime(PyObject *self, PyObject *args)
{
   SubsecondTime time = Sim()->getClockSkewMinimizationServer()->getGlobalTime();
   return PyLong_FromUnsignedLongLong(time.getFS());
}

//////////
// icount(): Return current global instruction count
//////////

static PyObject *
getIcount(PyObject *self, PyObject *args)
{
   UInt64 icount = MagicServer::getGlobalInstructionCount();
   return PyLong_FromUnsignedLongLong(icount);
}

//////////
// module definition
//////////

static PyMethodDef PyStatsMethods[] = {
   {"get",  getStatsValue, METH_VARARGS, "Retrieve current value of statistic (objectName, index, metricName)."},
   {"getter", getStatsGetter, METH_VARARGS, "Return object to retrieve statistics value."},
   {"write", writeStats, METH_VARARGS, "Write statistics (<prefix>, [<filename>])."},
   {"register", registerStats, METH_VARARGS, "Register callback that defines statistics value for (objectName, index, metricName)."},
   {"marker", writeMarker, METH_VARARGS, "Record a marker (coreid, threadid, arg0, arg1, [description])."},
   {"time", getTime, METH_VARARGS, "Retrieve the current global time in femtoseconds (approximate, last barrier)."},
   {"icount", getIcount, METH_VARARGS, "Retrieve current global instruction count."},
   {NULL, NULL, 0, NULL} /* Sentinel */
};

void HooksPy::PyStats::setup(void)
{
   PyObject *pModule = Py_InitModule("sim_stats", PyStatsMethods);

   statsGetterType.tp_new = PyType_GenericNew;
   if (PyType_Ready(&statsGetterType) < 0)
      return;

   Py_INCREF(&statsGetterType);
   PyModule_AddObject(pModule, "Getter", (PyObject *)&statsGetterType);
}
<commit_msg>[scripting] Allow per-thread statistics to be registered<commit_after>#include "hooks_py.h"
#include "simulator.h"
#include "clock_skew_minimization_object.h"
#include "stats.h"
#include "magic_server.h"
#include "thread_stats_manager.h"

//////////
// get(): retrieve a stats value
//////////

static PyObject *
getStatsValue(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL;
   long int index = -1;

   if (!PyArg_ParseTuple(args, "sls", &objectName, &index, &metricName))
      return NULL;

   StatsMetricBase *metric = Sim()->getStatsManager()->getMetricObject(objectName, index, metricName);

   if (!metric) {
      PyErr_SetString(PyExc_ValueError, "Stats metric not found");
      return NULL;
   }

   return PyLong_FromUnsignedLongLong(metric->recordMetric());
}

//////////
// getter(): return a statsGetterObject Python object which, when called, returns a stats value
//////////

typedef struct {
   PyObject_HEAD
   StatsMetricBase *metric;
} statsGetterObject;

static PyObject *
statsGetterGet(PyObject *self, PyObject *args, PyObject *kw)
{
   statsGetterObject *getter = (statsGetterObject *)self;
   StatsMetricBase *metric = getter->metric;
   return PyLong_FromUnsignedLongLong(metric->recordMetric());
}

static PyTypeObject statsGetterType = {
   PyObject_HEAD_INIT(NULL)
   0,                         /*ob_size*/
   "statsGetter",             /*tp_name*/
   sizeof(statsGetterObject), /*tp_basicsize*/
   0,                         /*tp_itemsize*/
   0,                         /*tp_dealloc*/
   0,                         /*tp_print*/
   0,                         /*tp_getattr*/
   0,                         /*tp_setattr*/
   0,                         /*tp_compare*/
   0,                         /*tp_repr*/
   0,                         /*tp_as_number*/
   0,                         /*tp_as_sequence*/
   0,                         /*tp_as_mapping*/
   0,                         /*tp_hash */
   statsGetterGet,            /*tp_call*/
   0,                         /*tp_str*/
   0,                         /*tp_getattro*/
   0,                         /*tp_setattro*/
   0,                         /*tp_as_buffer*/
   Py_TPFLAGS_DEFAULT,        /*tp_flags*/
   "Stats getter objects",    /*tp_doc*/
   0,                         /*tp_traverse*/
   0,                         /*tp_clear*/
   0,                         /*tp_richcompare*/
   0,                         /*tp_weaklistoffset*/
   0,                         /*tp_iter*/
   0,                         /*tp_iternext*/
   0,                         /*tp_methods*/
   0,                         /*tp_members*/
   0,                         /*tp_getset*/
   0,                         /*tp_base*/
   0,                         /*tp_dict*/
   0,                         /*tp_descr_get*/
   0,                         /*tp_descr_set*/
   0,                         /*tp_dictoffset*/
   0,                         /*tp_init*/
   0,                         /*tp_alloc*/
   0,                         /*tp_new*/
   0,                         /*tp_free*/
   0,                         /*tp_is_gc*/
   0,                         /*tp_bases*/
   0,                         /*tp_mro*/
   0,                         /*tp_cache*/
   0,                         /*tp_subclasses*/
   0,                         /*tp_weaklist*/
   0,                         /*tp_del*/
   0,                         /*tp_version_tag*/
};

static PyObject *
getStatsGetter(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL;
   long int index = -1;

   if (!PyArg_ParseTuple(args, "sls", &objectName, &index, &metricName))
      return NULL;

   StatsMetricBase *metric = Sim()->getStatsManager()->getMetricObject(objectName, index, metricName);

   if (!metric) {
      PyErr_SetString(PyExc_ValueError, "Stats metric not found");
      return NULL;
   }

   statsGetterObject *pGetter = PyObject_New(statsGetterObject, &statsGetterType);
   pGetter->metric = metric;

   return (PyObject *)pGetter;
}

//////////
// write(): write the current set of statistics out to sim.stats or our own file
//////////

static PyObject *
writeStats(PyObject *self, PyObject *args)
{
   const char *prefix = NULL;

   if (!PyArg_ParseTuple(args, "s", &prefix))
      return NULL;

   Sim()->getStatsManager()->recordStats(prefix);

   Py_RETURN_NONE;
}

//////////
// register(): register a callback function that returns a statistics value
//////////

static UInt64 statsCallback(String objectName, UInt32 index, String metricName, UInt64 _pFunc)
{
   PyObject *pFunc = (PyObject*)_pFunc;
   PyObject *pResult = HooksPy::callPythonFunction(pFunc, Py_BuildValue("(sls)", objectName.c_str(), index, metricName.c_str()));

   if (!PyLong_Check(pResult)) {
      fprintf(stderr, "Stats callback: return value must be (convertable into) 64-bit unsigned integer\n");
      Py_XDECREF(pResult);
      return 0;
   }

   UInt64 val = PyLong_AsLongLong(pResult);
   Py_XDECREF(pResult);

   return val;
}

static PyObject *
registerStats(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL;
   long int index = -1;
   PyObject *pFunc = NULL;

   if (!PyArg_ParseTuple(args, "slsO", &objectName, &index, &metricName, &pFunc))
      return NULL;

   if (!PyCallable_Check(pFunc)) {
      PyErr_SetString(PyExc_TypeError, "Fourth argument must be callable");
      return NULL;
   }
   Py_INCREF(pFunc);

   Sim()->getStatsManager()->registerMetric(new StatsMetricCallback(objectName, index, metricName, (StatsCallback)statsCallback, (UInt64)pFunc));

   Py_RETURN_NONE;
}

static PyObject *
registerPerThread(PyObject *self, PyObject *args)
{
   const char *objectName = NULL, *metricName = NULL, *sPerThread = NULL;

   if (!PyArg_ParseTuple(args, "sss", &sPerThread, &objectName, &metricName))
      return NULL;

   ThreadStatNamedStat::registerStat(strdup(sPerThread), objectName, metricName);

   Py_RETURN_NONE;
}

//////////
// marker(): record a marker
//////////

static PyObject *
writeMarker(PyObject *self, PyObject *args)
{
   UInt64 core_id = INVALID_CORE_ID, thread_id = INVALID_THREAD_ID, arg0 = 0, arg1 = 0;
   const char *description = NULL;

   if (!PyArg_ParseTuple(args, "llll|z", &core_id, &thread_id, &arg0, &arg1, &description))
      return NULL;

   Sim()->getStatsManager()->logMarker(Sim()->getClockSkewMinimizationServer()->getGlobalTime(), core_id, thread_id, arg0, arg1, description);

   Py_RETURN_NONE;
}

//////////
// time(): Return current global time in femtoseconds
//////////

static PyObject *
getTime(PyObject *self, PyObject *args)
{
   SubsecondTime time = Sim()->getClockSkewMinimizationServer()->getGlobalTime();
   return PyLong_FromUnsignedLongLong(time.getFS());
}

//////////
// icount(): Return current global instruction count
//////////

static PyObject *
getIcount(PyObject *self, PyObject *args)
{
   UInt64 icount = MagicServer::getGlobalInstructionCount();
   return PyLong_FromUnsignedLongLong(icount);
}

//////////
// module definition
//////////

static PyMethodDef PyStatsMethods[] = {
   {"get",  getStatsValue, METH_VARARGS, "Retrieve current value of statistic (objectName, index, metricName)."},
   {"getter", getStatsGetter, METH_VARARGS, "Return object to retrieve statistics value."},
   {"write", writeStats, METH_VARARGS, "Write statistics (<prefix>, [<filename>])."},
   {"register", registerStats, METH_VARARGS, "Register callback that defines statistics value for (objectName, index, metricName)."},
   {"register_per_thread", registerPerThread, METH_VARARGS, "Add a per-thread statistic (perthreadName) based on a named statistic (objectName, metricName)."},
   {"marker", writeMarker, METH_VARARGS, "Record a marker (coreid, threadid, arg0, arg1, [description])."},
   {"time", getTime, METH_VARARGS, "Retrieve the current global time in femtoseconds (approximate, last barrier)."},
   {"icount", getIcount, METH_VARARGS, "Retrieve current global instruction count."},
   {NULL, NULL, 0, NULL} /* Sentinel */
};

void HooksPy::PyStats::setup(void)
{
   PyObject *pModule = Py_InitModule("sim_stats", PyStatsMethods);

   statsGetterType.tp_new = PyType_GenericNew;
   if (PyType_Ready(&statsGetterType) < 0)
      return;

   Py_INCREF(&statsGetterType);
   PyModule_AddObject(pModule, "Getter", (PyObject *)&statsGetterType);
}
<|endoftext|>


<commit_before>/*
 * BKTree-LevelDB
 *
 * Copyright (c) 2016 "0of" Magnus
 * Licensed under the MIT license.
 * https://github.com/0of/bktree-leveldb/blob/master/LICENSE
 */

#include <exception>
#include <atomic>

#include "LevenshteinDistance.h"
#include "BKTree.h"

#include "TestSuite.h"

using TestSpec = LTest::SequentialTestSpec;
using Container = LTest::SequentialTestRunnableContainer;

class AssertionFailed : public std::exception {};

template<typename Spec>
void cases(Spec& spec) {
  spec.it("should query key1 & key2", []() {
    std::unique_ptr<BKTree<LevenshteinDistancePolicy>> bktree{ BKTree<LevenshteinDistancePolicy>::New("/tmp/tmpdb", "/tmp/tmpdb_i") };
    bktree->insert("key1", "value1");
    bktree->insert("key2", "value2");

    auto q = bktree->query("key1", 999, 999);

    if (q.find("value1") == q.end() || q.find("value2") == q.end())
      throw AssertionFailed{};
  });
}

int main(void) {
  auto container = std::make_unique<Container>();
  auto spec = std::make_shared<TestSpec>();

  cases(*spec);

  container->scheduleToRun(spec);
  container->start();
  std::this_thread::sleep_for(1s);

  return 0;
}<commit_msg>test cases<commit_after>/*
 * BKTree-LevelDB
 *
 * Copyright (c) 2016 "0of" Magnus
 * Licensed under the MIT license.
 * https://github.com/0of/bktree-leveldb/blob/master/LICENSE
 */

#include <exception>
#include <atomic>
#include <unordered_map>
#include <map>

#include "LevenshteinDistance.h"
#include "BKTree.h"

#include "TestSuite.h"

using TestSpec = LTest::SequentialTestSpec;
using Container = LTest::SequentialTestRunnableContainer;

class AssertionFailed : public std::exception {};

class CacheEntryContainer {
private:
  std::map<std::uint32_t, std::string> &_entry;
  std::vector<std::uint32_t>::const_iterator _it;

public:
  CacheEntryContainer(std::map<std::uint32_t, std::string> &entry, std::vector<std::uint32_t>::const_iterator begin)
  :_entry(entry)
  , _it(begin)
  {}

public:
  void emplace_back(std::string::const_iterator begin, std::string::const_iterator end) {
    _entry[*_it++] = std::string(begin, end);
  }
};

class ChildrenKeysCacheImpl : public ChildrenKeysCache {
private:
  std::unordered_map<std::string, std::map<std::uint32_t, std::string>> _cache;

public:
  bool get(const std::string& key, std::queue<std::string>& keys, const std::pair<std::uint32_t, std::uint32_t>& range) {
    auto found = _cache.find(key);
    if (found != _cache.end()) {
      // hit
      auto lowerBound = found->second.lower_bound(range.first);
      auto upperBound = found->second.upper_bound(range.second);

      for (; lowerBound != upperBound; ++lowerBound) {
        keys.push(lowerBound->second);
      }

      return true;
    }

    return false;
  }

  template<typename Callable, typename LoadAllCallable>
  void update(const std::string& key, const std::vector<std::uint32_t>& distances, Callable&& loadChildKey, LoadAllCallable&& loadAll) {
    std::map<std::uint32_t, std::string> cacheEntry;
    CacheEntryContainer container {cacheEntry, distances.begin()};

    loadAll(key, container);

    _cache[key] = std::move(cacheEntry);
  }
};

struct ChildrenKeyPolicyImpl {
  static void insert(std::string& keys, const std::string& newKey, std::uint32_t pos) {
    keys.insert(keys.cbegin() + pos * 4, newKey.cbegin(), newKey.cend());
  }

  static void split(const std::string& keys, CacheEntryContainer& splitKeys) {
    for (auto it = keys.cbegin(); it != keys.cend(); it += 4) {
      splitKeys.emplace_back(it, it + 4);
    }
  }
};

template<typename Spec>
void cases(Spec& spec) {
  spec.it("should query key1 & key2", []() {
    std::unique_ptr<BKTree<LevenshteinDistancePolicy, ChildrenKeysCacheImpl, ChildrenKeyPolicyImpl>> bktree{ BKTree<LevenshteinDistancePolicy, ChildrenKeysCacheImpl, ChildrenKeyPolicyImpl>::New("/tmp/tmpdb", "/tmp/tmpdb_i") };
    bktree->insert("key1", "value1");
    bktree->insert("key2", "value2");

    auto q = bktree->query("key1", 999, 999);

    if (q.find("value1") == q.end() || q.find("value2") == q.end())
      throw AssertionFailed{};
  });
}

int main(void) {
  auto container = std::make_unique<Container>();
  auto spec = std::make_shared<TestSpec>();

  cases(*spec);

  container->scheduleToRun(spec);
  container->start();
  std::this_thread::sleep_for(1s);

  return 0;
}<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TEST_HPP
#define TEST_HPP

#include <boost/config.hpp>
#include <exception>
#include <sstream>

#include "libtorrent/config.hpp"

#ifdef TORRENT_BUILDING_TEST_SHARED
#define EXPORT BOOST_SYMBOL_EXPORT
#else
#define EXPORT BOOST_SYMBOL_IMPORT
#endif

#if defined(_MSC_VER)
#define COUNTER_GUARD(x)
#else
#define COUNTER_GUARD(type) \
    struct BOOST_PP_CAT(type, _counter_guard) \
    { \
        ~BOOST_PP_CAT(type, _counter_guard()) \
        { \
            TEST_CHECK(counted_type<type>::count == 0); \
        } \
    } BOOST_PP_CAT(type, _guard)
#endif

#define TEST_REPORT_AUX(x, line, file) \
	report_failure(x, line, file)

#ifdef BOOST_NO_EXCEPTIONS
#define TEST_CHECK(x) \
	if (!(x)) \
		TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__);
#define TEST_EQUAL(x, y) \
	if (x != y) { \
		std::stringstream s__; \
		s__ << "TEST_EQUAL_ERROR:\n" #x ": " << x << "\nexpected: " << y << std::endl; \
		TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
	}
#else
#define TEST_CHECK(x) \
	try \
	{ \
		if (!(x)) \
			TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__); \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#define TEST_EQUAL(x, y) \
	try { \
		if (x != y) { \
			std::stringstream s__; \
			s__ << "TEST_EQUAL_ERROR: " #x ": " << x << " expected: " << y << std::endl; \
			TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
		} \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}
#endif

#define TEST_ERROR(x) \
	TEST_REPORT_AUX((std::string("ERROR: \"") + x + "\"").c_str(), __FILE__, __LINE__)

#define TEST_NOTHROW(x) \
	try \
	{ \
		x; \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#endif // TEST_HPP

<commit_msg>fix test header issue<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TEST_HPP
#define TEST_HPP

#include <boost/config.hpp>
#include <exception>
#include <sstream>

#include "libtorrent/config.hpp"

#ifdef TORRENT_BUILDING_TEST_SHARED
#define EXPORT BOOST_SYMBOL_EXPORT
#else
#define EXPORT BOOST_SYMBOL_IMPORT
#endif

void EXPORT report_failure(char const* err, char const* file, int line);

#if defined(_MSC_VER)
#define COUNTER_GUARD(x)
#else
#define COUNTER_GUARD(type) \
    struct BOOST_PP_CAT(type, _counter_guard) \
    { \
        ~BOOST_PP_CAT(type, _counter_guard()) \
        { \
            TEST_CHECK(counted_type<type>::count == 0); \
        } \
    } BOOST_PP_CAT(type, _guard)
#endif

#define TEST_REPORT_AUX(x, line, file) \
	report_failure(x, line, file)

#ifdef BOOST_NO_EXCEPTIONS
#define TEST_CHECK(x) \
	if (!(x)) \
		TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__);
#define TEST_EQUAL(x, y) \
	if (x != y) { \
		std::stringstream s__; \
		s__ << "TEST_EQUAL_ERROR:\n" #x ": " << x << "\nexpected: " << y << std::endl; \
		TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
	}
#else
#define TEST_CHECK(x) \
	try \
	{ \
		if (!(x)) \
			TEST_REPORT_AUX("TEST_CHECK failed: \"" #x "\"", __FILE__, __LINE__); \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#define TEST_EQUAL(x, y) \
	try { \
		if (x != y) { \
			std::stringstream s__; \
			s__ << "TEST_EQUAL_ERROR: " #x ": " << x << " expected: " << y << std::endl; \
			TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
		} \
	} \
	catch (std::exception& e) \
	{ \
		TEST_ERROR("Exception thrown: " #x " :" + std::string(e.what())); \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}
#endif

#define TEST_ERROR(x) \
	TEST_REPORT_AUX((std::string("ERROR: \"") + x + "\"").c_str(), __FILE__, __LINE__)

#define TEST_NOTHROW(x) \
	try \
	{ \
		x; \
	} \
	catch (...) \
	{ \
		TEST_ERROR("Exception thrown: " #x); \
	}

#endif // TEST_HPP

<|endoftext|>


<commit_before>/*!
@file
@copyright The code is licensed under the MIT License
           <http://opensource.org/licenses/MIT>,
           Copyright (c) 2015 Niels Lohmann.
@author Niels Lohmann <http://nlohmann.me>
@see https://github.com/nlohmann/fifo_map
*/

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

// allow accessing private members
#define private public

#include "fifo_map.hpp"
using nlohmann::fifo_map;

#include <string>

/// helper function to check order of keys
const auto collect_keys = [](const fifo_map<std::string, int>& m)
{
    std::string result;
    for (auto x : m)
    {
        result += x.first;
    }
    return result;
};

TEST_CASE("element access")
{
    fifo_map<std::string, int> m = {{"C", 1}, {"A", 2}, {"B", 3}};
    const fifo_map<std::string, int> mc = m;

    SECTION("at")
    {
        CHECK(m.at("C") == 1);
        CHECK(m.at("A") == 2);
        CHECK(m.at("B") == 3);

        CHECK_THROWS_AS(m.at("Z"), std::out_of_range);

        CHECK(mc.at("C") == 1);
        CHECK(mc.at("A") == 2);
        CHECK(mc.at("B") == 3);

        CHECK_THROWS_AS(mc.at("Z"), std::out_of_range);
    }

    SECTION("operator[] (rvalue)")
    {
        CHECK(m["C"] == 1);
        CHECK(m["A"] == 2);
        CHECK(m["B"] == 3);

        CHECK_NOTHROW(m["Z"]);
        CHECK(m["Z"] == 0);
    }

    SECTION("operator[] (lvalue)")
    {
        const std::string s_C = "C";
        const std::string s_A = "A";
        const std::string s_B = "B";
        const std::string s_Z = "Z";
        CHECK(m[s_C] == 1);
        CHECK(m[s_A] == 2);
        CHECK(m[s_B] == 3);

        CHECK_NOTHROW(m[s_Z]);
        CHECK(m[s_Z] == 0);
    }
}

TEST_CASE("iterators")
{
    fifo_map<std::string, int> m = {{"C", 1}, {"A", 2}, {"B", 3}};
    const fifo_map<std::string, int> mc = m;

    SECTION("begin/end with nonconst object")
    {
        fifo_map<std::string, int>::iterator it = m.begin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == m.end());
    }

    SECTION("begin/end with const object")
    {
        fifo_map<std::string, int>::const_iterator it = mc.begin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == mc.end());
    }

    SECTION("cbegin/cend with nonconst object")
    {
        fifo_map<std::string, int>::const_iterator it = m.cbegin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == m.cend());
    }

    SECTION("cbegin/cend with const object")
    {
        fifo_map<std::string, int>::const_iterator it = mc.cbegin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == mc.cend());
    }

    SECTION("begin/end with nonconst object")
    {
        fifo_map<std::string, int>::iterator it = m.begin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == m.end());
    }

    SECTION("rbegin/rend with nonconst object")
    {
        fifo_map<std::string, int>::reverse_iterator it = m.rbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == m.rend());
    }

    SECTION("rbegin/rend with const object")
    {
        fifo_map<std::string, int>::const_reverse_iterator it = mc.rbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == mc.rend());
    }

    SECTION("crbegin/crend with nonconst object")
    {
        fifo_map<std::string, int>::const_reverse_iterator it = m.crbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == m.crend());
    }

    SECTION("crbegin/crend with const object")
    {
        fifo_map<std::string, int>::const_reverse_iterator it = mc.crbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == mc.crend());
    }
}

TEST_CASE("capacity")
{
    nlohmann::fifo_map<std::string, int> m_empty;
    nlohmann::fifo_map<std::string, int> m_filled = {{"A", 1}, {"B", 2}};

    SECTION("empty")
    {
        CHECK(m_empty.empty());
        CHECK(! m_filled.empty());
    }

    SECTION("size")
    {
        CHECK(m_empty.size() == 0);
        CHECK(m_filled.size() == 2);
    }

    SECTION("max_size")
    {
        CHECK(m_empty.max_size() >= m_empty.size());
        CHECK(m_filled.max_size() >= m_filled.size());
    }
}

TEST_CASE("modifiers")
{
    nlohmann::fifo_map<std::string, int> m_empty;
    nlohmann::fifo_map<std::string, int> m_filled = {{"X", 1}, {"C", 2}};

    SECTION("clear")
    {
        CHECK(!m_filled.empty());
        CHECK(m_empty.empty());
        m_filled.clear();
        m_empty.clear();
        CHECK(m_filled.empty());
        CHECK(m_empty.empty());
    }

    SECTION("insert")
    {
        SECTION("insert value_type (lvalue)")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            const nlohmann::fifo_map<std::string, int>::value_type v1 = {"A", 3};
            auto res1 = m_filled.insert(v1);
            CHECK(m_filled["A"] == 3);
            CHECK(res1.second == true);
            CHECK(res1.first->first == "A");
            CHECK(res1.first->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            const nlohmann::fifo_map<std::string, int>::value_type v2 = {"A", 4};
            auto res2 = m_filled.insert(v2);
            CHECK(m_filled["A"] == 3);
            CHECK(res2.second == false);
            CHECK(res2.first->first == "A");
            CHECK(res2.first->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert value_type (rvalue)")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            auto res1 = m_filled.insert({"A", 3});
            CHECK(m_filled["A"] == 3);
            CHECK(res1.second == true);
            CHECK(res1.first->first == "A");
            CHECK(res1.first->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            auto res2 = m_filled.insert({"A", 4});
            CHECK(m_filled["A"] == 3);
            CHECK(res2.second == false);
            CHECK(res2.first->first == "A");
            CHECK(res2.first->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert value_type (lvalue) with hint")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            const nlohmann::fifo_map<std::string, int>::value_type v1 = {"A", 3};
            auto res1 = m_filled.insert(m_filled.end(), v1);
            CHECK(m_filled["A"] == 3);
            CHECK(res1->first == "A");
            CHECK(res1->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            const nlohmann::fifo_map<std::string, int>::value_type v2 = {"A", 4};
            auto res2 = m_filled.insert(m_filled.end(), v2);
            CHECK(m_filled["A"] == 3);
            CHECK(res2->first == "A");
            CHECK(res2->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert value_type (rvalue) with hint")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            auto res1 = m_filled.insert(m_filled.end(), {"A", 3});
            CHECK(m_filled["A"] == 3);
            CHECK(res1->first == "A");
            CHECK(res1->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            auto res2 = m_filled.insert(m_filled.end(), {"A", 4});
            CHECK(m_filled["A"] == 3);
            CHECK(res2->first == "A");
            CHECK(res2->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert initializer list")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert initializer list
            m_filled.insert({{"A", 3}, {"Z", 4}, {"B", 5}});
            CHECK(m_filled["A"] == 3);
            CHECK(m_filled["Z"] == 4);
            CHECK(m_filled["B"] == 5);

            // check that keys and values were inserted
            CHECK(m_filled.size() == 5);
            CHECK(m_filled.m_keys.size() == 5);
            CHECK(collect_keys(m_filled) == "XCAZB");

            // insert empty initializer list
            m_filled.insert({});

            // check that map remained unchanged
            CHECK(m_filled.size() == 5);
            CHECK(m_filled.m_keys.size() == 5);
            CHECK(collect_keys(m_filled) == "XCAZB");
        }

        SECTION("insert range")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert range
            std::map<std::string, int> values = {{"A", 3}, {"Z", 4}, {"B", 5}};
            m_filled.insert(values.begin(), values.end());
            CHECK(m_filled["A"] == 3);
            CHECK(m_filled["Z"] == 4);
            CHECK(m_filled["B"] == 5);

            // check that keys and values were inserted
            CHECK(m_filled.size() == 5);
            CHECK(m_filled.m_keys.size() == 5);
            CHECK(collect_keys(m_filled) == "XCABZ");
        }
    }
}
<commit_msg>more test cases<commit_after>/*!
@file
@copyright The code is licensed under the MIT License
           <http://opensource.org/licenses/MIT>,
           Copyright (c) 2015 Niels Lohmann.
@author Niels Lohmann <http://nlohmann.me>
@see https://github.com/nlohmann/fifo_map
*/

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

// allow accessing private members
#define private public

#include "fifo_map.hpp"
using nlohmann::fifo_map;

#include <string>

/// helper function to check order of keys
const auto collect_keys = [](const fifo_map<std::string, int>& m)
{
    std::string result;
    for (auto x : m)
    {
        result += x.first;
    }
    return result;
};

TEST_CASE("element access")
{
    fifo_map<std::string, int> m = {{"C", 1}, {"A", 2}, {"B", 3}};
    const fifo_map<std::string, int> mc = m;

    SECTION("at")
    {
        CHECK(m.at("C") == 1);
        CHECK(m.at("A") == 2);
        CHECK(m.at("B") == 3);

        CHECK_THROWS_AS(m.at("Z"), std::out_of_range);

        CHECK(mc.at("C") == 1);
        CHECK(mc.at("A") == 2);
        CHECK(mc.at("B") == 3);

        CHECK_THROWS_AS(mc.at("Z"), std::out_of_range);
    }

    SECTION("operator[] (rvalue)")
    {
        CHECK(m["C"] == 1);
        CHECK(m["A"] == 2);
        CHECK(m["B"] == 3);

        CHECK_NOTHROW(m["Z"]);
        CHECK(m["Z"] == 0);
    }

    SECTION("operator[] (lvalue)")
    {
        const std::string s_C = "C";
        const std::string s_A = "A";
        const std::string s_B = "B";
        const std::string s_Z = "Z";
        CHECK(m[s_C] == 1);
        CHECK(m[s_A] == 2);
        CHECK(m[s_B] == 3);

        CHECK_NOTHROW(m[s_Z]);
        CHECK(m[s_Z] == 0);
    }
}

TEST_CASE("iterators")
{
    fifo_map<std::string, int> m = {{"C", 1}, {"A", 2}, {"B", 3}};
    const fifo_map<std::string, int> mc = m;

    SECTION("begin/end with nonconst object")
    {
        fifo_map<std::string, int>::iterator it = m.begin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == m.end());
    }

    SECTION("begin/end with const object")
    {
        fifo_map<std::string, int>::const_iterator it = mc.begin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == mc.end());
    }

    SECTION("cbegin/cend with nonconst object")
    {
        fifo_map<std::string, int>::const_iterator it = m.cbegin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == m.cend());
    }

    SECTION("cbegin/cend with const object")
    {
        fifo_map<std::string, int>::const_iterator it = mc.cbegin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == mc.cend());
    }

    SECTION("begin/end with nonconst object")
    {
        fifo_map<std::string, int>::iterator it = m.begin();
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it == m.end());
    }

    SECTION("rbegin/rend with nonconst object")
    {
        fifo_map<std::string, int>::reverse_iterator it = m.rbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == m.rend());
    }

    SECTION("rbegin/rend with const object")
    {
        fifo_map<std::string, int>::const_reverse_iterator it = mc.rbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == mc.rend());
    }

    SECTION("crbegin/crend with nonconst object")
    {
        fifo_map<std::string, int>::const_reverse_iterator it = m.crbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == m.crend());
    }

    SECTION("crbegin/crend with const object")
    {
        fifo_map<std::string, int>::const_reverse_iterator it = mc.crbegin();
        CHECK(it->first == "B");
        CHECK(it->second == 3);
        ++it;
        CHECK(it->first == "A");
        CHECK(it->second == 2);
        ++it;
        CHECK(it->first == "C");
        CHECK(it->second == 1);
        ++it;
        CHECK(it == mc.crend());
    }
}

TEST_CASE("capacity")
{
    nlohmann::fifo_map<std::string, int> m_empty;
    nlohmann::fifo_map<std::string, int> m_filled = {{"A", 1}, {"B", 2}};

    SECTION("empty")
    {
        CHECK(m_empty.empty());
        CHECK(! m_filled.empty());
    }

    SECTION("size")
    {
        CHECK(m_empty.size() == 0);
        CHECK(m_filled.size() == 2);
    }

    SECTION("max_size")
    {
        CHECK(m_empty.max_size() >= m_empty.size());
        CHECK(m_filled.max_size() >= m_filled.size());
    }
}

TEST_CASE("modifiers")
{
    nlohmann::fifo_map<std::string, int> m_empty;
    nlohmann::fifo_map<std::string, int> m_filled = {{"X", 1}, {"C", 2}};

    SECTION("clear")
    {
        CHECK(!m_filled.empty());
        CHECK(m_empty.empty());
        m_filled.clear();
        m_empty.clear();
        CHECK(m_filled.empty());
        CHECK(m_empty.empty());
    }

    SECTION("insert")
    {
        SECTION("insert value_type (lvalue)")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            const nlohmann::fifo_map<std::string, int>::value_type v1 = {"A", 3};
            auto res1 = m_filled.insert(v1);
            CHECK(m_filled["A"] == 3);
            CHECK(res1.second == true);
            CHECK(res1.first->first == "A");
            CHECK(res1.first->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            const nlohmann::fifo_map<std::string, int>::value_type v2 = {"A", 4};
            auto res2 = m_filled.insert(v2);
            CHECK(m_filled["A"] == 3);
            CHECK(res2.second == false);
            CHECK(res2.first->first == "A");
            CHECK(res2.first->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert value_type (rvalue)")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            auto res1 = m_filled.insert({"A", 3});
            CHECK(m_filled["A"] == 3);
            CHECK(res1.second == true);
            CHECK(res1.first->first == "A");
            CHECK(res1.first->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            auto res2 = m_filled.insert({"A", 4});
            CHECK(m_filled["A"] == 3);
            CHECK(res2.second == false);
            CHECK(res2.first->first == "A");
            CHECK(res2.first->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert value_type (lvalue) with hint")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            const nlohmann::fifo_map<std::string, int>::value_type v1 = {"A", 3};
            auto res1 = m_filled.insert(m_filled.end(), v1);
            CHECK(m_filled["A"] == 3);
            CHECK(res1->first == "A");
            CHECK(res1->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            const nlohmann::fifo_map<std::string, int>::value_type v2 = {"A", 4};
            auto res2 = m_filled.insert(m_filled.end(), v2);
            CHECK(m_filled["A"] == 3);
            CHECK(res2->first == "A");
            CHECK(res2->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert value_type (rvalue) with hint")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert new value
            auto res1 = m_filled.insert(m_filled.end(), {"A", 3});
            CHECK(m_filled["A"] == 3);
            CHECK(res1->first == "A");
            CHECK(res1->second == 3);

            // check that key and value were inserted
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");

            // insert already present value
            auto res2 = m_filled.insert(m_filled.end(), {"A", 4});
            CHECK(m_filled["A"] == 3);
            CHECK(res2->first == "A");
            CHECK(res2->second == 3);

            // check that map remained unchanged
            CHECK(m_filled.size() == 3);
            CHECK(m_filled.m_keys.size() == 3);
            CHECK(collect_keys(m_filled) == "XCA");
        }

        SECTION("insert initializer list")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert initializer list
            m_filled.insert({{"A", 3}, {"Z", 4}, {"B", 5}});
            CHECK(m_filled["A"] == 3);
            CHECK(m_filled["Z"] == 4);
            CHECK(m_filled["B"] == 5);

            // check that keys and values were inserted
            CHECK(m_filled.size() == 5);
            CHECK(m_filled.m_keys.size() == 5);
            CHECK(collect_keys(m_filled) == "XCAZB");

            // insert empty initializer list
            m_filled.insert({});

            // check that map remained unchanged
            CHECK(m_filled.size() == 5);
            CHECK(m_filled.m_keys.size() == 5);
            CHECK(collect_keys(m_filled) == "XCAZB");
        }

        SECTION("insert range")
        {
            // check initial state
            CHECK(m_filled.size() == 2);
            CHECK(m_filled.m_keys.size() == 2);
            CHECK(collect_keys(m_filled) == "XC");

            // insert range
            std::map<std::string, int> values = {{"A", 3}, {"Z", 4}, {"B", 5}};
            m_filled.insert(values.begin(), values.end());
            CHECK(m_filled["A"] == 3);
            CHECK(m_filled["Z"] == 4);
            CHECK(m_filled["B"] == 5);

            // check that keys and values were inserted
            CHECK(m_filled.size() == 5);
            CHECK(m_filled.m_keys.size() == 5);
            CHECK(collect_keys(m_filled) == "XCABZ");
        }
    }
}

TEST_CASE("observers")
{
    nlohmann::fifo_map<std::string, int> m = {{"A", 1}, {"B", 2}};

    SECTION("key_comp")
    {
        auto comp = m.key_comp();
        CHECK(comp("A", "B"));
        CHECK(comp("A", "C"));
        CHECK(! comp("A", "A"));
        CHECK(! comp("B", "A"));
        CHECK(! comp("C", "C"));
    }
}

TEST_CASE("non-member functions")
{
    nlohmann::fifo_map<std::string, int> m1 = {{"A", 1}, {"B", 2}};
    nlohmann::fifo_map<std::string, int> m2 = {{"B", 2}, {"A", 1}};
    nlohmann::fifo_map<std::string, int> m3 = {{"A", 3}, {"B", 4}};

    SECTION("comparison")
    {
        CHECK(m1 == m1);

        CHECK(m1 != m2);
        CHECK(m1 != m3);

        CHECK(m1 < m3);
        CHECK(m1 <= m3);

        CHECK(m3 > m1);
        CHECK(m3 >= m1);
    }
}
<|endoftext|>


<commit_before>#include "lineup_node.h"

using namespace liven;

void lineup_node::set_lineup(unique_sequence<std::shared_ptr<node>> lineup_) {
	for (auto node : lineup) {remove_child(node);}
	lineup = lineup_;
	for (auto node : lineup) {add_child(node);}
	update_locations();
}

void lineup_node::insert(lineup_node::iterator pos,std::shared_ptr<node> n) {
	lineup.insert(pos,n);
	add_child(n);
	update_locations();
}

void lineup_node::erase(lineup_node::iterator pos) {
	remove_child(*pos);
	lineup.erase(pos);
	update_locations();
}

void lineup_node::remove(std::shared_ptr<node> n) {
	auto it = std::find(lineup.begin(),lineup.end(),n);
	if (it != lineup.end()) {
		erase(it);
		remove_child(*it);
	}
}

void lineup_node::push_back(std::shared_ptr<node> n) {
	insert(end(),n);
}

void lineup_node::pop_back() {
	lineup.pop_back();
}

void lineup_node::update_locations() {
	auto it = lineup.begin();
	auto end = lineup.end();
	point<3> current_location = point<3>(0,0,0);
	while (it != end) {
		(*it)->set_location(current_location);
		int new_coord = current_location.get_coordinate(dim) + (*it)->bounding_rect().get_size(dim);
		current_location.set_coordinate(dim, new_coord);
		++it;
	}
}<commit_msg>use own_bounding_rect for updating locations<commit_after>#include "lineup_node.h"

using namespace liven;

void lineup_node::set_lineup(unique_sequence<std::shared_ptr<node>> lineup_) {
	for (auto node : lineup) {remove_child(node);}
	lineup = lineup_;
	for (auto node : lineup) {add_child(node);}
	update_locations();
}

void lineup_node::insert(lineup_node::iterator pos,std::shared_ptr<node> n) {
	lineup.insert(pos,n);
	add_child(n);
	update_locations();
}

void lineup_node::erase(lineup_node::iterator pos) {
	remove_child(*pos);
	lineup.erase(pos);
	update_locations();
}

void lineup_node::remove(std::shared_ptr<node> n) {
	auto it = std::find(lineup.begin(),lineup.end(),n);
	if (it != lineup.end()) {
		erase(it);
		remove_child(*it);
	}
}

void lineup_node::push_back(std::shared_ptr<node> n) {
	insert(end(),n);
}

void lineup_node::pop_back() {
	lineup.pop_back();
}

void lineup_node::update_locations() {
	auto it = lineup.begin();
	auto end = lineup.end();
	point<3> current_location = point<3>(0,0,0);
	while (it != end) {
		(*it)->set_location(current_location);
		int new_coord = current_location.get_coordinate(dim) + (*it)->own_bounding_rect().get_size(dim);
		current_location.set_coordinate(dim, new_coord);
		++it;
	}
}<|endoftext|>