<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>

#include <QtCore/qpauseanimation.h>
#include <QtCore/qpropertyanimation.h>
#include <QtCore/qsequentialanimationgroup.h>

#include <private/qabstractanimation_p.h>

//TESTED_CLASS=QPauseAnimation
//TESTED_FILES=

class TestablePauseAnimation : public QPauseAnimation
{
    Q_OBJECT
public:
    TestablePauseAnimation(QObject *parent = 0)
        : QPauseAnimation(parent),
        m_updateCurrentTimeCount(0)
    {
    }

    int m_updateCurrentTimeCount;
protected:
    void updateCurrentTime(int currentTime)
    {
        //qDebug() << this << "update current time: " << currentTime;
        QPauseAnimation::updateCurrentTime(currentTime);
        ++m_updateCurrentTimeCount;
    }
};

class tst_QPauseAnimation : public QObject
{
  Q_OBJECT
public:
    tst_QPauseAnimation();
    virtual ~tst_QPauseAnimation();

public Q_SLOTS:
    void init();
    void cleanup();

private slots:
    void changeDirectionWhileRunning();
    void noTimerUpdates_data();
    void noTimerUpdates();
    void mulitplePauseAnimations();
    void pauseAndPropertyAnimations();
    void pauseResume();
    void sequentialPauseGroup();
    void sequentialGroupWithPause();
    void multipleSequentialGroups();
    void zeroDuration();
};

tst_QPauseAnimation::tst_QPauseAnimation()
{
}

tst_QPauseAnimation::~tst_QPauseAnimation()
{
}

void tst_QPauseAnimation::init()
{
    qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
    qRegisterMetaType<QAbstractAnimation::DeletionPolicy>("QAbstractAnimation::DeletionPolicy");
}

void tst_QPauseAnimation::cleanup()
{
}

void tst_QPauseAnimation::changeDirectionWhileRunning()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    TestablePauseAnimation animation;
    animation.setDuration(400);
    animation.start();
    QTest::qWait(100);
    QVERIFY(animation.state() == QAbstractAnimation::Running);
    animation.setDirection(QAbstractAnimation::Backward);
    QTest::qWait(animation.totalDuration() + 50);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::noTimerUpdates_data()
{
    QTest::addColumn<int>("duration");
    QTest::addColumn<int>("loopCount");

    QTest::newRow("0") << 200 << 1;
    QTest::newRow("1") << 160 << 1;
    QTest::newRow("2") << 160 << 2;
    QTest::newRow("3") << 200 << 3;
}

void tst_QPauseAnimation::noTimerUpdates()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    QFETCH(int, duration);
    QFETCH(int, loopCount);

    TestablePauseAnimation animation;
    animation.setDuration(duration);
    animation.setLoopCount(loopCount);
    animation.start();
    QTest::qWait(animation.totalDuration() + 100);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation.m_updateCurrentTimeCount, 2);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::mulitplePauseAnimations()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    TestablePauseAnimation animation;
    animation.setDuration(200);

    TestablePauseAnimation animation2;
    animation2.setDuration(800);

    animation.start();
    animation2.start();
    QTest::qWait(animation.totalDuration() + 100);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation2.state() == QAbstractAnimation::Running);
    QCOMPARE(animation.m_updateCurrentTimeCount, 2);
    QCOMPARE(animation2.m_updateCurrentTimeCount, 2);

    QTest::qWait(550);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation2.m_updateCurrentTimeCount, 3);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::pauseAndPropertyAnimations()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    TestablePauseAnimation pause;
    pause.setDuration(200);

    QObject o;
    o.setProperty("ole", 42);

    QPropertyAnimation animation(&o, "ole");
    animation.setEndValue(43);

    pause.start();

    QTest::qWait(100);
    animation.start();

    QVERIFY(animation.state() == QAbstractAnimation::Running);
    QVERIFY(pause.state() == QAbstractAnimation::Running);
    QCOMPARE(pause.m_updateCurrentTimeCount, 2);

    QTest::qWait(animation.totalDuration() + 100);

    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QVERIFY(pause.state() == QAbstractAnimation::Stopped);
    QVERIFY(pause.m_updateCurrentTimeCount > 3);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::pauseResume()
{
    TestablePauseAnimation animation;
    animation.setDuration(400);
    animation.start();
    QVERIFY(animation.state() == QAbstractAnimation::Running);
    QTest::qWait(200);
    animation.pause();
    QVERIFY(animation.state() == QAbstractAnimation::Paused);
    animation.start();
    QTest::qWait(250);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation.m_updateCurrentTimeCount, 3);
}

void tst_QPauseAnimation::sequentialPauseGroup()
{
    QSequentialAnimationGroup group;

    TestablePauseAnimation animation1(&group);
    animation1.setDuration(200);
    TestablePauseAnimation animation2(&group);
    animation2.setDuration(200);
    TestablePauseAnimation animation3(&group);
    animation3.setDuration(200);

    group.start();

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation1.state() == QAbstractAnimation::Running);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation3.state() == QAbstractAnimation::Stopped);

    QTest::qWait(250);

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation1.state() == QAbstractAnimation::Stopped);
    QCOMPARE(&animation2, group.currentAnimation());
    QVERIFY(animation2.state() == QAbstractAnimation::Running);
    QVERIFY(animation3.state() == QAbstractAnimation::Stopped);

    QTest::qWait(250);

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation1.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QCOMPARE(&animation3, group.currentAnimation());
    QVERIFY(animation3.state() == QAbstractAnimation::Running);

    QTest::qWait(250);

    QVERIFY(group.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation1.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation3.state() == QAbstractAnimation::Stopped);

    QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
    QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
    QCOMPARE(animation3.m_updateCurrentTimeCount, 2);
}

void tst_QPauseAnimation::sequentialGroupWithPause()
{
    QSequentialAnimationGroup group;

    QObject o;
    o.setProperty("ole", 42);

    QPropertyAnimation animation(&o, "ole", &group);
    animation.setEndValue(43);
    TestablePauseAnimation pause(&group);
    pause.setDuration(250);

    group.start();

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation.state() == QAbstractAnimation::Running);
    QVERIFY(pause.state() == QAbstractAnimation::Stopped);

    QTest::qWait(300);

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(&pause, group.currentAnimation());
    QVERIFY(pause.state() == QAbstractAnimation::Running);

    QTest::qWait(300);

    QVERIFY(group.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QVERIFY(pause.state() == QAbstractAnimation::Stopped);

    QCOMPARE(pause.m_updateCurrentTimeCount, 2);
}

void tst_QPauseAnimation::multipleSequentialGroups()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    QParallelAnimationGroup group;
    group.setLoopCount(2);

    QSequentialAnimationGroup subgroup1(&group);

    QObject o;
    o.setProperty("ole", 42);

    QPropertyAnimation animation(&o, "ole", &subgroup1);
    animation.setEndValue(43);
    animation.setDuration(300);
    TestablePauseAnimation pause(&subgroup1);
    pause.setDuration(200);

    QSequentialAnimationGroup subgroup2(&group);

    o.setProperty("ole2", 42);
    QPropertyAnimation animation2(&o, "ole2", &subgroup2);
    animation2.setEndValue(43);
    animation2.setDuration(200);
    TestablePauseAnimation pause2(&subgroup2);
    pause2.setDuration(250);

    QSequentialAnimationGroup subgroup3(&group);

    TestablePauseAnimation pause3(&subgroup3);
    pause3.setDuration(400);

    o.setProperty("ole3", 42);
    QPropertyAnimation animation3(&o, "ole3", &subgroup3);
    animation3.setEndValue(43);
    animation3.setDuration(200);

    QSequentialAnimationGroup subgroup4(&group);

    TestablePauseAnimation pause4(&subgroup4);
    pause4.setDuration(310);

    TestablePauseAnimation pause5(&subgroup4);
    pause5.setDuration(60);

    group.start();

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup1.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup2.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup3.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup4.state() == QAbstractAnimation::Running);

    QTest::qWait(group.totalDuration() + 100);

    QVERIFY(group.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup1.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup2.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup3.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup4.state() == QAbstractAnimation::Stopped);

    QCOMPARE(pause5.m_updateCurrentTimeCount, 4);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::zeroDuration()
{
    TestablePauseAnimation animation;
    animation.start();
    QTest::qWait(animation.totalDuration() + 100);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation.m_updateCurrentTimeCount, 1);
}

QTEST_MAIN(tst_QPauseAnimation)
#include "tst_qpauseanimation.moc"
<commit_msg>Fixes QPauseAnimation autotests for unreliable timer intervals on Windows<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>

#include <QtCore/qpauseanimation.h>
#include <QtCore/qpropertyanimation.h>
#include <QtCore/qsequentialanimationgroup.h>

#include <private/qabstractanimation_p.h>

//TESTED_CLASS=QPauseAnimation
//TESTED_FILES=

class TestablePauseAnimation : public QPauseAnimation
{
    Q_OBJECT
public:
    TestablePauseAnimation(QObject *parent = 0)
        : QPauseAnimation(parent),
        m_updateCurrentTimeCount(0)
    {
    }

    int m_updateCurrentTimeCount;
protected:
    void updateCurrentTime(int currentTime)
    {
        //qDebug() << this << "update current time: " << currentTime;
        QPauseAnimation::updateCurrentTime(currentTime);
        ++m_updateCurrentTimeCount;
    }
};

