<commit_before>/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Aurel Popirtac <mailto:ext-Aurel.Popirtac@nokia.com>
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "credentialsaccessmanager.h"

#include "signond-common.h"
#include "ui-key-authorizer.h"
#include "misc.h"

#include <QFile>
#include <QBuffer>

#define RETURN_IF_NOT_INITIALIZED(return_value)                  \
    do {                                                         \
        if (!m_isInitialized) {                                  \
            m_error = NotInitialized;                            \
            TRACE() << "CredentialsAccessManager not initialized."; \
            return return_value;                                \
        }                                                       \
    } while (0)

using namespace SignonDaemonNS;

/* ---------------------- CAMConfiguration ---------------------- */

CAMConfiguration::CAMConfiguration()
        : m_storagePath(QLatin1String(signonDefaultStoragePath)),
          m_dbName(QLatin1String(signonDefaultDbName)),
          m_useEncryption(signonDefaultUseEncryption),
          m_fileSystemType(QLatin1String(signonDefaultFileSystemType)),
          m_fileSystemSize(signonMinumumDbSize),
          m_encryptionPassphrase(QByteArray())
{}

void CAMConfiguration::serialize(QIODevice *device)
{
    if (device == NULL)
        return;

    if (!device->open(QIODevice::ReadWrite)) {
        return;
    }

    QString buffer;
    QTextStream stream(&buffer);
    stream << "\n\n====== Credentials Access Manager Configuration ======\n\n";
    stream << "File system mount name " << encryptedFSPath() << '\n';
    stream << "File system format: " << m_fileSystemType << '\n';
    stream << "File system size:" << m_fileSystemSize << "megabytes\n";

    const char *usingEncryption = m_useEncryption ? "true" : "false";
    stream << "Using encryption: " << usingEncryption << '\n';
    stream << "Credentials database name: " << m_dbName << '\n';
    stream << "======================================================\n\n";
    device->write(buffer.toUtf8());
    device->close();
}

QString CAMConfiguration::metadataDBPath() const
{
    return m_storagePath + QDir::separator() + m_dbName;
}

QString CAMConfiguration::encryptedFSPath() const
{
    return m_storagePath +
        QDir::separator() +
        QLatin1String(signonDefaultFileSystemName);
}

/* ---------------------- CredentialsAccessManager ---------------------- */

CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL;

CredentialsAccessManager::CredentialsAccessManager(QObject *parent)
        : QObject(parent),
          m_isInitialized(false),
          m_systemOpened(false),
          m_error(NoError),
          keyManagers(),
          m_pCredentialsDB(NULL),
          m_pCryptoFileSystemManager(NULL),
          m_keyHandler(NULL),
          m_keyAuthorizer(NULL),
          m_CAMConfiguration(CAMConfiguration())
{
}

CredentialsAccessManager::~CredentialsAccessManager()
{
    closeCredentialsSystem();

    m_pInstance = NULL;
}

CredentialsAccessManager *CredentialsAccessManager::instance(QObject *parent)
{
    if (!m_pInstance)
        m_pInstance = new CredentialsAccessManager(parent);

    return m_pInstance;
}

void CredentialsAccessManager::finalize()
{
    if (m_systemOpened)
        closeCredentialsSystem();

    if (m_pCryptoFileSystemManager)
        delete m_pCryptoFileSystemManager;

    // Disconnect all key managers
    foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
        keyManager->disconnect();

    m_isInitialized = false;
    m_error = NoError;
}

bool CredentialsAccessManager::init(const CAMConfiguration &camConfiguration)
{
    if (m_isInitialized) {
        TRACE() << "CAM already initialized.";
        m_error = AlreadyInitialized;
        return false;
    }

    m_CAMConfiguration = camConfiguration;

    QBuffer config;
    m_CAMConfiguration.serialize(&config);
    TRACE() << "\n\nInitualizing CredentialsAccessManager with configuration: " << config.data();

    if (!createStorageDir()) {
        BLAME() << "Failed to create storage directory.";
        return false;
    }

    if (m_CAMConfiguration.m_useEncryption) {
        //Initialize CryptoManager
        m_pCryptoFileSystemManager = new CryptoManager(this);
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemMounted()),
                         this, SLOT(onEncryptedFSMounted()));
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemUnmounting()),
                         this, SLOT(onEncryptedFSUnmounting()));
        m_pCryptoFileSystemManager->setFileSystemPath(m_CAMConfiguration.encryptedFSPath());
        m_pCryptoFileSystemManager->setFileSystemSize(m_CAMConfiguration.m_fileSystemSize);
        m_pCryptoFileSystemManager->setFileSystemType(m_CAMConfiguration.m_fileSystemType);

        m_keyHandler = new KeyHandler(this);

        m_keyAuthorizer = new UiKeyAuthorizer(m_keyHandler, this);
        QObject::connect(m_keyAuthorizer,
                         SIGNAL(keyAuthorizationQueried(const SignOn::Key,int)),
                         this,
                         SLOT(onKeyAuthorizationQueried(const SignOn::Key,int)));

        /* These signal connections should be done after instantiating the
         * KeyAuthorizer, so that the KeyAuthorizer's slot will be called
         * first (or we could connect to them in queued mode)
         */
        QObject::connect(m_keyHandler, SIGNAL(ready()),
                         this, SIGNAL(credentialsSystemReady()));
        QObject::connect(m_keyHandler, SIGNAL(keyInserted(SignOn::Key)),
                         this, SLOT(onKeyInserted(SignOn::Key)));
        QObject::connect(m_keyHandler,
                         SIGNAL(lastAuthorizedKeyRemoved(SignOn::Key)),
                         this,
                         SLOT(onLastAuthorizedKeyRemoved(SignOn::Key)));
        QObject::connect(m_keyHandler, SIGNAL(keyRemoved(SignOn::Key)),
                         this, SLOT(onKeyRemoved(SignOn::Key)));
        m_keyHandler->initialize(m_pCryptoFileSystemManager, keyManagers);
    }

    m_isInitialized = true;
    m_error = NoError;

    TRACE() << "CredentialsAccessManager successfully initialized...";
    return true;
}

void CredentialsAccessManager::addKeyManager(
    SignOn::AbstractKeyManager *keyManager)
{
    keyManagers.append(keyManager);
}

bool CredentialsAccessManager::openSecretsDB()
{
    //todo remove this variable after LUKS implementation becomes stable.
    QString dbPath;

    if (m_CAMConfiguration.m_useEncryption) {
        dbPath = m_pCryptoFileSystemManager->fileSystemMountPath()
            + QDir::separator()
            + m_CAMConfiguration.m_dbName;

        if (!m_pCryptoFileSystemManager->fileSystemIsMounted()) {
            /* Do not attempt to mount the FS; we know that it will be mounted
             * automatically, as soon as some encryption keys are provided */
            m_error = CredentialsDbNotMounted;
            return false;
        }
    } else {
        dbPath = m_CAMConfiguration.metadataDBPath() + QLatin1String(".creds");
    }

    TRACE() << "Database name: [" << dbPath << "]";

    if (!m_pCredentialsDB->openSecretsDB(dbPath))
        return false;

    m_error = NoError;
    return true;
}

bool CredentialsAccessManager::isSecretsDBOpen()
{
    return m_pCredentialsDB->isSecretsDBOpen();
}

bool CredentialsAccessManager::closeSecretsDB()
{
    m_pCredentialsDB->closeSecretsDB();

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->unmountFileSystem()) {
            m_error = CredentialsDbUnmountFailed;
            return false;
        }
    }

    return true;
}

bool CredentialsAccessManager::createStorageDir()
{
    QString dbPath = m_CAMConfiguration.metadataDBPath();

    QFileInfo fileInfo(dbPath);
    if (!fileInfo.exists()) {
        QDir storageDir(fileInfo.dir());
        if (!storageDir.mkpath(storageDir.path())) {
            BLAME() << "Could not create storage directory:" <<
                storageDir.path();
            m_error = CredentialsDbSetupFailed;
            return false;
        }
        setUserOwnership(storageDir.path());
    }
    return true;

}
bool CredentialsAccessManager::openMetaDataDB()
{
    QString dbPath = m_CAMConfiguration.metadataDBPath();

    m_pCredentialsDB = new CredentialsDB(dbPath);

    if (!m_pCredentialsDB->init()) {
        m_error = CredentialsDbConnectionError;
        return false;
    }

    return true;
}

void CredentialsAccessManager::closeMetaDataDB()
{
    if (m_pCredentialsDB) {
        delete m_pCredentialsDB;
        m_pCredentialsDB = NULL;
    }
}

bool CredentialsAccessManager::openCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!openMetaDataDB()) {
        BLAME() << "Couldn't open metadata DB!";
        return false;
    }

    if (!openSecretsDB()) {
        BLAME() << "Failed to open secrets DB.";
        /* Even if the secrets DB couldn't be opened, signond is still usable:
         * that's why we return "true" anyways. */
    }

    m_systemOpened = true;
    return true;
}

bool CredentialsAccessManager::closeCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!credentialsSystemOpened())
        return true;

    bool allClosed = true;
    if (isSecretsDBOpen() && !closeSecretsDB())
        allClosed = false;

    closeMetaDataDB();

    m_error = NoError;
    m_systemOpened = false;
    return allClosed;
}

bool CredentialsAccessManager::deleteCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (m_systemOpened && !closeCredentialsSystem()) {
        /* The close operation failed: we cannot proceed */
        return false;
    }

    m_error = NoError;

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->deleteFileSystem())
            m_error = CredentialsDbDeletionFailed;
    } else {
        QFile dbFile(m_CAMConfiguration.m_dbName);
        if (dbFile.exists()) {
            if (!dbFile.remove())
                m_error = CredentialsDbDeletionFailed;
        }
    }

    return m_error == NoError;
}

CredentialsDB *CredentialsAccessManager::credentialsDB() const
{
    RETURN_IF_NOT_INITIALIZED(NULL);

    return m_pCredentialsDB;
}

