<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2013 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 * #L%
 */
#include "joynr/PrivateCopyAssign.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "joynr/MessageRouter.h"
#include "tests/utils/MockObjects.h"
#include "joynr/system/RoutingTypes/ChannelAddress.h"
#include "joynr/MessagingStubFactory.h"
#include "joynr/MessageQueue.h"
#include "libjoynr/in-process/InProcessMessagingStubFactory.h"
#include <chrono>
#include <cstdint>

using namespace joynr;

class MessageRouterTest : public ::testing::Test {
public:
    MessageRouterTest() :
        settingsFileName("MessageRouterTest.settings"),
        settings(settingsFileName),
        messagingSettings(settings),
        messagingStubFactory(new MockMessagingStubFactory()),
        messageQueue(new MessageQueue()),
        messageRouter(new MessageRouter(new MessagingStubFactory(), nullptr, 6, messageQueue)),
        joynrMessage()
    {
        // provision global capabilities directory
        std::shared_ptr<joynr::system::RoutingTypes::Address> addressCapabilitiesDirectory(
            new system::RoutingTypes::ChannelAddress(
                        messagingSettings.getCapabilitiesDirectoryChannelId())
        );
        messageRouter->addProvisionedNextHop(messagingSettings.getCapabilitiesDirectoryParticipantId(), addressCapabilitiesDirectory);
        // provision channel url directory
        std::shared_ptr<joynr::system::RoutingTypes::Address> addressChannelUrlDirectory(
            new system::RoutingTypes::ChannelAddress(
                        messagingSettings.getChannelUrlDirectoryChannelId())
        );
        messageRouter->addProvisionedNextHop(messagingSettings.getChannelUrlDirectoryParticipantId(), addressChannelUrlDirectory);
        JoynrTimePoint now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
        joynrMessage.setHeaderExpiryDate(now + std::chrono::milliseconds(100));
    }

    ~MessageRouterTest() {
        std::remove(settingsFileName.c_str());
    }

    void SetUp(){
        joynrMessage.setType(JoynrMessage::VALUE_MESSAGE_TYPE_ONE_WAY);
    }
    void TearDown(){
    }
protected:
    std::string settingsFileName;
    Settings settings;
    MessagingSettings messagingSettings;
    MockMessagingStubFactory* messagingStubFactory;
    MessageQueue* messageQueue;
    MessageRouter* messageRouter;
    JoynrMessage joynrMessage;
private:
    DISALLOW_COPY_AND_ASSIGN(MessageRouterTest);
};

TEST_F(MessageRouterTest, DISABLED_routeDelegatesToStubFactory){
    // cH: this thest doesn't make sense anymore, since the MessageRouter
    // will create the MessagingStubFactory internally and therefor couldn't
    // be mocked. However, this test was already disabled.
    EXPECT_CALL(*messagingStubFactory, create(_)).Times(1);

    messageRouter->route(joynrMessage);

}

TEST_F(MessageRouterTest, addMessageToQueue){
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 2);
}

TEST_F(MessageRouterTest, doNotAddMessageToQueue){
    // this message should be added because no destination header set
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // the message now has a known destination and should be directly routed
    joynrMessage.setHeaderTo(messagingSettings.getCapabilitiesDirectoryParticipantId());
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);
}

TEST_F(MessageRouterTest, resendMessageWhenDestinationAddressIsAdded){
    // this message should be added because no destination header set
    joynrMessage.setHeaderTo("TEST");
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // add destination address -> message should be routed
    std::shared_ptr<system::RoutingTypes::ChannelAddress> address(new system::RoutingTypes::ChannelAddress("TEST"));
    messageRouter->addNextHop("TEST", address);
    EXPECT_EQ(messageQueue->getQueueLength(), 0);
}

TEST_F(MessageRouterTest, outdatedMessagesAreRemoved){
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // we wait for the time out (500ms) and the thread sleep (1000ms)
    std::this_thread::sleep_for(std::chrono::milliseconds(1200));
    EXPECT_EQ(messageQueue->getQueueLength(), 0);
}
<commit_msg>[C++,Test] Mqtt unit tests MessageRouter<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2016 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 * #L%
 */
#include "joynr/PrivateCopyAssign.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "joynr/MessageRouter.h"
#include "tests/utils/MockObjects.h"
#include "joynr/system/RoutingTypes/ChannelAddress.h"
#include "joynr/MessagingStubFactory.h"
#include "joynr/MessageQueue.h"
#include "libjoynr/in-process/InProcessMessagingStubFactory.h"
#include <chrono>
#include <cstdint>

using ::testing::AllOf;
using ::testing::Property;
using ::testing::Return;
using ::testing::WhenDynamicCastTo;
using namespace joynr;

class MessageRouterTest : public ::testing::Test {
public:
    MessageRouterTest() :
        settings(),
        messagingSettings(settings),
        messagingStubFactory(new MockMessagingStubFactory()),
        messageQueue(new MessageQueue()),
        messageRouter(new MessageRouter(messagingStubFactory, nullptr, 6, messageQueue)),
        joynrMessage()
    {
        // provision global capabilities directory
        std::shared_ptr<joynr::system::RoutingTypes::Address> addressCapabilitiesDirectory(
            new system::RoutingTypes::ChannelAddress(
                        messagingSettings.getCapabilitiesDirectoryChannelId())
        );
        messageRouter->addProvisionedNextHop(messagingSettings.getCapabilitiesDirectoryParticipantId(), addressCapabilitiesDirectory);
        // provision channel url directory
        std::shared_ptr<joynr::system::RoutingTypes::Address> addressChannelUrlDirectory(
            new system::RoutingTypes::ChannelAddress(
                        messagingSettings.getChannelUrlDirectoryChannelId())
        );
        messageRouter->addProvisionedNextHop(messagingSettings.getChannelUrlDirectoryParticipantId(), addressChannelUrlDirectory);
        JoynrTimePoint now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
        joynrMessage.setHeaderExpiryDate(now + std::chrono::milliseconds(100));
    }

    ~MessageRouterTest() {
        std::remove(settingsFileName.c_str());
        delete messagingStubFactory;
    }

    void SetUp(){
        joynrMessage.setType(JoynrMessage::VALUE_MESSAGE_TYPE_ONE_WAY);
    }
    void TearDown(){
    }
protected:
    std::string settingsFileName;
    Settings settings;
    MessagingSettings messagingSettings;
    MockMessagingStubFactory* messagingStubFactory;
    MessageQueue* messageQueue;
    MessageRouter* messageRouter;
    JoynrMessage joynrMessage;
    void routeMessageToAddress(
            const std::string& destinationParticipantId,
            std::shared_ptr<system::RoutingTypes::Address> address);
private:
    DISALLOW_COPY_AND_ASSIGN(MessageRouterTest);
};

TEST_F(MessageRouterTest, DISABLED_routeDelegatesToStubFactory){
    // cH: this thest doesn't make sense anymore, since the MessageRouter
    // will create the MessagingStubFactory internally and therefor couldn't
    // be mocked. However, this test was already disabled.
    EXPECT_CALL(*messagingStubFactory, create(_)).Times(1);

    messageRouter->route(joynrMessage);

}

TEST_F(MessageRouterTest, addMessageToQueue){
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 2);
}

TEST_F(MessageRouterTest, doNotAddMessageToQueue){
    const std::string testHttp = "TEST_HTTP";
    const std::string testMqtt = "TEST_MQTT";
    // this message should be added because no destination header set
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // add destination address -> message should be routed
    auto httpAddress = std::make_shared<system::RoutingTypes::ChannelAddress>(testHttp);
    messageRouter->addNextHop(testHttp, httpAddress);
    // the message now has a known destination and should be directly routed
    joynrMessage.setHeaderTo(testHttp);
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // add destination address -> message should be routed
    auto mqttAddress = std::make_shared<system::RoutingTypes::MqttAddress>(testMqtt);
    messageRouter->addNextHop(testMqtt, mqttAddress);
    // the message now has a known destination and should be directly routed
    joynrMessage.setHeaderTo(testMqtt);
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);
}

TEST_F(MessageRouterTest, resendMessageWhenDestinationAddressIsAdded){
    const std::string testHttp = "TEST_HTTP";
    const std::string testMqtt = "TEST_MQTT";
    // this message should be added because destination is unknown
    joynrMessage.setHeaderTo(testHttp);
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // add destination address -> message should be routed
    auto httpAddress = std::make_shared<system::RoutingTypes::ChannelAddress>(testHttp);
    messageRouter->addNextHop(testHttp, httpAddress);
    EXPECT_EQ(messageQueue->getQueueLength(), 0);

    joynrMessage.setHeaderTo(testMqtt);
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    auto mqttAddress = std::make_shared<system::RoutingTypes::MqttAddress>(testMqtt);
    messageRouter->addNextHop(testMqtt, mqttAddress);
    EXPECT_EQ(messageQueue->getQueueLength(), 0);
}

TEST_F(MessageRouterTest, outdatedMessagesAreRemoved){
    messageRouter->route(joynrMessage);
    EXPECT_EQ(messageQueue->getQueueLength(), 1);

    // we wait for the time out (500ms) and the thread sleep (1000ms)
    std::this_thread::sleep_for(std::chrono::milliseconds(1200));
    EXPECT_EQ(messageQueue->getQueueLength(), 0);
}

void MessageRouterTest::routeMessageToAddress(
        const std::string& destinationParticipantId,
        std::shared_ptr<system::RoutingTypes::Address> address) {
    messageRouter->addNextHop(destinationParticipantId, address);
    joynrMessage.setHeaderTo(destinationParticipantId);
    ON_CALL(*messagingStubFactory, create(_)).WillByDefault(Return(nullptr));
    messageRouter->route(joynrMessage);
}

