<commit_before>#pragma once

#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>

namespace xml11 {

namespace {

#define CreateErrorText(param) \
    (std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": Error in " + (param));

using BufferType = std::decay_t<decltype(xmlBufferCreate())>;
using WriterType = std::decay_t<decltype(xmlNewTextWriterMemory({}, {}))>;
using ReaderType = std::decay_t<decltype(xmlReaderForMemory({}, {}, {}, {}, {}))>;

using BufferTypePtr = std::shared_ptr<BufferType>;
using WriterTypePtr = std::shared_ptr<WriterType>;
using ReaderTypePtr = std::shared_ptr<ReaderType>;

static inline void InitializeParser() noexcept
{
    xmlInitParser();
}

static inline void CleanupParser() noexcept
{
    if (xmlGetLastError()) {
        xmlResetError(xmlGetLastError());
        xmlResetLastError();
    }

    xmlSetStructuredErrorFunc(NULL, NULL);
    xmlSetGenericErrorFunc(NULL, NULL);
    initGenericErrorDefaultFunc(NULL);
    xmlCleanupParser();
}

template<class T, class Fn>
static inline void ReleaseMemory(const T* buffer, Fn fn) noexcept
{
    if (buffer) {
        if (*buffer) {
            fn(*buffer);
        }
        delete buffer;
        buffer = nullptr;
    }
}

static inline void FreeXmlBuffer(const BufferType* buffer) noexcept
{
    ReleaseMemory(buffer, xmlBufferFree);
}

static inline void FreeXmlWriter(const WriterType* writer) noexcept
{
    ReleaseMemory(writer, xmlFreeTextWriter);
}

static inline void FreeXmlReader(const ReaderType* reader) noexcept
{
    ReleaseMemory(reader, xmlFreeTextReader);
}

static inline BufferType* CreateBuffer() noexcept
{
    return new BufferType(xmlBufferCreateSize(BASE_BUFFER_SIZE));
}

static inline WriterType* CreateWriter(const BufferTypePtr& buffer) noexcept
{
    return new WriterType(xmlNewTextWriterMemory(*buffer, 0 /* compress */));
}

static inline ReaderType* CreateReader(const std::string& text) noexcept
{
    return new ReaderType(xmlReaderForMemory(text.data(), text.size(), NULL, NULL, XML_PARSE_NOBLANKS));
}

static inline BufferTypePtr GetXmlBuffer(const bool useCaching) noexcept
{
    if (useCaching) {
        static const auto buffer = BufferTypePtr(CreateBuffer(), FreeXmlBuffer);
        xmlBufferEmpty(*buffer);
        return buffer;
    }

    return BufferTypePtr(CreateBuffer(), FreeXmlBuffer);
}

static inline WriterTypePtr GetXmlWriter(const bool useCaching, const BufferTypePtr& buffer) noexcept
{
    if (useCaching) {
        static const auto writer = WriterTypePtr(CreateWriter(buffer), FreeXmlWriter);
        return writer;
    }

    return WriterTypePtr(CreateWriter(buffer), FreeXmlWriter);
}

static inline ReaderTypePtr GetXmlReader(const bool useCaching, const std::string& text) noexcept
{
    if (useCaching) {
        static ReaderTypePtr reader = nullptr;
        if (reader) { // reuse xml text reader instance
            xmlReaderNewMemory(*reader, text.data(), text.size(), NULL, NULL, XML_PARSE_NOBLANKS);
        }
        else {
            reader = ReaderTypePtr(CreateReader(text), FreeXmlReader);
        }
        return reader;
    }

    return ReaderTypePtr(CreateReader(text), FreeXmlReader);
}

static inline int ConvertXmlToText__(
    const std::shared_ptr<NodeImpl>& root,
    const xmlTextWriterPtr writer,
    const ValueFilter& valueFilter)
{
    if (xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>(root->name().c_str())) < 0) {
        return -1;
    }

    for (const auto& node : root->nodes()) {
        if (not node) {
            continue;
        }
        if (node->type() == NodeType::ATTRIBUTE or node->type() == NodeType::OPTIONAL_ATTRIBUTE) {
            if (valueFilter) {
                if (xmlTextWriterWriteAttribute(
                        writer,
                        reinterpret_cast<const xmlChar*>(node->name().c_str()),
                        reinterpret_cast<const xmlChar*>(GenerateString(node->text(), valueFilter).c_str())) < 0) {
                    return -1;
                }
            }
            else {
                if (xmlTextWriterWriteAttribute(
                        writer,
                        reinterpret_cast<const xmlChar*>(node->name().c_str()),
                        reinterpret_cast<const xmlChar*>(node->text().c_str())) < 0) {
                    return -1;
                }
            }
        }
    }

    for (const auto& node : root->nodes()) {
        if (not node) {
            continue;
        }
        if (node->type() == NodeType::ELEMENT or node->type() == NodeType::OPTIONAL) {
            if (ConvertXmlToText__(node, writer, valueFilter) < 0) {
                return -1;
            }
        }
    }

    if (not root->text().empty()) {
        if (valueFilter) {
            if (xmlTextWriterWriteRaw(
                    writer,
                    reinterpret_cast<const xmlChar*>(GenerateString(root->text(), valueFilter).c_str())) < 0) {
                return -1;
            }
        }
        else {
            if (xmlTextWriterWriteRaw(
                    writer,
                    reinterpret_cast<const xmlChar*>(root->text().c_str())) < 0) {
                return -1;
            }
        }
    }

    if (xmlTextWriterEndElement(writer) < 0) {
        return -1;
    }

    return 0;
}

static inline void ErrorHandler(void *ctx, const xmlErrorPtr error)
{
    using std::to_string;

    if (not error || error->code == XML_ERR_OK) {
        return;
    }

    auto res = static_cast<std::string*>(ctx);

    if (not res) {
        xmlResetError(error);
        return;
    }

    auto& result = *res;
    result.reserve(1024);

    result += "LibXML2: ";

    switch (error->level) {
    case XML_ERR_NONE:
        result += "";
        break;
    case XML_ERR_WARNING:
        result += "Warning: ";
        break;
    case XML_ERR_ERROR:
        result += "Error: ";
        break;
    case XML_ERR_FATAL:
        result += "Fatal error: ";
        break;
    default:
        result += "Unknown error: ";
        break;
    }

    const int line = error->line;

    if (error->file != NULL) {
        result += error->file;
    } else if (line != 0) {
        result += "Entity: line " + to_string(line) + ", column: " + to_string(error->int2);
    }

    const auto node = static_cast<xmlNodePtr>(error->node);
    if (error->node != NULL and node->type == XML_ELEMENT_NODE) {
        result += ", element ";
        result += reinterpret_cast<const char*>(node->name);
    }

    result += ": ";
    result += error->message;
    result += '\n';

    xmlResetError(error);
}

static inline std::string ConvertXmlToText_(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    const ValueFilter& valueFilter,
    const bool useCaching,
    std::string& error)
{
    static auto MEMORY_ALLOCATION_POLICY = XML_BUFFER_ALLOC_DOUBLEIT;
    int rc {};

    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    const auto buffer = GetXmlBuffer(useCaching);

    if (not buffer or not *buffer) {
        if (error.empty()) {
            error = CreateErrorText("GetXmlBuffer");
        }
        return {};
    }

    xmlBufferSetAllocationScheme(*buffer, MEMORY_ALLOCATION_POLICY);

    const auto writer = GetXmlWriter(useCaching, buffer);

    if (not writer or not *writer) {
        if (error.empty()) {
            error = CreateErrorText("GetXmlWriter");
        }
        return {};
    }

    if ((rc = xmlTextWriterStartDocument(*writer, NULL/*version*/, "UTF-8", NULL/*standalone*/)) < 0) {
        if (error.empty()) {
            error = CreateErrorText("xmlTextWriterStartDocument");
        }
        return {};
    }

    xmlTextWriterSetIndentString(*writer, reinterpret_cast<const xmlChar*>(indent ? "  " : ""));
    xmlTextWriterSetIndent(*writer, indent ? 1 : 0 /*indent*/);

    if ((rc = ConvertXmlToText__(root, *writer, valueFilter)) < 0) {
        if (error.empty()) {
            error = CreateErrorText("ConvertXmlToText__");
        }
        return {};
    }

    if ((rc = xmlTextWriterEndDocument(*writer)) < 0) {
        if (error.empty()) {
            error = CreateErrorText("xmlTextWriterEndDocument");
        }
        return {};
    }

    return std::string(reinterpret_cast<const std::string::value_type*>(xmlBufferContent(*buffer)),
                       xmlBufferLength(*buffer));
}

static inline NodeImpl& FindLastByDepth(NodeImpl& root, size_t depth)
{
    auto* node = &root;
    for (depth -= 1; depth and not node->nodes().empty() and node->nodes().back(); --depth) {
        node = &*node->nodes().back();
    }
    return *node;
}

static inline void FetchAllAttributes(
    NodeImpl& node,
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    if (xmlTextReaderHasAttributes(reader)) {
        while (xmlTextReaderMoveToNextAttribute(reader)) {
            const xmlChar* name = xmlTextReaderConstName(reader);
            const xmlChar* value = xmlTextReaderConstValue(reader);

            if (name and value) {
                if (valueFilter) {
                    NodeImpl prop {
                        {reinterpret_cast<const char*>(name), static_cast<size_t>(xmlStrlen(name))},
                        GenerateString(
                            std::string(reinterpret_cast<const char*>(value),
                                        static_cast<size_t>(xmlStrlen(value))),
                            valueFilter)
                    };
                    prop.type(NodeType::ATTRIBUTE);
                    prop.isCaseInsensitive(isCaseInsensitive);
                    node.addNode(std::move(prop));
                }
                else {
                    NodeImpl prop {
                        {reinterpret_cast<const char*>(name), static_cast<size_t>(xmlStrlen(name))},
                        {reinterpret_cast<const char*>(value), static_cast<size_t>(xmlStrlen(value))},
                    };
                    prop.type(NodeType::ATTRIBUTE);
                    prop.isCaseInsensitive(isCaseInsensitive);
                    node.addNode(std::move(prop));
                }
            }
        }
        xmlTextReaderMoveToElement(reader);
    }
}

static inline std::shared_ptr<NodeImpl> ParseXmlFromText__(
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    const ValueFilter& valueFilter)
{
    auto ret = xmlTextReaderRead(reader);
    auto nodeType = xmlTextReaderNodeType(reader);

    if (nodeType != XML_ELEMENT_NODE or (ret != 1 and ret != 0)) {
        return nullptr;
    }

    const xmlChar* rootName = xmlTextReaderConstName(reader);

    if (not rootName) {
        return nullptr;
    }

    const auto root = std::make_shared<NodeImpl>(
        std::string{reinterpret_cast<const char*>(rootName), static_cast<size_t>(xmlStrlen(rootName))});
    root->isCaseInsensitive(isCaseInsensitive);

    FetchAllAttributes(*root, reader, isCaseInsensitive, valueFilter);

    for (ret = xmlTextReaderRead(reader); ret == 1; ret = xmlTextReaderRead(reader)) {
        nodeType = xmlTextReaderNodeType(reader);

        if (nodeType == XML_ELEMENT_NODE) {
            const xmlChar* name = xmlTextReaderConstName(reader);

            if (name) {
                NodeImpl node {
                    {reinterpret_cast<const char*>(name), static_cast<size_t>(xmlStrlen(name))},
                };
                node.type(NodeType::ELEMENT);
                node.isCaseInsensitive(isCaseInsensitive);

                FetchAllAttributes(node, reader, isCaseInsensitive, valueFilter);

                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.addNode(std::move(node));
            }
        }
        else if (nodeType == XML_TEXT_NODE and xmlTextReaderHasValue(reader)) {
            const xmlChar* value = xmlTextReaderConstValue(reader);

            if (value) {
                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                if (valueFilter) {
                    lastNode.text().append(GenerateString(
                                               std::string(reinterpret_cast<const char*>(value),
                                                           static_cast<size_t>(xmlStrlen(value))),
                                               valueFilter));
                }
                else {
                    lastNode.text().append(reinterpret_cast<const char*>(value), xmlStrlen(value));
                }
            }
        }
        else if (nodeType == XML_CDATA_SECTION_NODE and xmlTextReaderHasValue(reader)) {
            const xmlChar* value = xmlTextReaderConstValue(reader);

            if (value) {
                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.text() += "<![CDATA[";
                if (valueFilter) {
                    lastNode.text().append(GenerateString(
                        std::string(reinterpret_cast<const char*>(value),
                                    static_cast<size_t>(xmlStrlen(value))),
                        valueFilter));
                }
                else {
                    lastNode.text().append(reinterpret_cast<const char*>(value), xmlStrlen(value));
                }
                lastNode.text() += "]]>";
            }
        }
    }

    return ret != 0 ? nullptr : root;
}

static inline std::shared_ptr<NodeImpl> ParseXmlFromText_(
    const std::string& text,
    const bool isCaseInsensitive,
    const ValueFilter& valueFilter,
    const bool useCaching,
    std::string& error)
{
    if (text.empty()) {
        return nullptr;
    }

    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    const auto reader = GetXmlReader(useCaching, text);

    if (not reader or not *reader) {
        if (error.empty()) {
            error = CreateErrorText("GetXmlReader");
        }
        return nullptr;
    }

    const auto node = ParseXmlFromText__(*reader, isCaseInsensitive, valueFilter);

    if (not node and error.empty()) {
        error = CreateErrorText("ParseXmlFromText__");
    }

    return node;
}

} /* anonymous namespace */