bool CredentialsAccessManager::isCredentialsSystemReady() const
{
    return (m_keyHandler != 0) ? m_keyHandler->isReady() : true;
}

void CredentialsAccessManager::onKeyInserted(const SignOn::Key key)
{
    TRACE() << "Key inserted.";

    if (!m_keyHandler->keyIsAuthorized(key))
        m_keyAuthorizer->queryKeyAuthorization(
            key, AbstractKeyAuthorizer::KeyInserted);
}

void CredentialsAccessManager::onLastAuthorizedKeyRemoved(const SignOn::Key key)
{
    Q_UNUSED(key);
    TRACE() << "All keys disabled. Closing secure storage.";
    if (isSecretsDBOpen() || m_pCryptoFileSystemManager->fileSystemIsMounted())
        if (!closeSecretsDB())
            BLAME() << "Error occurred while closing secure storage.";
}

void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key)
{
    TRACE() << "Key removed.";

    if (m_keyHandler->keyIsAuthorized(key)) {
        if (!m_keyHandler->revokeKeyAuthorization(key)) {
            BLAME() << "Revoking key authorization failed";
        }
    }
}

void CredentialsAccessManager::onKeyAuthorizationQueried(const SignOn::Key key,
                                                         int result)
{
    TRACE() << "result:" << result;

    if (result != AbstractKeyAuthorizer::Denied) {
        KeyHandler::AuthorizeFlags flags = KeyHandler::None;
        if (result == AbstractKeyAuthorizer::Exclusive) {
            TRACE() << "Reformatting secure storage.";
            flags |= KeyHandler::FormatStorage;
        }

        if (!m_keyHandler->authorizeKey(key, flags)) {
            BLAME() << "Authorization failed";
        }
    }

    replyToSecureStorageEventNotifiers();
}

bool CredentialsAccessManager::keysAvailable() const
{
    if (m_keyHandler == 0) return false;
    return !m_keyHandler->insertedKeys().isEmpty();
}

void CredentialsAccessManager::replyToSecureStorageEventNotifiers()
{
    TRACE();
    //Notify secure storage notifiers if any.
    int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE;
    if ((m_pCredentialsDB != 0) && m_pCredentialsDB->isSecretsDBOpen())
        eventType = SIGNON_SECURE_STORAGE_AVAILABLE;

    // Signal objects that posted secure storage not available events
    foreach (EventSender object, m_secureStorageEventNotifiers) {
        if (object.isNull())
            continue;

        SecureStorageEvent *secureStorageEvent =
            new SecureStorageEvent((QEvent::Type)eventType);

        QCoreApplication::postEvent(
            object.data(),
            secureStorageEvent,
            Qt::HighEventPriority);
    }

    m_secureStorageEventNotifiers.clear();
}

void CredentialsAccessManager::customEvent(QEvent *event)
{
    TRACE() << "Custom event received.";
    if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
        QObject::customEvent(event);
        return;
    }

    SecureStorageEvent *localEvent =
        static_cast<SecureStorageEvent *>(event);

    /* All senders of this event will receive a reply when
     * the secure storage becomes available or an error occurs. */
    m_secureStorageEventNotifiers.append(localEvent->m_sender);

    TRACE() << "Processing secure storage not available event.";
    if ((localEvent == 0) || (m_pCredentialsDB == 0)) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    //Double check if the secrets DB is indeed unavailable
    if (m_pCredentialsDB->isSecretsDBOpen()) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    SignOn::Key key; /* we don't specity any key */
    m_keyAuthorizer->queryKeyAuthorization(key,
                                           AbstractKeyAuthorizer::StorageNeeded);

    QObject::customEvent(event);
}

void CredentialsAccessManager::onEncryptedFSMounted()
{
    TRACE();
    if (!credentialsSystemOpened()) return;

    if (!isSecretsDBOpen()) {
        if (openSecretsDB()) {
            TRACE() << "Secrets DB opened.";
        } else {
            BLAME() << "Failed to open secrets DB.";
        }
    } else {
        BLAME() << "Secrets DB already opened?";
    }
}

void CredentialsAccessManager::onEncryptedFSUnmounting()
{
    TRACE();
    if (!credentialsSystemOpened()) return;

    if (isSecretsDBOpen()) {
        m_pCredentialsDB->closeSecretsDB();
    }
}

<commit_msg>CAM: use default key authorizer<commit_after>/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Aurel Popirtac <mailto:ext-Aurel.Popirtac@nokia.com>
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "credentialsaccessmanager.h"

#include "default-key-authorizer.h"
#include "signond-common.h"
#include "misc.h"

#include <QFile>
#include <QBuffer>

#define RETURN_IF_NOT_INITIALIZED(return_value)                  \
    do {                                                         \
        if (!m_isInitialized) {                                  \
            m_error = NotInitialized;                            \
            TRACE() << "CredentialsAccessManager not initialized."; \
            return return_value;                                \
        }                                                       \
    } while (0)

using namespace SignonDaemonNS;

/* ---------------------- CAMConfiguration ---------------------- */

CAMConfiguration::CAMConfiguration()
        : m_storagePath(QLatin1String(signonDefaultStoragePath)),
          m_dbName(QLatin1String(signonDefaultDbName)),
          m_useEncryption(signonDefaultUseEncryption),
          m_fileSystemType(QLatin1String(signonDefaultFileSystemType)),
          m_fileSystemSize(signonMinumumDbSize),
          m_encryptionPassphrase(QByteArray())
{}

void CAMConfiguration::serialize(QIODevice *device)
{
    if (device == NULL)
        return;

    if (!device->open(QIODevice::ReadWrite)) {
        return;
    }

    QString buffer;
    QTextStream stream(&buffer);
    stream << "\n\n====== Credentials Access Manager Configuration ======\n\n";
    stream << "File system mount name " << encryptedFSPath() << '\n';
    stream << "File system format: " << m_fileSystemType << '\n';
    stream << "File system size:" << m_fileSystemSize << "megabytes\n";

    const char *usingEncryption = m_useEncryption ? "true" : "false";
    stream << "Using encryption: " << usingEncryption << '\n';
    stream << "Credentials database name: " << m_dbName << '\n';
    stream << "======================================================\n\n";
    device->write(buffer.toUtf8());
    device->close();
}

QString CAMConfiguration::metadataDBPath() const
{
    return m_storagePath + QDir::separator() + m_dbName;
}

QString CAMConfiguration::encryptedFSPath() const
{
    return m_storagePath +
        QDir::separator() +
        QLatin1String(signonDefaultFileSystemName);
}

/* ---------------------- CredentialsAccessManager ---------------------- */

CredentialsAccessManager *CredentialsAccessManager::m_pInstance = NULL;

CredentialsAccessManager::CredentialsAccessManager(QObject *parent)
        : QObject(parent),
          m_isInitialized(false),
          m_systemOpened(false),
          m_error(NoError),
          keyManagers(),
          m_pCredentialsDB(NULL),
          m_pCryptoFileSystemManager(NULL),
          m_keyHandler(NULL),
          m_keyAuthorizer(NULL),
          m_CAMConfiguration(CAMConfiguration())
{
}

CredentialsAccessManager::~CredentialsAccessManager()
{
    closeCredentialsSystem();

    m_pInstance = NULL;
}

CredentialsAccessManager *CredentialsAccessManager::instance(QObject *parent)
{
    if (!m_pInstance)
        m_pInstance = new CredentialsAccessManager(parent);

    return m_pInstance;
}

void CredentialsAccessManager::finalize()
{
    if (m_systemOpened)
        closeCredentialsSystem();

    if (m_pCryptoFileSystemManager)
        delete m_pCryptoFileSystemManager;

    // Disconnect all key managers
    foreach (SignOn::AbstractKeyManager *keyManager, keyManagers)
        keyManager->disconnect();

    m_isInitialized = false;
    m_error = NoError;
}

bool CredentialsAccessManager::init(const CAMConfiguration &camConfiguration)
{
    if (m_isInitialized) {
        TRACE() << "CAM already initialized.";
        m_error = AlreadyInitialized;
        return false;
    }

    m_CAMConfiguration = camConfiguration;

    QBuffer config;
    m_CAMConfiguration.serialize(&config);
    TRACE() << "\n\nInitualizing CredentialsAccessManager with configuration: " << config.data();

    if (!createStorageDir()) {
        BLAME() << "Failed to create storage directory.";
        return false;
    }

    if (m_CAMConfiguration.m_useEncryption) {
        //Initialize CryptoManager
        m_pCryptoFileSystemManager = new CryptoManager(this);
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemMounted()),
                         this, SLOT(onEncryptedFSMounted()));
        QObject::connect(m_pCryptoFileSystemManager, SIGNAL(fileSystemUnmounting()),
                         this, SLOT(onEncryptedFSUnmounting()));
        m_pCryptoFileSystemManager->setFileSystemPath(m_CAMConfiguration.encryptedFSPath());
        m_pCryptoFileSystemManager->setFileSystemSize(m_CAMConfiguration.m_fileSystemSize);
        m_pCryptoFileSystemManager->setFileSystemType(m_CAMConfiguration.m_fileSystemType);

        m_keyHandler = new KeyHandler(this);

        m_keyAuthorizer = new DefaultKeyAuthorizer(m_keyHandler, this);
        QObject::connect(m_keyAuthorizer,
                         SIGNAL(keyAuthorizationQueried(const SignOn::Key,int)),
                         this,
                         SLOT(onKeyAuthorizationQueried(const SignOn::Key,int)));

        /* These signal connections should be done after instantiating the
         * KeyAuthorizer, so that the KeyAuthorizer's slot will be called
         * first (or we could connect to them in queued mode)
         */
        QObject::connect(m_keyHandler, SIGNAL(ready()),
                         this, SIGNAL(credentialsSystemReady()));
        QObject::connect(m_keyHandler, SIGNAL(keyInserted(SignOn::Key)),
                         this, SLOT(onKeyInserted(SignOn::Key)));
        QObject::connect(m_keyHandler,
                         SIGNAL(lastAuthorizedKeyRemoved(SignOn::Key)),
                         this,
                         SLOT(onLastAuthorizedKeyRemoved(SignOn::Key)));
        QObject::connect(m_keyHandler, SIGNAL(keyRemoved(SignOn::Key)),
                         this, SLOT(onKeyRemoved(SignOn::Key)));
        m_keyHandler->initialize(m_pCryptoFileSystemManager, keyManagers);
    }

    m_isInitialized = true;
    m_error = NoError;

    TRACE() << "CredentialsAccessManager successfully initialized...";
    return true;
}