TEST_F(MessageRouterTest, routeMessageToHttpAddress) {
    const std::string destinationParticipantId = "TEST_routeMessageToHttpAddress";
    const std::string destinationChannelId = "TEST_routeMessageToHttpAddress_channelId";
    auto address = std::make_shared<system::RoutingTypes::ChannelAddress>(destinationChannelId);
    EXPECT_CALL(*messagingStubFactory,
            create(AllOf(
                    A<const joynr::system::RoutingTypes::Address&>(),
                    WhenDynamicCastTo<const system::RoutingTypes::ChannelAddress&>(
                            Property(&system::RoutingTypes::ChannelAddress::getChannelId, Eq(destinationChannelId))
                            )
                    ))
            ).Times(1);
    routeMessageToAddress(destinationParticipantId, address);
}

TEST_F(MessageRouterTest, routeMessageToMqttAddress) {
    const std::string destinationParticipantId = "TEST_routeMessageToMqttAddress";
    const std::string destinationChannelId = "TEST_routeMessageToMqttAddress_channelId";
    auto address = std::make_shared<system::RoutingTypes::MqttAddress>(destinationChannelId);
    EXPECT_CALL(*messagingStubFactory,
            create(AllOf(
                    A<const joynr::system::RoutingTypes::Address&>(),
                    WhenDynamicCastTo<const system::RoutingTypes::MqttAddress&>(
                            Property(&system::RoutingTypes::MqttAddress::getChannelId, Eq(destinationChannelId))
                            )
                    ))
            ).Times(1);
    routeMessageToAddress(destinationParticipantId, address);
}
<|endoftext|>


<commit_before>#include "acmacs-base/argv.hh"
// #include "acmacs-base/range-v3.hh"
#include "acmacs-base/enumerate.hh"
#include "acmacs-base/string-join.hh"
#include "acmacs-chart-2/factory-import.hh"
#include "acmacs-chart-2/chart.hh"
#include "hidb-5/hidb-set.hh"
#include "hidb-5/hidb.hh"
#include "acmacs-whocc/log.hh"

// ----------------------------------------------------------------------

using namespace acmacs::argv;
struct Options : public argv
{
    Options(int a_argc, const char* const a_argv[], on_error on_err = on_error::exit) : argv() { parse(a_argc, a_argv, on_err); }

    option<str_array> verbose{*this, 'v', "verbose", desc{"comma separated list (or multiple switches) of log enablers"}};

    argument<str_array> tables{*this, arg_name{".ace"}, mandatory};
};

int main(int argc, char* const argv[])
{
    using namespace std::string_view_literals;
    int exit_code = 0;
    try {
        Options opt(argc, argv);
        acmacs::log::enable(opt.verbose);

        const auto show_matches = [](const auto& hidb, const auto& hidb_ag_sr, size_t no, const auto& ag_sr) {
            const auto make_field = [](const auto& value, const auto& to_compare) {
                if (!value.empty() && value == to_compare)
                    return fmt::format("<{}>", value);
                else
                    return fmt::format("{}", value);
            };

            constexpr auto is_antigen = std::is_same_v<std::decay_t<decltype(ag_sr)>, acmacs::chart::Antigen>;
            const auto full_name = ag_sr.full_name();
            const auto reassortant = ag_sr.reassortant();
            const auto annotations = acmacs::string::join(acmacs::string::join_space, ag_sr.annotations());

            std::vector<std::pair<std::string, fmt::memory_buffer>> hidb_variants;
            bool full_name_match_present{false};
            for (const auto& [hidb_antigen, hidb_index] : hidb_ag_sr) {
                const auto hidb_full_name = hidb_antigen->full_name();
                full_name_match_present |= hidb_full_name == full_name;
                auto& variant = hidb_variants.emplace_back(hidb_full_name, fmt::memory_buffer{});
                // mark matching matching annotations, reassortant, passage, serum_id
                if constexpr (is_antigen)
                    fmt::format_to(variant.second, "{}",
                                   acmacs::string::join(acmacs::string::join_space,
                                                        /* hidb_antigen->name(), */ make_field(acmacs::string::join(acmacs::string::join_space, hidb_antigen->annotations()), annotations),
                                                        make_field(hidb_antigen->reassortant(), reassortant), make_field(hidb_antigen->passage(), ag_sr.passage())));
                else
                    fmt::format_to(variant.second, "{}",
                                   acmacs::string::join(acmacs::string::join_space,
                                                        /* hidb_antigen->name(), */ make_field(acmacs::string::join(acmacs::string::join_space, hidb_antigen->annotations()), annotations),
                                                        make_field(hidb_antigen->reassortant(), reassortant), make_field(hidb_antigen->serum_id(), ag_sr.serum_id())));
                // fmt::format_to(variant.second, "        {{{}}}\n", hidb_full_name);
                fmt::format_to(variant.second, "\n");
                const auto by_lab_assay = hidb.tables(*hidb_antigen, hidb::lab_assay_rbc_table_t::recent_first);
                for (auto entry : by_lab_assay) {
                    fmt::format_to(variant.second, "        {{{} {}}} ({})", entry.lab, acmacs::chart::assay_rbc_short(entry.assay, entry.rbc), entry.tables.size());
                    for (auto table : entry.tables)
                        fmt::format_to(variant.second, " {}", table->date());
                    fmt::format_to(variant.second, "\n");
                }
            }
            std::sort(std::begin(hidb_variants), std::end(hidb_variants), [&full_name](const auto& e1, const auto& e2) {
                const auto f1 = e1.first == full_name, f2 = e2.first == full_name;
                if (f1 && !f2)
                    return true;
                else if (!f1 && f2)
                    return false;
                else
                    return e1.first < e2.first;
            });
            // if (!full_name_match_present) {
            //     const auto new_var = hidb_variants.emplace(hidb_variants.begin(), "*** New ***", fmt::memory_buffer{});
            //     fmt::format_to(new_var->second, "*** New ***\n");
            // }

            fmt::print("{} {} {:3d} {}\n", full_name_match_present ? '+' : '-', is_antigen ? "AG" : "SR", no, full_name);
            for (const auto& variant : hidb_variants) {
                // if (full_name_match_present) {
                //     fmt::print("  + ");
                //     full_name_match_present = false;
                // }
                // else
                    fmt::print("    ");
                fmt::print("{}", fmt::to_string(variant.second));
            }
        };

        fmt::print("# -*- Mode: eu-whocc-check-new-tables; -*-\n\n");
        for (const auto& filename : *opt.tables) {
            auto chart = acmacs::chart::import_from_file(filename);
            fmt::print(">> {}\n\n", chart->make_name());
            const auto& hidb = hidb::get(chart->info()->virus_type(acmacs::chart::Info::Compute::Yes));
            auto tables = hidb.tables();

            auto antigens = chart->antigens();
            for (auto [ag_no, antigen] : acmacs::enumerate(*antigens)) {
                if (!antigen->distinct()) {
                    const auto hidb_antigens = hidb.antigens()->find(antigen->name(), hidb::fix_location::no);
                    if (!hidb_antigens.empty())
                        show_matches(hidb, hidb_antigens, ag_no, *antigen);
                    fmt::print("\n");
                }
            }
            fmt::print("\n");

            auto sera = chart->sera();
            for (auto [sr_no, serum] : acmacs::enumerate(*sera)) {
                const auto hidb_sera = hidb.sera()->find(serum->name(), hidb::fix_location::no);
                // if (!hidb_sera.empty())
                show_matches(hidb, hidb_sera, sr_no, *serum);
                fmt::print("\n");
            }
            fmt::print("\n\n");
            fmt::print("> ====================================================================================================\n\n");
        }
    }
    catch (std::exception& err) {
        AD_ERROR("{}", err);
        exit_code = 2;
    }
    return exit_code;
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>hidb API refactored<commit_after>#include "acmacs-base/argv.hh"
// #include "acmacs-base/range-v3.hh"
#include "acmacs-base/enumerate.hh"
#include "acmacs-base/string-join.hh"
#include "acmacs-chart-2/factory-import.hh"
#include "acmacs-chart-2/chart.hh"
#include "hidb-5/hidb-set.hh"
#include "hidb-5/hidb.hh"
#include "acmacs-whocc/log.hh"

// ----------------------------------------------------------------------

using namespace acmacs::argv;
struct Options : public argv
{
    Options(int a_argc, const char* const a_argv[], on_error on_err = on_error::exit) : argv() { parse(a_argc, a_argv, on_err); }

    option<str_array> verbose{*this, 'v', "verbose", desc{"comma separated list (or multiple switches) of log enablers"}};

    argument<str_array> tables{*this, arg_name{".ace"}, mandatory};
};

int main(int argc, char* const argv[])
{
    using namespace std::string_view_literals;
    int exit_code = 0;
    try {
        Options opt(argc, argv);
        acmacs::log::enable(opt.verbose);

        const auto show_matches = [](const auto& hidb, const auto& hidb_ag_sr, const auto& found_ag_sr, size_t no, const auto& ag_sr) {
            const auto make_field = [](const auto& value, const auto& to_compare) {
                if (!value.empty() && value == to_compare)
                    return fmt::format("<{}>", value);
                else
                    return fmt::format("{}", value);
            };

            constexpr auto is_antigen = std::is_same_v<std::decay_t<decltype(ag_sr)>, acmacs::chart::Antigen>;
            const auto full_name = ag_sr.full_name();
            const auto reassortant = ag_sr.reassortant();
            const auto annotations = acmacs::string::join(acmacs::string::join_space, ag_sr.annotations());

            std::vector<std::pair<std::string, fmt::memory_buffer>> hidb_variants;
            bool full_name_match_present{false};
            for (const auto hidb_index : found_ag_sr) {
                auto hidb_antigen = hidb_ag_sr.at(hidb_index);
                const auto hidb_full_name = hidb_antigen->full_name();
                full_name_match_present |= hidb_full_name == full_name;
                auto& variant = hidb_variants.emplace_back(hidb_full_name, fmt::memory_buffer{});
                // mark matching matching annotations, reassortant, passage, serum_id
                if constexpr (is_antigen)
                    fmt::format_to(variant.second, "{}",
                                   acmacs::string::join(acmacs::string::join_space,
                                                        /* hidb_antigen->name(), */ make_field(acmacs::string::join(acmacs::string::join_space, hidb_antigen->annotations()), annotations),
                                                        make_field(hidb_antigen->reassortant(), reassortant), make_field(hidb_antigen->passage(), ag_sr.passage())));
                else
                    fmt::format_to(variant.second, "{}",
                                   acmacs::string::join(acmacs::string::join_space,
                                                        /* hidb_antigen->name(), */ make_field(acmacs::string::join(acmacs::string::join_space, hidb_antigen->annotations()), annotations),
                                                        make_field(hidb_antigen->reassortant(), reassortant), make_field(hidb_antigen->serum_id(), ag_sr.serum_id())));
                // fmt::format_to(variant.second, "        {{{}}}\n", hidb_full_name);
                fmt::format_to(variant.second, "\n");
                const auto by_lab_assay = hidb.tables(*hidb_antigen, hidb::lab_assay_rbc_table_t::recent_first);
                for (auto entry : by_lab_assay) {
                    fmt::format_to(variant.second, "        {{{} {}}} ({})", entry.lab, acmacs::chart::assay_rbc_short(entry.assay, entry.rbc), entry.tables.size());
                    for (auto table : entry.tables)
                        fmt::format_to(variant.second, " {}", table->date());
                    fmt::format_to(variant.second, "\n");
                }
            }
            std::sort(std::begin(hidb_variants), std::end(hidb_variants), [&full_name](const auto& e1, const auto& e2) {
                const auto f1 = e1.first == full_name, f2 = e2.first == full_name;
                if (f1 && !f2)
                    return true;
                else if (!f1 && f2)
                    return false;
                else
                    return e1.first < e2.first;
            });
            // if (!full_name_match_present) {
            //     const auto new_var = hidb_variants.emplace(hidb_variants.begin(), "*** New ***", fmt::memory_buffer{});
            //     fmt::format_to(new_var->second, "*** New ***\n");
            // }

            fmt::print("{} {} {:3d} {}\n", full_name_match_present ? '+' : '-', is_antigen ? "AG" : "SR", no, full_name);
            for (const auto& variant : hidb_variants) {
                // if (full_name_match_present) {
                //     fmt::print("  + ");
                //     full_name_match_present = false;
                // }
                // else
                    fmt::print("    ");
                fmt::print("{}", fmt::to_string(variant.second));
            }
        };

        fmt::print("# -*- Mode: eu-whocc-check-new-tables; -*-\n\n");
        for (const auto& filename : *opt.tables) {
            auto chart = acmacs::chart::import_from_file(filename);
            fmt::print(">> {}\n\n", chart->make_name());
            const auto& hidb = hidb::get(chart->info()->virus_type(acmacs::chart::Info::Compute::Yes));
            auto tables = hidb.tables();

            auto antigens = chart->antigens();
            for (auto [ag_no, antigen] : acmacs::enumerate(*antigens)) {
                if (!antigen->distinct()) {
                    const auto hidb_antigens = hidb.antigens()->find(antigen->name(), hidb::fix_location::no);
                    if (!hidb_antigens.empty())
                        show_matches(hidb, *hidb.antigens(), hidb_antigens, ag_no, *antigen);
                    fmt::print("\n");
                }
            }
            fmt::print("\n");

            auto sera = chart->sera();
            for (auto [sr_no, serum] : acmacs::enumerate(*sera)) {
                const auto hidb_sera = hidb.sera()->find(serum->name(), hidb::fix_location::no);
                // if (!hidb_sera.empty())
                show_matches(hidb, *hidb.sera(), hidb_sera, sr_no, *serum);
                fmt::print("\n");
            }
            fmt::print("\n\n");
            fmt::print("> ====================================================================================================\n\n");
        }
    }
    catch (std::exception& err) {
        AD_ERROR("{}", err);
        exit_code = 2;
    }
    return exit_code;
}

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <stan/agrad/fvar.hpp>
#include <stan/agrad/var.hpp>
#include <test/agrad/util.hpp>

TEST(Agrad_Fwd_Atan,Fvar) {
  using stan::agrad::fvar;
  using std::atan;

  fvar<double> x(0.5,1.0);

  fvar<double> a = atan(x);
  EXPECT_FLOAT_EQ(atan(0.5), a.val_);
  EXPECT_FLOAT_EQ(1 / (1 + 0.5 * 0.5), a.d_);

  fvar<double> b = 2 * atan(x) + 4;
  EXPECT_FLOAT_EQ(2 * atan(0.5) + 4, b.val_);
  EXPECT_FLOAT_EQ(2 / (1 + 0.5 * 0.5), b.d_);

  fvar<double> c = -atan(x) + 5;
  EXPECT_FLOAT_EQ(-atan(0.5) + 5, c.val_);
  EXPECT_FLOAT_EQ(-1 / (1 + 0.5 * 0.5), c.d_);

  fvar<double> d = -3 * atan(x) + 5 * x;
  EXPECT_FLOAT_EQ(-3 * atan(0.5) + 5 * 0.5, d.val_);
  EXPECT_FLOAT_EQ(-3 / (1 + 0.5 * 0.5) + 5, d.d_);
}

TEST(Agrad_Fwd_Atan,FvarVar_1stDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<var> x(1.5,1.3);
  fvar<var> a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val());
  EXPECT_FLOAT_EQ(1.3 / (1.0 + 1.5 * 1.5), a.d_.val());

  AVEC y = createAVEC(x.val_);
  VEC g;
  a.val_.grad(y,g);
  EXPECT_FLOAT_EQ(1.0 / (1.0 + 1.5 * 1.5), g[0]);
}