class EnableConsistentTiming
{
public:
    EnableConsistentTiming()
    {
        QUnifiedTimer *timer = QUnifiedTimer::instance();
        timer->setConsistentTiming(true);
    }
    ~EnableConsistentTiming()
    {
        QUnifiedTimer *timer = QUnifiedTimer::instance();
        timer->setConsistentTiming(false);
    }
};

class tst_QPauseAnimation : public QObject
{
  Q_OBJECT
public:
    tst_QPauseAnimation();
    virtual ~tst_QPauseAnimation();

public Q_SLOTS:
    void init();
    void cleanup();

private slots:
    void changeDirectionWhileRunning();
    void noTimerUpdates_data();
    void noTimerUpdates();
    void mulitplePauseAnimations();
    void pauseAndPropertyAnimations();
    void pauseResume();
    void sequentialPauseGroup();
    void sequentialGroupWithPause();
    void multipleSequentialGroups();
    void zeroDuration();
};

tst_QPauseAnimation::tst_QPauseAnimation()
{
}

tst_QPauseAnimation::~tst_QPauseAnimation()
{
}

void tst_QPauseAnimation::init()
{
    qRegisterMetaType<QAbstractAnimation::State>("QAbstractAnimation::State");
    qRegisterMetaType<QAbstractAnimation::DeletionPolicy>("QAbstractAnimation::DeletionPolicy");
}

void tst_QPauseAnimation::cleanup()
{
}

void tst_QPauseAnimation::changeDirectionWhileRunning()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    TestablePauseAnimation animation;
    animation.setDuration(400);
    animation.start();
    QTest::qWait(100);
    QVERIFY(animation.state() == QAbstractAnimation::Running);
    animation.setDirection(QAbstractAnimation::Backward);
    QTest::qWait(animation.totalDuration() + 50);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::noTimerUpdates_data()
{
    QTest::addColumn<int>("duration");
    QTest::addColumn<int>("loopCount");

    QTest::newRow("0") << 200 << 1;
    QTest::newRow("1") << 160 << 1;
    QTest::newRow("2") << 160 << 2;
    QTest::newRow("3") << 200 << 3;
}

void tst_QPauseAnimation::noTimerUpdates()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    QFETCH(int, duration);
    QFETCH(int, loopCount);

    TestablePauseAnimation animation;
    animation.setDuration(duration);
    animation.setLoopCount(loopCount);
    animation.start();
    QTest::qWait(animation.totalDuration() + 100);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation.m_updateCurrentTimeCount, 2);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::mulitplePauseAnimations()
{
    QUnifiedTimer *timer = QUnifiedTimer::instance();
    timer->setConsistentTiming(true);

    TestablePauseAnimation animation;
    animation.setDuration(200);

    TestablePauseAnimation animation2;
    animation2.setDuration(800);

    animation.start();
    animation2.start();
    QTest::qWait(animation.totalDuration() + 100);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation2.state() == QAbstractAnimation::Running);
    QCOMPARE(animation.m_updateCurrentTimeCount, 2);
    QCOMPARE(animation2.m_updateCurrentTimeCount, 2);

    QTest::qWait(550);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation2.m_updateCurrentTimeCount, 3);

    timer->setConsistentTiming(false);
}

void tst_QPauseAnimation::pauseAndPropertyAnimations()
{
    EnableConsistentTiming enabled;

    TestablePauseAnimation pause;
    pause.setDuration(200);

    QObject o;
    o.setProperty("ole", 42);

    QPropertyAnimation animation(&o, "ole");
    animation.setEndValue(43);

    pause.start();

    QTest::qWait(100);
    animation.start();

    QVERIFY(animation.state() == QAbstractAnimation::Running);
    QVERIFY(pause.state() == QAbstractAnimation::Running);
    QCOMPARE(pause.m_updateCurrentTimeCount, 2);

    QTest::qWait(animation.totalDuration() + 100);

#ifdef Q_OS_WIN
    if (animation.state() != QAbstractAnimation::Stopped)
        QEXPECT_FAIL("", "On windows, consistent timing is not working properly due to bad timer resolution", Abort);
#endif
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QVERIFY(pause.state() == QAbstractAnimation::Stopped);
    QVERIFY(pause.m_updateCurrentTimeCount > 3);
}

void tst_QPauseAnimation::pauseResume()
{
    TestablePauseAnimation animation;
    animation.setDuration(400);
    animation.start();
    QVERIFY(animation.state() == QAbstractAnimation::Running);
    QTest::qWait(200);
    animation.pause();
    QVERIFY(animation.state() == QAbstractAnimation::Paused);
    animation.start();
    QTest::qWait(250);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation.m_updateCurrentTimeCount, 3);
}

void tst_QPauseAnimation::sequentialPauseGroup()
{
    QSequentialAnimationGroup group;

    TestablePauseAnimation animation1(&group);
    animation1.setDuration(200);
    TestablePauseAnimation animation2(&group);
    animation2.setDuration(200);
    TestablePauseAnimation animation3(&group);
    animation3.setDuration(200);

    group.start();

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation1.state() == QAbstractAnimation::Running);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation3.state() == QAbstractAnimation::Stopped);

    group.setCurrentTime(250);

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation1.state() == QAbstractAnimation::Stopped);
    QCOMPARE(&animation2, group.currentAnimation());
    QVERIFY(animation2.state() == QAbstractAnimation::Running);
    QVERIFY(animation3.state() == QAbstractAnimation::Stopped);

    group.setCurrentTime(500);

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation1.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QCOMPARE(&animation3, group.currentAnimation());
    QVERIFY(animation3.state() == QAbstractAnimation::Running);

    group.setCurrentTime(750);

    QVERIFY(group.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation1.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation2.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation3.state() == QAbstractAnimation::Stopped);

    QCOMPARE(animation1.m_updateCurrentTimeCount, 2);
    QCOMPARE(animation2.m_updateCurrentTimeCount, 2);
    QCOMPARE(animation3.m_updateCurrentTimeCount, 2);
}

void tst_QPauseAnimation::sequentialGroupWithPause()
{
    QSequentialAnimationGroup group;

    QObject o;
    o.setProperty("ole", 42);

    QPropertyAnimation animation(&o, "ole", &group);
    animation.setEndValue(43);
    TestablePauseAnimation pause(&group);
    pause.setDuration(250);

    group.start();

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation.state() == QAbstractAnimation::Running);
    QVERIFY(pause.state() == QAbstractAnimation::Stopped);

    group.setCurrentTime(300);

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(&pause, group.currentAnimation());
    QVERIFY(pause.state() == QAbstractAnimation::Running);

    group.setCurrentTime(600);

    QVERIFY(group.state() == QAbstractAnimation::Stopped);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QVERIFY(pause.state() == QAbstractAnimation::Stopped);

    QCOMPARE(pause.m_updateCurrentTimeCount, 2);
}

void tst_QPauseAnimation::multipleSequentialGroups()
{
    EnableConsistentTiming enabled;

    QParallelAnimationGroup group;
    group.setLoopCount(2);

    QSequentialAnimationGroup subgroup1(&group);

    QObject o;
    o.setProperty("ole", 42);

    QPropertyAnimation animation(&o, "ole", &subgroup1);
    animation.setEndValue(43);
    animation.setDuration(300);
    TestablePauseAnimation pause(&subgroup1);
    pause.setDuration(200);

    QSequentialAnimationGroup subgroup2(&group);

    o.setProperty("ole2", 42);
    QPropertyAnimation animation2(&o, "ole2", &subgroup2);
    animation2.setEndValue(43);
    animation2.setDuration(200);
    TestablePauseAnimation pause2(&subgroup2);
    pause2.setDuration(250);

    QSequentialAnimationGroup subgroup3(&group);

    TestablePauseAnimation pause3(&subgroup3);
    pause3.setDuration(400);

    o.setProperty("ole3", 42);
    QPropertyAnimation animation3(&o, "ole3", &subgroup3);
    animation3.setEndValue(43);
    animation3.setDuration(200);

    QSequentialAnimationGroup subgroup4(&group);

    TestablePauseAnimation pause4(&subgroup4);
    pause4.setDuration(310);

    TestablePauseAnimation pause5(&subgroup4);
    pause5.setDuration(60);

    group.start();

    QVERIFY(group.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup1.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup2.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup3.state() == QAbstractAnimation::Running);
    QVERIFY(subgroup4.state() == QAbstractAnimation::Running);

    QTest::qWait(group.totalDuration() + 100);

#ifdef Q_OS_WIN
    if (group.state() != QAbstractAnimation::Stopped)
        QEXPECT_FAIL("", "On windows, consistent timing is not working properly due to bad timer resolution", Abort);
#endif
    QVERIFY(group.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup1.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup2.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup3.state() == QAbstractAnimation::Stopped);
    QVERIFY(subgroup4.state() == QAbstractAnimation::Stopped);

    QCOMPARE(pause5.m_updateCurrentTimeCount, 4);
}

void tst_QPauseAnimation::zeroDuration()
{
    TestablePauseAnimation animation;
    animation.start();
    QTest::qWait(animation.totalDuration() + 100);
    QVERIFY(animation.state() == QAbstractAnimation::Stopped);
    QCOMPARE(animation.m_updateCurrentTimeCount, 1);
}

QTEST_MAIN(tst_QPauseAnimation)
#include "tst_qpauseanimation.moc"
<|endoftext|>


<commit_before>// ---------------------------------------------------------------------
//
// Copyright (C) 2006 - 2015 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#include "../tests.h"
#include <deal.II/base/data_out_base.h>

#include <fstream>
#include <string>
#include <vector>

#include "patches.h"