inline std::string ConvertXmlToText(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    const ValueFilter& valueFilter,
    const bool useCaching)
{
    std::string error;

    InitializeParser();
    const auto result = ConvertXmlToText_(root, indent, valueFilter, useCaching, error);
    CleanupParser();

    if (not error.empty()) {
        throw Xml11Exception{error};
    }

    return result;
}

inline std::shared_ptr<NodeImpl> ParseXmlFromText(
    const std::string& text,
    const bool isCaseInsensitive,
    const ValueFilter& valueFilter,
    const bool useCaching)
{
    std::string error;

    InitializeParser();
    const auto result = ParseXmlFromText_(text, isCaseInsensitive, valueFilter, useCaching, error);
    CleanupParser();

    if (not error.empty()) {
        throw Xml11Exception{error};
    }

    return result;
}

} /* namespace xml11 */
<commit_msg>Add possibility to work with huge data strings<commit_after>#pragma once

#include <libxml/xmlreader.h>
#include <libxml/xmlwriter.h>

namespace xml11 {

namespace {

#define CreateErrorText(param) \
    (std::string(__FILE__) + ": " + __FUNCTION__ + ": " + std::to_string(__LINE__) + ": Error in " + (param));

static const size_t parseOptions = XML_PARSE_NOBLANKS | XML_PARSE_HUGE;

using BufferType = std::decay_t<decltype(xmlBufferCreate())>;
using WriterType = std::decay_t<decltype(xmlNewTextWriterMemory({}, {}))>;
using ReaderType = std::decay_t<decltype(xmlReaderForMemory({}, {}, {}, {}, {}))>;

using BufferTypePtr = std::shared_ptr<BufferType>;
using WriterTypePtr = std::shared_ptr<WriterType>;
using ReaderTypePtr = std::shared_ptr<ReaderType>;

static inline void InitializeParser() noexcept
{
    xmlInitParser();
}

static inline void CleanupParser() noexcept
{
    if (xmlGetLastError()) {
        xmlResetError(xmlGetLastError());
        xmlResetLastError();
    }

    xmlSetStructuredErrorFunc(NULL, NULL);
    xmlSetGenericErrorFunc(NULL, NULL);
    initGenericErrorDefaultFunc(NULL);
    xmlCleanupParser();
}

template<class T, class Fn>
static inline void ReleaseMemory(const T* buffer, Fn fn) noexcept
{
    if (buffer) {
        if (*buffer) {
            fn(*buffer);
        }
        delete buffer;
        buffer = nullptr;
    }
}

static inline void FreeXmlBuffer(const BufferType* buffer) noexcept
{
    ReleaseMemory(buffer, xmlBufferFree);
}

static inline void FreeXmlWriter(const WriterType* writer) noexcept
{
    ReleaseMemory(writer, xmlFreeTextWriter);
}

static inline void FreeXmlReader(const ReaderType* reader) noexcept
{
    ReleaseMemory(reader, xmlFreeTextReader);
}

static inline BufferType* CreateBuffer() noexcept
{
    return new BufferType(xmlBufferCreateSize(BASE_BUFFER_SIZE));
}

static inline WriterType* CreateWriter(const BufferTypePtr& buffer) noexcept
{
    return new WriterType(xmlNewTextWriterMemory(*buffer, 0 /* compress */));
}

static inline ReaderType* CreateReader(const std::string& text) noexcept
{
    return new ReaderType(xmlReaderForMemory(text.data(), text.size(), NULL, NULL, parseOptions));
}

static inline BufferTypePtr GetXmlBuffer(const bool useCaching) noexcept
{
    if (useCaching) {
        static const auto buffer = BufferTypePtr(CreateBuffer(), FreeXmlBuffer);
        xmlBufferEmpty(*buffer);
        return buffer;
    }

    return BufferTypePtr(CreateBuffer(), FreeXmlBuffer);
}

static inline WriterTypePtr GetXmlWriter(const bool useCaching, const BufferTypePtr& buffer) noexcept
{
    if (useCaching) {
        static const auto writer = WriterTypePtr(CreateWriter(buffer), FreeXmlWriter);
        return writer;
    }

    return WriterTypePtr(CreateWriter(buffer), FreeXmlWriter);
}

static inline ReaderTypePtr GetXmlReader(const bool useCaching, const std::string& text) noexcept
{
    if (useCaching) {
        static ReaderTypePtr reader = nullptr;
        if (reader) { // reuse xml text reader instance
            xmlReaderNewMemory(*reader, text.data(), text.size(), NULL, NULL, parseOptions);
        }
        else {
            reader = ReaderTypePtr(CreateReader(text), FreeXmlReader);
        }
        return reader;
    }

    return ReaderTypePtr(CreateReader(text), FreeXmlReader);
}

static inline int ConvertXmlToText__(
    const std::shared_ptr<NodeImpl>& root,
    const xmlTextWriterPtr writer,
    const ValueFilter& valueFilter)
{
    if (xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>(root->name().c_str())) < 0) {
        return -1;
    }

    for (const auto& node : root->nodes()) {
        if (not node) {
            continue;
        }
        if (node->type() == NodeType::ATTRIBUTE or node->type() == NodeType::OPTIONAL_ATTRIBUTE) {
            if (valueFilter) {
                if (xmlTextWriterWriteAttribute(
                        writer,
                        reinterpret_cast<const xmlChar*>(node->name().c_str()),
                        reinterpret_cast<const xmlChar*>(GenerateString(node->text(), valueFilter).c_str())) < 0) {
                    return -1;
                }
            }
            else {
                if (xmlTextWriterWriteAttribute(
                        writer,
                        reinterpret_cast<const xmlChar*>(node->name().c_str()),
                        reinterpret_cast<const xmlChar*>(node->text().c_str())) < 0) {
                    return -1;
                }
            }
        }
    }

    for (const auto& node : root->nodes()) {
        if (not node) {
            continue;
        }
        if (node->type() == NodeType::ELEMENT or node->type() == NodeType::OPTIONAL) {
            if (ConvertXmlToText__(node, writer, valueFilter) < 0) {
                return -1;
            }
        }
    }

    if (not root->text().empty()) {
        if (valueFilter) {
            if (xmlTextWriterWriteRaw(
                    writer,
                    reinterpret_cast<const xmlChar*>(GenerateString(root->text(), valueFilter).c_str())) < 0) {
                return -1;
            }
        }
        else {
            if (xmlTextWriterWriteRaw(
                    writer,
                    reinterpret_cast<const xmlChar*>(root->text().c_str())) < 0) {
                return -1;
            }
        }
    }

    if (xmlTextWriterEndElement(writer) < 0) {
        return -1;
    }