void CredentialsAccessManager::addKeyManager(
    SignOn::AbstractKeyManager *keyManager)
{
    keyManagers.append(keyManager);
}

bool CredentialsAccessManager::openSecretsDB()
{
    //todo remove this variable after LUKS implementation becomes stable.
    QString dbPath;

    if (m_CAMConfiguration.m_useEncryption) {
        dbPath = m_pCryptoFileSystemManager->fileSystemMountPath()
            + QDir::separator()
            + m_CAMConfiguration.m_dbName;

        if (!m_pCryptoFileSystemManager->fileSystemIsMounted()) {
            /* Do not attempt to mount the FS; we know that it will be mounted
             * automatically, as soon as some encryption keys are provided */
            m_error = CredentialsDbNotMounted;
            return false;
        }
    } else {
        dbPath = m_CAMConfiguration.metadataDBPath() + QLatin1String(".creds");
    }

    TRACE() << "Database name: [" << dbPath << "]";

    if (!m_pCredentialsDB->openSecretsDB(dbPath))
        return false;

    m_error = NoError;
    return true;
}

bool CredentialsAccessManager::isSecretsDBOpen()
{
    return m_pCredentialsDB->isSecretsDBOpen();
}

bool CredentialsAccessManager::closeSecretsDB()
{
    m_pCredentialsDB->closeSecretsDB();

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->unmountFileSystem()) {
            m_error = CredentialsDbUnmountFailed;
            return false;
        }
    }

    return true;
}

bool CredentialsAccessManager::createStorageDir()
{
    QString dbPath = m_CAMConfiguration.metadataDBPath();

    QFileInfo fileInfo(dbPath);
    if (!fileInfo.exists()) {
        QDir storageDir(fileInfo.dir());
        if (!storageDir.mkpath(storageDir.path())) {
            BLAME() << "Could not create storage directory:" <<
                storageDir.path();
            m_error = CredentialsDbSetupFailed;
            return false;
        }
        setUserOwnership(storageDir.path());
    }
    return true;

}
bool CredentialsAccessManager::openMetaDataDB()
{
    QString dbPath = m_CAMConfiguration.metadataDBPath();

    m_pCredentialsDB = new CredentialsDB(dbPath);

    if (!m_pCredentialsDB->init()) {
        m_error = CredentialsDbConnectionError;
        return false;
    }

    return true;
}

void CredentialsAccessManager::closeMetaDataDB()
{
    if (m_pCredentialsDB) {
        delete m_pCredentialsDB;
        m_pCredentialsDB = NULL;
    }
}

bool CredentialsAccessManager::openCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!openMetaDataDB()) {
        BLAME() << "Couldn't open metadata DB!";
        return false;
    }

    if (!openSecretsDB()) {
        BLAME() << "Failed to open secrets DB.";
        /* Even if the secrets DB couldn't be opened, signond is still usable:
         * that's why we return "true" anyways. */
    }

    m_systemOpened = true;
    return true;
}

bool CredentialsAccessManager::closeCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (!credentialsSystemOpened())
        return true;

    bool allClosed = true;
    if (isSecretsDBOpen() && !closeSecretsDB())
        allClosed = false;

    closeMetaDataDB();

    m_error = NoError;
    m_systemOpened = false;
    return allClosed;
}

bool CredentialsAccessManager::deleteCredentialsSystem()
{
    RETURN_IF_NOT_INITIALIZED(false);

    if (m_systemOpened && !closeCredentialsSystem()) {
        /* The close operation failed: we cannot proceed */
        return false;
    }

    m_error = NoError;

    if (m_CAMConfiguration.m_useEncryption) {
        if (!m_pCryptoFileSystemManager->deleteFileSystem())
            m_error = CredentialsDbDeletionFailed;
    } else {
        QFile dbFile(m_CAMConfiguration.m_dbName);
        if (dbFile.exists()) {
            if (!dbFile.remove())
                m_error = CredentialsDbDeletionFailed;
        }
    }

    return m_error == NoError;
}

CredentialsDB *CredentialsAccessManager::credentialsDB() const
{
    RETURN_IF_NOT_INITIALIZED(NULL);

    return m_pCredentialsDB;
}

bool CredentialsAccessManager::isCredentialsSystemReady() const
{
    return (m_keyHandler != 0) ? m_keyHandler->isReady() : true;
}

void CredentialsAccessManager::onKeyInserted(const SignOn::Key key)
{
    TRACE() << "Key inserted.";

    if (!m_keyHandler->keyIsAuthorized(key))
        m_keyAuthorizer->queryKeyAuthorization(
            key, AbstractKeyAuthorizer::KeyInserted);
}

void CredentialsAccessManager::onLastAuthorizedKeyRemoved(const SignOn::Key key)
{
    Q_UNUSED(key);
    TRACE() << "All keys disabled. Closing secure storage.";
    if (isSecretsDBOpen() || m_pCryptoFileSystemManager->fileSystemIsMounted())
        if (!closeSecretsDB())
            BLAME() << "Error occurred while closing secure storage.";
}

void CredentialsAccessManager::onKeyRemoved(const SignOn::Key key)
{
    TRACE() << "Key removed.";

    if (m_keyHandler->keyIsAuthorized(key)) {
        if (!m_keyHandler->revokeKeyAuthorization(key)) {
            BLAME() << "Revoking key authorization failed";
        }
    }
}

void CredentialsAccessManager::onKeyAuthorizationQueried(const SignOn::Key key,
                                                         int result)
{
    TRACE() << "result:" << result;

    if (result != AbstractKeyAuthorizer::Denied) {
        KeyHandler::AuthorizeFlags flags = KeyHandler::None;
        if (result == AbstractKeyAuthorizer::Exclusive) {
            TRACE() << "Reformatting secure storage.";
            flags |= KeyHandler::FormatStorage;
        }

        if (!m_keyHandler->authorizeKey(key, flags)) {
            BLAME() << "Authorization failed";
        }
    }

    replyToSecureStorageEventNotifiers();
}

bool CredentialsAccessManager::keysAvailable() const
{
    if (m_keyHandler == 0) return false;
    return !m_keyHandler->insertedKeys().isEmpty();
}

void CredentialsAccessManager::replyToSecureStorageEventNotifiers()
{
    TRACE();
    //Notify secure storage notifiers if any.
    int eventType = SIGNON_SECURE_STORAGE_NOT_AVAILABLE;
    if ((m_pCredentialsDB != 0) && m_pCredentialsDB->isSecretsDBOpen())
        eventType = SIGNON_SECURE_STORAGE_AVAILABLE;

    // Signal objects that posted secure storage not available events
    foreach (EventSender object, m_secureStorageEventNotifiers) {
        if (object.isNull())
            continue;

        SecureStorageEvent *secureStorageEvent =
            new SecureStorageEvent((QEvent::Type)eventType);

        QCoreApplication::postEvent(
            object.data(),
            secureStorageEvent,
            Qt::HighEventPriority);
    }

    m_secureStorageEventNotifiers.clear();
}

void CredentialsAccessManager::customEvent(QEvent *event)
{
    TRACE() << "Custom event received.";
    if (event->type() != SIGNON_SECURE_STORAGE_NOT_AVAILABLE) {
        QObject::customEvent(event);
        return;
    }

    SecureStorageEvent *localEvent =
        static_cast<SecureStorageEvent *>(event);

    /* All senders of this event will receive a reply when
     * the secure storage becomes available or an error occurs. */
    m_secureStorageEventNotifiers.append(localEvent->m_sender);

    TRACE() << "Processing secure storage not available event.";
    if ((localEvent == 0) || (m_pCredentialsDB == 0)) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    //Double check if the secrets DB is indeed unavailable
    if (m_pCredentialsDB->isSecretsDBOpen()) {
        replyToSecureStorageEventNotifiers();
        QObject::customEvent(event);
        return;
    }

    SignOn::Key key; /* we don't specity any key */
    m_keyAuthorizer->queryKeyAuthorization(key,
                                           AbstractKeyAuthorizer::StorageNeeded);

    QObject::customEvent(event);
}

void CredentialsAccessManager::onEncryptedFSMounted()
{
    TRACE();
    if (!credentialsSystemOpened()) return;

    if (!isSecretsDBOpen()) {
        if (openSecretsDB()) {
            TRACE() << "Secrets DB opened.";
        } else {
            BLAME() << "Failed to open secrets DB.";
        }
    } else {
        BLAME() << "Secrets DB already opened?";
    }
}

void CredentialsAccessManager::onEncryptedFSUnmounting()
{
    TRACE();
    if (!credentialsSystemOpened()) return;

    if (isSecretsDBOpen()) {
        m_pCredentialsDB->closeSecretsDB();
    }
}

<|endoftext|>


<commit_before>#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>

#include <utility>

#include "LinuxUprobesUnwindingVisitor.h"