// Check that the compression levels supported by VtkFlags are valid (that is,
// they are successfully passed to zlib).

template <int dim, int spacedim>
void check(DataOutBase::VtkFlags flags,
           std::ostream &out)
{
  const unsigned int np = 4;

  std::vector<DataOutBase::Patch<dim, spacedim> > patches(np);

  create_patches(patches);

  std::vector<std::string> names(5);
  names[0] = "x1";
  names[1] = "x2";
  names[2] = "x3";
  names[3] = "x4";
  names[4] = "i";
  std::vector<std_cxx11::tuple<unsigned int, unsigned int, std::string> > vectors;
  DataOutBase::write_vtu(patches, names, vectors, flags, out);
}

template<int dim, int spacedim>
void check_all(std::ostream &log)
{
  for (unsigned int i = 0; i < 4; ++i)
    {
      DataOutBase::VtkFlags flags;
      switch (i)
        {
        case (0):
          flags.compression_level = DataOutBase::VtkFlags::ZlibCompressionLevel::no_compression;
          break;
        case (1):
          flags.compression_level = DataOutBase::VtkFlags::ZlibCompressionLevel::best_speed;
          break;
        case (2):
          flags.compression_level = DataOutBase::VtkFlags::ZlibCompressionLevel::best_compression;
          break;
        case (3):
          flags.compression_level = DataOutBase::VtkFlags::ZlibCompressionLevel::default_compression;
          break;
        default:
          Assert(false, ExcInternalError());
        }
      log << "==============================\n"
          << dim
          << spacedim
          << "-"
          << flags.compression_level
          << ".vtu"
          << "\n==============================\n";
      check<dim, spacedim>(flags, log);
    }
}

int main()
{
  std::ofstream logfile("output");
  check_all<1,1>(logfile);
  check_all<2,2>(logfile);
  check_all<3,3>(logfile);
}
<commit_msg>Fix a test to run in C++11 mode. The implementation was fixed in a previous commit.<commit_after>// ---------------------------------------------------------------------
//
// Copyright (C) 2006 - 2015 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, redistribute
// it, and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#include "../tests.h"
#include <deal.II/base/data_out_base.h>

#include <fstream>
#include <string>
#include <vector>

#include "patches.h"

// Check that the compression levels supported by VtkFlags are valid (that is,
// they are successfully passed to zlib).

template <int dim, int spacedim>
void check(DataOutBase::VtkFlags flags,
           std::ostream &out)
{
  const unsigned int np = 4;

  std::vector<DataOutBase::Patch<dim, spacedim> > patches(np);

  create_patches(patches);

  std::vector<std::string> names(5);
  names[0] = "x1";
  names[1] = "x2";
  names[2] = "x3";
  names[3] = "x4";
  names[4] = "i";
  std::vector<std_cxx11::tuple<unsigned int, unsigned int, std::string> > vectors;
  DataOutBase::write_vtu(patches, names, vectors, flags, out);
}

template<int dim, int spacedim>
void check_all(std::ostream &log)
{
  for (unsigned int i = 0; i < 4; ++i)
    {
      DataOutBase::VtkFlags flags;
      switch (i)
        {
        case (0):
          flags.compression_level = DataOutBase::VtkFlags::no_compression;
          break;
        case (1):
          flags.compression_level = DataOutBase::VtkFlags::best_speed;
          break;
        case (2):
          flags.compression_level = DataOutBase::VtkFlags::best_compression;
          break;
        case (3):
          flags.compression_level = DataOutBase::VtkFlags::default_compression;
          break;
        default:
          Assert(false, ExcInternalError());
        }
      log << "==============================\n"
          << dim
          << spacedim
          << "-"
          << flags.compression_level
          << ".vtu"
          << "\n==============================\n";
      check<dim, spacedim>(flags, log);
    }
}

int main()
{
  std::ofstream logfile("output");
  check_all<1,1>(logfile);
  check_all<2,2>(logfile);
  check_all<3,3>(logfile);
}
<|endoftext|>


<commit_before>/*********************************************************************
 * tm700_demo_node.cpp
 *
 * Copyright 2016 Copyright 2016 Techman Robot Inc.
 *
 * 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.
 *********************************************************************
 *
 * Author: Yun-Hsuan Tsai
 */

#include <ros/ros.h>
#include <ros/console.h>

#include <moveit/move_group_interface/move_group.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/robot_state/conversions.h>

#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>

#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

#include "tm_msgs/SetIO.h"
//#include "tm_msgs/SetIORequest.h"
//#include "tm_msgs/SetIOResponse.h"

//added by Yu-Hsien, 2017/3/9
//get the current joint value of each joint
bool get_current_joint_value(moveit::planning_interface::MoveGroup& group,
                                moveit::planning_interface::MoveGroup::Plan& plan,
															  const std::string& target_name,
															  unsigned int max_try_times = 1
															){
			if(!ros::ok()) return false;
			bool success = false;

			for(unsigned int i= 0; i<max_try_times; i++){

				group.getCurrentJointValues(target_name);
        for(int i = 0; i<target_name.size(); i++){
					printf("%f\n", target_name[i]);
				}

				if(group.move()){
					success = true;
					break;
				}
				else {
					if(!ros::ok()) break;
					sleep(1);
				}
			}
			return success;
}

bool try_move_to_named_target(moveit::planning_interface::MoveGroup& group,
			      moveit::planning_interface::MoveGroup::Plan& plan,
			      const std::string& target_name,
			      unsigned int max_try_times = 1
			     ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setNamedTarget(target_name);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
  return success;
}

bool try_move_to_joint_target(moveit::planning_interface::MoveGroup& group,
			      moveit::planning_interface::MoveGroup::Plan& plan,
			      const std::vector<double>& joint_target,
			      unsigned int max_try_times = 1
			     ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setJointValueTarget(joint_target);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
}

int main(int argc, char **argv)
{

  ros::init(argc, argv, "tm700_demo_test");
  ros::NodeHandle node_handle;
  ros::ServiceClient set_io_client = node_handle.serviceClient<tm_msgs::SetIO>("tm_driver/set_io");
  tm_msgs::SetIO io_srv;
  io_srv.request.fun = 2;//tm_msgs::SetIORequest::FUN_SET_EE_DIGITAL_OUT;
  io_srv.request.ch = 0;
  io_srv.request.value = 0.0;

  // start a background "spinner", so our node can process ROS messages
  //  - this lets us know when the move is completed
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(1);

  // Setup
  // ^^^^^
  // The :move_group_interface:`MoveGroup` class can be easily
  // setup using just the name
  // of the group you would like to control and plan for.
  moveit::planning_interface::MoveGroup group("manipulator");
  // We will use the :planning_scene_interface:`PlanningSceneInterface`
  // class to deal directly with the world.
  moveit::planning_interface::PlanningSceneInterface planning_scene_interface;
  // (Optional) Create a publisher for visualizing plans in Rviz.
  //ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
  //moveit_msgs::DisplayTrajectory display_trajectory;

  // Getting Basic Information
  // ^^^^^^^^^^^^^^^^^^^^^^^^^
  // We can print the name of the reference frame for this robot.
  ROS_INFO("Reference frame: %s", group.getPlanningFrame().c_str());
  // We can also print the name of the end-effector link for this group.
  ROS_INFO("Reference frame: %s", group.getEndEffectorLink().c_str());

  moveit::planning_interface::MoveGroup::Plan my_plan;

  set_io_client.call(io_srv);

  group.setPlanningTime(30.0);

  try_move_to_named_target(group, my_plan, "home", 100);

  std::vector<double> joint_target_1;
  std::vector<double> joint_target_2;

  joint_target_1.assign(6, 0.0f);
  joint_target_1[0] = 0.0174533*( 30.0);
  joint_target_1[1] = 0.0174533*( 15.0);
  joint_target_1[2] = 0.0174533*(105.0);
  joint_target_1[3] = 0.0174533*(-30.0);
  joint_target_1[4] = 0.0174533*( 90.0);
  joint_target_1[5] = 0.0174533*( 30.0);

  joint_target_2.assign(6, 0.0f);
  joint_target_2[0] = 0.0174533*(-30.0);
  joint_target_2[1] = 0.0174533*(-15.0);
  joint_target_2[2] = 0.0174533*( 90.0);
  joint_target_2[3] = 0.0174533*(-75.0);
  joint_target_2[4] = 0.0174533*(120.0);

  int step = 0;

  while (ros::ok()) {
    switch (step) {
      case 0: //gripper off
	io_srv.request.fun = 2;
	io_srv.request.ch = 0;
	io_srv.request.value = 0.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 1: //move to ready
	ROS_INFO("move...");
	try_move_to_named_target(group, my_plan, "ready", 100);
	break;

      case 2: //light on
	io_srv.request.fun = 2;
	io_srv.request.ch = 3;
	io_srv.request.value = 1.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 3: //wait 3 sec
	sleep(3);
	break;

      case 4: //light off
	io_srv.request.fun = 2;
	io_srv.request.ch = 3;
	io_srv.request.value = 0.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 5: //move 1
	ROS_INFO("move...");
	try_move_to_joint_target(group, my_plan, joint_target_1, 100);
	break;

      case 6: //gripper on
	io_srv.request.fun = 2;
	io_srv.request.ch = 0;
	io_srv.request.value = 1.0;
	if (set_io_client.call(io_srv))
	  ROS_INFO("Set IO success");
	else
	  ROS_WARN("Failed to call service set_io");
	break;

      case 7: //wait 1 sec
	sleep(1);
	break;

      case 8: //move 2...
	ROS_INFO("move...");
	try_move_to_joint_target(group, my_plan, joint_target_2, 100);
	break;
    }
    step = (step + 1) % 9;
  }
  return 0;
}
<commit_msg>update my local tm700_demo_test.cpp<commit_after>/*********************************************************************
 * tm700_demo_node.cpp
 *
 * Copyright 2016 Copyright 2016 Techman Robot Inc.
 *
 * 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.
 *********************************************************************
 *
 * Author: Yun-Hsuan Tsai
 */