TEST(Agrad_Fwd_Atan,FvarVar_2ndDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<var> x(1.5,1.3);
  fvar<var> a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val());
  EXPECT_FLOAT_EQ(1.3 / (1.0 + 1.5 * 1.5), a.d_.val());

  AVEC y = createAVEC(x.val_);
  VEC g;
  a.d_.grad(y,g);
  EXPECT_FLOAT_EQ(1.3 * -0.28402368, g[0]);
}

TEST(Agrad_Fwd_Atan,FvarFvarDouble) {
  using stan::agrad::fvar;
  using std::atan;

  fvar<fvar<double> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 2.0;

  fvar<fvar<double> > a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_);
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.val_.d_);
  EXPECT_FLOAT_EQ(0, a.d_.val_);
  EXPECT_FLOAT_EQ(0, a.d_.d_);

  fvar<fvar<double> > y;
  y.val_.val_ = 1.5;
  y.d_.val_ = 2.0;

  a = atan(y);
  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_);
  EXPECT_FLOAT_EQ(0, a.val_.d_);
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.d_.val_);
  EXPECT_FLOAT_EQ(0, a.d_.d_);
}

TEST(Agrad_Fwd_Atan,FvarFvarVar_1stDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<fvar<var> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 2.0;

  fvar<fvar<var> > a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.val_.d_.val());
  EXPECT_FLOAT_EQ(0, a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC p = createAVEC(x.val_.val_);
  VEC g;
  a.val_.val_.grad(p,g);
  EXPECT_FLOAT_EQ(1.0 / (1.0 + 1.5 * 1.5), g[0]);

  fvar<fvar<var> > y;
  y.val_.val_ = 1.5;
  y.d_.val_ = 2.0;

  fvar<fvar<var> > b = atan(y);
  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(0, a.val_.d_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC q = createAVEC(y.val_.val_);
  VEC r;
  b.val_.val_.grad(q,r);
  EXPECT_FLOAT_EQ(1.0 / (1.0 + 1.5 * 1.5), r[0]);
}

TEST(Agrad_Fwd_Atan,FvarFvarVar_2ndDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<fvar<var> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 2.0;

  fvar<fvar<var> > a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.val_.d_.val());
  EXPECT_FLOAT_EQ(0, a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC p = createAVEC(x.val_.val_);
  VEC g;
  a.val_.d_.grad(p,g);
  EXPECT_FLOAT_EQ(2.0 * -0.28402368, g[0]);

  fvar<fvar<var> > y;
  y.val_.val_ = 1.5;
  y.d_.val_ = 2.0;

  fvar<fvar<var> > b = atan(y);
  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(0, a.val_.d_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC q = createAVEC(y.val_.val_);
  VEC r;
  b.d_.val_.grad(q,r);
  EXPECT_FLOAT_EQ(2.0 * -0.28402368, r[0]);
}
Deriv
<commit_msg>removed typo<commit_after>#include <gtest/gtest.h>
#include <stan/agrad/fvar.hpp>
#include <stan/agrad/var.hpp>
#include <test/agrad/util.hpp>

TEST(Agrad_Fwd_Atan,Fvar) {
  using stan::agrad::fvar;
  using std::atan;

  fvar<double> x(0.5,1.0);

  fvar<double> a = atan(x);
  EXPECT_FLOAT_EQ(atan(0.5), a.val_);
  EXPECT_FLOAT_EQ(1 / (1 + 0.5 * 0.5), a.d_);

  fvar<double> b = 2 * atan(x) + 4;
  EXPECT_FLOAT_EQ(2 * atan(0.5) + 4, b.val_);
  EXPECT_FLOAT_EQ(2 / (1 + 0.5 * 0.5), b.d_);

  fvar<double> c = -atan(x) + 5;
  EXPECT_FLOAT_EQ(-atan(0.5) + 5, c.val_);
  EXPECT_FLOAT_EQ(-1 / (1 + 0.5 * 0.5), c.d_);

  fvar<double> d = -3 * atan(x) + 5 * x;
  EXPECT_FLOAT_EQ(-3 * atan(0.5) + 5 * 0.5, d.val_);
  EXPECT_FLOAT_EQ(-3 / (1 + 0.5 * 0.5) + 5, d.d_);
}

TEST(Agrad_Fwd_Atan,FvarVar_1stDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<var> x(1.5,1.3);
  fvar<var> a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val());
  EXPECT_FLOAT_EQ(1.3 / (1.0 + 1.5 * 1.5), a.d_.val());

  AVEC y = createAVEC(x.val_);
  VEC g;
  a.val_.grad(y,g);
  EXPECT_FLOAT_EQ(1.0 / (1.0 + 1.5 * 1.5), g[0]);
}

TEST(Agrad_Fwd_Atan,FvarVar_2ndDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<var> x(1.5,1.3);
  fvar<var> a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val());
  EXPECT_FLOAT_EQ(1.3 / (1.0 + 1.5 * 1.5), a.d_.val());

  AVEC y = createAVEC(x.val_);
  VEC g;
  a.d_.grad(y,g);
  EXPECT_FLOAT_EQ(1.3 * -0.28402368, g[0]);
}