namespace {
unwindstack::FrameData MakeTestFrame(std::string function_name) {
  unwindstack::FrameData frame_data{};
  frame_data.function_name = std::move(function_name);
  frame_data.map_name = "a.out";
  return frame_data;
}

std::vector<unwindstack::FrameData> MakeTestCallstack(
    const std::vector<std::string>& function_names) {
  std::vector<unwindstack::FrameData> callstack;
  for (auto name_it = function_names.rbegin(); name_it != function_names.rend();
       ++name_it) {
    callstack.push_back(MakeTestFrame(*name_it));
  }
  return callstack;
}

unwindstack::FrameData MakeTestUprobesFrame() {
  unwindstack::FrameData uprobes_frame{};
  uprobes_frame.function_name = "uprobes";
  uprobes_frame.map_name = "[uprobes]";
  return uprobes_frame;
}

std::vector<unwindstack::FrameData> MakeTestUprobesCallstack(
    const std::vector<std::string>& function_names) {
  std::vector<unwindstack::FrameData> callstack;
  for (auto name_it = function_names.rbegin(); name_it != function_names.rend();
       ++name_it) {
    callstack.push_back(MakeTestFrame(*name_it));
  }
  callstack.push_back(MakeTestUprobesFrame());
  return callstack;
}

std::vector<std::pair<std::string, std::string>>
TestCallstackToStringPairVector(
    const std::vector<unwindstack::FrameData>& callstack) {
  std::vector<std::pair<std::string, std::string>> vector{};
  for (const auto& frame : callstack) {
    vector.emplace_back(frame.map_name, frame.function_name);
  }
  return vector;
}
}  // namespace

TEST(UprobesCallstackManager, NoUprobes) {
  std::vector<unwindstack::FrameData> unwound_cs, real_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha", "beta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha", "gamma"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));
}