#include <ros/ros.h>
#include <ros/console.h>

#include <moveit/move_group_interface/move_group.h>
#include <moveit/planning_scene_interface/planning_scene_interface.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/robot_state/conversions.h>

#include <moveit_msgs/DisplayRobotState.h>
#include <moveit_msgs/DisplayTrajectory.h>

#include <moveit_msgs/AttachedCollisionObject.h>
#include <moveit_msgs/CollisionObject.h>

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cmath>

#include "tm_msgs/SetIO.h"
//#include "tm_msgs/SetIORequest.h"
//#include "tm_msgs/SetIOResponse.h"

//get current joint values of TM5
void get_current_joint_values(moveit::planning_interface::MoveGroup& group,
                              moveit::planning_interface::MoveGroup::Plan& plan,
                                                            std::vector<double>& record_joint
                                                        ){
        //if(!ros::ok()) return false;
        bool success = false;

        std::vector<double> joint_value;
        joint_value = group.getCurrentJointValues();
    record_joint = group.getCurrentJointValues();

    ROS_INFO("In get_current_joint_values()");
        for(int i = 0; i<joint_value.size(); i++){
            joint_value[i] = joint_value[i]*180/M_PI;
            printf("Joint %d: %lf\n",i+1, joint_value[i]);
        }
}

bool try_move_to_named_target(moveit::planning_interface::MoveGroup& group,
                  moveit::planning_interface::MoveGroup::Plan& plan,
                  const std::string& target_name,
                  unsigned int max_try_times = 1
                 ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setNamedTarget(target_name);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
  return success;
}

bool try_move_to_joint_target(moveit::planning_interface::MoveGroup& group,
                  moveit::planning_interface::MoveGroup::Plan& plan,
                  const std::vector<double>& joint_target,
                  unsigned int max_try_times = 1
                 ) {
  if(!ros::ok()) return false;
  bool success = false;

  for(unsigned int i = 0; i < max_try_times; i++) {

    group.setJointValueTarget(joint_target);

    if(group.move()) {
      success = true;
      break;
    }
    else {
      if(!ros::ok()) break;
      sleep(1);
    }
  }
}

int main(int argc, char **argv)
{

  ros::init(argc, argv, "tm700_demo_test");
  ros::NodeHandle node_handle;
  ros::ServiceClient set_io_client = node_handle.serviceClient<tm_msgs::SetIO>("tm_driver/set_io");
  tm_msgs::SetIO io_srv;
  io_srv.request.fun = 2;//tm_msgs::SetIORequest::FUN_SET_EE_DIGITAL_OUT;
  io_srv.request.ch = 0;
  io_srv.request.value = 0.0;

  // start a background "spinner", so our node can process ROS messages
  //  - this lets us know when the move is completed
  ros::AsyncSpinner spinner(1);
  spinner.start();

  sleep(1);

  // Setup
  // ^^^^^
  // The :move_group_interface:`MoveGroup` class can be easily
  // setup using just the name
  // of the group you would like to control and plan for.
  moveit::planning_interface::MoveGroup group("manipulator");
  // We will use the :planning_scene_interface:`PlanningSceneInterface`
  // class to deal directly with the world.
  moveit::planning_interface::PlanningSceneInterface planning_scene_interface;
  // (Optional) Create a publisher for visualizing plans in Rviz.
  //ros::Publisher display_publisher = node_handle.advertise<moveit_msgs::DisplayTrajectory>("/move_group/display_planned_path", 1, true);
  //moveit_msgs::DisplayTrajectory display_trajectory;

  // Getting Basic Information
  // ^^^^^^^^^^^^^^^^^^^^^^^^^
  // We can print the name of the reference frame for this robot.
  ROS_INFO("Reference frame: %s", group.getPlanningFrame().c_str());
  // We can also print the name of the end-effector link for this group.
  ROS_INFO("Reference frame: %s", group.getEndEffectorLink().c_str());

  moveit::planning_interface::MoveGroup::Plan my_plan;

  set_io_client.call(io_srv);

  group.setPlanningTime(30.0);

  //try_move_to_named_target(group, my_plan, "home", 100);

  std::vector<double> joint_target_1;
  std::vector<double> joint_target_2;

    std::vector<double> record_joint_1;
    std::vector<double> record_joint_2;
    std::vector<double> record_joint_3;

  double joint_value = 0;

  joint_target_1.assign(6, 0.0f);
  joint_target_1[0] = 0.0174533*( 30.0);
  joint_target_1[1] = 0.0174533*( 15.0);
  joint_target_1[2] = 0.0174533*(105.0);
  joint_target_1[3] = 0.0174533*(-30.0);
  joint_target_1[4] = 0.0174533*( 90.0);
  joint_target_1[5] = 0.0174533*( 30.0);

  joint_target_2.assign(6, 0.0f);
  joint_target_2[0] = 0.0174533*(-30.0);
  joint_target_2[1] = 0.0174533*(-15.0);
  joint_target_2[2] = 0.0174533*( 90.0);
  joint_target_2[3] = 0.0174533*(-75.0);
  joint_target_2[4] = 0.0174533*(120.0);

  int step = 0;
  int flag = 0;

  while (ros::ok()) {
    switch (5) {

     case 0: //gripper off
       io_srv.request.fun = 2;
       io_srv.request.ch = 0;
       io_srv.request.value = 0.0;

       if (set_io_client.call(io_srv))
         ROS_INFO("Set IO success");
       else
         ROS_WARN("Failed to call service set_io");
       break;

     case 1: //move to ready
       ROS_INFO("move...");
       //try_move_to_named_target(group, my_plan, "ready", 100);
       break;

     case 2: //light on
   /*
       io_srv.request.fun = 2;
       io_srv.request.ch = 3;
       io_srv.request.value = 1.0;
   */
       if (set_io_client.call(io_srv))
         ROS_INFO("Set IO success");
       else
         ROS_WARN("Failed to call service set_io");
       break;

     case 3: //wait 3 sec
       sleep(3);
       break;

    case 4: //light off
      io_srv.request.fun = 2;
      io_srv.request.ch = 3;
      io_srv.request.value = 0.0;
      if (set_io_client.call(io_srv))
        ROS_INFO("Set IO success");
      else
        ROS_WARN("Failed to call service set_io");
      break;

    case 5: //move 1
      //ROS_INFO("move...");
      //try_move_to_joint_target(group, my_plan, joint_target_1, 100);
      ROS_INFO("Teaching Pose 1...");
    while(flag == 0){
      printf("Finish Teaching? Yes: 1, No:0\n");
      scanf("%d", &flag);
      get_current_joint_values(group, my_plan, record_joint_1);
    }
    flag = 0;

    ROS_INFO("Teaching Pose 2...");
    while(flag == 0){
      printf("Finish Teaching? Yes: 1, No:0\n");
      scanf("%d", &flag);
      get_current_joint_values(group, my_plan, record_joint_2);
    }
    flag = 0;

    ROS_INFO("Teaching Pose 3...");
    while(flag == 0){
      printf("Finish Teaching? Yes: 1, No:0\n");
      scanf("%d", &flag);
      get_current_joint_values(group, my_plan, record_joint_3);
    }

    //ROS_INFO("Teaching Pose 1...");
      for(int i = 0; i<record_joint_1.size(); i++){
          joint_value = record_joint_1[i]*180/M_PI;
          printf("Joint %d: degree: %lf, rad: %lf\n", i+1, joint_value, record_joint_1[i]);
      }

    while(ros::ok()){
      try_move_to_named_target(group, my_plan, "home", 100);
      //wait 3 seconds
      sleep(3);
      try_move_to_joint_target(group, my_plan, record_joint_1, 100);
      sleep(3);
      try_move_to_joint_target(group, my_plan, record_joint_2, 100);
      sleep(3);
      try_move_to_joint_target(group, my_plan, record_joint_3, 100);
      sleep(3);
    }

      break;

    case 6: //gripper on
      io_srv.request.fun = 2;
      io_srv.request.ch = 0;
      io_srv.request.value = 1.0;
      if (set_io_client.call(io_srv))
        ROS_INFO("Set IO success");
      else
        ROS_WARN("Failed to call service set_io");
      break;

    case 7: //wait 1 sec
      sleep(1);
      break;

    case 8: //move 2...
      ROS_INFO("move...");
      //try_move_to_joint_target(group, my_plan, joint_target_2, 100);
      break;
    }
    step = (step + 1) % 9;
  }
  return 0;
}<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "osl/diagnose.h"
#include "rtl/strbuf.hxx"
#include "NeonTypes.hxx"
#include "DAVException.hxx"
#include "DAVProperties.hxx"
#include "NeonPropFindRequest.hxx"
#include "LinkSequence.hxx"
#include "LockSequence.hxx"
#include "LockEntrySequence.hxx"
#include "UCBDeadPropertyValue.hxx"

using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
using namespace std;
using namespace webdav_ucp;