TEST(Agrad_Fwd_Atan,FvarFvarDouble) {
  using stan::agrad::fvar;
  using std::atan;

  fvar<fvar<double> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 2.0;

  fvar<fvar<double> > a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_);
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.val_.d_);
  EXPECT_FLOAT_EQ(0, a.d_.val_);
  EXPECT_FLOAT_EQ(0, a.d_.d_);

  fvar<fvar<double> > y;
  y.val_.val_ = 1.5;
  y.d_.val_ = 2.0;

  a = atan(y);
  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_);
  EXPECT_FLOAT_EQ(0, a.val_.d_);
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.d_.val_);
  EXPECT_FLOAT_EQ(0, a.d_.d_);
}

TEST(Agrad_Fwd_Atan,FvarFvarVar_1stDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<fvar<var> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 2.0;

  fvar<fvar<var> > a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.val_.d_.val());
  EXPECT_FLOAT_EQ(0, a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC p = createAVEC(x.val_.val_);
  VEC g;
  a.val_.val_.grad(p,g);
  EXPECT_FLOAT_EQ(1.0 / (1.0 + 1.5 * 1.5), g[0]);

  fvar<fvar<var> > y;
  y.val_.val_ = 1.5;
  y.d_.val_ = 2.0;

  fvar<fvar<var> > b = atan(y);
  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(0, a.val_.d_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC q = createAVEC(y.val_.val_);
  VEC r;
  b.val_.val_.grad(q,r);
  EXPECT_FLOAT_EQ(1.0 / (1.0 + 1.5 * 1.5), r[0]);
}

TEST(Agrad_Fwd_Atan,FvarFvarVar_2ndDeriv) {
  using stan::agrad::fvar;
  using stan::agrad::var;
  using std::atan;

  fvar<fvar<var> > x;
  x.val_.val_ = 1.5;
  x.val_.d_ = 2.0;

  fvar<fvar<var> > a = atan(x);

  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.val_.d_.val());
  EXPECT_FLOAT_EQ(0, a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC p = createAVEC(x.val_.val_);
  VEC g;
  a.val_.d_.grad(p,g);
  EXPECT_FLOAT_EQ(2.0 * -0.28402368, g[0]);

  fvar<fvar<var> > y;
  y.val_.val_ = 1.5;
  y.d_.val_ = 2.0;

  fvar<fvar<var> > b = atan(y);
  EXPECT_FLOAT_EQ(atan(1.5), a.val_.val_.val());
  EXPECT_FLOAT_EQ(0, a.val_.d_.val());
  EXPECT_FLOAT_EQ(2.0 / (1.0 + 1.5 * 1.5), a.d_.val_.val());
  EXPECT_FLOAT_EQ(0, a.d_.d_.val());

  AVEC q = createAVEC(y.val_.val_);
  VEC r;
  b.d_.val_.grad(q,r);
  EXPECT_FLOAT_EQ(2.0 * -0.28402368, r[0]);
}
<|endoftext|>


<commit_before>// The Art of C++ / PostgreSQL
// Copyright (c) 2016 Daniel Frey

#include "../macros.hpp"

#include <cassert>
#include <stdexcept>
#include <tao/utility/getenv.hpp>
#include <tao/postgres/connection.hpp>

int main()
{
  // overwrite the default with an environment variable if needed
  const auto connection_string = tao::utility::getenv( "TAO_TEST_DATABASE", "dbname=template1" );

  // connection_string must be valid
  TEST_THROWS( tao::postgres::connection::create( "=" ) );

  // connection_string must reference an existing and accessible database
  TEST_THROWS( tao::postgres::connection::create( "dbname=DOES_NOT_EXIST" ) );

  // open a connection
  const auto connection = tao::postgres::connection::create( connection_string );

  // open a seconds, independent connection (and discard it immediately)
  tao::postgres::connection::create( connection_string );

  // execute an SQL statement
  connection->execute( "DROP TABLE IF EXISTS tao_connection_test" );

  // execution of empty statements fails
  TEST_THROWS( connection->execute( "" ) );

  // execution of invalid statements fails
  TEST_THROWS( connection->execute( "FOO BAR BAZ" ) );

  // prepare a statement
  connection->prepare( "drop_table", "DROP TABLE IF EXISTS tao_connection_test" );

  // a prepared statement's name must be a valid C++ identifier
  TEST_THROWS( connection->prepare( "drop table", "DROP TABLE IF EXISTS tao_connection_test" ) );

  // execute a prepared statement
  //
  // note: the name of a prepared statement must be a valid identifier, all
  // actual SQL statements can be writen in a form which does not match a valid
  // identifier, so you can always make sure that they can not be confused.
  connection->execute( "drop_table" );

  // a statement which is not a query does not return "affected rows"
  TEST_THROWS( connection->execute( "drop_table" ).rows_affected() );

  // deallocate a prepared statement
  connection->deallocate( "drop_table" );

  // no longer possible
  TEST_THROWS( connection->execute( "drop_table" ) );

  // deallocate must refer to a prepared statement
  TEST_THROWS( connection->deallocate( "drop_table" ) );

  // deallocate must get a valid name
  TEST_THROWS( connection->deallocate( "FOO BAR" ) );

  // create a test table
  connection->execute( "CREATE TABLE tao_connection_test ( a INTEGER PRIMARY KEY, b INTEGER )" );

  // a DELETE statement does not yield a result set
  TEST_THROWS( connection->execute( "DELETE FROM tao_connection_test" ).empty() );

  // out of range access throws
  TEST_THROWS( connection->execute( "SELECT * FROM tao_connection_test" ).at( 0 ) );

  // insert some data
  connection->execute( "INSERT INTO tao_connection_test VALUES ( 1, 42 )" );

  // read data
  TEST_ASSERT( connection->execute( "SELECT b FROM tao_connection_test WHERE a = 1" )[ 0 ][ 0 ].get() == std::string( "42" ) );
}
<commit_msg>More tests of prepared statement names<commit_after>// The Art of C++ / PostgreSQL
// Copyright (c) 2016 Daniel Frey

#include "../macros.hpp"

#include <cassert>
#include <stdexcept>
#include <tao/utility/getenv.hpp>
#include <tao/postgres/connection.hpp>

int main()
{
  // overwrite the default with an environment variable if needed
  const auto connection_string = tao::utility::getenv( "TAO_TEST_DATABASE", "dbname=template1" );

  // connection_string must be valid
  TEST_THROWS( tao::postgres::connection::create( "=" ) );

  // connection_string must reference an existing and accessible database
  TEST_THROWS( tao::postgres::connection::create( "dbname=DOES_NOT_EXIST" ) );

  // open a connection
  const auto connection = tao::postgres::connection::create( connection_string );

  // open a seconds, independent connection (and discard it immediately)
  tao::postgres::connection::create( connection_string );

  // execute an SQL statement
  connection->execute( "DROP TABLE IF EXISTS tao_connection_test" );

  // execution of empty statements fails
  TEST_THROWS( connection->execute( "" ) );

  // execution of invalid statements fails
  TEST_THROWS( connection->execute( "FOO BAR BAZ" ) );

  // a prepared statement's name must be a valid C++ identifier
  TEST_THROWS( connection->prepare( "", "DROP TABLE IF EXISTS tao_connection_test" ) );
  TEST_THROWS( connection->prepare( "0drop_table", "DROP TABLE IF EXISTS tao_connection_test" ) );
  TEST_THROWS( connection->prepare( "drop table", "DROP TABLE IF EXISTS tao_connection_test" ) );

  // prepare a statement
  connection->prepare( "drop_table", "DROP TABLE IF EXISTS tao_connection_test" );

  // execute a prepared statement
  //
  // note: the name of a prepared statement must be a valid identifier, all
  // actual SQL statements can be writen in a form which does not match a valid
  // identifier, so you can always make sure that they can not be confused.
  connection->execute( "drop_table" );

  // a statement which is not a query does not return "affected rows"
  TEST_THROWS( connection->execute( "drop_table" ).rows_affected() );

  // deallocate a prepared statement
  connection->deallocate( "drop_table" );

  // no longer possible
  TEST_THROWS( connection->execute( "drop_table" ) );

  // deallocate must refer to a prepared statement
  TEST_THROWS( connection->deallocate( "drop_table" ) );

  // deallocate must get a valid name
  TEST_THROWS( connection->deallocate( "FOO BAR" ) );

  // create a test table
  connection->execute( "CREATE TABLE tao_connection_test ( a INTEGER PRIMARY KEY, b INTEGER )" );

  // a DELETE statement does not yield a result set
  TEST_THROWS( connection->execute( "DELETE FROM tao_connection_test" ).empty() );

  // out of range access throws
  TEST_THROWS( connection->execute( "SELECT * FROM tao_connection_test" ).at( 0 ) );

  // insert some data
  connection->execute( "INSERT INTO tao_connection_test VALUES ( 1, 42 )" );

  // read data
  TEST_ASSERT( connection->execute( "SELECT b FROM tao_connection_test WHERE a = 1" )[ 0 ][ 0 ].get() == std::string( "42" ) );
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
#ident "Copyright (c) 2007-2012 Tokutek Inc.  All rights reserved."
#include "test.h"

// verify stats after a new row inserted into the root
// verify stats after a row overwrite in the root
// verify stats after a row deletion in the root
// verify stats after an update callback inserts row
// verify stats after an update callback overwrites row
// verify ststs after an update callback deletes row

#include <db.h>
#include <unistd.h>
#include <sys/stat.h>

static int
my_update_callback(DB *db UU(), const DBT *key UU(), const DBT *old_val, const DBT *extra, void (*set_val)(const DBT *new_val, void *set_extra), void *set_extra) {
    if (old_val != NULL && old_val->size == 42) // special code for delete
        set_val(NULL, set_extra);
    else
        set_val(extra, set_extra);
    return 0;
}

static void
run_test (void) {
    int r;

    r = system("rm -rf " ENVDIR); CKERR(r);
    r = toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);       CKERR(r);

    DB_ENV *env = NULL;
    r = db_env_create(&env, 0); CKERR(r);
    env->set_errfile(env, stderr);
    r = env->set_redzone(env, 0); CKERR(r);
    env->set_update(env, my_update_callback);
    r = env->open(env, ENVDIR, DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN|DB_CREATE|DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);

    DB *db = NULL;
    r = db_create(&db, env, 0); CKERR(r);
    DB_TXN *txn = NULL;
    r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
    r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
    r = txn->commit(txn, 0);    CKERR(r);

    // verify that stats include a new row inserted into the root
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; char val = 1;
        DBT k,v;
        r = db->put(db, txn, dbt_init(&k, &key, sizeof key), dbt_init(&v, &val, sizeof val), 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify that stats are updated by row overwrite in the root
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; int val = 2;
        DBT k,v;
        r = db->put(db, txn, dbt_init(&k, &key, sizeof key), dbt_init(&v, &val, sizeof val), 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify that stats are updated by row deletion in the root
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1;
        DBT k;
        r = db->del(db, txn, dbt_init(&k, &key, sizeof key), 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 1 && s.bt_dsize == 0); // since garbage collection may not occur, the key count may not be updated

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        // garbage collection is not happening here yet, so
        // the number of keys should be 1
        assert(s.bt_nkeys == 1 && s.bt_dsize == 0);
    }

    // verify update of non-existing key inserts a row
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; char val = 1;
        DBT k = { .data = &key, .size = sizeof key };
        DBT e = { .data = &val, .size = sizeof val };
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify update callback overwrites the row
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; int val = 2;
        DBT k = { .data = &key, .size = sizeof key };
        DBT e = { .data = &val, .size = sizeof val };
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify update callback deletes the row
    {
        // insert a new row
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; char val[42]; memset(val, 0, sizeof val);
        DBT k = { .data = &key, .size = sizeof key };
        DBT e = { .data = &val, .size = sizeof val };
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 2 && s.bt_dsize == sizeof key + sizeof val);

        // update it again, this should delete the row
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 2 && s.bt_dsize == 0); // since garbage collection may not occur, the key count may not be updated

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 2 && s.bt_dsize == 0);
    }

    r = db->close(db, 0);     CKERR(r);

    r = env->close(env, 0);   CKERR(r);
}