    return 0;
}

static inline void ErrorHandler(void *ctx, const xmlErrorPtr error)
{
    using std::to_string;

    if (not error || error->code == XML_ERR_OK) {
        return;
    }

    auto res = static_cast<std::string*>(ctx);

    if (not res) {
        xmlResetError(error);
        return;
    }

    auto& result = *res;
    result.reserve(1024);

    result += "LibXML2: ";

    switch (error->level) {
    case XML_ERR_NONE:
        result += "";
        break;
    case XML_ERR_WARNING:
        result += "Warning: ";
        break;
    case XML_ERR_ERROR:
        result += "Error: ";
        break;
    case XML_ERR_FATAL:
        result += "Fatal error: ";
        break;
    default:
        result += "Unknown error: ";
        break;
    }

    const int line = error->line;

    if (error->file != NULL) {
        result += error->file;
    } else if (line != 0) {
        result += "Entity: line " + to_string(line) + ", column: " + to_string(error->int2);
    }

    const auto node = static_cast<xmlNodePtr>(error->node);
    if (error->node != NULL and node->type == XML_ELEMENT_NODE) {
        result += ", element ";
        result += reinterpret_cast<const char*>(node->name);
    }

    result += ": ";
    result += error->message;
    result += '\n';

    xmlResetError(error);
}

static inline std::string ConvertXmlToText_(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    const ValueFilter& valueFilter,
    const bool useCaching,
    std::string& error)
{
    static auto MEMORY_ALLOCATION_POLICY = XML_BUFFER_ALLOC_DOUBLEIT;
    int rc {};

    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    const auto buffer = GetXmlBuffer(useCaching);

    if (not buffer or not *buffer) {
        if (error.empty()) {
            error = CreateErrorText("GetXmlBuffer");
        }
        return {};
    }

    xmlBufferSetAllocationScheme(*buffer, MEMORY_ALLOCATION_POLICY);

    const auto writer = GetXmlWriter(useCaching, buffer);

    if (not writer or not *writer) {
        if (error.empty()) {
            error = CreateErrorText("GetXmlWriter");
        }
        return {};
    }

    if ((rc = xmlTextWriterStartDocument(*writer, NULL/*version*/, "UTF-8", NULL/*standalone*/)) < 0) {
        if (error.empty()) {
            error = CreateErrorText("xmlTextWriterStartDocument");
        }
        return {};
    }

    xmlTextWriterSetIndentString(*writer, reinterpret_cast<const xmlChar*>(indent ? "  " : ""));
    xmlTextWriterSetIndent(*writer, indent ? 1 : 0 /*indent*/);

    if ((rc = ConvertXmlToText__(root, *writer, valueFilter)) < 0) {
        if (error.empty()) {
            error = CreateErrorText("ConvertXmlToText__");
        }
        return {};
    }

    if ((rc = xmlTextWriterEndDocument(*writer)) < 0) {
        if (error.empty()) {
            error = CreateErrorText("xmlTextWriterEndDocument");
        }
        return {};
    }

    return std::string(reinterpret_cast<const std::string::value_type*>(xmlBufferContent(*buffer)),
                       xmlBufferLength(*buffer));
}

static inline NodeImpl& FindLastByDepth(NodeImpl& root, size_t depth)
{
    auto* node = &root;
    for (depth -= 1; depth and not node->nodes().empty() and node->nodes().back(); --depth) {
        node = &*node->nodes().back();
    }
    return *node;
}

static inline void FetchAllAttributes(
    NodeImpl& node,
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    ValueFilter valueFilter)
{
    if (xmlTextReaderHasAttributes(reader)) {
        while (xmlTextReaderMoveToNextAttribute(reader)) {
            const xmlChar* name = xmlTextReaderConstName(reader);
            const xmlChar* value = xmlTextReaderConstValue(reader);

            if (name and value) {
                if (valueFilter) {
                    NodeImpl prop {
                        {reinterpret_cast<const char*>(name), static_cast<size_t>(xmlStrlen(name))},
                        GenerateString(
                            std::string(reinterpret_cast<const char*>(value),
                                        static_cast<size_t>(xmlStrlen(value))),
                            valueFilter)
                    };
                    prop.type(NodeType::ATTRIBUTE);
                    prop.isCaseInsensitive(isCaseInsensitive);
                    node.addNode(std::move(prop));
                }
                else {
                    NodeImpl prop {
                        {reinterpret_cast<const char*>(name), static_cast<size_t>(xmlStrlen(name))},
                        {reinterpret_cast<const char*>(value), static_cast<size_t>(xmlStrlen(value))},
                    };
                    prop.type(NodeType::ATTRIBUTE);
                    prop.isCaseInsensitive(isCaseInsensitive);
                    node.addNode(std::move(prop));
                }
            }
        }
        xmlTextReaderMoveToElement(reader);
    }
}

static inline std::shared_ptr<NodeImpl> ParseXmlFromText__(
    const xmlTextReaderPtr reader,
    const bool isCaseInsensitive,
    const ValueFilter& valueFilter)
{
    auto ret = xmlTextReaderRead(reader);
    auto nodeType = xmlTextReaderNodeType(reader);

    if (nodeType != XML_ELEMENT_NODE or (ret != 1 and ret != 0)) {
        return nullptr;
    }

    const xmlChar* rootName = xmlTextReaderConstName(reader);

    if (not rootName) {
        return nullptr;
    }

    const auto root = std::make_shared<NodeImpl>(
        std::string{reinterpret_cast<const char*>(rootName), static_cast<size_t>(xmlStrlen(rootName))});
    root->isCaseInsensitive(isCaseInsensitive);

    FetchAllAttributes(*root, reader, isCaseInsensitive, valueFilter);

    for (ret = xmlTextReaderRead(reader); ret == 1; ret = xmlTextReaderRead(reader)) {
        nodeType = xmlTextReaderNodeType(reader);

        if (nodeType == XML_ELEMENT_NODE) {
            const xmlChar* name = xmlTextReaderConstName(reader);

            if (name) {
                NodeImpl node {
                    {reinterpret_cast<const char*>(name), static_cast<size_t>(xmlStrlen(name))},
                };
                node.type(NodeType::ELEMENT);
                node.isCaseInsensitive(isCaseInsensitive);

                FetchAllAttributes(node, reader, isCaseInsensitive, valueFilter);

                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.addNode(std::move(node));
            }
        }
        else if (nodeType == XML_TEXT_NODE and xmlTextReaderHasValue(reader)) {
            const xmlChar* value = xmlTextReaderConstValue(reader);

            if (value) {
                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                if (valueFilter) {
                    lastNode.text().append(GenerateString(
                                               std::string(reinterpret_cast<const char*>(value),
                                                           static_cast<size_t>(xmlStrlen(value))),
                                               valueFilter));
                }
                else {
                    lastNode.text().append(reinterpret_cast<const char*>(value), xmlStrlen(value));
                }
            }
        }
        else if (nodeType == XML_CDATA_SECTION_NODE and xmlTextReaderHasValue(reader)) {
            const xmlChar* value = xmlTextReaderConstValue(reader);

            if (value) {
                auto& lastNode = FindLastByDepth(*root, xmlTextReaderDepth(reader));
                lastNode.text() += "<![CDATA[";
                if (valueFilter) {
                    lastNode.text().append(GenerateString(
                        std::string(reinterpret_cast<const char*>(value),
                                    static_cast<size_t>(xmlStrlen(value))),
                        valueFilter));
                }
                else {
                    lastNode.text().append(reinterpret_cast<const char*>(value), xmlStrlen(value));
                }
                lastNode.text() += "]]>";
            }
        }
    }

    return ret != 0 ? nullptr : root;
}

static inline std::shared_ptr<NodeImpl> ParseXmlFromText_(
    const std::string& text,
    const bool isCaseInsensitive,
    const ValueFilter& valueFilter,
    const bool useCaching,
    std::string& error)
{
    if (text.empty()) {
        return nullptr;
    }

    xmlSetStructuredErrorFunc(&error, reinterpret_cast<xmlStructuredErrorFunc>(ErrorHandler));

    const auto reader = GetXmlReader(useCaching, text);

    if (not reader or not *reader) {
        if (error.empty()) {
            error = CreateErrorText("GetXmlReader");
        }
        return nullptr;
    }

    const auto node = ParseXmlFromText__(*reader, isCaseInsensitive, valueFilter);

    if (not node and error.empty()) {
        error = CreateErrorText("ParseXmlFromText__");
    }

    return node;
}

} /* anonymous namespace */

inline std::string ConvertXmlToText(
    const std::shared_ptr<NodeImpl>& root,
    const bool indent,
    const ValueFilter& valueFilter,
    const bool useCaching)
{
    std::string error;

    InitializeParser();
    const auto result = ConvertXmlToText_(root, indent, valueFilter, useCaching, error);
    CleanupParser();

    if (not error.empty()) {
        throw Xml11Exception{error};
    }

    return result;
}

inline std::shared_ptr<NodeImpl> ParseXmlFromText(
    const std::string& text,
    const bool isCaseInsensitive,
    const ValueFilter& valueFilter,
    const bool useCaching)
{
    std::string error;

    InitializeParser();
    const auto result = ParseXmlFromText_(text, isCaseInsensitive, valueFilter, useCaching, error);
    CleanupParser();

    if (not error.empty()) {
        throw Xml11Exception{error};
    }

    return result;
}

} /* namespace xml11 */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: kernihdl.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: mib $ $Date: 2000-10-23 12:58:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_PROPERTYHANDLER_KERNINGTYPES_HXX
#include "kernihdl.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

// --

#ifndef _XMLOFF_XMLKYWD_HXX
#include <xmlkywd.hxx>
#endif

#ifndef _XMLOFF_XMLUCONV_HXX
#include "xmluconv.hxx"
#endif

using namespace ::rtl;
using namespace ::com::sun::star::uno;

///////////////////////////////////////////////////////////////////////////////
//
// class XMLKerningPropHdl
//

XMLKerningPropHdl::~XMLKerningPropHdl()
{
    // nothing to do
}

sal_Bool XMLKerningPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_True;
    sal_Int32 nKerning = 0;

    if( !rStrImpValue.equalsAsciiL( sXML_kerning_normal,
                                    sizeof(sXML_kerning_normal) ) )
    {
        bRet = rUnitConverter.convertMeasure( nKerning, rStrImpValue );
    }

    rValue <<= (sal_Int16)nKerning;

    return bRet;
}