namespace
{
    // strip "DAV:" namespace from XML snippets to avoid
    // parser error (undeclared namespace) later on.
    OString stripDavNamespace( const OString & in )
    {
        const OString inXML( in.toAsciiLowerCase() );

        OStringBuffer buf;
        sal_Int32 start = 0;
        sal_Int32 end = inXML.indexOf( "dav:" );
        while ( end != -1 )
        {
            if ( inXML[ end - 1 ] == '<' ||
                 inXML[ end - 1 ] == '/' )
            {
                // copy from original buffer - preserve case.
                buf.append( in.copy( start, end - start ) );
            }
            else
            {
                // copy from original buffer - preserve case.
                buf.append( in.copy( start, end - start + 4 ) );
            }
            start = end + 4;
            end = inXML.indexOf( "dav:", start );
        }
        buf.append( inXML.copy( start ) );

        return OString( buf.makeStringAndClear() );
    }
}

extern "C" int NPFR_propfind_iter( void* userdata,
                                   const NeonPropName* pname,
                                   const char* value,
                                   const HttpStatus* status )
{
    /*
        HTTP Response Status Classes:

        - 1: Informational - Request received, continuing process

        - 2: Success - The action was successfully received,
          understood, and accepted

        - 3: Redirection - Further action must be taken in order to
          complete the request

        - 4: Client Error - The request contains bad syntax or cannot
          be fulfilled

        - 5: Server Error - The server failed to fulfill an apparently
          valid request
    */

    if ( status->klass > 2 )
        return 0; // Error getting this property. Go on.

    // Create & set the PropertyValue
    DAVPropertyValue thePropertyValue;
    thePropertyValue.IsCaseSensitive = true;

    OSL_ENSURE( pname->nspace, "NPFR_propfind_iter - No namespace!" );

    DAVProperties::createUCBPropName( pname->nspace,
                                      pname->name,
                                      thePropertyValue.Name );
    bool bHasValue = false;
    if ( DAVProperties::isUCBDeadProperty( *pname ) )
    {
        // DAV dead property added by WebDAV UCP?
        if ( UCBDeadPropertyValue::createFromXML(
                 value, thePropertyValue.Value ) )
        {
            OSL_ENSURE( thePropertyValue.Value.hasValue(),
                        "NPFR_propfind_iter - No value!" );
            bHasValue = true;
        }
    }

    if ( !bHasValue )
    {
        if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "resourcetype" ) == 0 )
        {
            OString aValue( value );
            aValue = aValue.trim(); // #107358# remove leading/trailing spaces
            if ( !aValue.isEmpty() )
            {
                aValue = stripDavNamespace( aValue ).toAsciiLowerCase();
                if ( aValue == "<collection" )
                {
                    thePropertyValue.Value
                        <<= OUString("collection");
                }
            }

            if ( !thePropertyValue.Value.hasValue() )
            {
                // Take over the value exactly as supplied by the server.
                thePropertyValue.Value <<= OUString::createFromAscii( value );
            }
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "supportedlock" ) == 0 )
        {
            Sequence< LockEntry > aEntries;
            LockEntrySequence::createFromXML(
                stripDavNamespace( value ), aEntries );
            thePropertyValue.Value <<= aEntries;
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "lockdiscovery" ) == 0 )
        {
            Sequence< Lock > aLocks;
            LockSequence::createFromXML(
                stripDavNamespace( value ), aLocks );
            thePropertyValue.Value <<= aLocks;
        }
        else if ( rtl_str_compareIgnoreAsciiCase( pname->name, "source" ) == 0 )
        {
            Sequence< Link > aLinks;
            LinkSequence::createFromXML(
                stripDavNamespace( value ), aLinks );
            thePropertyValue.Value <<= aLinks;
        }
        else
        {
            thePropertyValue.Value
                <<= OStringToOUString( value, RTL_TEXTENCODING_UTF8 );
        }
    }

    // Add the newly created PropertyValue
    DAVResource* theResource = static_cast< DAVResource * >( userdata );
    theResource->properties.push_back( thePropertyValue );

    return 0; // Go on.
}

extern "C" void NPFR_propfind_results( void* userdata,
                                       const ne_uri* uri,
                                       const NeonPropFindResultSet* set )
{
    // @@@ href is not the uri! DAVResource ctor wants uri!

    DAVResource theResource(
        OStringToOUString( uri->path, RTL_TEXTENCODING_UTF8 ) );

    ne_propset_iterate( set, NPFR_propfind_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResource > * theResources
        = static_cast< vector< DAVResource > * >( userdata );
    theResources->push_back( theResource );
}

extern "C" int NPFR_propnames_iter( void* userdata,
                                    const NeonPropName* pname,
                                    const char* /*value*/,
                                    const HttpStatus* /*status*/ )
{
    OUString aFullName;
    DAVProperties::createUCBPropName( pname->nspace,
                                      pname->name,
                                      aFullName );

    DAVResourceInfo* theResource = static_cast< DAVResourceInfo * >( userdata );
    theResource->properties.push_back( aFullName );
    return 0;
}

extern "C" void NPFR_propnames_results( void* userdata,
                                        const ne_uri* uri,
                                        const NeonPropFindResultSet* results )
{
    // @@@ href is not the uri! DAVResourceInfo ctor wants uri!
    // Create entry for the resource.
    DAVResourceInfo theResource(
        OStringToOUString( uri->path, RTL_TEXTENCODING_UTF8 ) );

    // Fill entry.
    ne_propset_iterate( results, NPFR_propnames_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResourceInfo > * theResources
        = static_cast< vector< DAVResourceInfo > * >( userdata );
    theResources->push_back( theResource );
}

extern osl::Mutex aGlobalNeonMutex;

NeonPropFindRequest::NeonPropFindRequest( HttpSession* inSession,
                                          const char* inPath,
                                          const Depth inDepth,
                                          const vector< OUString >& inPropNames,
                                          vector< DAVResource >& ioResources,
                                          int & nError )
{
    // Generate the list of properties we're looking for
    int thePropCount = inPropNames.size();
    if ( thePropCount > 0 )
    {
        NeonPropName* thePropNames = new NeonPropName[ thePropCount + 1 ];
        int theIndex;

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
        {
            // Split fullname into namespace and name!
            DAVProperties::createNeonPropName(
                inPropNames[ theIndex ], thePropNames[ theIndex ] );
        }
        thePropNames[ theIndex ].nspace = NULL;
        thePropNames[ theIndex ].name   = NULL;

        {
            osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
            nError = ne_simple_propfind( inSession,
                                         inPath,
                                         inDepth,
                                         thePropNames,
                                         NPFR_propfind_results,
                                         &ioResources );
        }

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
            free( (void *)thePropNames[ theIndex ].name );

        delete [] thePropNames;
    }
    else
    {
        // ALLPROP
        osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
        nError = ne_simple_propfind( inSession,
                                     inPath,
                                     inDepth,
                                     NULL, // 0 == allprop
                                     NPFR_propfind_results,
                                     &ioResources );
    }

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResources.empty() )
        nError = NE_ERROR;
}

NeonPropFindRequest::NeonPropFindRequest(
                            HttpSession* inSession,
                            const char* inPath,
                            const Depth inDepth,
                            std::vector< DAVResourceInfo > & ioResInfo,
                            int & nError )
{
    {
        osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
        nError = ne_propnames( inSession,
                            inPath,
                            inDepth,
                            NPFR_propnames_results,
                            &ioResInfo );
    }

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResInfo.empty() )
        nError = NE_ERROR;
}