int
test_main (int argc , char * const argv[]) {
    parse_args(argc, argv);
    run_test();
    return 0;
}
<commit_msg>refs #5700, fix test<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
#ident "Copyright (c) 2007-2012 Tokutek Inc.  All rights reserved."
#include "test.h"

// verify stats after a new row inserted into the root
// verify stats after a row overwrite in the root
// verify stats after a row deletion in the root
// verify stats after an update callback inserts row
// verify stats after an update callback overwrites row
// verify ststs after an update callback deletes row

#include <db.h>
#include <unistd.h>
#include <sys/stat.h>

static int
my_update_callback(DB *db UU(), const DBT *key UU(), const DBT *old_val, const DBT *extra, void (*set_val)(const DBT *new_val, void *set_extra), void *set_extra) {
    if (old_val != NULL && old_val->size == 42) // special code for delete
        set_val(NULL, set_extra);
    else
        set_val(extra, set_extra);
    return 0;
}

static void
run_test (void) {
    int r;

    r = system("rm -rf " ENVDIR); CKERR(r);
    r = toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);       CKERR(r);

    DB_ENV *env = NULL;
    r = db_env_create(&env, 0); CKERR(r);
    env->set_errfile(env, stderr);
    r = env->set_redzone(env, 0); CKERR(r);
    env->set_update(env, my_update_callback);
    r = env->open(env, ENVDIR, DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN|DB_CREATE|DB_PRIVATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);

    DB *db = NULL;
    r = db_create(&db, env, 0); CKERR(r);
    DB_TXN *txn = NULL;
    r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
    r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
    r = txn->commit(txn, 0);    CKERR(r);

    // verify that stats include a new row inserted into the root
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; char val = 1;
        DBT k,v;
        r = db->put(db, txn, dbt_init(&k, &key, sizeof key), dbt_init(&v, &val, sizeof val), 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify that stats are updated by row overwrite in the root
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; int val = 2;
        DBT k,v;
        r = db->put(db, txn, dbt_init(&k, &key, sizeof key), dbt_init(&v, &val, sizeof val), 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify that stats are updated by row deletion in the root
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1;
        DBT k;
        r = db->del(db, txn, dbt_init(&k, &key, sizeof key), 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 1 && s.bt_dsize == 0); // since garbage collection may not occur, the key count may not be updated

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        // garbage collection is not happening here yet, so
        // the number of keys should be 1
        assert(s.bt_nkeys == 1 && s.bt_dsize == 0);
    }

    // verify update of non-existing key inserts a row
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; char val = 1;
        DBT k = { .data = &key, .size = sizeof key };
        DBT e = { .data = &val, .size = sizeof val };
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 1 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify update callback overwrites the row
    {
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; int val = 2;
        DBT k = { .data = &key, .size = sizeof key };
        DBT e = { .data = &val, .size = sizeof val };
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys == 2 && s.bt_dsize == sizeof key + sizeof val);
    }

    // verify update callback deletes the row
    {
        // insert a new row
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        int key = 1; char val[42]; memset(val, 0, sizeof val);
        DBT k = { .data = &key, .size = sizeof key };
        DBT e = { .data = &val, .size = sizeof val };
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        DB_BTREE_STAT64 s;
        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 2 && s.bt_dsize == sizeof key + sizeof val);

        // update it again, this should delete the row
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->update(db, txn, &k, &e, 0); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 2 && s.bt_dsize == 0); // since garbage collection may not occur, the key count may not be updated

        r = db->close(db, 0);     CKERR(r);

        r = db_create(&db, env, 0); CKERR(r);
        r = env->txn_begin(env, 0, &txn, 0); CKERR(r);
        r = db->open(db, txn, "foo.db", 0, DB_BTREE, DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
        r = txn->commit(txn, 0);    CKERR(r);

        r = db->stat64(db, NULL, &s); CKERR(r);
        assert(s.bt_nkeys <= 2 && s.bt_dsize == 0);
    }

    r = db->close(db, 0);     CKERR(r);

    r = env->close(env, 0);   CKERR(r);
}