sal_Bool XMLKerningPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;
    sal_Int16 nValue;

    if( rValue >>= nValue )
    {
        OUStringBuffer aOut;

        if( nValue == 0 )
            aOut.appendAscii( sXML_kerning_normal );
        else
            rUnitConverter.convertMeasure( aOut, nValue );

        rStrExpValue = aOut.makeStringAndClear();

        bRet = sal_True;
    }

    return bRet;
}
<commit_msg>- fixed: kerning attribute "normal" now imported correctly          (previously, the "normal" attribute was interpreted as no attribute)<commit_after>/*************************************************************************
 *
 *  $RCSfile: kernihdl.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: dvo $ $Date: 2001-04-10 17:29:15 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _XMLOFF_PROPERTYHANDLER_KERNINGTYPES_HXX
#include "kernihdl.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif

// --

#ifndef _XMLOFF_XMLKYWD_HXX
#include <xmlkywd.hxx>
#endif

#ifndef _XMLOFF_XMLUCONV_HXX
#include "xmluconv.hxx"
#endif

using namespace ::rtl;
using namespace ::com::sun::star::uno;

///////////////////////////////////////////////////////////////////////////////
//
// class XMLKerningPropHdl
//

XMLKerningPropHdl::~XMLKerningPropHdl()
{
    // nothing to do
}

sal_Bool XMLKerningPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_True;
    sal_Int32 nKerning = 0;

    if( !rStrImpValue.equalsAsciiL( sXML_kerning_normal,
                                    sizeof(sXML_kerning_normal)-1 ) )
    {
        bRet = rUnitConverter.convertMeasure( nKerning, rStrImpValue );
    }

    rValue <<= (sal_Int16)nKerning;

    return bRet;
}

sal_Bool XMLKerningPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const
{
    sal_Bool bRet = sal_False;
    sal_Int16 nValue;

    if( rValue >>= nValue )
    {
        OUStringBuffer aOut;

        if( nValue == 0 )
            aOut.appendAscii( sXML_kerning_normal );
        else
            rUnitConverter.convertMeasure( aOut, nValue );

        rStrExpValue = aOut.makeStringAndClear();

        bRet = sal_True;
    }

    return bRet;
}
<|endoftext|>


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

  Library: CppMicroServices

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  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.

=============================================================================*/

#include <usLDAPFilter.h>

#include "usTestingMacros.h"
#include <usServiceInterface.h>
#include <usGetModuleContext.h>
#include <usModuleContext.h>

#include US_BASECLASS_HEADER

#include <stdexcept>

US_USE_NAMESPACE

struct ITestServiceA
{
  virtual ~ITestServiceA() {}
};

US_DECLARE_SERVICE_INTERFACE(ITestServiceA, "org.cppmicroservices.testing.ITestServiceA")

int TestMultipleServiceRegistrations()
{
  struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA
  {
  };

  ModuleContext* context = GetModuleContext();

  TestServiceA s1;
  TestServiceA s2;

  ServiceRegistration reg1 = context->RegisterService<ITestServiceA>(&s1);
  ServiceRegistration reg2 = context->RegisterService<ITestServiceA>(&s2);

  std::list<ServiceReference> refs = context->GetServiceReferences<ITestServiceA>();
  US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Testing for two registered ITestServiceA services")

  reg2.Unregister();
  refs = context->GetServiceReferences<ITestServiceA>();
  US_TEST_CONDITION_REQUIRED(refs.size() == 1, "Testing for one registered ITestServiceA services")

  reg1.Unregister();
  refs = context->GetServiceReferences<ITestServiceA>();
  US_TEST_CONDITION_REQUIRED(refs.empty(), "Testing for no ITestServiceA services")

  return EXIT_SUCCESS;
}

int TestServicePropertiesUpdate()
{
  struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA
  {
  };

  ModuleContext* context = GetModuleContext();

  TestServiceA s1;
  ServiceProperties props;
  props["string"] = std::string("A std::string");
  props["bool"] = false;
  const char* str = "A const char*";
  props["const char*"] = str;

  ServiceRegistration reg1 = context->RegisterService<ITestServiceA>(&s1, props);
  ServiceReference ref1 = context->GetServiceReference<ITestServiceA>();

  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count")
  US_TEST_CONDITION_REQUIRED(any_cast<bool>(ref1.GetProperty("bool")) == false, "Testing bool property")

  // register second service with higher rank
  TestServiceA s2;
  ServiceProperties props2;
  props2[ServiceConstants::SERVICE_RANKING()] = 50;

  ServiceRegistration reg2 = context->RegisterService<ITestServiceA>(&s2, props2);

  // Get the service with the highest rank, this should be s2.
  ServiceReference ref2 = context->GetServiceReference<ITestServiceA>();
  TestServiceA* service = dynamic_cast<TestServiceA*>(context->GetService<ITestServiceA>(ref2));
  US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank")

  props["bool"] = true;
  // change the service ranking
  props[ServiceConstants::SERVICE_RANKING()] = 100;
  reg1.SetProperties(props);

  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 2, "Testing service count")
  US_TEST_CONDITION_REQUIRED(any_cast<bool>(ref1.GetProperty("bool")) == true, "Testing bool property")
  US_TEST_CONDITION_REQUIRED(any_cast<int>(ref1.GetProperty(ServiceConstants::SERVICE_RANKING())) == 100, "Testing updated ranking")

  // Service with the highest ranking should now be s1
  service = dynamic_cast<TestServiceA*>(context->GetService<ITestServiceA>(ref1));
  US_TEST_CONDITION_REQUIRED(service == &s1, "Testing highest service rank")

  reg1.Unregister();
  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").size() == 1, "Testing service count")

  service = dynamic_cast<TestServiceA*>(context->GetService<ITestServiceA>(ref2));
  US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank")

  reg2.Unregister();
  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences("").empty(), "Testing service count")

  return EXIT_SUCCESS;
}

int usServiceRegistryTest(int /*argc*/, char* /*argv*/[])
{
  US_TEST_BEGIN("ServiceRegistryTest");

  US_TEST_CONDITION(TestMultipleServiceRegistrations() == EXIT_SUCCESS, "Testing service registrations: ")
  US_TEST_CONDITION(TestServicePropertiesUpdate() == EXIT_SUCCESS, "Testing service property update: ")

  US_TEST_END()
}

<commit_msg>Test only for a specific service interface count.<commit_after>/*=============================================================================

  Library: CppMicroServices

  Copyright (c) German Cancer Research Center,
    Division of Medical and Biological Informatics

  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.

=============================================================================*/

#include <usLDAPFilter.h>

#include "usTestingMacros.h"
#include <usServiceInterface.h>
#include <usGetModuleContext.h>
#include <usModuleContext.h>

#include US_BASECLASS_HEADER

#include <stdexcept>

US_USE_NAMESPACE

struct ITestServiceA
{
  virtual ~ITestServiceA() {}
};

US_DECLARE_SERVICE_INTERFACE(ITestServiceA, "org.cppmicroservices.testing.ITestServiceA")

int TestMultipleServiceRegistrations()
{
  struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA
  {
  };

  ModuleContext* context = GetModuleContext();

  TestServiceA s1;
  TestServiceA s2;

  ServiceRegistration reg1 = context->RegisterService<ITestServiceA>(&s1);
  ServiceRegistration reg2 = context->RegisterService<ITestServiceA>(&s2);

  std::list<ServiceReference> refs = context->GetServiceReferences<ITestServiceA>();
  US_TEST_CONDITION_REQUIRED(refs.size() == 2, "Testing for two registered ITestServiceA services")

  reg2.Unregister();
  refs = context->GetServiceReferences<ITestServiceA>();
  US_TEST_CONDITION_REQUIRED(refs.size() == 1, "Testing for one registered ITestServiceA services")

  reg1.Unregister();
  refs = context->GetServiceReferences<ITestServiceA>();
  US_TEST_CONDITION_REQUIRED(refs.empty(), "Testing for no ITestServiceA services")

  return EXIT_SUCCESS;
}

int TestServicePropertiesUpdate()
{
  struct TestServiceA : public US_BASECLASS_NAME, public ITestServiceA
  {
  };

  ModuleContext* context = GetModuleContext();

  TestServiceA s1;
  ServiceProperties props;
  props["string"] = std::string("A std::string");
  props["bool"] = false;
  const char* str = "A const char*";
  props["const char*"] = str;

  ServiceRegistration reg1 = context->RegisterService<ITestServiceA>(&s1, props);
  ServiceReference ref1 = context->GetServiceReference<ITestServiceA>();

  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences<ITestServiceA>().size() == 1, "Testing service count")
  US_TEST_CONDITION_REQUIRED(any_cast<bool>(ref1.GetProperty("bool")) == false, "Testing bool property")

  // register second service with higher rank
  TestServiceA s2;
  ServiceProperties props2;
  props2[ServiceConstants::SERVICE_RANKING()] = 50;

  ServiceRegistration reg2 = context->RegisterService<ITestServiceA>(&s2, props2);

  // Get the service with the highest rank, this should be s2.
  ServiceReference ref2 = context->GetServiceReference<ITestServiceA>();
  TestServiceA* service = dynamic_cast<TestServiceA*>(context->GetService<ITestServiceA>(ref2));
  US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank")

  props["bool"] = true;
  // change the service ranking
  props[ServiceConstants::SERVICE_RANKING()] = 100;
  reg1.SetProperties(props);

  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences<ITestServiceA>().size() == 2, "Testing service count")
  US_TEST_CONDITION_REQUIRED(any_cast<bool>(ref1.GetProperty("bool")) == true, "Testing bool property")
  US_TEST_CONDITION_REQUIRED(any_cast<int>(ref1.GetProperty(ServiceConstants::SERVICE_RANKING())) == 100, "Testing updated ranking")

  // Service with the highest ranking should now be s1
  service = dynamic_cast<TestServiceA*>(context->GetService<ITestServiceA>(ref1));
  US_TEST_CONDITION_REQUIRED(service == &s1, "Testing highest service rank")

  reg1.Unregister();
  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences<ITestServiceA>("").size() == 1, "Testing service count")

  service = dynamic_cast<TestServiceA*>(context->GetService<ITestServiceA>(ref2));
  US_TEST_CONDITION_REQUIRED(service == &s2, "Testing highest service rank")

  reg2.Unregister();
  US_TEST_CONDITION_REQUIRED(context->GetServiceReferences<ITestServiceA>().empty(), "Testing service count")

  return EXIT_SUCCESS;
}

int usServiceRegistryTest(int /*argc*/, char* /*argv*/[])
{
  US_TEST_BEGIN("ServiceRegistryTest");

  US_TEST_CONDITION(TestMultipleServiceRegistrations() == EXIT_SUCCESS, "Testing service registrations: ")
  US_TEST_CONDITION(TestServicePropertiesUpdate() == EXIT_SUCCESS, "Testing service property update: ")

  US_TEST_END()
}

<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.

#include "test.hpp"

using namespace ::testing;
using ::testing::Return;

#define private public
#define protected public
#include "iceoryx_posh/internal/roudi/introspection/process_introspection.hpp"
#undef private
#undef protected

#include "iceoryx_posh/iceoryx_posh_types.hpp"
#include "mocks/chunk_mock.hpp"
#include "mocks/senderport_mock.hpp"

class ProcessIntrospection_test : public Test
{
  public:
    using ProcessIntrospection = iox::roudi::ProcessIntrospection<SenderPort_MOCK>;
    using Topic = iox::roudi::ProcessIntrospectionFieldTopic;