NeonPropFindRequest::~NeonPropFindRequest( )
{
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Related rhbz#961460: Fix regression around OUString::compareTo usage<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "osl/diagnose.h"
#include "rtl/strbuf.hxx"
#include "NeonTypes.hxx"
#include "DAVException.hxx"
#include "DAVProperties.hxx"
#include "NeonPropFindRequest.hxx"
#include "LinkSequence.hxx"
#include "LockSequence.hxx"
#include "LockEntrySequence.hxx"
#include "UCBDeadPropertyValue.hxx"

using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
using namespace std;
using namespace webdav_ucp;

namespace
{
    // strip "DAV:" namespace from XML snippets to avoid
    // parser error (undeclared namespace) later on.
    OString stripDavNamespace( const OString & in )
    {
        const OString inXML( in.toAsciiLowerCase() );

        OStringBuffer buf;
        sal_Int32 start = 0;
        sal_Int32 end = inXML.indexOf( "dav:" );
        while ( end != -1 )
        {
            if ( inXML[ end - 1 ] == '<' ||
                 inXML[ end - 1 ] == '/' )
            {
                // copy from original buffer - preserve case.
                buf.append( in.copy( start, end - start ) );
            }
            else
            {
                // copy from original buffer - preserve case.
                buf.append( in.copy( start, end - start + 4 ) );
            }
            start = end + 4;
            end = inXML.indexOf( "dav:", start );
        }
        buf.append( inXML.copy( start ) );

        return OString( buf.makeStringAndClear() );
    }
}

extern "C" int NPFR_propfind_iter( void* userdata,
                                   const NeonPropName* pname,
                                   const char* value,
                                   const HttpStatus* status )
{
    /*
        HTTP Response Status Classes:

        - 1: Informational - Request received, continuing process

        - 2: Success - The action was successfully received,
          understood, and accepted

        - 3: Redirection - Further action must be taken in order to
          complete the request

        - 4: Client Error - The request contains bad syntax or cannot
          be fulfilled

        - 5: Server Error - The server failed to fulfill an apparently
          valid request
    */

    if ( status->klass > 2 )
        return 0; // Error getting this property. Go on.

    // Create & set the PropertyValue
    DAVPropertyValue thePropertyValue;
    thePropertyValue.IsCaseSensitive = true;

    OSL_ENSURE( pname->nspace, "NPFR_propfind_iter - No namespace!" );

    DAVProperties::createUCBPropName( pname->nspace,
                                      pname->name,
                                      thePropertyValue.Name );
    bool bHasValue = false;
    if ( DAVProperties::isUCBDeadProperty( *pname ) )
    {
        // DAV dead property added by WebDAV UCP?
        if ( UCBDeadPropertyValue::createFromXML(
                 value, thePropertyValue.Value ) )
        {
            OSL_ENSURE( thePropertyValue.Value.hasValue(),
                        "NPFR_propfind_iter - No value!" );
            bHasValue = true;
        }
    }

    if ( !bHasValue )
    {
        if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "resourcetype" ) == 0 )
        {
            OString aValue( value );
            aValue = aValue.trim(); // #107358# remove leading/trailing spaces
            if ( !aValue.isEmpty() )
            {
                aValue = stripDavNamespace( aValue ).toAsciiLowerCase();
                if ( aValue.startsWith("<collection") )
                {
                    thePropertyValue.Value
                        <<= OUString("collection");
                }
            }

            if ( !thePropertyValue.Value.hasValue() )
            {
                // Take over the value exactly as supplied by the server.
                thePropertyValue.Value <<= OUString::createFromAscii( value );
            }
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "supportedlock" ) == 0 )
        {
            Sequence< LockEntry > aEntries;
            LockEntrySequence::createFromXML(
                stripDavNamespace( value ), aEntries );
            thePropertyValue.Value <<= aEntries;
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "lockdiscovery" ) == 0 )
        {
            Sequence< Lock > aLocks;
            LockSequence::createFromXML(
                stripDavNamespace( value ), aLocks );
            thePropertyValue.Value <<= aLocks;
        }
        else if ( rtl_str_compareIgnoreAsciiCase( pname->name, "source" ) == 0 )
        {
            Sequence< Link > aLinks;
            LinkSequence::createFromXML(
                stripDavNamespace( value ), aLinks );
            thePropertyValue.Value <<= aLinks;
        }
        else
        {
            thePropertyValue.Value
                <<= OStringToOUString( value, RTL_TEXTENCODING_UTF8 );
        }
    }

    // Add the newly created PropertyValue
    DAVResource* theResource = static_cast< DAVResource * >( userdata );
    theResource->properties.push_back( thePropertyValue );

    return 0; // Go on.
}

extern "C" void NPFR_propfind_results( void* userdata,
                                       const ne_uri* uri,
                                       const NeonPropFindResultSet* set )
{
    // @@@ href is not the uri! DAVResource ctor wants uri!

    DAVResource theResource(
        OStringToOUString( uri->path, RTL_TEXTENCODING_UTF8 ) );

    ne_propset_iterate( set, NPFR_propfind_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResource > * theResources
        = static_cast< vector< DAVResource > * >( userdata );
    theResources->push_back( theResource );
}

extern "C" int NPFR_propnames_iter( void* userdata,
                                    const NeonPropName* pname,
                                    const char* /*value*/,
                                    const HttpStatus* /*status*/ )
{
    OUString aFullName;
    DAVProperties::createUCBPropName( pname->nspace,
                                      pname->name,
                                      aFullName );

    DAVResourceInfo* theResource = static_cast< DAVResourceInfo * >( userdata );
    theResource->properties.push_back( aFullName );
    return 0;
}

extern "C" void NPFR_propnames_results( void* userdata,
                                        const ne_uri* uri,
                                        const NeonPropFindResultSet* results )
{
    // @@@ href is not the uri! DAVResourceInfo ctor wants uri!
    // Create entry for the resource.
    DAVResourceInfo theResource(
        OStringToOUString( uri->path, RTL_TEXTENCODING_UTF8 ) );

    // Fill entry.
    ne_propset_iterate( results, NPFR_propnames_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResourceInfo > * theResources
        = static_cast< vector< DAVResourceInfo > * >( userdata );
    theResources->push_back( theResource );
}

extern osl::Mutex aGlobalNeonMutex;

NeonPropFindRequest::NeonPropFindRequest( HttpSession* inSession,
                                          const char* inPath,
                                          const Depth inDepth,
                                          const vector< OUString >& inPropNames,
                                          vector< DAVResource >& ioResources,
                                          int & nError )
{
    // Generate the list of properties we're looking for
    int thePropCount = inPropNames.size();
    if ( thePropCount > 0 )
    {
        NeonPropName* thePropNames = new NeonPropName[ thePropCount + 1 ];
        int theIndex;

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
        {
            // Split fullname into namespace and name!
            DAVProperties::createNeonPropName(
                inPropNames[ theIndex ], thePropNames[ theIndex ] );
        }
        thePropNames[ theIndex ].nspace = NULL;
        thePropNames[ theIndex ].name   = NULL;

        {
            osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
            nError = ne_simple_propfind( inSession,
                                         inPath,
                                         inDepth,
                                         thePropNames,
                                         NPFR_propfind_results,
                                         &ioResources );
        }

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
            free( (void *)thePropNames[ theIndex ].name );

        delete [] thePropNames;
    }
    else
    {
        // ALLPROP
        osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
        nError = ne_simple_propfind( inSession,
                                     inPath,
                                     inDepth,
                                     NULL, // 0 == allprop
                                     NPFR_propfind_results,
                                     &ioResources );
    }

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResources.empty() )
        nError = NE_ERROR;
}

NeonPropFindRequest::NeonPropFindRequest(
                            HttpSession* inSession,
                            const char* inPath,
                            const Depth inDepth,
                            std::vector< DAVResourceInfo > & ioResInfo,
                            int & nError )
{
    {
        osl::Guard< osl::Mutex > theGlobalGuard( aGlobalNeonMutex );
        nError = ne_propnames( inSession,
                            inPath,
                            inDepth,
                            NPFR_propnames_results,
                            &ioResInfo );
    }

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResInfo.empty() )
        nError = NE_ERROR;
}