int
test_main (int argc , char * const argv[]) {
    parse_args(argc, argv);
    run_test();
    return 0;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Bastien Durix

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.
*/

/**
 *  \brief Provides tests for skeleton library
 *  \author Bastien Durix
 */

#include <iostream>
#include <math.h>

#include <cstdlib>

#include <skeleton/GraphCurveSkeleton.h>
#include <skeleton/model/Classic.h>
#include <mathtools/geometry/euclidian/HyperSphere.h>

using namespace mathtools::affine;
using namespace mathtools::geometry::euclidian;

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE TestMathtools
#include <boost/test/unit_test.hpp>

skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >::Ptr skel = skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >::Ptr();
Frame<2>::Ptr frame = Frame<2>::Ptr();
skeleton::model::Classic<2>::Ptr modclass = skeleton::model::Classic<2>::Ptr();
unsigned int ind1 = 0;
unsigned int ind2 = 0;

BOOST_AUTO_TEST_CASE( SkeletonCreation )
{
	// frame creation
	frame = Frame<2>::CreateFrame(Eigen::Vector2d(1.0,0.0),Eigen::Vector2d(2.0,1.0),Eigen::Vector2d(1.0,0.0));

	// model creation
	modclass = skeleton::model::Classic<2>::Ptr(new skeleton::model::Classic<2>{frame});

	// skeleton creation
	skel = skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >::Ptr(new skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >(modclass));
}

BOOST_AUTO_TEST_CASE( AddingNode )
{
	// creating a random node
	Eigen::Vector3d vec3((double)(rand()%201)/10.0-1.0,
						 (double)(rand()%201)/10.0-1.0,
						 (double)(rand()%201)/10.0);

	// adding a node
	ind1 = skel->addNode(vec3);

	// getting the node (vector form)
	Eigen::Vector3d vec = skel->getNode(ind1);

	BOOST_REQUIRE( vec.isApprox(vec3,std::numeric_limits<double>::epsilon()) );

	// getting the node (center form)
	Point<2> pt = skel->getNode<Point<2> >(ind1);

	BOOST_REQUIRE( pt.getCoords().isApprox(frame->getBasis()->getMatrix()*vec3.block<2,1>(0,0)+frame->getOrigin()) );
}

BOOST_AUTO_TEST_CASE( AddingSphere )
{
	// hypersphere creation
	HyperSphere<2> sph(Point<2>(1.0,0.0),5.0,frame);

	// adding a node
	ind2 = skel->addNode<HyperSphere<2> >(sph);

	// get the vector associated to the node
	Eigen::Vector3d vecsph = skel->getNode(ind2);

	// convert the node to a sphere
	HyperSphere<2> sphcpy = skel->getModel()->toObj<HyperSphere<2> >(vecsph);

	BOOST_REQUIRE( sphcpy.getCenter().getCoords().isApprox(sph.getCenter().getCoords(),std::numeric_limits<double>::epsilon()) );
	BOOST_REQUIRE( sphcpy.getRadius() == sph.getRadius() );
	BOOST_REQUIRE( sphcpy.getFrame()->getBasis()->getMatrix().isApprox(sph.getFrame()->getBasis()->getMatrix(),std::numeric_limits<double>::epsilon()) );
	BOOST_REQUIRE( ind1 != ind2);
}

BOOST_AUTO_TEST_CASE( getAllNodes )
{
	// get all indices
	std::list<unsigned int> listnod;

	skel->getAllNodes(listnod);

	listnod.unique();

	BOOST_REQUIRE( listnod.size() == 2 );
	BOOST_REQUIRE( std::find(listnod.begin(),listnod.end(),ind1) != listnod.end() );
	BOOST_REQUIRE( std::find(listnod.begin(),listnod.end(),ind2) != listnod.end() );
}

BOOST_AUTO_TEST_CASE( addEdge )
{
	// adding an edge
	skel->addEdge(ind1, ind2);

	std::list<unsigned int> neigh;
	skel->getNeighbors(ind1,neigh);

	BOOST_REQUIRE( neigh.size() == 1 );
	BOOST_REQUIRE( *(neigh.begin()) == ind2 );
}

BOOST_AUTO_TEST_CASE( remEdge )
{
	// removing an edge
	skel->remEdge(ind1, ind2);

	std::list<unsigned int> neigh;
	skel->getNeighbors(ind1,neigh);

	BOOST_REQUIRE( neigh.size() == 0 );
}

BOOST_AUTO_TEST_CASE( remNode )
{
	skel->remNode(ind1);

	try
	{
		skel->getNode(ind1);
		BOOST_FAIL( "Deleted a node already removed" );
	}
	catch(...)
	{}
}
<commit_msg>Deleted useless includes in test_skeleton<commit_after>/*
Copyright (c) 2016 Bastien Durix

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.
*/

/**
 *  \brief Provides tests for skeleton library
 *  \author Bastien Durix
 */

#include <skeleton/GraphCurveSkeleton.h>
#include <skeleton/model/Classic.h>
#include <mathtools/geometry/euclidian/HyperSphere.h>

using namespace mathtools::affine;
using namespace mathtools::geometry::euclidian;

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE TestMathtools
#include <boost/test/unit_test.hpp>

skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >::Ptr skel = skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >::Ptr();
Frame<2>::Ptr frame = Frame<2>::Ptr();
skeleton::model::Classic<2>::Ptr modclass = skeleton::model::Classic<2>::Ptr();
unsigned int ind1 = 0;
unsigned int ind2 = 0;

BOOST_AUTO_TEST_CASE( SkeletonCreation )
{
	// frame creation
	frame = Frame<2>::CreateFrame(Eigen::Vector2d(1.0,0.0),Eigen::Vector2d(2.0,1.0),Eigen::Vector2d(1.0,0.0));

	// model creation
	modclass = skeleton::model::Classic<2>::Ptr(new skeleton::model::Classic<2>{frame});

	// skeleton creation
	skel = skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >::Ptr(new skeleton::GraphCurveSkeleton<skeleton::model::Classic<2> >(modclass));
}

BOOST_AUTO_TEST_CASE( AddingNode )
{
	// creating a random node
	Eigen::Vector3d vec3((double)(rand()%201)/10.0-1.0,
						 (double)(rand()%201)/10.0-1.0,
						 (double)(rand()%201)/10.0);

	// adding a node
	ind1 = skel->addNode(vec3);

	// getting the node (vector form)
	Eigen::Vector3d vec = skel->getNode(ind1);

	BOOST_REQUIRE( vec.isApprox(vec3,std::numeric_limits<double>::epsilon()) );

	// getting the node (center form)
	Point<2> pt = skel->getNode<Point<2> >(ind1);

	BOOST_REQUIRE( pt.getCoords().isApprox(frame->getBasis()->getMatrix()*vec3.block<2,1>(0,0)+frame->getOrigin()) );
}

BOOST_AUTO_TEST_CASE( AddingSphere )
{
	// hypersphere creation
	HyperSphere<2> sph(Point<2>(1.0,0.0),5.0,frame);

	// adding a node
	ind2 = skel->addNode<HyperSphere<2> >(sph);

	// get the vector associated to the node
	Eigen::Vector3d vecsph = skel->getNode(ind2);

	// convert the node to a sphere
	HyperSphere<2> sphcpy = skel->getModel()->toObj<HyperSphere<2> >(vecsph);

	BOOST_REQUIRE( sphcpy.getCenter().getCoords().isApprox(sph.getCenter().getCoords(),std::numeric_limits<double>::epsilon()) );
	BOOST_REQUIRE( sphcpy.getRadius() == sph.getRadius() );
	BOOST_REQUIRE( sphcpy.getFrame()->getBasis()->getMatrix().isApprox(sph.getFrame()->getBasis()->getMatrix(),std::numeric_limits<double>::epsilon()) );
	BOOST_REQUIRE( ind1 != ind2);
}

BOOST_AUTO_TEST_CASE( getAllNodes )
{
	// get all indices
	std::list<unsigned int> listnod;

	skel->getAllNodes(listnod);

	listnod.unique();

	BOOST_REQUIRE( listnod.size() == 2 );
	BOOST_REQUIRE( std::find(listnod.begin(),listnod.end(),ind1) != listnod.end() );
	BOOST_REQUIRE( std::find(listnod.begin(),listnod.end(),ind2) != listnod.end() );
}

BOOST_AUTO_TEST_CASE( addEdge )
{
	// adding an edge
	skel->addEdge(ind1, ind2);

	std::list<unsigned int> neigh;
	skel->getNeighbors(ind1,neigh);

	BOOST_REQUIRE( neigh.size() == 1 );
	BOOST_REQUIRE( *(neigh.begin()) == ind2 );
}

BOOST_AUTO_TEST_CASE( remEdge )
{
	// removing an edge
	skel->remEdge(ind1, ind2);

	std::list<unsigned int> neigh;
	skel->getNeighbors(ind1,neigh);

	BOOST_REQUIRE( neigh.size() == 0 );
}

BOOST_AUTO_TEST_CASE( remNode )
{
	skel->remNode(ind1);

	try
	{
		skel->getNode(ind1);
		BOOST_FAIL( "Deleted a node already removed" );
	}
	catch(...)
	{}
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee — CLIPP Unparse Modifier Implementation
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#include "unparse_modifier.hpp"

#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>

using namespace std;

namespace IronBee {
namespace CLIPP {

namespace {

static const char* c_eol("\r\n");

struct data_t
{
    boost::any old_source;
    typedef pair<string, string> txdata_t;
    typedef list<txdata_t> txdata_list_t;
    txdata_list_t txdatas;
};

class UnparseDelegate :
    public Input::Delegate
{
private:
    static
    void headers(string& dst, const Input::HeaderEvent& event)
    {
        BOOST_FOREACH(const Input::header_t& header, event.headers) {
            if (header.first.data) {
                dst.append(header.first.data, header.first.length);
                dst += ": ";
                if (header.second.data) {
                    dst.append(
                        header.second.data,
                        header.second.length
                    );
                }
                dst += c_eol;
            }
        }
    }

    static
    void body(string& dst, const Input::DataEvent& event)
    {
        if (event.data.data) {
            dst += c_eol;
            dst.append(event.data.data, event.data.length);
        }
    }

public:
    explicit
    UnparseDelegate(
        data_t::txdata_t& txdata
    ) :
        m_txdata(txdata)
    {
        // nop
    }

    void request_started(const Input::RequestEvent& event)
    {
        if (event.raw.data) {
            m_txdata.first.append(event.raw.data, event.raw.length);
        }
        else {
            if (event.method.data) {
                m_txdata.first.append(event.method.data, event.method.length);
                m_txdata.first.append(" ");
            }
            if (event.uri.data) {
                m_txdata.first.append(event.uri.data, event.uri.length);
                m_txdata.first.append(" ");
            }
            if (event.protocol.data) {
                m_txdata.first.append(
                    event.protocol.data,
                    event.protocol.length
                );
            }
        }
        m_txdata.first += c_eol;
    }

    void request_headers(const Input::HeaderEvent& event)
    {
        headers(m_txdata.first, event);
    }

    void request_body(const Input::DataEvent& event)
    {
        body(m_txdata.first, event);
    }

    void response_started(const Input::ResponseEvent& event)
    {
        if (event.raw.data) {
            m_txdata.second.append(event.raw.data, event.raw.length);
        }
        else {
            if (event.protocol.data) {
                m_txdata.second.append(
                    event.protocol.data,
                    event.protocol.length
                );
                m_txdata.second.append(" ");
            }
            if (event.status.data) {
                m_txdata.second.append(
                    event.status.data,
                    event.status.length
                );
                m_txdata.second.append(" ");
            }
            if (event.message.data) {
                m_txdata.second.append(
                    event.message.data,
                    event.message.length
                );
            }
        }
        m_txdata.second += c_eol;

    }

    void response_headers(const Input::HeaderEvent& event)
    {
        headers(m_txdata.second, event);
    }

    void response_body(const Input::DataEvent& event)
    {
        body(m_txdata.second, event);
    }

private:
    data_t::txdata_t&   m_txdata;
};

void add_events(Input::Transaction& tx, const data_t::txdata_t txdata)
{
    tx.connection_data_in(Input::Buffer(txdata.first));
    tx.connection_data_out(Input::Buffer(txdata.second));
}

}

bool UnparseModifier::operator()(Input::input_p& input)
{
    if (! input) {
        return true;
    }

    boost::shared_ptr<data_t> data = boost::make_shared<data_t>();
    data->old_source   = input->source;

    Input::transaction_list_t new_transactions;
    BOOST_FOREACH(Input::Transaction& tx, input->connection.transactions) {
        new_transactions.push_back(Input::Transaction());
        Input::Transaction& new_tx = new_transactions.back();

        data_t::txdata_t* current_txdata = NULL;
        BOOST_FOREACH(Input::event_p& event, tx.events) {
            switch (event->which) {
                case Input::CONNECTION_DATA_IN:
                case Input::CONNECTION_DATA_OUT:
                    new_tx.events.push_back(event);
                    break;
                case Input::REQUEST_STARTED: {
                    if (current_txdata) {
                        add_events(new_tx, *current_txdata);
                    }
                    data->txdatas.push_back(data_t::txdata_t());
                    current_txdata = &data->txdatas.back();
                    UnparseDelegate delegate(*current_txdata);
                    event->dispatch(delegate);
                    break;
                }
                case Input::REQUEST_FINISHED:
                case Input::RESPONSE_FINISHED:
                    // nop
                    break;
                default: {
                    if (! current_txdata) {
                        throw runtime_error(
                            "Expecting connection data in/out or request "
                            "started but got something else."
                        );
                    }
                    UnparseDelegate delegate(*current_txdata);
                    event->dispatch(delegate);
                }
            }
        }
        if (current_txdata) {
            add_events(new_tx, *current_txdata);
        }
    }
    input->connection.transactions.swap(new_transactions);

    return true;
}

} // CLIPP
} // IronBee<commit_msg>clipp: Update @unparse to support new event names.<commit_after>/*****************************************************************************
 * Licensed to Qualys, Inc. (QUALYS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * QUALYS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 ****************************************************************************/

/**
 * @file
 * @brief IronBee — CLIPP Unparse Modifier Implementation
 *
 * @author Christopher Alfeld <calfeld@qualys.com>
 */

#include "unparse_modifier.hpp"

#include <boost/foreach.hpp>
#include <boost/make_shared.hpp>

using namespace std;

namespace IronBee {
namespace CLIPP {

namespace {

static const char* c_eol("\r\n");

struct data_t
{
    boost::any old_source;
    typedef pair<string, string> txdata_t;
    typedef list<txdata_t> txdata_list_t;
    txdata_list_t txdatas;
};

class UnparseDelegate :
    public Input::Delegate
{
private:
    static
    void headers(string& dst, const Input::HeaderEvent& event)
    {
        BOOST_FOREACH(const Input::header_t& header, event.headers) {
            if (header.first.data) {
                dst.append(header.first.data, header.first.length);
                dst += ": ";
                if (header.second.data) {
                    dst.append(
                        header.second.data,
                        header.second.length
                    );
                }
                dst += c_eol;
            }
        }
    }

    static
    void body(string& dst, const Input::DataEvent& event)
    {
        if (event.data.data) {
            dst += c_eol;
            dst.append(event.data.data, event.data.length);
        }
    }

public:
    explicit
    UnparseDelegate(
        data_t::txdata_t& txdata
    ) :
        m_txdata(txdata)
    {
        // nop
    }

    void request_started(const Input::RequestEvent& event)
    {
        if (event.raw.data) {
            m_txdata.first.append(event.raw.data, event.raw.length);
        }
        else {
            if (event.method.data) {
                m_txdata.first.append(event.method.data, event.method.length);
                m_txdata.first.append(" ");
            }
            if (event.uri.data) {
                m_txdata.first.append(event.uri.data, event.uri.length);
                m_txdata.first.append(" ");
            }
            if (event.protocol.data) {
                m_txdata.first.append(
                    event.protocol.data,
                    event.protocol.length
                );
            }
        }
        m_txdata.first += c_eol;
    }

    void request_header(const Input::HeaderEvent& event)
    {
        headers(m_txdata.first, event);
    }

    void request_body(const Input::DataEvent& event)
    {
        body(m_txdata.first, event);
    }

    void response_started(const Input::ResponseEvent& event)
    {
        if (event.raw.data) {
            m_txdata.second.append(event.raw.data, event.raw.length);
        }
        else {
            if (event.protocol.data) {
                m_txdata.second.append(
                    event.protocol.data,
                    event.protocol.length
                );
                m_txdata.second.append(" ");
            }
            if (event.status.data) {
                m_txdata.second.append(
                    event.status.data,
                    event.status.length
                );
                m_txdata.second.append(" ");
            }
            if (event.message.data) {
                m_txdata.second.append(
                    event.message.data,
                    event.message.length
                );
            }
        }
        m_txdata.second += c_eol;

    }

    void response_header(const Input::HeaderEvent& event)
    {
        headers(m_txdata.second, event);
    }

    void response_body(const Input::DataEvent& event)
    {
        body(m_txdata.second, event);
    }

private:
    data_t::txdata_t&   m_txdata;
};

void add_events(Input::Transaction& tx, const data_t::txdata_t txdata)
{
    tx.connection_data_in(Input::Buffer(txdata.first));
    tx.connection_data_out(Input::Buffer(txdata.second));
}

}

bool UnparseModifier::operator()(Input::input_p& input)
{
    if (! input) {
        return true;
    }

    boost::shared_ptr<data_t> data = boost::make_shared<data_t>();
    data->old_source   = input->source;

    Input::transaction_list_t new_transactions;
    BOOST_FOREACH(Input::Transaction& tx, input->connection.transactions) {
        new_transactions.push_back(Input::Transaction());
        Input::Transaction& new_tx = new_transactions.back();

        data_t::txdata_t* current_txdata = NULL;
        BOOST_FOREACH(Input::event_p& event, tx.events) {
            switch (event->which) {
                case Input::CONNECTION_DATA_IN:
                case Input::CONNECTION_DATA_OUT:
                    new_tx.events.push_back(event);
                    break;
                case Input::REQUEST_STARTED: {
                    if (current_txdata) {
                        add_events(new_tx, *current_txdata);
                    }
                    data->txdatas.push_back(data_t::txdata_t());
                    current_txdata = &data->txdatas.back();
                    UnparseDelegate delegate(*current_txdata);
                    event->dispatch(delegate);
                    break;
                }
                case Input::REQUEST_FINISHED:
                case Input::RESPONSE_FINISHED:
                    // nop
                    break;
                default: {
                    if (! current_txdata) {
                        throw runtime_error(
                            "Expecting connection data in/out or request "
                            "started but got something else."
                        );
                    }
                    UnparseDelegate delegate(*current_txdata);
                    event->dispatch(delegate);
                }
            }
        }
        if (current_txdata) {
            add_events(new_tx, *current_txdata);
        }
    }
    input->connection.transactions.swap(new_transactions);

    return true;
}

} // CLIPP
} // IronBee<|endoftext|>


<commit_before>#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <vector>
#include <cstdio>

#define ASSERT(X) \
    if (!(X)) { \
        *(int*)3 = 42; \
    }

constexpr UINT DISJOINT_SO_RANGES = 2;

const std::string vs_src(R"(
struct vs_in
{
    float2 xy : POSITION;
};

struct vs_out
{
    float4 pos : SV_POSITION;
    float2 xy : POSITION;
};

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
vs_out Main(vs_in input)
{
    vs_out output;
    output.pos = float4(0,0,0,1);
    output.xy = input.xy * 3;
    return output;
}
)");

int
main(const int argc, const char* const argv[])
{
    HRESULT hr;

    UINT flags = D3D11_CREATE_DEVICE_DEBUG;
    const std::vector<D3D_FEATURE_LEVEL> feature_levels({
        //D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
    });
    ID3D11Device* device = nullptr;
    D3D_FEATURE_LEVEL feature_level;
    ID3D11DeviceContext* context = nullptr;
    hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_REFERENCE, nullptr,
                           flags, feature_levels.data(), feature_levels.size(),
                           D3D11_SDK_VERSION, &device, &feature_level, &context);
    ASSERT(device);

    // --

    ID3DBlob* vs_blob = nullptr;
    ID3DBlob* err_blob = nullptr;
    hr = D3DCompile(vs_src.data(), vs_src.size(), "vs_src", nullptr, nullptr, "Main", "vs_5_0",
        D3DCOMPILE_ENABLE_STRICTNESS, 0, &vs_blob, &err_blob);
    const char* err_str = nullptr;
    if (err_blob) {
        err_str = (const char*)err_blob->GetBufferPointer();
        printf("%s", err_str);
    }
    ASSERT(vs_blob);
    const auto vs_bytes_ptr = vs_blob->GetBufferPointer();
    const auto vs_bytes_size = vs_blob->GetBufferSize();

    ID3D11VertexShader* vs_shader = nullptr;
    hr = device->CreateVertexShader(vs_bytes_ptr, vs_bytes_size,
                                    nullptr, &vs_shader);
    ASSERT(vs_shader);

    ID3D11GeometryShader* gs_shader = nullptr;
    {
        const D3D11_SO_DECLARATION_ENTRY descs[] {
            { 0, "POSITION", 0, 0, 1, 0 },
            { 0, "POSITION", 0, 1, 1, 1 },
        };
        const UINT strides[2] { 4, 4 };
        hr = device->CreateGeometryShaderWithStreamOutput(vs_bytes_ptr, vs_bytes_size,
            descs, DISJOINT_SO_RANGES, strides, DISJOINT_SO_RANGES,
            D3D11_SO_NO_RASTERIZED_STREAM, nullptr, &gs_shader);
        ASSERT(gs_shader);
    }

    // --

    const float in_data[]{
        0.5, 1, 2, 3,
    };

    ID3D11Buffer* in_buffer = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_DEFAULT,
            D3D11_BIND_VERTEX_BUFFER,
            0, 0,
            0
        };
        const D3D11_SUBRESOURCE_DATA data{ in_data };
        hr = device->CreateBuffer(&desc, &data, &in_buffer);
        ASSERT(in_buffer);
    }

    ID3D11Buffer* out_buffer = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_DEFAULT,
            D3D11_BIND_STREAM_OUTPUT,
            0, 0,
            0
        };
        hr = device->CreateBuffer(&desc, nullptr, &out_buffer);
        ASSERT(out_buffer);
    }

    ID3D11Buffer* read_buffer = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_STAGING,
            0,
            D3D11_CPU_ACCESS_READ, 0,
            0
        };
        hr = device->CreateBuffer(&desc, nullptr, &read_buffer);
        ASSERT(read_buffer);
    }

    // --

    context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
    context->VSSetShader(vs_shader, nullptr, 0);
    context->GSSetShader(gs_shader, nullptr, 0);

    ID3D11InputLayout* input_layout = nullptr;
    {
        const D3D11_INPUT_ELEMENT_DESC desc{
            "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
            D3D11_INPUT_PER_VERTEX_DATA, 0
        };
        hr = device->CreateInputLayout(&desc, 1, vs_bytes_ptr, vs_bytes_size,
            &input_layout);
        ASSERT(input_layout);
    }
    context->IASetInputLayout(input_layout);

    {
        const UINT strides[]{ 8 };
        const UINT offsets[]{ 0 };
        context->IASetVertexBuffers(0, 1, &in_buffer, strides, offsets);
    }
    {
        ID3D11Buffer* const buffers[]{ out_buffer, out_buffer };
        const UINT offsets[]{ 0, 8 };
        context->SOSetTargets(DISJOINT_SO_RANGES, buffers, offsets);
    }
    context->Draw(1, 0);

    // --

    context->CopyResource(read_buffer, out_buffer);

    D3D11_MAPPED_SUBRESOURCE mapped{};
    hr = context->Map(read_buffer, 0, D3D11_MAP_READ, 0, &mapped);
    ASSERT(mapped.pData);

    const auto out_data = (const float*)mapped.pData;
    ASSERT(out_data[0] == in_data[0] * 3.0f);

    context->Unmap(read_buffer, 0);

    // --

    printf("OK\n");
    return 0;
}
<commit_msg>Update stream output test to be easy to revert to non-same dest buffers.<commit_after>#include <d3d11_1.h>
#include <d3dcompiler.h>
#include <vector>
#include <cstdio>