    ProcessIntrospection_test()
    {
        m_senderPortImpl_mock = m_senderPortImpl.details;
    }

    ~ProcessIntrospection_test()
    {
    }

    virtual void SetUp()
    {
        internal::CaptureStdout();
    }

    virtual void TearDown()
    {
        std::string output = internal::GetCapturedStdout();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    std::unique_ptr<ChunkMock<Topic>> createMemoryChunkAndSend(ProcessIntrospection& introspection)
    {
        std::unique_ptr<ChunkMock<Topic>> chunk{new ChunkMock<Topic>};

        m_senderPortImpl_mock->reserveSampleReturn = chunk->chunkHeader();
        m_senderPortImpl_mock->deliverChunk = 0;

        introspection.send();

        EXPECT_THAT(m_senderPortImpl_mock->deliverChunk, Eq(1u));
        m_senderPortImpl_mock->deliverChunk = 0;

        return chunk;
    }

    SenderPort_MOCK m_senderPortImpl;
    std::shared_ptr<SenderPort_MOCK::mock_t> m_senderPortImpl_mock = m_senderPortImpl.details;
};

TEST_F(ProcessIntrospection_test, CTOR)
{
    ProcessIntrospection m_introspection;
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(0u));
}

TEST_F(ProcessIntrospection_test, registerSenderPort)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1u));
}

TEST_F(ProcessIntrospection_test, send)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        auto chunk = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk->sample()->m_processList.size(), Eq(0u));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1u));
}

TEST_F(ProcessIntrospection_test, addRemoveProcess)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        const int PID = 42;
        const char PROCESS_NAME[] = "/chuck_norris";

        m_senderPortImpl_mock->hasSubscribersReturn = true;

        // invalid removal doesn't cause problems
        m_introspection.removeProcess(PID);
        auto chunk1 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk1->sample()->m_processList.size(), Eq(0u));

        // a new process should be sent
        m_introspection.addProcess(PID, iox::cxx::string<100>(PROCESS_NAME));
        auto chunk2 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk2->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk2->sample()->m_processList[0].m_pid, Eq(PID));
        EXPECT_THAT(iox::cxx::string<100>(PROCESS_NAME) == chunk2->sample()->m_processList[0].m_name, Eq(true));

        // list should be empty after removal
        m_introspection.removeProcess(PID);
        auto chunk3 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk3->sample()->m_processList.size(), Eq(0u));

        // if there isn't any change, no data are deliverd
        m_introspection.send();
        EXPECT_THAT(m_senderPortImpl_mock->deliverChunk, Eq(0u));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1u));
}

TEST_F(ProcessIntrospection_test, thread)
{
    {
        ChunkMock<Topic> chunk;

        const int PID = 42;
        const char PROCESS_NAME[] = "/chuck_norris";

        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;

        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        m_senderPortImpl_mock->reserveSampleReturn = chunk.chunkHeader();
        // we use the deliverChunk call to check how often the thread calls the send method

        std::chrono::milliseconds& sendIntervalSleep =
            const_cast<std::chrono::milliseconds&>(m_introspection.m_sendIntervalSleep);
        sendIntervalSleep = std::chrono::milliseconds(10);

        m_introspection.setSendInterval(10);
        m_introspection.run();

        for (size_t i = 0; i < 3; ++i)
        {
            m_introspection.addProcess(PID, iox::ProcessName_t(PROCESS_NAME));
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
            m_introspection.removeProcess(PID);
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
        }
        // within this time, the thread should have sent the 6 updates
        m_introspection.stop();

        for (size_t i = 0; i < 3; ++i)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
            m_introspection.addProcess(PID, iox::ProcessName_t(PROCESS_NAME));
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
            m_introspection.removeProcess(PID);
        }
        // if the thread doesn't stop, we have 12 runs after the sleep period
        EXPECT_THAT(m_senderPortImpl_mock->activate, Eq(1u));
        EXPECT_THAT(4 <= m_senderPortImpl_mock->deliverChunk && m_senderPortImpl_mock->deliverChunk <= 8, Eq(true));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1u));
}

TEST_F(ProcessIntrospection_test, addRemoveRunnable)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        const int PID = 42;
        const char PROCESS_NAME[] = "/chuck_norris";
        const char RUNNABLE_1[] = "the_wrecking_crew";
        const char RUNNABLE_2[] = "the_octagon";
        const char RUNNABLE_3[] = "the_hitman";

        m_senderPortImpl_mock->hasSubscribersReturn = true;

        // invalid removal of unknown runnable of unknown process
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk1 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk1->sample()->m_processList.size(), Eq(0u));

        // a new process
        m_introspection.addProcess(PID, iox::ProcessName_t(PROCESS_NAME));

        // invalid removal of unknown runnable of known process
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk2 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk2->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk2->sample()->m_processList[0].m_runnables.size(), Eq(0u));

        // add a runnable
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk3 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk3->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk3->sample()->m_processList[0].m_runnables.size(), Eq(1u));

        // add it again, must be ignored
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk4 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk4->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk4->sample()->m_processList[0].m_runnables.size(), Eq(1u));

        // add some more
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_2));
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_3));
        auto chunk5 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk5->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk5->sample()->m_processList[0].m_runnables.size(), Eq(3u));

        // remove some runnables
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_3));
        auto chunk6 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk6->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk6->sample()->m_processList[0].m_runnables.size(), Eq(1u));
        EXPECT_THAT(strcmp(RUNNABLE_2, chunk6->sample()->m_processList[0].m_runnables[0].c_str()), Eq(0));

        // remove last runnable list empty again
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_2));
        auto chunk7 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk7->sample()->m_processList.size(), Eq(1u));
        EXPECT_THAT(chunk7->sample()->m_processList[0].m_runnables.size(), Eq(0u));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1u));
}
<commit_msg>iox-#260 uppdercase literal suffix u->U<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// 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.

#include "test.hpp"

using namespace ::testing;
using ::testing::Return;

#define private public
#define protected public
#include "iceoryx_posh/internal/roudi/introspection/process_introspection.hpp"
#undef private
#undef protected

#include "iceoryx_posh/iceoryx_posh_types.hpp"
#include "mocks/chunk_mock.hpp"
#include "mocks/senderport_mock.hpp"

class ProcessIntrospection_test : public Test
{
  public:
    using ProcessIntrospection = iox::roudi::ProcessIntrospection<SenderPort_MOCK>;
    using Topic = iox::roudi::ProcessIntrospectionFieldTopic;

    ProcessIntrospection_test()
    {
        m_senderPortImpl_mock = m_senderPortImpl.details;
    }

    ~ProcessIntrospection_test()
    {
    }

    virtual void SetUp()
    {
        internal::CaptureStdout();
    }

    virtual void TearDown()
    {
        std::string output = internal::GetCapturedStdout();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    std::unique_ptr<ChunkMock<Topic>> createMemoryChunkAndSend(ProcessIntrospection& introspection)
    {
        std::unique_ptr<ChunkMock<Topic>> chunk{new ChunkMock<Topic>};

        m_senderPortImpl_mock->reserveSampleReturn = chunk->chunkHeader();
        m_senderPortImpl_mock->deliverChunk = 0;

        introspection.send();

        EXPECT_THAT(m_senderPortImpl_mock->deliverChunk, Eq(1U));
        m_senderPortImpl_mock->deliverChunk = 0;

        return chunk;
    }

    SenderPort_MOCK m_senderPortImpl;
    std::shared_ptr<SenderPort_MOCK::mock_t> m_senderPortImpl_mock = m_senderPortImpl.details;
};

TEST_F(ProcessIntrospection_test, CTOR)
{
    ProcessIntrospection m_introspection;
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(0U));
}

TEST_F(ProcessIntrospection_test, registerSenderPort)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1U));
}

TEST_F(ProcessIntrospection_test, send)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        auto chunk = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk->sample()->m_processList.size(), Eq(0U));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1U));
}

TEST_F(ProcessIntrospection_test, addRemoveProcess)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        const int PID = 42;
        const char PROCESS_NAME[] = "/chuck_norris";

        m_senderPortImpl_mock->hasSubscribersReturn = true;

        // invalid removal doesn't cause problems
        m_introspection.removeProcess(PID);
        auto chunk1 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk1->sample()->m_processList.size(), Eq(0U));

        // a new process should be sent
        m_introspection.addProcess(PID, iox::cxx::string<100>(PROCESS_NAME));
        auto chunk2 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk2->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk2->sample()->m_processList[0].m_pid, Eq(PID));
        EXPECT_THAT(iox::cxx::string<100>(PROCESS_NAME) == chunk2->sample()->m_processList[0].m_name, Eq(true));

        // list should be empty after removal
        m_introspection.removeProcess(PID);
        auto chunk3 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk3->sample()->m_processList.size(), Eq(0U));

        // if there isn't any change, no data are deliverd
        m_introspection.send();
        EXPECT_THAT(m_senderPortImpl_mock->deliverChunk, Eq(0U));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1U));
}

TEST_F(ProcessIntrospection_test, thread)
{
    {
        ChunkMock<Topic> chunk;

        const int PID = 42;
        const char PROCESS_NAME[] = "/chuck_norris";

        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;

        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        m_senderPortImpl_mock->reserveSampleReturn = chunk.chunkHeader();
        // we use the deliverChunk call to check how often the thread calls the send method

        std::chrono::milliseconds& sendIntervalSleep =
            const_cast<std::chrono::milliseconds&>(m_introspection.m_sendIntervalSleep);
        sendIntervalSleep = std::chrono::milliseconds(10);

        m_introspection.setSendInterval(10);
        m_introspection.run();

        for (size_t i = 0; i < 3; ++i)
        {
            m_introspection.addProcess(PID, iox::ProcessName_t(PROCESS_NAME));
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
            m_introspection.removeProcess(PID);
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
        }
        // within this time, the thread should have sent the 6 updates
        m_introspection.stop();

        for (size_t i = 0; i < 3; ++i)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
            m_introspection.addProcess(PID, iox::ProcessName_t(PROCESS_NAME));
            std::this_thread::sleep_for(std::chrono::milliseconds(15));
            m_introspection.removeProcess(PID);
        }
        // if the thread doesn't stop, we have 12 runs after the sleep period
        EXPECT_THAT(m_senderPortImpl_mock->activate, Eq(1U));
        EXPECT_THAT(4 <= m_senderPortImpl_mock->deliverChunk && m_senderPortImpl_mock->deliverChunk <= 8, Eq(true));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1U));
}