NeonPropFindRequest::~NeonPropFindRequest( )
{
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * 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 <folly/FileUtil.h>
#include <folly/portability/Unistd.h>
#include <folly/json.h>
#include <wangle/client/persistence/FilePersistenceLayer.h>

namespace wangle {

bool FilePersistenceLayer::persist(
  const folly::dynamic& dynObj) noexcept {
  std::string serializedCache;
  try {
    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    serializedCache = folly::json::serialize(dynObj, opts);
  } catch (const std::exception& err) {
    LOG(ERROR) << "Serializing to JSON failed with error: " << err.what();
    return false;
  }
  bool persisted = false;
  const auto fd = folly::openNoInt(
    file_.c_str(),
    O_WRONLY | O_CREAT | O_TRUNC,
    S_IRUSR | S_IWUSR
  );
  if (fd == -1) {
    return false;
  }
  const auto nWritten = folly::writeFull(
    fd,
    serializedCache.data(),
    serializedCache.size()
  );
  persisted = nWritten >= 0 &&
    (static_cast<size_t>(nWritten) == serializedCache.size());
  if (!persisted) {
    LOG(ERROR) << "Failed to write to " << file_ << ":";
    if (nWritten == -1) {
      LOG(ERROR) << "write failed with errno " << errno;
    }
  }
  if (folly::fdatasyncNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to sync " << file_ << ": errno " << errno;
    persisted = false;
  }
  if (folly::closeNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to close " << file_ << ": errno " << errno;
    persisted = false;
  }
  return persisted;
}

folly::Optional<folly::dynamic> FilePersistenceLayer::load() noexcept {
  std::string serializedCache;
  // not being able to read the backing storage means we just
  // start with an empty cache. Failing to deserialize, or write,
  // is a real error so we report errors there.
  if (!folly::readFile(file_.c_str(), serializedCache)) {
    return folly::none;
  }

  try {
    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    return folly::parseJson(serializedCache, opts);
  } catch (const std::exception& err) {
    LOG(ERROR) << "Deserialization of cache file " << file_
               << " failed with parse error: " << err.what();
  }
  return folly::none;
}

void FilePersistenceLayer::clear() {
  // This may fail but it's ok
  ::unlink(file_.c_str());
}

} // namespace wangle
<commit_msg>wangle: unbreak FilePersistenceLayer.cpp build on win32<commit_after>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * 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 <folly/FileUtil.h>
#include <folly/portability/Unistd.h>
#include <folly/json.h>
#include <wangle/client/persistence/FilePersistenceLayer.h>

namespace wangle {

bool FilePersistenceLayer::persist(
  const folly::dynamic& dynObj) noexcept {
  std::string serializedCache;
  try {
    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    serializedCache = folly::json::serialize(dynObj, opts);
  } catch (const std::exception& err) {
    LOG(ERROR) << "Serializing to JSON failed with error: " << err.what();
    return false;
  }
  bool persisted = false;
  const auto fd = folly::openNoInt(
    file_.c_str(),
    O_WRONLY | O_CREAT | O_TRUNC,
    0600
  );
  if (fd == -1) {
    return false;
  }
  const auto nWritten = folly::writeFull(
    fd,
    serializedCache.data(),
    serializedCache.size()
  );
  persisted = nWritten >= 0 &&
    (static_cast<size_t>(nWritten) == serializedCache.size());
  if (!persisted) {
    LOG(ERROR) << "Failed to write to " << file_ << ":";
    if (nWritten == -1) {
      LOG(ERROR) << "write failed with errno " << errno;
    }
  }
  if (folly::fdatasyncNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to sync " << file_ << ": errno " << errno;
    persisted = false;
  }
  if (folly::closeNoInt(fd) != 0) {
    LOG(ERROR) << "Failed to close " << file_ << ": errno " << errno;
    persisted = false;
  }
  return persisted;
}

folly::Optional<folly::dynamic> FilePersistenceLayer::load() noexcept {
  std::string serializedCache;
  // not being able to read the backing storage means we just
  // start with an empty cache. Failing to deserialize, or write,
  // is a real error so we report errors there.
  if (!folly::readFile(file_.c_str(), serializedCache)) {
    return folly::none;
  }

  try {
    folly::json::serialization_opts opts;
    opts.allow_non_string_keys = true;
    return folly::parseJson(serializedCache, opts);
  } catch (const std::exception& err) {
    LOG(ERROR) << "Deserialization of cache file " << file_
               << " failed with parse error: " << err.what();
  }
  return folly::none;
}

void FilePersistenceLayer::clear() {
  // This may fail but it's ok
  ::unlink(file_.c_str());
}

} // namespace wangle
<|endoftext|>


<commit_before>#include <GL/glew.h>
#include <GL/gl.h>
#include <orz/exception.h>
#include <cstring>
#include "hw3d_opengl_staging_texture_pbo.h"
#include "hw3d_opengl_common.h"

namespace Hw3D
{
	StagingTexture::Lock OpenGlStagingTexturePbo::LockRegion(const Geom::RectInt &region, bool readOnly)
	{
		if (region.Width() < 0 || region.Height() < 0)
		{
			DO_THROW(Err::InvalidParam, "Attempted to lock a region with zero width or height");
		}
		m_lockedArea = region;

		StagingTexture::Lock l;
		l.Pitch = GetSize().Width * 4;
		auto bytesToLock = (region.Width() + (region.Height() - 1) * GetSize().Width) * 4;
		auto offset = (region.Left() + region.Top() * GetSize().Width) * 4;

		GLenum err;
		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_bufferObject);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed binding buffer: " + GetGlErrorString(err));
		}

		GLbitfield flags = 0;
		if (!readOnly)
		{
			flags |= GL_MAP_WRITE_BIT;
		}

		auto ptr = glMapBufferRange(
			GL_PIXEL_UNPACK_BUFFER,
			offset,
			bytesToLock,
			flags);

		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed mapping texture buffer: " + GetGlErrorString(err));
		}

		if (ptr == nullptr)
		{
			DO_THROW(Err::CriticalError, "Failed mapping buffer object");
		}

		l.Buffer = reinterpret_cast<uint8_t *>(ptr);

		return l;
	}

	void OpenGlStagingTexturePbo::UnlockRegion()
	{
		GLenum err;

		glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed unmapping buffer object: " + GetGlErrorString(err));
		}

	}

	void OpenGlStagingTexturePbo::Transfer(Geom::RectInt sourceRect, Geom::PointInt destinationTopLeft)
	{
		GLenum err;
		glPixelStorei(GL_UNPACK_ROW_LENGTH, GetSize().Width);

		auto offset = (sourceRect.Top() + sourceRect.Left() * GetSize().Width) * 4;

		glTexSubImage2D(
			GL_TEXTURE_2D,
			0,
			destinationTopLeft.X,
			destinationTopLeft.Y,
			sourceRect.Width(),
			sourceRect.Height(),
			GetGlFormat(D3DFormat()),
			GetGlDataType(D3DFormat()),
			reinterpret_cast<void*>(offset)
		);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed copying data to texture: " + GetGlErrorString(err));
		}

		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "glBindBuffer failed: " + GetGlErrorString(err));
		}
	}

	OpenGlStagingTexturePbo::OpenGlStagingTexturePbo(Geom::SizeInt dimensions, Format fmt):
		OpenGlStagingTexture(dimensions, fmt),
		m_bufferObject(0)
	{
		GLenum err;

		// Create texture
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "glTexImage2D failed: " + GetGlErrorString(err));
		}

		// Create buffer object that will be used for transfers during Lock/Unlock
		glGenBuffers(1, &m_bufferObject);
		if(m_bufferObject == GL_INVALID_VALUE)
		{
			DO_THROW(Err::CriticalError, "Failed allocating PBO");
		}
		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_bufferObject);
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed binding buffer: " + GetGlErrorString(err));
		}
		glBufferData(GL_PIXEL_UNPACK_BUFFER, dimensions.Width * dimensions.Height * 4, nullptr, GL_STREAM_DRAW);
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed allocating buffer data: " + GetGlErrorString(err));
		}

		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "glBindBuffer failed: " + GetGlErrorString(err));
		}
	}

	OpenGlStagingTexturePbo::~OpenGlStagingTexturePbo()
	{
		glDeleteBuffers(1, &m_bufferObject);
	}
}
<commit_msg>Improve PBO performance by always setting the read flag<commit_after>#include <GL/glew.h>
#include <GL/gl.h>
#include <orz/exception.h>
#include <cstring>
#include "hw3d_opengl_staging_texture_pbo.h"
#include "hw3d_opengl_common.h"

namespace Hw3D
{
	StagingTexture::Lock OpenGlStagingTexturePbo::LockRegion(const Geom::RectInt &region, bool readOnly)
	{
		if (region.Width() < 0 || region.Height() < 0)
		{
			DO_THROW(Err::InvalidParam, "Attempted to lock a region with zero width or height");
		}
		m_lockedArea = region;

		StagingTexture::Lock l;
		l.Pitch = GetSize().Width * 4;
		auto bytesToLock = (region.Width() + (region.Height() - 1) * GetSize().Width) * 4;
		auto offset = (region.Left() + region.Top() * GetSize().Width) * 4;

		GLenum err;
		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_bufferObject);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed binding buffer: " + GetGlErrorString(err));
		}

		GLbitfield flags = GL_MAP_READ_BIT;
		if (!readOnly)
		{
			flags |= GL_MAP_WRITE_BIT;
		}

		auto ptr = glMapBufferRange(
			GL_PIXEL_UNPACK_BUFFER,
			offset,
			bytesToLock,
			flags);

		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed mapping texture buffer: " + GetGlErrorString(err));
		}

		if (ptr == nullptr)
		{
			DO_THROW(Err::CriticalError, "Failed mapping buffer object");
		}

		l.Buffer = reinterpret_cast<uint8_t *>(ptr);

		return l;
	}

	void OpenGlStagingTexturePbo::UnlockRegion()
	{
		GLenum err;

		glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed unmapping buffer object: " + GetGlErrorString(err));
		}

	}

	void OpenGlStagingTexturePbo::Transfer(Geom::RectInt sourceRect, Geom::PointInt destinationTopLeft)
	{
		GLenum err;
		glPixelStorei(GL_UNPACK_ROW_LENGTH, GetSize().Width);

		auto offset = (sourceRect.Top() + sourceRect.Left() * GetSize().Width) * 4;

		glTexSubImage2D(
			GL_TEXTURE_2D,
			0,
			destinationTopLeft.X,
			destinationTopLeft.Y,
			sourceRect.Width(),
			sourceRect.Height(),
			GetGlFormat(D3DFormat()),
			GetGlDataType(D3DFormat()),
			reinterpret_cast<void*>(offset)
		);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed copying data to texture: " + GetGlErrorString(err));
		}

		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
		if ((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "glBindBuffer failed: " + GetGlErrorString(err));
		}
	}

	OpenGlStagingTexturePbo::OpenGlStagingTexturePbo(Geom::SizeInt dimensions, Format fmt):
		OpenGlStagingTexture(dimensions, fmt),
		m_bufferObject(0)
	{
		GLenum err;

		// Create texture
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "glTexImage2D failed: " + GetGlErrorString(err));
		}

		// Create buffer object that will be used for transfers during Lock/Unlock
		glGenBuffers(1, &m_bufferObject);
		if(m_bufferObject == GL_INVALID_VALUE)
		{
			DO_THROW(Err::CriticalError, "Failed allocating PBO");
		}
		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_bufferObject);
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed binding buffer: " + GetGlErrorString(err));
		}
		glBufferData(GL_PIXEL_UNPACK_BUFFER, dimensions.Width * dimensions.Height * 4, nullptr, GL_STREAM_DRAW);
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "Failed allocating buffer data: " + GetGlErrorString(err));
		}

		glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
		if((err = glGetError()) != GL_NO_ERROR)
		{
			DO_THROW(Err::CriticalError, "glBindBuffer failed: " + GetGlErrorString(err));
		}
	}

	OpenGlStagingTexturePbo::~OpenGlStagingTexturePbo()
	{
		glDeleteBuffers(1, &m_bufferObject);
	}
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

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

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "tensorflow/compiler/aot/codegen.h"
#include "tensorflow/compiler/aot/compile.h"
#include "tensorflow/compiler/aot/flags.h"
#include "tensorflow/compiler/aot/tfcompile.pb.h"
#include "tensorflow/compiler/aot/tfcompile_util.h"
#include "tensorflow/compiler/xla/legacy_flags/compiler_functor_flags.h"
#include "tensorflow/compiler/xla/legacy_flags/cpu_compiler_flags.h"
#include "tensorflow/compiler/xla/legacy_flags/cpu_runtime_flags.h"
#include "tensorflow/compiler/xla/service/compiler.h"
#include "tensorflow/core/framework/function.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/graph/graph.h"
#include "tensorflow/core/graph/tensor_id.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/protobuf.h"
#include "tensorflow/core/util/command_line_flags.h"