TEST(UprobesCallstackManager, OneUprobe) {
  std::vector<unwindstack::FrameData> unwound_cs, real_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // Begin FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION"});
  real_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION", "beta"});
  real_cs = MakeTestCallstack({"main", "alpha", "FUNCTION", "beta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));
}

TEST(UprobesCallstackManager, DifferentThread) {
  std::vector<unwindstack::FrameData> unwound_cs, real_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  // Begin FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // Sample from another thread.
  unwound_cs = real_cs = MakeTestCallstack({"thread", "omega"});
  processed_cs = callstack_manager.ProcessSampledCallstack(111, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));
}

TEST(UprobesCallstackManager, TwoNestedUprobesAndAnotherUprobe) {
  std::vector<unwindstack::FrameData> unwound_cs, real_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // Begin FOO().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha", "FOO"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FOO"});
  real_cs = MakeTestCallstack({"main", "alpha", "FOO"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // Begin BAR().
  unwound_cs = MakeTestUprobesCallstack({"FOO", "beta", "BAR"});
  real_cs = MakeTestCallstack({"main", "alpha", "FOO", "beta", "BAR"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"BAR", "gamma"});
  real_cs = MakeTestCallstack({"main", "alpha", "FOO", "beta", "BAR", "gamma"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End BAR().
  unwound_cs = MakeTestUprobesCallstack({"FOO"});
  real_cs = MakeTestCallstack({"main", "alpha", "FOO"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({
      "FOO",
      "delta",
  });
  real_cs = MakeTestCallstack({"main", "alpha", "FOO", "delta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End FOO().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = real_cs = MakeTestCallstack({"main"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // Begin FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "epsilon", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION"});
  real_cs = MakeTestCallstack({"main", "epsilon", "FUNCTION"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION", "zeta"});
  real_cs = MakeTestCallstack({"main", "epsilon", "FUNCTION", "zeta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "epsilon"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = real_cs = MakeTestCallstack({"main"});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));
}

TEST(UprobesCallstackManager, UnwindingError) {
  std::vector<unwindstack::FrameData> unwound_cs, real_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  // Begin FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // Unwind error.
  unwound_cs = real_cs = MakeTestCallstack({});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));
}

TEST(UprobesCallstackManager, UnwindingErrorOnStack) {
  std::vector<unwindstack::FrameData> unwound_cs, real_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  // Begin FUNCTION() with unwind error.
  unwound_cs = real_cs = MakeTestCallstack({});
  processed_cs = callstack_manager.ProcessUprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION", "beta"});
  real_cs = MakeTestCallstack({});
  processed_cs = callstack_manager.ProcessSampledCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));

  // End FUNCTION().
  unwound_cs = real_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(42, unwound_cs);
  EXPECT_THAT(
      TestCallstackToStringPairVector(processed_cs),
      ::testing::ElementsAreArray(TestCallstackToStringPairVector(real_cs)));
}
<commit_msg>Minor fixes to LinuxUprobesUnwindingVisitorTests.cpp<commit_after>#include <gmock/gmock-matchers.h>
#include <gtest/gtest.h>

#include <utility>

#include "LinuxUprobesUnwindingVisitor.h"

namespace {
unwindstack::FrameData MakeTestFrame(std::string function_name) {
  unwindstack::FrameData frame_data{};
  frame_data.function_name = std::move(function_name);
  frame_data.map_name = "a.out";
  return frame_data;
}

std::vector<unwindstack::FrameData> MakeTestCallstack(
    const std::vector<std::string>& function_names) {
  std::vector<unwindstack::FrameData> callstack;
  for (auto name_it = function_names.rbegin(); name_it != function_names.rend();
       ++name_it) {
    callstack.push_back(MakeTestFrame(*name_it));
  }
  return callstack;
}

unwindstack::FrameData MakeTestUprobesFrame() {
  unwindstack::FrameData uprobes_frame{};
  uprobes_frame.function_name = "uprobes";
  uprobes_frame.map_name = "[uprobes]";
  return uprobes_frame;
}

std::vector<unwindstack::FrameData> MakeTestUprobesCallstack(
    const std::vector<std::string>& function_names) {
  std::vector<unwindstack::FrameData> callstack;
  for (auto name_it = function_names.rbegin(); name_it != function_names.rend();
       ++name_it) {
    callstack.push_back(MakeTestFrame(*name_it));
  }
  callstack.push_back(MakeTestUprobesFrame());
  return callstack;
}

std::vector<std::pair<std::string, std::string>>
TestCallstackToStringPairVector(
    const std::vector<unwindstack::FrameData>& callstack) {
  std::vector<std::pair<std::string, std::string>> vector{};
  for (const auto& frame : callstack) {
    vector.emplace_back(frame.map_name, frame.function_name);
  }
  return vector;
}
}  // namespace

TEST(UprobesCallstackManager, NoUprobes) {
  constexpr pid_t tid = 42;
  std::vector<unwindstack::FrameData> unwound_cs, expected_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha", "beta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha", "gamma"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));
}

TEST(UprobesCallstackManager, OneUprobe) {
  constexpr pid_t tid = 42;
  std::vector<unwindstack::FrameData> unwound_cs, expected_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // Begin FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION"});
  expected_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION", "beta"});
  expected_cs = MakeTestCallstack({"main", "alpha", "FUNCTION", "beta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));
}

TEST(UprobesCallstackManager, DifferentThread) {
  constexpr pid_t tid = 42;
  std::vector<unwindstack::FrameData> unwound_cs, expected_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  // Begin FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // Sample from another thread.
  unwound_cs = expected_cs = MakeTestCallstack({"thread", "omega"});
  processed_cs = callstack_manager.ProcessSampledCallstack(111, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));
}

TEST(UprobesCallstackManager, TwoNestedUprobesAndAnotherUprobe) {
  constexpr pid_t tid = 42;
  std::vector<unwindstack::FrameData> unwound_cs, expected_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // Begin FOO().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha", "FOO"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FOO"});
  expected_cs = MakeTestCallstack({"main", "alpha", "FOO"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // Begin BAR().
  unwound_cs = MakeTestUprobesCallstack({"FOO", "beta", "BAR"});
  expected_cs = MakeTestCallstack({"main", "alpha", "FOO", "beta", "BAR"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"BAR", "gamma"});
  expected_cs =
      MakeTestCallstack({"main", "alpha", "FOO", "beta", "BAR", "gamma"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End BAR().
  unwound_cs = MakeTestUprobesCallstack({"FOO"});
  expected_cs = MakeTestCallstack({"main", "alpha", "FOO"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FOO", "delta"});
  expected_cs = MakeTestCallstack({"main", "alpha", "FOO", "delta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End FOO().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = expected_cs = MakeTestCallstack({"main"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // Begin FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "epsilon", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION"});
  expected_cs = MakeTestCallstack({"main", "epsilon", "FUNCTION"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION", "zeta"});
  expected_cs = MakeTestCallstack({"main", "epsilon", "FUNCTION", "zeta"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "epsilon"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = expected_cs = MakeTestCallstack({"main"});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));
}

TEST(UprobesCallstackManager, UnwindingError) {
  constexpr pid_t tid = 42;
  std::vector<unwindstack::FrameData> unwound_cs, expected_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  // Begin FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha", "FUNCTION"});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // Unwind error.
  unwound_cs = expected_cs = MakeTestCallstack({});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));
}

TEST(UprobesCallstackManager, UnwindingErrorOnStack) {
  constexpr pid_t tid = 42;
  std::vector<unwindstack::FrameData> unwound_cs, expected_cs, processed_cs;
  UprobesCallstackManager callstack_manager{};

  // Begin FUNCTION() with unwind error.
  unwound_cs = expected_cs = MakeTestCallstack({});
  processed_cs = callstack_manager.ProcessUprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  unwound_cs = MakeTestUprobesCallstack({"FUNCTION", "beta"});
  expected_cs = MakeTestCallstack({});
  processed_cs = callstack_manager.ProcessSampledCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));

  // End FUNCTION().
  unwound_cs = expected_cs = MakeTestCallstack({"main", "alpha"});
  processed_cs = callstack_manager.ProcessUretprobesCallstack(tid, unwound_cs);
  EXPECT_THAT(TestCallstackToStringPairVector(processed_cs),
              ::testing::ElementsAreArray(
                  TestCallstackToStringPairVector(expected_cs)));
}
<|endoftext|>


<commit_before>//====================================================================
#include "AliForwarddNdetaTask.h"
#include <TMath.h>
#include <TH2D.h>
#include <TH1D.h>
#include <THStack.h>
#include <TList.h>
#include <AliAnalysisManager.h>
#include <AliAODEvent.h>
#include <AliAODHandler.h>
#include <AliAODInputHandler.h>
#include "AliForwardUtil.h"
#include "AliAODForwardMult.h"

//____________________________________________________________________
AliForwarddNdetaTask::AliForwarddNdetaTask()
  : AliBasedNdetaTask()
{
  //
  // Constructor
  //
}

//____________________________________________________________________
AliForwarddNdetaTask::AliForwarddNdetaTask(const char* /* name */)
  : AliBasedNdetaTask("Forward")
{
  //
  // Constructor
  //
  // Paramters
  //   name    Name of task
}

//____________________________________________________________________
AliForwarddNdetaTask::AliForwarddNdetaTask(const AliForwarddNdetaTask& o)
  : AliBasedNdetaTask(o)
{
  //
  // Copy constructor
  //
}

//____________________________________________________________________
AliBasedNdetaTask::CentralityBin*
AliForwarddNdetaTask::MakeCentralityBin(const char* name, Short_t l, Short_t h)
  const
{
  //
  // Make a new centrality bin
  //
  // Parameters:
  //    name   Histogram names
  //    l      Lower cut
  //    h      Upper cut
  //
  // Return:
  //    Newly allocated object (of our type)
  //
  return new AliForwarddNdetaTask::CentralityBin(name, l, h);
}

//____________________________________________________________________
void
AliForwarddNdetaTask::UserExec(Option_t* option)
{
  //
  // Called at each event
  //
  // This is called once in the master
  //
  // Parameters:
  //    option Not used
  //
  AliBasedNdetaTask::UserExec(option);

  AliAODEvent* aod = dynamic_cast<AliAODEvent*>(InputEvent());
  if (!aod) {
    AliError("Cannot get the AOD event");
    return;
  }

  TObject* obj = aod->FindListObject("Forward");
  if (!obj) {
    AliWarning("No forward object found");
    return;
  }
  AliAODForwardMult* forward = static_cast<AliAODForwardMult*>(obj);

  TObject* oPrimary   = aod->FindListObject("primary");
  if (!oPrimary) return;

  TH2D* primary   = static_cast<TH2D*>(oPrimary);

  // Loop over centrality bins
  TIter next(fListOfCentralities);
  CentralityBin* bin = 0;
  while ((bin = static_cast<CentralityBin*>(next())))
    bin->ProcessPrimary(forward, fTriggerMask, fVtxMin, fVtxMax, primary);
}

//____________________________________________________________________
TH2D*
AliForwarddNdetaTask::GetHistogram(const AliAODEvent* aod, Bool_t mc)
{
  //
  // Retrieve the histogram
  //
  // Parameters:
  //    aod AOD event
  //    mc  Whether to get the MC histogram or not
  //
  // Return:
  //    Retrieved histogram or null
  //
  TObject* obj = 0;
  if (mc) obj = aod->FindListObject("ForwardMC");
  else    obj = aod->FindListObject("Forward");

  // We should have a forward object at least
  if (!obj) {
    if (!mc) AliWarning("No Forward object found AOD");
    return 0;
  }
  AliAODForwardMult* forward = static_cast<AliAODForwardMult*>(obj);
  return &(forward->GetHistogram());
}

//========================================================================
void
AliForwarddNdetaTask::CentralityBin::ProcessPrimary(const AliAODForwardMult*
						    forward,
						    Int_t triggerMask,
						    Double_t vzMin,
						    Double_t vzMax,
						    const TH2D* primary)
{
  // Check the centrality class unless this is the 'all' bin
  if (!IsAllBin()) {
    Double_t centrality = forward->GetCentrality();
    if (centrality < fLow || centrality >= fHigh) return;
  }

  // translate rea trigger mask to MC trigger mask
  Int_t mask = AliAODForwardMult::kB;
  if (triggerMask == AliAODForwardMult::kNSD)
    mask = AliAODForwardMult::kMCNSD;

  // Now use our normal check, but with the new mask
  if (!forward->CheckEvent(mask, vzMin, vzMax, 0, 0, 0)) return;

  // Create sum histogram
  if (!fSumPrimary) {
    fSumPrimary = static_cast<TH2D*>(primary->Clone("truth"));
    fSumPrimary->SetDirectory(0);
    fSumPrimary->Reset();
    fSums->Add(fSumPrimary);
  }

  fSumPrimary->Add(primary);
}

//________________________________________________________________________
void
AliForwarddNdetaTask::CentralityBin::End(TList*      sums,
					 TList*      results,
					 UShort_t    scheme,
					 const TH1*  shapeCorr,
					 Double_t    trigEff,
					 Bool_t      symmetrice,
					 Int_t       rebin,
					 Bool_t      rootProj,
					 Bool_t      corrEmpty,
					 Bool_t      cutEdges,
					 Int_t       triggerMask,
					 Int_t       color,
					 Int_t       marker)
{
  AliInfo(Form("In End of %s with corrEmpty=%d, cutEdges=%d, rootProj=%d",
	       GetName(), corrEmpty, cutEdges, rootProj));
  AliBasedNdetaTask::CentralityBin::End(sums, results, scheme,
					shapeCorr, trigEff,
					symmetrice, rebin,
					rootProj, corrEmpty, cutEdges,
					triggerMask, color, marker);

  fSumPrimary     = static_cast<TH2D*>(fSums->FindObject("truth"));

  if (!fSumPrimary) return;
  Int_t n = (triggerMask == AliAODForwardMult::kNSD ?
	     Int_t(fTriggers->GetBinContent(AliAODForwardMult::kBinMCNSD)) :
	     Int_t(fTriggers->GetBinContent(AliAODForwardMult::kBinAll)));
  AliInfo(Form("Normalising MC truth to %d", n));

  TH1D* dndetaTruth = fSumPrimary->ProjectionX("dndetaTruth",1,
					       fSumPrimary->GetNbinsY(),"e");
  dndetaTruth->Scale(1./n, "width");

  SetHistogramAttributes(dndetaTruth, color-2, marker+4, "Monte-Carlo truth");

  fOutput->Add(dndetaTruth);
  fOutput->Add(Rebin(dndetaTruth, rebin, cutEdges));
}

//________________________________________________________________________
//
// EOF
//
<commit_msg>Primaries must be counted before trigger cuts else they are not MC truth<commit_after>//====================================================================
#include "AliForwarddNdetaTask.h"
#include <TMath.h>
#include <TH2D.h>
#include <TH1D.h>
#include <THStack.h>
#include <TList.h>
#include <AliAnalysisManager.h>
#include <AliAODEvent.h>
#include <AliAODHandler.h>
#include <AliAODInputHandler.h>
#include "AliForwardUtil.h"
#include "AliAODForwardMult.h"

//____________________________________________________________________
AliForwarddNdetaTask::AliForwarddNdetaTask()
  : AliBasedNdetaTask()
{
  //
  // Constructor
  //
}

//____________________________________________________________________
AliForwarddNdetaTask::AliForwarddNdetaTask(const char* /* name */)
  : AliBasedNdetaTask("Forward")
{
  //
  // Constructor
  //
  // Paramters
  //   name    Name of task
}

//____________________________________________________________________
AliForwarddNdetaTask::AliForwarddNdetaTask(const AliForwarddNdetaTask& o)
  : AliBasedNdetaTask(o)
{
  //
  // Copy constructor
  //
}

//____________________________________________________________________
AliBasedNdetaTask::CentralityBin*
AliForwarddNdetaTask::MakeCentralityBin(const char* name, Short_t l, Short_t h)
  const
{
  //
  // Make a new centrality bin
  //
  // Parameters:
  //    name   Histogram names
  //    l      Lower cut
  //    h      Upper cut
  //
  // Return:
  //    Newly allocated object (of our type)
  //
  return new AliForwarddNdetaTask::CentralityBin(name, l, h);
}

//____________________________________________________________________
void
AliForwarddNdetaTask::UserExec(Option_t* option)
{
  //
  // Called at each event
  //
  // This is called once in the master
  //
  // Parameters:
  //    option Not used
  //
  AliBasedNdetaTask::UserExec(option);

  AliAODEvent* aod = dynamic_cast<AliAODEvent*>(InputEvent());
  if (!aod) {
    AliError("Cannot get the AOD event");
    return;
  }

  TObject* obj = aod->FindListObject("Forward");
  if (!obj) {
    AliWarning("No forward object found");
    return;
  }
  AliAODForwardMult* forward = static_cast<AliAODForwardMult*>(obj);

  TObject* oPrimary   = aod->FindListObject("primary");
  if (!oPrimary) return;

  TH2D* primary   = static_cast<TH2D*>(oPrimary);

  // Loop over centrality bins
  TIter next(fListOfCentralities);
  CentralityBin* bin = 0;
  while ((bin = static_cast<CentralityBin*>(next())))
    bin->ProcessPrimary(forward, fTriggerMask, fVtxMin, fVtxMax, primary);
}

//____________________________________________________________________
TH2D*
AliForwarddNdetaTask::GetHistogram(const AliAODEvent* aod, Bool_t mc)
{
  //
  // Retrieve the histogram
  //
  // Parameters:
  //    aod AOD event
  //    mc  Whether to get the MC histogram or not
  //
  // Return:
  //    Retrieved histogram or null
  //
  TObject* obj = 0;
  if (mc) obj = aod->FindListObject("ForwardMC");
  else    obj = aod->FindListObject("Forward");

  // We should have a forward object at least
  if (!obj) {
    if (!mc) AliWarning("No Forward object found AOD");
    return 0;
  }
  AliAODForwardMult* forward = static_cast<AliAODForwardMult*>(obj);
  return &(forward->GetHistogram());
}

//========================================================================
void
AliForwarddNdetaTask::CentralityBin::ProcessPrimary(const AliAODForwardMult*
						    forward,
						    Int_t triggerMask,
						    Double_t vzMin,
						    Double_t vzMax,
						    const TH2D* primary)
{
  // Check the centrality class unless this is the 'all' bin
  if (!IsAllBin()) {
    Double_t centrality = forward->GetCentrality();
    if (centrality < fLow || centrality >= fHigh) return;
  }

  // Create sum histogram
  if (!fSumPrimary) {
    fSumPrimary = static_cast<TH2D*>(primary->Clone("truth"));
    fSumPrimary->SetDirectory(0);
    fSumPrimary->Reset();
    fSums->Add(fSumPrimary);
  }
  if (triggerMask == AliAODForwardMult::kNSD && forward->IsTriggerBits(triggerMask|AliAODForwardMult::kB))
    fSumPrimary->Add(primary);

  // translate rea trigger mask to MC trigger mask
  Int_t mask = AliAODForwardMult::kB;
  if (triggerMask == AliAODForwardMult::kNSD)
    mask = AliAODForwardMult::kMCNSD;

  // Now use our normal check, but with the new mask
  if (!forward->CheckEvent(mask, vzMin, vzMax, 0, 0, 0)) return;

}

//________________________________________________________________________
void
AliForwarddNdetaTask::CentralityBin::End(TList*      sums,
					 TList*      results,
					 UShort_t    scheme,
					 const TH1*  shapeCorr,
					 Double_t    trigEff,
					 Bool_t      symmetrice,
					 Int_t       rebin,
					 Bool_t      rootProj,
					 Bool_t      corrEmpty,
					 Bool_t      cutEdges,
					 Int_t       triggerMask,
					 Int_t       color,
					 Int_t       marker)
{
  AliInfo(Form("In End of %s with corrEmpty=%d, cutEdges=%d, rootProj=%d",
	       GetName(), corrEmpty, cutEdges, rootProj));
  AliBasedNdetaTask::CentralityBin::End(sums, results, scheme,
					shapeCorr, trigEff,
					symmetrice, rebin,
					rootProj, corrEmpty, cutEdges,
					triggerMask, color, marker);

  fSumPrimary     = static_cast<TH2D*>(fSums->FindObject("truth"));

  if (!fSumPrimary) return;
  Int_t n = (triggerMask == AliAODForwardMult::kNSD ?
	     Int_t(fTriggers->GetBinContent(AliAODForwardMult::kBinMCNSD)) :
	     Int_t(fTriggers->GetBinContent(AliAODForwardMult::kBinAll)));
  AliInfo(Form("Normalising MC truth to %d", n));

  TH1D* dndetaTruth = fSumPrimary->ProjectionX("dndetaTruth",1,
					       fSumPrimary->GetNbinsY(),"e");
  dndetaTruth->Scale(1./n, "width");

  SetHistogramAttributes(dndetaTruth, color-2, marker+4, "Monte-Carlo truth");

  fOutput->Add(dndetaTruth);
  fOutput->Add(Rebin(dndetaTruth, rebin, cutEdges));
}

//________________________________________________________________________
//
// EOF
//
<|endoftext|>


<commit_before>AliAnalysisTaskPerformanceStrange *AddTaskPerformanceStrange(Short_t lCollidingSystems = 0,   // 0->pp,   1->AA
							     Short_t lAnalysisMC       = 1,   // 0->No MC or 1->MC analysis
							     TString lAnalysisCut      = "no",
							     TString lAnalysisPidMode  = "withoutPID" )
{
// Creates, configures and attaches to the train a strangeness task.
   // Get the pointer to the existing analysis manager via the static access method.
   //==============================================================================
   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
   if (!mgr) {
      ::Error("AddTaskPerformanceStrange", "No analysis manager to connect to.");
      return NULL;
   }

   // Check the analysis type using the event handlers connected to the analysis manager.
   //==============================================================================
   if (!mgr->GetInputEventHandler()) {
      ::Error("AddTaskPerformanceStrange", "This task requires an input event handler");
      return NULL;
   }
   TString type = mgr->GetInputEventHandler()->GetDataType(); // can be "ESD" or "AOD"

   // Create and configure the task
	AliAnalysisTaskPerformanceStrange *taskperformancestrange = new AliAnalysisTaskPerformanceStrange("TaskPerformanceStrange");
   taskperformancestrange->SetCollidingSystems(lCollidingSystems);
   taskperformancestrange->SetAnalysisType(type);
   taskperformancestrange->SetAnalysisMC(lAnalysisMC);
   taskperformancestrange->SetAnalysisCut(lAnalysisCut);
   taskperformancestrange->SetUsePID((lAnalysisPidMode);
   mgr->AddTask(taskperformancestrange);

   // Create ONLY the output containers for the data produced by the task.
   // Get and connect other common input/output containers via the manager as below
   //==============================================================================
   TString outputFileName = AliAnalysisManager::GetCommonFileName();
   outputFileName += ":PWG2Strange";
   if (lCollidingSystems) outputFileName += "_AA";
   else outputFileName += "_PP";
   if (mgr->GetMCtruthEventHandler()) outputFileName += "_MC";

   AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("clistPerformanceStrange",
							     TList::Class(),
							     AliAnalysisManager::kOutputContainer,
							     outputFileName );

   mgr->ConnectInput(taskperformancestrange, 0, mgr->GetCommonInputContainer());
   mgr->ConnectOutput(taskperformancestrange, 1, coutput1);
   return taskperformancestrange;
}
<commit_msg>Argghh... small typo... corrected<commit_after>AliAnalysisTaskPerformanceStrange *AddTaskPerformanceStrange(Short_t lCollidingSystems = 0,   // 0->pp,   1->AA
							     Short_t lAnalysisMC       = 1,   // 0->No MC or 1->MC analysis
							     TString lAnalysisCut      = "no",
							     TString lAnalysisPidMode  = "withoutPID" )
{
// Creates, configures and attaches to the train a strangeness task.
   // Get the pointer to the existing analysis manager via the static access method.
   //==============================================================================
   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
   if (!mgr) {
      ::Error("AddTaskPerformanceStrange", "No analysis manager to connect to.");
      return NULL;
   }

   // Check the analysis type using the event handlers connected to the analysis manager.
   //==============================================================================
   if (!mgr->GetInputEventHandler()) {
      ::Error("AddTaskPerformanceStrange", "This task requires an input event handler");
      return NULL;
   }
   TString type = mgr->GetInputEventHandler()->GetDataType(); // can be "ESD" or "AOD"

   // Create and configure the task
	AliAnalysisTaskPerformanceStrange *taskperformancestrange = new AliAnalysisTaskPerformanceStrange("TaskPerformanceStrange");
   taskperformancestrange->SetCollidingSystems(lCollidingSystems);
   taskperformancestrange->SetAnalysisType(type);
   taskperformancestrange->SetAnalysisMC(lAnalysisMC);
   taskperformancestrange->SetAnalysisCut(lAnalysisCut);
   taskperformancestrange->SetUsePID(lAnalysisPidMode);
   mgr->AddTask(taskperformancestrange);

   // Create ONLY the output containers for the data produced by the task.
   // Get and connect other common input/output containers via the manager as below
   //==============================================================================
   TString outputFileName = AliAnalysisManager::GetCommonFileName();
   outputFileName += ":PWG2Strange";
   if (lCollidingSystems) outputFileName += "_AA";
   else outputFileName += "_PP";
   if (mgr->GetMCtruthEventHandler()) outputFileName += "_MC";

   AliAnalysisDataContainer *coutput1 = mgr->CreateContainer("clistPerformanceStrange",
							     TList::Class(),
							     AliAnalysisManager::kOutputContainer,
							     outputFileName );

   mgr->ConnectInput(taskperformancestrange, 0, mgr->GetCommonInputContainer());
   mgr->ConnectOutput(taskperformancestrange, 1, coutput1);
   return taskperformancestrange;
}

<|endoftext|>


<commit_before>
// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <cstdlib>

#include "openMVG/sfm/sfm.hpp"
#include "openMVG/system/timer.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::sfm;

/// From 2 given image file-names, find the two corresponding index in the View list
bool computeIndexFromImageNames(
  const SfM_Data & sfm_data,
  const std::pair<std::string,std::string>& initialPairName,
  Pair& initialPairIndex)
{
  if (initialPairName.first == initialPairName.second)
  {
    std::cerr << "\nInvalid image names. You cannot use the same image to initialize a pair." << std::endl;
    return false;
  }

  initialPairIndex = Pair(UndefinedIndexT, UndefinedIndexT);

  /// List views filenames and find the one that correspond to the user ones:
  std::vector<std::string> vec_camImageName;
  for (Views::const_iterator it = sfm_data.GetViews().begin();
    it != sfm_data.GetViews().end(); ++it)
  {
    const View * v = it->second.get();
    const std::string filename = stlplus::filename_part(v->s_Img_path);
    if (filename == initialPairName.first)
    {
      initialPairIndex.first = v->id_view;
    }
    else{
      if (filename == initialPairName.second)
      {
        initialPairIndex.second = v->id_view;
      }
    }
  }
  return (initialPairIndex.first != UndefinedIndexT &&
      initialPairIndex.second != UndefinedIndexT);
}

int main(int argc, char **argv)
{
  using namespace std;
  std::cout << "Sequential/Incremental reconstruction" << std::endl
            << " Perform incremental SfM (Initial Pair Essential + Resection)." << std::endl
            << std::endl;

  CmdLine cmd;

  std::string sSfM_Data_Filename;
  std::string sMatchesDir;
  std::string sOutDir = "";
  std::string sOutSfMDataFilepath = "";
  std::string sOutInterFileExtension = ".ply";
  std::pair<std::string,std::string> initialPairString("","");
  bool bRefineIntrinsics = true;
  int minInputTrackLength = 2;
  int i_User_camera_model = PINHOLE_CAMERA_RADIAL3;
  bool allowUserInteraction = true;

  cmd.add( make_option('i', sSfM_Data_Filename, "input_file") );
  cmd.add( make_option('m', sMatchesDir, "matchdir") );
  cmd.add( make_option('o', sOutDir, "outdir") );
  cmd.add( make_option('s', sOutSfMDataFilepath, "out_sfmdata_file") );
  cmd.add( make_option('e', sOutInterFileExtension, "inter_file_extension") );
  cmd.add( make_option('a', initialPairString.first, "initialPairA") );
  cmd.add( make_option('b', initialPairString.second, "initialPairB") );
  cmd.add( make_option('c', i_User_camera_model, "camera_model") );
  cmd.add( make_option('f', bRefineIntrinsics, "refineIntrinsics") );
  cmd.add( make_option('t', minInputTrackLength, "minInputTrackLength") );
  cmd.add( make_option('u', allowUserInteraction, "allowUserInteraction") );

  try {
    if (argc == 1) throw std::string("Invalid parameter.");
    cmd.process(argc, argv);
  } catch(const std::string& s) {
    std::cerr << "Usage: " << argv[0] << '\n'
    << "[-i|--input_file] path to a SfM_Data scene\n"
    << "[-m|--matchdir] path to the matches that corresponds to the provided SfM_Data scene\n"
    << "[-o|--outdir] path where the output data will be stored\n"
    << "[-s|--out_sfmdata_file] path of the output sfmdata file (default: $outdir/sfm_data.json)\n"
    << "[-e|--inter_file_extension] extension of the intermediate file export (default: .ply)\n"
    << "[-a|--initialPairA] filename of the first image (without path)\n"
    << "[-b|--initialPairB] filename of the second image (without path)\n"
    << "[-c|--camera_model] Camera model type for view with unknown intrinsic:\n"
      << "\t 1: Pinhole \n"
      << "\t 2: Pinhole radial 1\n"
      << "\t 3: Pinhole radial 3 (default)\n"
    << "[-f|--refineIntrinsics] \n"
    << "\t 0-> intrinsic parameters are kept as constant\n"
    << "\t 1-> refine intrinsic parameters (default). \n"
    << "[-t|--minInputTrackLength N] minimum track length in input of SfM (default: 2)\n"
    << "[-p|--matchFilePerImage] \n"
    << "\t To use one match file per image instead of a global file.\n"
    << "[-u|--allowUserInteraction] Enable/Disable user interactions. (default: true)\n"
    << "\t If the process is done on renderfarm, it doesn't make sense to wait for user inputs.\n"
    << std::endl;

    std::cerr << s << std::endl;
    return EXIT_FAILURE;
  }

  if(sOutSfMDataFilepath.empty())
    sOutSfMDataFilepath = stlplus::create_filespec(sOutDir, "sfm_data", "json");

  // Load input SfM_Data scene
  SfM_Data sfm_data;
  if (!Load(sfm_data, sSfM_Data_Filename, ESfM_Data(VIEWS|INTRINSICS))) {
    std::cerr << std::endl
      << "The input SfM_Data file \""<< sSfM_Data_Filename << "\" cannot be read." << std::endl;
    return EXIT_FAILURE;
  }

  // Init the regions_type from the image describer file (used for image regions extraction)
  using namespace openMVG::features;
  const std::string sImage_describer = stlplus::create_filespec(sMatchesDir, "image_describer", "json");
  std::unique_ptr<Regions> regions_type = Init_region_type_from_file(sImage_describer);
  if (!regions_type)
  {
    std::cerr << "Invalid: "
      << sImage_describer << " regions type file." << std::endl;
    return EXIT_FAILURE;
  }

  // Features reading
  std::shared_ptr<Features_Provider> feats_provider = std::make_shared<Features_Provider>();
  if (!feats_provider->load(sfm_data, sMatchesDir, regions_type)) {
    std::cerr << std::endl
      << "Invalid features." << std::endl;
    return EXIT_FAILURE;
  }
  // Matches reading
  std::shared_ptr<Matches_Provider> matches_provider = std::make_shared<Matches_Provider>();

  if(!matches_provider->load(sfm_data, sMatchesDir, "f"))
  {
    std::cerr << std::endl << "Unable to load matches file from: " << sMatchesDir << std::endl;
    return EXIT_FAILURE;
  }

  if (sOutDir.empty())
  {
    std::cerr << "\nIt is an invalid output directory" << std::endl;
    return EXIT_FAILURE;
  }

  if (!stlplus::folder_exists(sOutDir))
    stlplus::folder_create(sOutDir);

  //---------------------------------------
  // Sequential reconstruction process
  //---------------------------------------

  openMVG::system::Timer timer;
  SequentialSfMReconstructionEngine sfmEngine(
    sfm_data,
    sOutDir,
    stlplus::create_filespec(sOutDir, "Reconstruction_Report.html"));

  // Configure the features_provider & the matches_provider
  sfmEngine.SetFeaturesProvider(feats_provider.get());
  sfmEngine.SetMatchesProvider(matches_provider.get());

  // Configure reconstruction parameters
  sfmEngine.Set_bFixedIntrinsics(!bRefineIntrinsics);
  sfmEngine.SetUnknownCameraType(EINTRINSIC(i_User_camera_model));
  sfmEngine.setMinInputTrackLength(minInputTrackLength);
  sfmEngine.setSfmdataInterFileExtension(sOutInterFileExtension);
  sfmEngine.setAllowUserInteraction(allowUserInteraction);

  // Handle Initial pair parameter
  if (!initialPairString.first.empty() && !initialPairString.second.empty())
  {
    Pair initialPairIndex;
    if(!computeIndexFromImageNames(sfm_data, initialPairString, initialPairIndex))
    {
        std::cerr << "Could not find the initial pairs <" << initialPairString.first
          <<  ", " << initialPairString.second << ">!\n";
      return EXIT_FAILURE;
    }
    sfmEngine.setInitialPair(initialPairIndex);
  }

  if (!sfmEngine.Process())
  {
    return EXIT_FAILURE;
  }

  // get the color for the 3D points
  sfmEngine.Colorize();

  std::cout << std::endl << " Total Ac-Sfm took (s): " << timer.elapsed() << std::endl;

  std::cout << "...Generating SfM_Report.html" << std::endl;
  Generate_SfM_Report(sfmEngine.Get_SfM_Data(),
    stlplus::create_filespec(sOutDir, "SfMReconstruction_Report.html"));

  //-- Export to disk computed scene (data & visualizable results)
  std::cout << "...Export SfM_Data to disk:" << std::endl;
  std::cout << "   " << sOutSfMDataFilepath << std::endl;

  Save(sfmEngine.Get_SfM_Data(), sOutSfMDataFilepath, ESfM_Data(ALL));

  Save(sfmEngine.Get_SfM_Data(), stlplus::create_filespec(sOutDir, "cloud_and_poses", sOutInterFileExtension), ESfM_Data(VIEWS | EXTRINSICS | INTRINSICS | STRUCTURE));

  return EXIT_SUCCESS;
}
<commit_msg>[SfM] Allows image path for setting initial pair<commit_after>
// Copyright (c) 2012, 2013 Pierre MOULON.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <cstdlib>

#include "openMVG/sfm/sfm.hpp"
#include "openMVG/system/timer.hpp"

#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"

using namespace openMVG;
using namespace openMVG::cameras;
using namespace openMVG::sfm;

bool computeIndexFromImageName(
  const SfM_Data & sfm_data,
  const std::string& initialName,
  IndexT& initialIndex)
{
  initialIndex = UndefinedIndexT;

  bool isName = (initialName == stlplus::filename_part(initialName));

  /// List views filenames and find the one that correspond to the user ones:
  for(Views::const_iterator it = sfm_data.GetViews().begin();
    it != sfm_data.GetViews().end(); ++it)
  {
    const View * v = it->second.get();
    std::string filename;

    if(isName)
    {
      filename = stlplus::filename_part(v->s_Img_path);
    }
    else
    {
      if(stlplus::is_full_path(v->s_Img_path))
      {
        filename = v->s_Img_path;
      }
      else
      {
        filename = sfm_data.s_root_path + v->s_Img_path;
      }
    }

    if (filename == initialName)
    {
      if(initialIndex == UndefinedIndexT)
      {
          initialIndex = v->id_view;
      }
      else
      {
        std::cout<<"Error: Two pictures named :" << initialName << " !" << std::endl;
      }
    }
  }
  return initialIndex != UndefinedIndexT;
}

int main(int argc, char **argv)
{
  using namespace std;
  std::cout << "Sequential/Incremental reconstruction" << std::endl
            << " Perform incremental SfM (Initial Pair Essential + Resection)." << std::endl
            << std::endl;

  CmdLine cmd;

  std::string sSfM_Data_Filename;
  std::string sMatchesDir;
  std::string sOutDir = "";
  std::string sOutSfMDataFilepath = "";
  std::string sOutInterFileExtension = ".ply";
  std::pair<std::string,std::string> initialPairString("","");
  bool bRefineIntrinsics = true;
  int minInputTrackLength = 2;
  int i_User_camera_model = PINHOLE_CAMERA_RADIAL3;
  bool allowUserInteraction = true;

  cmd.add( make_option('i', sSfM_Data_Filename, "input_file") );
  cmd.add( make_option('m', sMatchesDir, "matchdir") );
  cmd.add( make_option('o', sOutDir, "outdir") );
  cmd.add( make_option('s', sOutSfMDataFilepath, "out_sfmdata_file") );
  cmd.add( make_option('e', sOutInterFileExtension, "inter_file_extension") );
  cmd.add( make_option('a', initialPairString.first, "initialPairA") );
  cmd.add( make_option('b', initialPairString.second, "initialPairB") );
  cmd.add( make_option('c', i_User_camera_model, "camera_model") );
  cmd.add( make_option('f', bRefineIntrinsics, "refineIntrinsics") );
  cmd.add( make_option('t', minInputTrackLength, "minInputTrackLength") );
  cmd.add( make_option('u', allowUserInteraction, "allowUserInteraction") );

  try {
    if (argc == 1) throw std::string("Invalid parameter.");
    cmd.process(argc, argv);
  } catch(const std::string& s) {
    std::cerr << "Usage: " << argv[0] << '\n'
    << "[-i|--input_file] path to a SfM_Data scene\n"
    << "[-m|--matchdir] path to the matches that corresponds to the provided SfM_Data scene\n"
    << "[-o|--outdir] path where the output data will be stored\n"
    << "[-s|--out_sfmdata_file] path of the output sfmdata file (default: $outdir/sfm_data.json)\n"
    << "[-e|--inter_file_extension] extension of the intermediate file export (default: .ply)\n"
    << "[-a|--initialPairA] filename of the first image (without path)\n"
    << "[-b|--initialPairB] filename of the second image (without path)\n"
    << "[-c|--camera_model] Camera model type for view with unknown intrinsic:\n"
      << "\t 1: Pinhole \n"
      << "\t 2: Pinhole radial 1\n"
      << "\t 3: Pinhole radial 3 (default)\n"
    << "[-f|--refineIntrinsics] \n"
    << "\t 0-> intrinsic parameters are kept as constant\n"
    << "\t 1-> refine intrinsic parameters (default). \n"
    << "[-t|--minInputTrackLength N] minimum track length in input of SfM (default: 2)\n"
    << "[-p|--matchFilePerImage] \n"
    << "\t To use one match file per image instead of a global file.\n"
    << "[-u|--allowUserInteraction] Enable/Disable user interactions. (default: true)\n"
    << "\t If the process is done on renderfarm, it doesn't make sense to wait for user inputs.\n"
    << std::endl;

    std::cerr << s << std::endl;
    return EXIT_FAILURE;
  }

  if(sOutSfMDataFilepath.empty())
    sOutSfMDataFilepath = stlplus::create_filespec(sOutDir, "sfm_data", "json");

  // Load input SfM_Data scene
  SfM_Data sfm_data;
  if (!Load(sfm_data, sSfM_Data_Filename, ESfM_Data(VIEWS|INTRINSICS))) {
    std::cerr << std::endl
      << "The input SfM_Data file \""<< sSfM_Data_Filename << "\" cannot be read." << std::endl;
    return EXIT_FAILURE;
  }

  // Init the regions_type from the image describer file (used for image regions extraction)
  using namespace openMVG::features;
  const std::string sImage_describer = stlplus::create_filespec(sMatchesDir, "image_describer", "json");
  std::unique_ptr<Regions> regions_type = Init_region_type_from_file(sImage_describer);
  if (!regions_type)
  {
    std::cerr << "Invalid: "
      << sImage_describer << " regions type file." << std::endl;
    return EXIT_FAILURE;
  }

  // Features reading
  std::shared_ptr<Features_Provider> feats_provider = std::make_shared<Features_Provider>();
  if (!feats_provider->load(sfm_data, sMatchesDir, regions_type)) {
    std::cerr << std::endl
      << "Invalid features." << std::endl;
    return EXIT_FAILURE;
  }
  // Matches reading
  std::shared_ptr<Matches_Provider> matches_provider = std::make_shared<Matches_Provider>();

  if(!matches_provider->load(sfm_data, sMatchesDir, "f"))
  {
    std::cerr << std::endl << "Unable to load matches file from: " << sMatchesDir << std::endl;
    return EXIT_FAILURE;
  }

  if (sOutDir.empty())
  {
    std::cerr << "\nIt is an invalid output directory" << std::endl;
    return EXIT_FAILURE;
  }

  if (!stlplus::folder_exists(sOutDir))
    stlplus::folder_create(sOutDir);

  //---------------------------------------
  // Sequential reconstruction process
  //---------------------------------------

  openMVG::system::Timer timer;
  SequentialSfMReconstructionEngine sfmEngine(
    sfm_data,
    sOutDir,
    stlplus::create_filespec(sOutDir, "Reconstruction_Report.html"));

  // Configure the features_provider & the matches_provider
  sfmEngine.SetFeaturesProvider(feats_provider.get());
  sfmEngine.SetMatchesProvider(matches_provider.get());

  // Configure reconstruction parameters
  sfmEngine.Set_bFixedIntrinsics(!bRefineIntrinsics);
  sfmEngine.SetUnknownCameraType(EINTRINSIC(i_User_camera_model));
  sfmEngine.setMinInputTrackLength(minInputTrackLength);
  sfmEngine.setSfmdataInterFileExtension(sOutInterFileExtension);
  sfmEngine.setAllowUserInteraction(allowUserInteraction);

  if (initialPairString.first == initialPairString.second)
  {
    std::cerr << "\nInvalid image names. You cannot use the same image to initialize a pair." << std::endl;
    return false;
  }

  // Handle Initial pair parameter
  if (!initialPairString.first.empty() && !initialPairString.second.empty())
  {
    Pair initialPairIndex;
    if(!computeIndexFromImageName(sfm_data, initialPairString.first, initialPairIndex.first)
            || !computeIndexFromImageName(sfm_data, initialPairString.second, initialPairIndex.second))
    {
        std::cerr << "Could not find the initial pairs <" << initialPairString.first
          <<  ", " << initialPairString.second << ">!\n";
        return EXIT_FAILURE;
    }

    sfmEngine.setInitialPair(initialPairIndex);
  }

  if (!sfmEngine.Process())
  {
    return EXIT_FAILURE;
  }

  // get the color for the 3D points
  sfmEngine.Colorize();

  std::cout << std::endl << " Total Ac-Sfm took (s): " << timer.elapsed() << std::endl;

  std::cout << "...Generating SfM_Report.html" << std::endl;
  Generate_SfM_Report(sfmEngine.Get_SfM_Data(),
    stlplus::create_filespec(sOutDir, "SfMReconstruction_Report.html"));

  //-- Export to disk computed scene (data & visualizable results)
  std::cout << "...Export SfM_Data to disk:" << std::endl;
  std::cout << "   " << sOutSfMDataFilepath << std::endl;

  Save(sfmEngine.Get_SfM_Data(), sOutSfMDataFilepath, ESfM_Data(ALL));

  Save(sfmEngine.Get_SfM_Data(), stlplus::create_filespec(sOutDir, "cloud_and_poses", sOutInterFileExtension), ESfM_Data(VIEWS | EXTRINSICS | INTRINSICS | STRUCTURE));

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 The Verible Authors.
//
// 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 "verilog/analysis/checkers/forbidden_anonymous_structs_unions_rule.h"

#include <initializer_list>

#include "gtest/gtest.h"
#include "common/analysis/syntax_tree_linter_test_utils.h"
#include "common/text/symbol.h"
#include "verilog/analysis/verilog_analyzer.h"

namespace verilog {
namespace analysis {
namespace {

using verible::LintTestCase;
using verible::RunLintTestCases;

// Tests that properly typedef'ed struct passes.
TEST(ForbiddenAnonymousStructsUnionsTest, AcceptsTypedefedStructs) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {"typedef struct {bit [8:0] op, arg1, arg2;} cmd;\ncmd a_cmd;"},
      {"typedef struct {byte a; reg b;} custom;\ncustom a_struct;"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

// Tests that anonymous structs are detected
TEST(ForbiddenAnonymousStructsUnionsTest, RejectsAnonymousStructs) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {{TK_struct, "struct"}, " {bit [8:0] op, arg1, arg2;} cmd;"},
      {{TK_struct, "struct"}, " {byte a; reg b;} custom;\ncustom a_struct;"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

// Tests that properly typedef'ed union passes.
TEST(ForbiddenAnonymousStructsUnionsTest, AcceptsTypedefedUnions) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {"typedef union {logic [8:0] arr; int status;} obj;\nobj a_obj;"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

// Tests that anonymous unions are detected
TEST(ForbiddenAnonymousStructsUnionsTest, RejectsAnonymousUnions) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {{TK_union, "union"}, " {bit [8:0] flags; int val;} result;"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

}  // namespace
}  // namespace analysis
}  // namespace verilog
<commit_msg>Adding anonymous struct test cases, that reflect current findings.<commit_after>// Copyright 2017-2020 The Verible Authors.
//
// 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 "verilog/analysis/checkers/forbidden_anonymous_structs_unions_rule.h"

#include <initializer_list>

#include "gtest/gtest.h"
#include "common/analysis/syntax_tree_linter_test_utils.h"
#include "common/text/symbol.h"
#include "verilog/analysis/verilog_analyzer.h"

namespace verilog {
namespace analysis {
namespace {

using verible::LintTestCase;
using verible::RunLintTestCases;

// Tests that properly typedef'ed struct passes.
TEST(ForbiddenAnonymousStructsUnionsTest, AcceptsTypedefedStructs) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {"typedef struct {bit [8:0] op, arg1, arg2;} cmd;\ncmd a_cmd;"},
      {"typedef struct {byte a; reg b;} custom;\ncustom a_struct;"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

// Tests that anonymous structs are detected
TEST(ForbiddenAnonymousStructsUnionsTest, RejectsAnonymousStructs) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {{TK_struct, "struct"}, " {bit [8:0] op, arg1, arg2;} cmd;"},
      {{TK_struct, "struct"}, " {byte a; reg b;} custom;\ncustom a_struct;"},
      {"module m #(parameter type T = ",
       {TK_struct, "struct"},
       " packed { int i; }) (); endmodule\n"},
      {"module nn; m #(.T(",
       {TK_struct, "struct"},
       " packed { int i;})) mm; endmodule\n"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

// Tests that properly typedef'ed union passes.
TEST(ForbiddenAnonymousStructsUnionsTest, AcceptsTypedefedUnions) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {"typedef union {logic [8:0] arr; int status;} obj;\nobj a_obj;"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

// Tests that anonymous unions are detected
TEST(ForbiddenAnonymousStructsUnionsTest, RejectsAnonymousUnions) {
  const std::initializer_list<LintTestCase> kTestCases = {
      {{TK_union, "union"}, " {bit [8:0] flags; int val;} result;"},
      {"module m #(parameter type T = ",
       {TK_union, "union"},
       " packed { int i; }) (); endmodule\n"},
      {"module nn; m #(.T(",
       {TK_union, "union"},
       " packed { int i;})) mm; endmodule\n"},
  };
  RunLintTestCases<VerilogAnalyzer, ForbiddenAnonymousStructsUnionsRule>(
      kTestCases);
}

}  // namespace
}  // namespace analysis
}  // namespace verilog
<|endoftext|>