TEST_F(ProcessIntrospection_test, addRemoveRunnable)
{
    {
        ProcessIntrospection m_introspection;
        m_senderPortImpl_mock->isConnectedToMembersReturn = true;
        m_introspection.registerSenderPort(std::move(m_senderPortImpl));

        const int PID = 42;
        const char PROCESS_NAME[] = "/chuck_norris";
        const char RUNNABLE_1[] = "the_wrecking_crew";
        const char RUNNABLE_2[] = "the_octagon";
        const char RUNNABLE_3[] = "the_hitman";

        m_senderPortImpl_mock->hasSubscribersReturn = true;

        // invalid removal of unknown runnable of unknown process
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk1 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk1->sample()->m_processList.size(), Eq(0U));

        // a new process
        m_introspection.addProcess(PID, iox::ProcessName_t(PROCESS_NAME));

        // invalid removal of unknown runnable of known process
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk2 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk2->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk2->sample()->m_processList[0].m_runnables.size(), Eq(0U));

        // add a runnable
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk3 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk3->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk3->sample()->m_processList[0].m_runnables.size(), Eq(1U));

        // add it again, must be ignored
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        auto chunk4 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk4->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk4->sample()->m_processList[0].m_runnables.size(), Eq(1U));

        // add some more
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_2));
        m_introspection.addRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_3));
        auto chunk5 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk5->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk5->sample()->m_processList[0].m_runnables.size(), Eq(3U));

        // remove some runnables
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_1));
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_3));
        auto chunk6 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk6->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk6->sample()->m_processList[0].m_runnables.size(), Eq(1U));
        EXPECT_THAT(strcmp(RUNNABLE_2, chunk6->sample()->m_processList[0].m_runnables[0].c_str()), Eq(0));

        // remove last runnable list empty again
        m_introspection.removeRunnable(iox::ProcessName_t(PROCESS_NAME), iox::RunnableName_t(RUNNABLE_2));
        auto chunk7 = createMemoryChunkAndSend(m_introspection);
        EXPECT_THAT(chunk7->sample()->m_processList.size(), Eq(1U));
        EXPECT_THAT(chunk7->sample()->m_processList[0].m_runnables.size(), Eq(0U));
    }
    EXPECT_THAT(m_senderPortImpl_mock->deactivate, Eq(1U));
}
<|endoftext|>


<commit_before>// alembicPlugin
// Initial code generated by Softimage SDK Wizard
// Executed Fri Aug 19 09:14:49 UTC+0200 2011 by helge
//
// Tip: You need to compile the generated code before you can load the plug-in.
// After you compile the plug-in, you can load it by clicking Update All in the Plugin Manager.
#include <xsi_application.h>
#include <xsi_context.h>
#include <xsi_pluginregistrar.h>
#include <xsi_status.h>
#include <xsi_argument.h>
#include <xsi_command.h>
#include <xsi_menu.h>
#include <xsi_uitoolkit.h>
#include <xsi_progressbar.h>
#include <xsi_comapihandler.h>
#include <xsi_project.h>
#include <xsi_selection.h>
#include <xsi_model.h>
#include <xsi_null.h>
#include <xsi_camera.h>
#include <xsi_customoperator.h>
#include <xsi_expression.h>
#include <xsi_kinematics.h>
#include <xsi_kinematicstate.h>
#include <xsi_factory.h>
#include <xsi_primitive.h>
#include <xsi_math.h>
#include <xsi_cluster.h>
#include <xsi_clusterproperty.h>
#include <xsi_primitive.h>
#include <xsi_geometry.h>
#include <xsi_polygonmesh.h>
#include <xsi_ppglayout.h>
#include <xsi_ppgitem.h>
#include <xsi_ppgeventcontext.h>
#include <xsi_icetree.h>
#include <xsi_icenode.h>
#include <xsi_icenodeinputport.h>
#include <xsi_icecompoundnode.h>
#include <xsi_utils.h>
#include <xsi_time.h>
#include <time.h>
#include <xsi_customoperator.h>
#include <xsi_operatorcontext.h>
#include <xsi_outputport.h>
#include "arnoldHelpers.h"

using namespace XSI;
using namespace MATH;

#include <boost/exception/all.hpp>

#include "AlembicLicensing.h"

#include "AlembicWriteJob.h"
#include "AlembicPoints.h"
#include "AlembicCurves.h"
#include "CommonProfiler.h"
#include "CommonMeshUtilities.h"
#include "CommonUtilities.h"

SICALLBACK XSILoadPlugin_2( PluginRegistrar& in_reg ) ;

SICALLBACK XSILoadPlugin( PluginRegistrar& in_reg )
{
	in_reg.PutAuthor(L"Helge Mathee");
	in_reg.PutName(L"ExocortexAlembicSoftimage");
	in_reg.PutVersion(1,0);

	//if( HasAlembicWriterLicense() ) {
		in_reg.RegisterCommand(L"alembic_export",L"alembic_export");

		in_reg.RegisterMenu(siMenuMainFileExportID,L"alembic_MenuExport",false,false);

		in_reg.RegisterProperty(L"alembic_export_settings");
	//}

	//if( HasAlembicReaderLicense() ) {
		in_reg.RegisterCommand(L"alembic_import",L"alembic_import");
		in_reg.RegisterCommand(L"alembic_attach_metadata",L"alembic_attach_metadata");
		in_reg.RegisterCommand(L"alembic_create_item",L"alembic_create_item");
		in_reg.RegisterCommand(L"alembic_path_manager",L"alembic_path_manager");
		in_reg.RegisterCommand(L"alembic_profile_stats",L"alembic_profile_stats");

		in_reg.RegisterOperator(L"alembic_xform");
		in_reg.RegisterOperator(L"alembic_camera");
		in_reg.RegisterOperator(L"alembic_polymesh");
		in_reg.RegisterOperator(L"alembic_polymesh_topo");
		in_reg.RegisterOperator(L"alembic_nurbs");
		in_reg.RegisterOperator(L"alembic_bbox");
		in_reg.RegisterOperator(L"alembic_normals");
		in_reg.RegisterOperator(L"alembic_uvs");
		in_reg.RegisterOperator(L"alembic_crvlist");
		in_reg.RegisterOperator(L"alembic_crvlist_topo");
		in_reg.RegisterOperator(L"alembic_visibility");
		in_reg.RegisterOperator(L"alembic_geomapprox");
		in_reg.RegisterOperator(L"alembic_standinop");

		in_reg.RegisterMenu(siMenuMainFileImportID,L"alembic_MenuImport",false,false);
		in_reg.RegisterMenu(siMenuMainFileProjectID,L"alembic_MenuPathManager",false,false);
		in_reg.RegisterMenu(siMenuMainFileProjectID,L"alembic_ProfileStats",false,false);
		in_reg.RegisterMenu(siMenuTbGetPropertyID,L"alembic_MenuMetaData",false,false);

		in_reg.RegisterProperty(L"alembic_import_settings");
		in_reg.RegisterProperty(L"alembic_timecontrol");
		in_reg.RegisterProperty(L"alembic_metadata");

		// register ICE nodes
		Register_alembic_curves(in_reg);
		Register_alembic_points(in_reg);

		XSILoadPlugin_2( in_reg );

		// register events
		in_reg.RegisterEvent(L"alembic_OnCloseScene",siOnCloseScene);
	//}

   ESS_LOG_INFO("PLUGIN loaded");

 	return CStatus::OK;
}

SICALLBACK XSIUnloadPlugin( const PluginRegistrar& in_reg )
{
   deleteAllArchives();

	CString strPluginName;
	strPluginName = in_reg.GetName();
	Application().LogMessage(strPluginName + L" has been unloaded.",siVerboseMsg);
	return CStatus::OK;
}

ESS_CALLBACK_START(alembic_MenuExport_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic 1.0",L"alembic_export",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_MenuImport_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic 1.0",L"alembic_import",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_MenuPathManager_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic Path Manager",L"alembic_path_manager",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_ProfileStats_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic Profile Stats",L"alembic_profile_stats",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_profile_stats_Init,CRef&)
	Context ctxt( in_ctxt );
	Command oCmd;
	oCmd = ctxt.GetSource();
	oCmd.PutDescription(L"");
	oCmd.EnableReturnValue(true);

	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_profile_stats_Execute, CRef&)
    ESS_PROFILE_REPORT();
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_OnCloseScene_OnEvent,CRef&)
   deleteAllArchives();
	return CStatus::OK;
ESS_CALLBACK_END
<commit_msg>fixed #144<commit_after>// alembicPlugin
// Initial code generated by Softimage SDK Wizard
// Executed Fri Aug 19 09:14:49 UTC+0200 2011 by helge
//
// Tip: You need to compile the generated code before you can load the plug-in.
// After you compile the plug-in, you can load it by clicking Update All in the Plugin Manager.
#include <xsi_application.h>
#include <xsi_context.h>
#include <xsi_pluginregistrar.h>
#include <xsi_status.h>
#include <xsi_argument.h>
#include <xsi_command.h>
#include <xsi_menu.h>
#include <xsi_uitoolkit.h>
#include <xsi_progressbar.h>
#include <xsi_comapihandler.h>
#include <xsi_project.h>
#include <xsi_selection.h>
#include <xsi_model.h>
#include <xsi_null.h>
#include <xsi_camera.h>
#include <xsi_customoperator.h>
#include <xsi_expression.h>
#include <xsi_kinematics.h>
#include <xsi_kinematicstate.h>
#include <xsi_factory.h>
#include <xsi_primitive.h>
#include <xsi_math.h>
#include <xsi_cluster.h>
#include <xsi_clusterproperty.h>
#include <xsi_primitive.h>
#include <xsi_geometry.h>
#include <xsi_polygonmesh.h>
#include <xsi_ppglayout.h>
#include <xsi_ppgitem.h>
#include <xsi_ppgeventcontext.h>
#include <xsi_icetree.h>
#include <xsi_icenode.h>
#include <xsi_icenodeinputport.h>
#include <xsi_icecompoundnode.h>
#include <xsi_utils.h>
#include <xsi_time.h>
#include <time.h>
#include <xsi_customoperator.h>
#include <xsi_operatorcontext.h>
#include <xsi_outputport.h>
#include "arnoldHelpers.h"

using namespace XSI;
using namespace MATH;

#include <boost/exception/all.hpp>

#include "AlembicLicensing.h"

#include "AlembicWriteJob.h"
#include "AlembicPoints.h"
#include "AlembicCurves.h"
#include "CommonProfiler.h"
#include "CommonMeshUtilities.h"
#include "CommonUtilities.h"