#define ASSERT(X) \
    if (!(X)) { \
        *(int*)3 = 42; \
    }

constexpr UINT DISJOINT_SO_RANGES = 2;

const std::string vs_src(R"(
struct vs_in
{
    float2 xy : POSITION;
};

struct vs_out
{
    float4 pos : SV_POSITION;
    float2 xy : POSITION;
};

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
vs_out Main(vs_in input)
{
    vs_out output;
    output.pos = float4(0,0,0,1);
    output.xy = input.xy * 3;
    return output;
}
)");

int
main(const int argc, const char* const argv[])
{
    HRESULT hr;

    UINT flags = D3D11_CREATE_DEVICE_DEBUG;
    const std::vector<D3D_FEATURE_LEVEL> feature_levels({
        //D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
    });
    ID3D11Device* device = nullptr;
    D3D_FEATURE_LEVEL feature_level;
    ID3D11DeviceContext* context = nullptr;
    hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_REFERENCE, nullptr,
                           flags, feature_levels.data(), feature_levels.size(),
                           D3D11_SDK_VERSION, &device, &feature_level, &context);
    ASSERT(device);

    // --

    ID3DBlob* vs_blob = nullptr;
    ID3DBlob* err_blob = nullptr;
    hr = D3DCompile(vs_src.data(), vs_src.size(), "vs_src", nullptr, nullptr, "Main", "vs_5_0",
        D3DCOMPILE_ENABLE_STRICTNESS, 0, &vs_blob, &err_blob);
    const char* err_str = nullptr;
    if (err_blob) {
        err_str = (const char*)err_blob->GetBufferPointer();
        printf("%s", err_str);
    }
    ASSERT(vs_blob);
    const auto vs_bytes_ptr = vs_blob->GetBufferPointer();
    const auto vs_bytes_size = vs_blob->GetBufferSize();

    ID3D11VertexShader* vs_shader = nullptr;
    hr = device->CreateVertexShader(vs_bytes_ptr, vs_bytes_size,
                                    nullptr, &vs_shader);
    ASSERT(vs_shader);

    ID3D11GeometryShader* gs_shader = nullptr;
    {
        const D3D11_SO_DECLARATION_ENTRY descs[] {
            { 0, "POSITION", 0, 0, 1, 0 },
            { 0, "POSITION", 0, 1, 1, 1 },
        };
        const UINT strides[2] { 4, 4 };
        hr = device->CreateGeometryShaderWithStreamOutput(vs_bytes_ptr, vs_bytes_size,
            descs, DISJOINT_SO_RANGES, strides, DISJOINT_SO_RANGES,
            D3D11_SO_NO_RASTERIZED_STREAM, nullptr, &gs_shader);
        ASSERT(gs_shader);
    }

    // --

    const float in_data[]{
        0.5, 1, 2, 3,
    };

    ID3D11Buffer* in_buffer = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_DEFAULT,
            D3D11_BIND_VERTEX_BUFFER,
            0, 0,
            0
        };
        const D3D11_SUBRESOURCE_DATA data{ in_data };
        hr = device->CreateBuffer(&desc, &data, &in_buffer);
        ASSERT(in_buffer);
    }

    ID3D11Buffer* out_buffer = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_DEFAULT,
            D3D11_BIND_STREAM_OUTPUT,
            0, 0,
            0
        };
        hr = device->CreateBuffer(&desc, nullptr, &out_buffer);
        ASSERT(out_buffer);
    }

    ID3D11Buffer* out_buffer2 = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_DEFAULT,
            D3D11_BIND_STREAM_OUTPUT,
            0, 0,
            0
        };
        hr = device->CreateBuffer(&desc, nullptr, &out_buffer2);
        ASSERT(out_buffer2);
    }

    ID3D11Buffer* read_buffer = nullptr;
    {
        const D3D11_BUFFER_DESC desc{
            sizeof(in_data), D3D11_USAGE_STAGING,
            0,
            D3D11_CPU_ACCESS_READ, 0,
            0
        };
        hr = device->CreateBuffer(&desc, nullptr, &read_buffer);
        ASSERT(read_buffer);
    }

    // --

    context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
    context->VSSetShader(vs_shader, nullptr, 0);
    context->GSSetShader(gs_shader, nullptr, 0);

    ID3D11InputLayout* input_layout = nullptr;
    {
        const D3D11_INPUT_ELEMENT_DESC desc{
            "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
            D3D11_INPUT_PER_VERTEX_DATA, 0
        };
        hr = device->CreateInputLayout(&desc, 1, vs_bytes_ptr, vs_bytes_size,
            &input_layout);
        ASSERT(input_layout);
    }
    context->IASetInputLayout(input_layout);

    {
        const UINT strides[]{ 8 };
        const UINT offsets[]{ 0 };
        context->IASetVertexBuffers(0, 1, &in_buffer, strides, offsets);
    }
    {
        //ID3D11Buffer* const buffers[]{ out_buffer, out_buffer2 };
        ID3D11Buffer* const buffers[]{ out_buffer, out_buffer };
        const UINT offsets[]{ 0, 8 };
        context->SOSetTargets(DISJOINT_SO_RANGES, buffers, offsets);
    }
    context->Draw(1, 0);

    // --

    context->CopyResource(read_buffer, out_buffer);

    D3D11_MAPPED_SUBRESOURCE mapped{};
    hr = context->Map(read_buffer, 0, D3D11_MAP_READ, 0, &mapped);
    ASSERT(mapped.pData);

    const auto out_data = (const float*)mapped.pData;
    ASSERT(out_data[0] == in_data[0] * 3.0f);

    context->Unmap(read_buffer, 0);

    // --

    printf("OK\n");
    return 0;
}
<|endoftext|>