namespace tensorflow {
namespace tfcompile {

const char kUsageHeader[] =
    "tfcompile performs ahead-of-time compilation of a TensorFlow graph,\n"
    "resulting in an object file compiled for your target architecture, and a\n"
    "header file that gives access to the functionality in the object file.\n"
    "A typical invocation looks like this:\n"
    "\n"
    "   $ tfcompile --graph=mygraph.pb --config=myfile.pbtxt\n"
    "\n";

Status ReadProtoFile(const string& kind, const string& fname,
                     protobuf::Message* proto) {
  if (StringPiece(fname).ends_with(".pbtxt")) {
    return ReadTextProto(Env::Default(), fname, proto);
  } else {
    return ReadBinaryProto(Env::Default(), fname, proto);
  }
}

void ParseTensorId(const string& name, TensorId* id) {
  const std::pair<StringPiece, int> name_index = ParseTensorName(name);
  id->set_node_name(name_index.first.ToString());
  id->set_output_index(name_index.second);
}

Status Main(const MainFlags& flags) {
  // Process config.
  Config config;
  TF_RETURN_IF_ERROR(ReadProtoFile("config", flags.config, &config));
  TF_RETURN_IF_ERROR(ValidateConfig(config));
  if (flags.dump_fetch_nodes) {
    std::set<string> nodes;
    for (const Fetch& fetch : config.fetch()) {
      nodes.insert(fetch.id().node_name());
    }
    std::cout << str_util::Join(nodes, ",");
    return Status::OK();
  }

  // Read and initialize the graph.
  GraphDef graph_def;
  TF_RETURN_IF_ERROR(ReadProtoFile("graph", flags.graph, &graph_def));
  std::unique_ptr<Graph> graph;
  FunctionLibraryDefinition flib(OpRegistry::Global(), graph_def.library());
  TF_RETURN_IF_ERROR(InitGraph(graph_def, config, flags, &flib, &graph));

  CompileResult compile_result;
  TF_RETURN_IF_ERROR(
      CompileGraph(std::move(graph), flags, &flib, &compile_result));

  // Write output files.
  Env* env = Env::Default();
  const std::vector<char>& obj = compile_result.aot->object_file_data();
  TF_RETURN_IF_ERROR(WriteStringToFile(env, flags.out_object,
                                       StringPiece(obj.data(), obj.size())));
  HeaderOpts header_opts;
  TF_RETURN_IF_ERROR(ParseCppClass(flags.cpp_class, &header_opts.class_name,
                                   &header_opts.namespaces));
  string header;
  TF_RETURN_IF_ERROR(
      GenerateHeader(header_opts, config, compile_result, &header));
  TF_RETURN_IF_ERROR(WriteStringToFile(env, flags.out_header, header));
  return Status::OK();
}

}  // end namespace tfcompile
}  // end namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::tfcompile::MainFlags flags;
  flags.target_triple = "x86_64-pc-linux";
  flags.out_object = "out.o";
  flags.out_header = "out.h";

  std::vector<tensorflow::Flag> flag_list;
  AppendMainFlags(&flag_list, &flags);
  xla::legacy_flags::AppendCompilerFunctorFlags(&flag_list);
  xla::legacy_flags::AppendCpuCompilerFlags(&flag_list);
  xla::legacy_flags::AppendCpuRuntimeFlags(&flag_list);

  tensorflow::string usage = tensorflow::tfcompile::kUsageHeader;
  usage += tensorflow::Flags::Usage(argv[0], flag_list);
  bool parsed_flags_ok = tensorflow::Flags::Parse(&argc, argv, flag_list);
  QCHECK(parsed_flags_ok) << "\n" << usage;

  tensorflow::port::InitMain(usage.c_str(), &argc, &argv);
  QCHECK(argc == 1 && !flags.config.empty() &&
         (flags.dump_fetch_nodes ||
          (!flags.graph.empty() && !flags.entry_point.empty())))
      << "\n"
      << usage;

  TF_QCHECK_OK(tensorflow::tfcompile::Main(flags));
  return 0;
}
<commit_msg>tfcompile: Be a little more verbose about missing required flags.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

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

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "tensorflow/compiler/aot/codegen.h"
#include "tensorflow/compiler/aot/compile.h"
#include "tensorflow/compiler/aot/flags.h"
#include "tensorflow/compiler/aot/tfcompile.pb.h"
#include "tensorflow/compiler/aot/tfcompile_util.h"
#include "tensorflow/compiler/xla/legacy_flags/compiler_functor_flags.h"
#include "tensorflow/compiler/xla/legacy_flags/cpu_compiler_flags.h"
#include "tensorflow/compiler/xla/legacy_flags/cpu_runtime_flags.h"
#include "tensorflow/compiler/xla/service/compiler.h"
#include "tensorflow/core/framework/function.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor_shape.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/graph/graph.h"
#include "tensorflow/core/graph/tensor_id.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/strings/numbers.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/protobuf.h"
#include "tensorflow/core/util/command_line_flags.h"

namespace tensorflow {
namespace tfcompile {

const char kUsageHeader[] =
    "tfcompile performs ahead-of-time compilation of a TensorFlow graph,\n"
    "resulting in an object file compiled for your target architecture, and a\n"
    "header file that gives access to the functionality in the object file.\n"
    "A typical invocation looks like this:\n"
    "\n"
    "   $ tfcompile --graph=mygraph.pb --config=myfile.pbtxt "
    "--cpp_class=\"mynamespace::MyComputation\"\n"
    "\n";

Status ReadProtoFile(const string& kind, const string& fname,
                     protobuf::Message* proto) {
  if (StringPiece(fname).ends_with(".pbtxt")) {
    return ReadTextProto(Env::Default(), fname, proto);
  } else {
    return ReadBinaryProto(Env::Default(), fname, proto);
  }
}

void ParseTensorId(const string& name, TensorId* id) {
  const std::pair<StringPiece, int> name_index = ParseTensorName(name);
  id->set_node_name(name_index.first.ToString());
  id->set_output_index(name_index.second);
}

Status Main(const MainFlags& flags) {
  // Process config.
  Config config;
  if (flags.config.empty()) {
    return errors::InvalidArgument("Must specify --config");
  }
  TF_RETURN_IF_ERROR(ReadProtoFile("config", flags.config, &config));
  TF_RETURN_IF_ERROR(ValidateConfig(config));
  if (flags.dump_fetch_nodes) {
    std::set<string> nodes;
    for (const Fetch& fetch : config.fetch()) {
      nodes.insert(fetch.id().node_name());
    }
    std::cout << str_util::Join(nodes, ",");
    return Status::OK();
  }

  // Read and initialize the graph.
  if (flags.graph.empty()) {
    return errors::InvalidArgument("Must specify --graph");
  }
  GraphDef graph_def;
  TF_RETURN_IF_ERROR(ReadProtoFile("graph", flags.graph, &graph_def));
  std::unique_ptr<Graph> graph;
  FunctionLibraryDefinition flib(OpRegistry::Global(), graph_def.library());
  TF_RETURN_IF_ERROR(InitGraph(graph_def, config, flags, &flib, &graph));

  CompileResult compile_result;
  TF_RETURN_IF_ERROR(
      CompileGraph(std::move(graph), flags, &flib, &compile_result));

  // Write output files.
  Env* env = Env::Default();
  const std::vector<char>& obj = compile_result.aot->object_file_data();
  TF_RETURN_IF_ERROR(WriteStringToFile(env, flags.out_object,
                                       StringPiece(obj.data(), obj.size())));
  HeaderOpts header_opts;
  if (flags.cpp_class.empty()) {
    return errors::InvalidArgument("Must specify --cpp_class");
  }
  TF_RETURN_IF_ERROR(ParseCppClass(flags.cpp_class, &header_opts.class_name,
                                   &header_opts.namespaces));
  string header;
  TF_RETURN_IF_ERROR(
      GenerateHeader(header_opts, config, compile_result, &header));
  TF_RETURN_IF_ERROR(WriteStringToFile(env, flags.out_header, header));
  return Status::OK();
}

}  // end namespace tfcompile
}  // end namespace tensorflow

int main(int argc, char** argv) {
  tensorflow::tfcompile::MainFlags flags;
  flags.target_triple = "x86_64-pc-linux";
  flags.out_object = "out.o";
  flags.out_header = "out.h";

  std::vector<tensorflow::Flag> flag_list;
  AppendMainFlags(&flag_list, &flags);
  xla::legacy_flags::AppendCompilerFunctorFlags(&flag_list);
  xla::legacy_flags::AppendCpuCompilerFlags(&flag_list);
  xla::legacy_flags::AppendCpuRuntimeFlags(&flag_list);

  tensorflow::string usage = tensorflow::tfcompile::kUsageHeader;
  usage += tensorflow::Flags::Usage(argv[0], flag_list);
  bool parsed_flags_ok = tensorflow::Flags::Parse(&argc, argv, flag_list);
  QCHECK(parsed_flags_ok) << "\n" << usage;

  tensorflow::port::InitMain(usage.c_str(), &argc, &argv);
  QCHECK(argc == 1) << "\nERROR: This command does not take any arguments "
                       "other than flags\n\n"
                    << usage;
  tensorflow::Status status = tensorflow::tfcompile::Main(flags);
  if (status.code() == tensorflow::error::INVALID_ARGUMENT) {
    std::cerr << "INVALID ARGUMENTS: " << status.error_message() << "\n\n"
              << usage;
    return 1;
  } else {
    TF_QCHECK_OK(status);
  }
  return 0;
}
<|endoftext|>