SICALLBACK XSILoadPlugin_2( PluginRegistrar& in_reg ) ;

SICALLBACK XSILoadPlugin( PluginRegistrar& in_reg )
{
	in_reg.PutAuthor(L"Helge Mathee");
	in_reg.PutName(L"ExocortexAlembicSoftimage");
	in_reg.PutVersion(1,0);

	//if( HasAlembicWriterLicense() ) {
		in_reg.RegisterCommand(L"alembic_export",L"alembic_export");

		in_reg.RegisterMenu(siMenuMainFileExportID,L"alembic_MenuExport",false,false);

		in_reg.RegisterProperty(L"alembic_export_settings");
	//}

	//if( HasAlembicReaderLicense() ) {
		in_reg.RegisterCommand(L"alembic_import",L"alembic_import");
		in_reg.RegisterCommand(L"alembic_attach_metadata",L"alembic_attach_metadata");
		in_reg.RegisterCommand(L"alembic_create_item",L"alembic_create_item");
		in_reg.RegisterCommand(L"alembic_path_manager",L"alembic_path_manager");
		in_reg.RegisterCommand(L"alembic_profile_stats",L"alembic_profile_stats");

		in_reg.RegisterOperator(L"alembic_xform");
		in_reg.RegisterOperator(L"alembic_camera");
		in_reg.RegisterOperator(L"alembic_polymesh");
		in_reg.RegisterOperator(L"alembic_polymesh_topo");
		in_reg.RegisterOperator(L"alembic_nurbs");
		in_reg.RegisterOperator(L"alembic_bbox");
		in_reg.RegisterOperator(L"alembic_normals");
		in_reg.RegisterOperator(L"alembic_uvs");
		in_reg.RegisterOperator(L"alembic_crvlist");
		in_reg.RegisterOperator(L"alembic_crvlist_topo");
		in_reg.RegisterOperator(L"alembic_visibility");
		in_reg.RegisterOperator(L"alembic_geomapprox");
		in_reg.RegisterOperator(L"alembic_standinop");

		in_reg.RegisterMenu(siMenuMainFileImportID,L"alembic_MenuImport",false,false);
		in_reg.RegisterMenu(siMenuMainFileProjectID,L"alembic_MenuPathManager",false,false);
		in_reg.RegisterMenu(siMenuMainFileProjectID,L"alembic_ProfileStats",false,false);
		in_reg.RegisterMenu(siMenuTbGetPropertyID,L"alembic_MenuMetaData",false,false);

		in_reg.RegisterProperty(L"alembic_import_settings");
		in_reg.RegisterProperty(L"alembic_timecontrol");
		in_reg.RegisterProperty(L"alembic_metadata");

		// register ICE nodes
		Register_alembic_curves(in_reg);
		Register_alembic_points(in_reg);

		//XSILoadPlugin_2( in_reg );

		// register events
		in_reg.RegisterEvent(L"alembic_OnCloseScene",siOnCloseScene);
	//}

   ESS_LOG_INFO("PLUGIN loaded");

 	return CStatus::OK;
}

SICALLBACK XSIUnloadPlugin( const PluginRegistrar& in_reg )
{
   deleteAllArchives();

	CString strPluginName;
	strPluginName = in_reg.GetName();
	Application().LogMessage(strPluginName + L" has been unloaded.",siVerboseMsg);
	return CStatus::OK;
}

ESS_CALLBACK_START(alembic_MenuExport_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic 1.0",L"alembic_export",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_MenuImport_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic 1.0",L"alembic_import",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_MenuPathManager_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic Path Manager",L"alembic_path_manager",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_ProfileStats_Init,CRef&)
	Context ctxt( in_ctxt );
	Menu oMenu;
	oMenu = ctxt.GetSource();
	MenuItem oNewItem;
	oMenu.AddCommandItem(L"Alembic Profile Stats",L"alembic_profile_stats",oNewItem);
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_profile_stats_Init,CRef&)
	Context ctxt( in_ctxt );
	Command oCmd;
	oCmd = ctxt.GetSource();
	oCmd.PutDescription(L"");
	oCmd.EnableReturnValue(true);

	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_profile_stats_Execute, CRef&)
    ESS_PROFILE_REPORT();
	return CStatus::OK;
ESS_CALLBACK_END

ESS_CALLBACK_START(alembic_OnCloseScene_OnEvent,CRef&)
   deleteAllArchives();
	return CStatus::OK;
ESS_CALLBACK_END
<|endoftext|>


<commit_before>//===- unittest/Tooling/JsonCompileCommandLineDatabaseTest ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "../../lib/Tooling/JsonCompileCommandLineDatabase.h"
#include "gtest/gtest.h"

namespace clang {
namespace tooling {

TEST(UnescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("");
  EXPECT_TRUE(Result.empty());
}

TEST(UnescapeJsonCommandLine, SplitsOnSpaces) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("a b c");
  ASSERT_EQ(3ul, Result.size());
  EXPECT_EQ("a", Result[0]);
  EXPECT_EQ("b", Result[1]);
  EXPECT_EQ("c", Result[2]);
}

TEST(UnescapeJsonCommandLine, MungesMultipleSpaces) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("   a   b   ");
  ASSERT_EQ(2ul, Result.size());
  EXPECT_EQ("a", Result[0]);
  EXPECT_EQ("b", Result[1]);
}

TEST(UnescapeJsonCommandLine, UnescapesBackslashCharacters) {
  std::vector<std::string> Backslash = UnescapeJsonCommandLine("a\\\\\\\\");
  ASSERT_EQ(1ul, Backslash.size());
  EXPECT_EQ("a\\", Backslash[0]);
  std::vector<std::string> Quote = UnescapeJsonCommandLine("a\\\\\\\"");
  ASSERT_EQ(1ul, Quote.size());
  EXPECT_EQ("a\"", Quote[0]);
}

TEST(UnescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("\\\"  a  b  \\\"");
  ASSERT_EQ(1ul, Result.size());
  EXPECT_EQ("  a  b  ", Result[0]);
}

TEST(UnescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "  \\\" a \\\"  \\\" b \\\"  ");
  ASSERT_EQ(2ul, Result.size());
  EXPECT_EQ(" a ", Result[0]);
  EXPECT_EQ(" b ", Result[1]);
}

TEST(UnescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "\\\"\\\"\\\"\\\"");
  ASSERT_EQ(1ul, Result.size());
  EXPECT_TRUE(Result[0].empty()) << Result[0];
}

TEST(UnescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "\\\"\\\\\\\"\\\"");
  ASSERT_EQ(1ul, Result.size());
  EXPECT_EQ("\"", Result[0]);
}

TEST(UnescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "  \\\\\\\"  \\\"a \\\\\\\" b \\\"     \\\"and\\\\\\\\c\\\"   \\\\\\\"");
  ASSERT_EQ(4ul, Result.size());
  EXPECT_EQ("\"", Result[0]);
  EXPECT_EQ("a \" b ", Result[1]);
  EXPECT_EQ("and\\c", Result[2]);
  EXPECT_EQ("\"", Result[3]);
}

TEST(UnescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
  std::vector<std::string> QuotedNoSpaces = UnescapeJsonCommandLine(
      "\\\"a\\\"\\\"b\\\"");
  ASSERT_EQ(1ul, QuotedNoSpaces.size());
  EXPECT_EQ("ab", QuotedNoSpaces[0]);

  std::vector<std::string> MixedNoSpaces = UnescapeJsonCommandLine(
      "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
  ASSERT_EQ(1ul, MixedNoSpaces.size());
  EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
}

TEST(JsonCompileCommandLineParser, FailsOnEmptyString) {
  JsonCompileCommandLineParser Parser("", NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, DoesNotReadAfterInput) {
  JsonCompileCommandLineParser Parser(llvm::StringRef(NULL, 0), NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyArray) {
  JsonCompileCommandLineParser Parser("[]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfNotClosingArray) {
  JsonCompileCommandLineParser JustOpening("[", NULL);
  EXPECT_FALSE(JustOpening.Parse()) << JustOpening.GetErrorMessage();
  JsonCompileCommandLineParser WithSpaces("  [  ", NULL);
  EXPECT_FALSE(WithSpaces.Parse()) << WithSpaces.GetErrorMessage();
  JsonCompileCommandLineParser WithGarbage("  [x", NULL);
  EXPECT_FALSE(WithGarbage.Parse()) << WithGarbage.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyArrayWithWhitespace) {
  JsonCompileCommandLineParser Spaces("   [   ]   ", NULL);
  EXPECT_TRUE(Spaces.Parse()) << Spaces.GetErrorMessage();
  JsonCompileCommandLineParser AllWhites("\t\r\n[\t\n \t\r ]\t\r \n\n", NULL);
  EXPECT_TRUE(AllWhites.Parse()) << AllWhites.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfNotStartingArray) {
  JsonCompileCommandLineParser ObjectStart("{", NULL);
  EXPECT_FALSE(ObjectStart.Parse()) << ObjectStart.GetErrorMessage();
  // We don't implement a full JSON parser, and thus parse only a subset
  // of valid JSON.
  JsonCompileCommandLineParser Object("{}", NULL);
  EXPECT_FALSE(Object.Parse()) << Object.GetErrorMessage();
  JsonCompileCommandLineParser Character("x", NULL);
  EXPECT_FALSE(Character.Parse()) << Character.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyObject) {
  JsonCompileCommandLineParser Parser("[{}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesObject) {
  JsonCompileCommandLineParser Parser("[{\"a\":\"/b\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesMultipleKeyValuePairsInObject) {
  JsonCompileCommandLineParser Parser(
      "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfNotClosingObject) {
  JsonCompileCommandLineParser MissingCloseOnEmpty("[{]", NULL);
  EXPECT_FALSE(MissingCloseOnEmpty.Parse())
      << MissingCloseOnEmpty.GetErrorMessage();
  JsonCompileCommandLineParser MissingCloseAfterPair("[{\"a\":\"b\"]", NULL);
  EXPECT_FALSE(MissingCloseAfterPair.Parse())
      << MissingCloseAfterPair.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfMissingColon) {
  JsonCompileCommandLineParser StringString("[{\"a\"\"/b\"}]", NULL);
  EXPECT_FALSE(StringString.Parse()) << StringString.GetErrorMessage();
  JsonCompileCommandLineParser StringSpaceString("[{\"a\" \"b\"}]", NULL);
  EXPECT_FALSE(StringSpaceString.Parse())
      << StringSpaceString.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnMissingQuote) {
  JsonCompileCommandLineParser OpenQuote("[{a\":\"b\"}]", NULL);
  EXPECT_FALSE(OpenQuote.Parse()) << OpenQuote.GetErrorMessage();
  JsonCompileCommandLineParser CloseQuote("[{\"a\":\"b}]", NULL);
  EXPECT_FALSE(CloseQuote.Parse()) << CloseQuote.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEscapedQuotes) {
  JsonCompileCommandLineParser Parser(
      "[{\"a\":\"\\\"b\\\"  \\\" \\\"\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyString) {
  JsonCompileCommandLineParser Parser("[{\"a\":\"\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnMissingString) {
  JsonCompileCommandLineParser MissingValue("[{\"a\":}]", NULL);
  EXPECT_FALSE(MissingValue.Parse()) << MissingValue.GetErrorMessage();
  JsonCompileCommandLineParser MissingKey("[{:\"b\"}]", NULL);
  EXPECT_FALSE(MissingKey.Parse()) << MissingKey.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesMultipleObjects) {
  JsonCompileCommandLineParser Parser(
      "["
      " { \"a\" : \"b\" },"
      " { \"a\" : \"b\" },"
      " { \"a\" : \"b\" }"
      "]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnMissingComma) {
  JsonCompileCommandLineParser Parser(
      "["
      " { \"a\" : \"b\" }"
      " { \"a\" : \"b\" }"
      "]", NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnSuperfluousComma) {
  JsonCompileCommandLineParser Parser(
      "[ { \"a\" : \"b\" }, ]", NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesSpacesInBetweenTokens) {
  JsonCompileCommandLineParser Parser(
      " \t \n\n \r [ \t \n\n \r"
      " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
      " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r"
      " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
      " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r",
      NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

} // end namespace tooling
} // end namespace clang
<commit_msg>Adds a test for the command line parser when a quoted string is not closed by a quote.<commit_after>//===- unittest/Tooling/JsonCompileCommandLineDatabaseTest ----------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "../../lib/Tooling/JsonCompileCommandLineDatabase.h"
#include "gtest/gtest.h"

namespace clang {
namespace tooling {

TEST(UnescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("");
  EXPECT_TRUE(Result.empty());
}

TEST(UnescapeJsonCommandLine, SplitsOnSpaces) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("a b c");
  ASSERT_EQ(3ul, Result.size());
  EXPECT_EQ("a", Result[0]);
  EXPECT_EQ("b", Result[1]);
  EXPECT_EQ("c", Result[2]);
}

TEST(UnescapeJsonCommandLine, MungesMultipleSpaces) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("   a   b   ");
  ASSERT_EQ(2ul, Result.size());
  EXPECT_EQ("a", Result[0]);
  EXPECT_EQ("b", Result[1]);
}

TEST(UnescapeJsonCommandLine, UnescapesBackslashCharacters) {
  std::vector<std::string> Backslash = UnescapeJsonCommandLine("a\\\\\\\\");
  ASSERT_EQ(1ul, Backslash.size());
  EXPECT_EQ("a\\", Backslash[0]);
  std::vector<std::string> Quote = UnescapeJsonCommandLine("a\\\\\\\"");
  ASSERT_EQ(1ul, Quote.size());
  EXPECT_EQ("a\"", Quote[0]);
}

TEST(UnescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
  std::vector<std::string> Result = UnescapeJsonCommandLine("\\\"  a  b  \\\"");
  ASSERT_EQ(1ul, Result.size());
  EXPECT_EQ("  a  b  ", Result[0]);
}

TEST(UnescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "  \\\" a \\\"  \\\" b \\\"  ");
  ASSERT_EQ(2ul, Result.size());
  EXPECT_EQ(" a ", Result[0]);
  EXPECT_EQ(" b ", Result[1]);
}

TEST(UnescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "\\\"\\\"\\\"\\\"");
  ASSERT_EQ(1ul, Result.size());
  EXPECT_TRUE(Result[0].empty()) << Result[0];
}

TEST(UnescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "\\\"\\\\\\\"\\\"");
  ASSERT_EQ(1ul, Result.size());
  EXPECT_EQ("\"", Result[0]);
}

TEST(UnescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
  std::vector<std::string> Result = UnescapeJsonCommandLine(
      "  \\\\\\\"  \\\"a \\\\\\\" b \\\"     \\\"and\\\\\\\\c\\\"   \\\\\\\"");
  ASSERT_EQ(4ul, Result.size());
  EXPECT_EQ("\"", Result[0]);
  EXPECT_EQ("a \" b ", Result[1]);
  EXPECT_EQ("and\\c", Result[2]);
  EXPECT_EQ("\"", Result[3]);
}

TEST(UnescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
  std::vector<std::string> QuotedNoSpaces = UnescapeJsonCommandLine(
      "\\\"a\\\"\\\"b\\\"");
  ASSERT_EQ(1ul, QuotedNoSpaces.size());
  EXPECT_EQ("ab", QuotedNoSpaces[0]);

  std::vector<std::string> MixedNoSpaces = UnescapeJsonCommandLine(
      "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
  ASSERT_EQ(1ul, MixedNoSpaces.size());
  EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
}

TEST(UnescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
  std::vector<std::string> Unclosed = UnescapeJsonCommandLine("\"abc");
  ASSERT_EQ(1ul, Unclosed.size());
  EXPECT_EQ("abc", Unclosed[0]);

  std::vector<std::string> EndsInBackslash = UnescapeJsonCommandLine("\"a\\");
  ASSERT_EQ(1ul, EndsInBackslash.size());
  EXPECT_EQ("a", EndsInBackslash[0]);

  std::vector<std::string> Empty = UnescapeJsonCommandLine("\"");
  ASSERT_EQ(1ul, Empty.size());
  EXPECT_EQ("", Empty[0]);
}

TEST(JsonCompileCommandLineParser, FailsOnEmptyString) {
  JsonCompileCommandLineParser Parser("", NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, DoesNotReadAfterInput) {
  JsonCompileCommandLineParser Parser(llvm::StringRef(NULL, 0), NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyArray) {
  JsonCompileCommandLineParser Parser("[]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfNotClosingArray) {
  JsonCompileCommandLineParser JustOpening("[", NULL);
  EXPECT_FALSE(JustOpening.Parse()) << JustOpening.GetErrorMessage();
  JsonCompileCommandLineParser WithSpaces("  [  ", NULL);
  EXPECT_FALSE(WithSpaces.Parse()) << WithSpaces.GetErrorMessage();
  JsonCompileCommandLineParser WithGarbage("  [x", NULL);
  EXPECT_FALSE(WithGarbage.Parse()) << WithGarbage.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyArrayWithWhitespace) {
  JsonCompileCommandLineParser Spaces("   [   ]   ", NULL);
  EXPECT_TRUE(Spaces.Parse()) << Spaces.GetErrorMessage();
  JsonCompileCommandLineParser AllWhites("\t\r\n[\t\n \t\r ]\t\r \n\n", NULL);
  EXPECT_TRUE(AllWhites.Parse()) << AllWhites.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfNotStartingArray) {
  JsonCompileCommandLineParser ObjectStart("{", NULL);
  EXPECT_FALSE(ObjectStart.Parse()) << ObjectStart.GetErrorMessage();
  // We don't implement a full JSON parser, and thus parse only a subset
  // of valid JSON.
  JsonCompileCommandLineParser Object("{}", NULL);
  EXPECT_FALSE(Object.Parse()) << Object.GetErrorMessage();
  JsonCompileCommandLineParser Character("x", NULL);
  EXPECT_FALSE(Character.Parse()) << Character.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyObject) {
  JsonCompileCommandLineParser Parser("[{}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesObject) {
  JsonCompileCommandLineParser Parser("[{\"a\":\"/b\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesMultipleKeyValuePairsInObject) {
  JsonCompileCommandLineParser Parser(
      "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfNotClosingObject) {
  JsonCompileCommandLineParser MissingCloseOnEmpty("[{]", NULL);
  EXPECT_FALSE(MissingCloseOnEmpty.Parse())
      << MissingCloseOnEmpty.GetErrorMessage();
  JsonCompileCommandLineParser MissingCloseAfterPair("[{\"a\":\"b\"]", NULL);
  EXPECT_FALSE(MissingCloseAfterPair.Parse())
      << MissingCloseAfterPair.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsIfMissingColon) {
  JsonCompileCommandLineParser StringString("[{\"a\"\"/b\"}]", NULL);
  EXPECT_FALSE(StringString.Parse()) << StringString.GetErrorMessage();
  JsonCompileCommandLineParser StringSpaceString("[{\"a\" \"b\"}]", NULL);
  EXPECT_FALSE(StringSpaceString.Parse())
      << StringSpaceString.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnMissingQuote) {
  JsonCompileCommandLineParser OpenQuote("[{a\":\"b\"}]", NULL);
  EXPECT_FALSE(OpenQuote.Parse()) << OpenQuote.GetErrorMessage();
  JsonCompileCommandLineParser CloseQuote("[{\"a\":\"b}]", NULL);
  EXPECT_FALSE(CloseQuote.Parse()) << CloseQuote.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEscapedQuotes) {
  JsonCompileCommandLineParser Parser(
      "[{\"a\":\"\\\"b\\\"  \\\" \\\"\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesEmptyString) {
  JsonCompileCommandLineParser Parser("[{\"a\":\"\"}]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnMissingString) {
  JsonCompileCommandLineParser MissingValue("[{\"a\":}]", NULL);
  EXPECT_FALSE(MissingValue.Parse()) << MissingValue.GetErrorMessage();
  JsonCompileCommandLineParser MissingKey("[{:\"b\"}]", NULL);
  EXPECT_FALSE(MissingKey.Parse()) << MissingKey.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesMultipleObjects) {
  JsonCompileCommandLineParser Parser(
      "["
      " { \"a\" : \"b\" },"
      " { \"a\" : \"b\" },"
      " { \"a\" : \"b\" }"
      "]", NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnMissingComma) {
  JsonCompileCommandLineParser Parser(
      "["
      " { \"a\" : \"b\" }"
      " { \"a\" : \"b\" }"
      "]", NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, FailsOnSuperfluousComma) {
  JsonCompileCommandLineParser Parser(
      "[ { \"a\" : \"b\" }, ]", NULL);
  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
}

TEST(JsonCompileCommandLineParser, ParsesSpacesInBetweenTokens) {
  JsonCompileCommandLineParser Parser(
      " \t \n\n \r [ \t \n\n \r"
      " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
      " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r"
      " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
      " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r",
      NULL);
  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
}

} // end namespace tooling
} // end namespace clang
<|endoftext|>