<commit_before>#ifndef __terark_db_db_context_hpp__
#define __terark_db_db_context_hpp__

#include "db_conf.hpp"

namespace terark {
	class BaseDFA;
}

namespace terark { namespace db {

typedef boost::intrusive_ptr<class DbTable> DbTablePtr;
typedef boost::intrusive_ptr<class StoreIterator> StoreIteratorPtr;

template<class T, class P>
void DbContextObjCacheFreeExcessMem(T*) {
}
template<class P>
void DbContextObjCacheFreeExcessMem(valvec<byte>* obj) {
    static size_t constexpr limit_size = 1024 * 1204;
    if (obj->size() > limit_size) {
        obj->clear();
    }
}

template<class T>
class DbContextObjCache {
private:
    struct Wrapper {
        DbContextObjCache* owner;
        T x;
    };
    struct CacheItem {
        CacheItem(Wrapper *o) : obj(o) {}
        CacheItem(CacheItem const &) = delete;
        CacheItem(CacheItem &&o) : obj(o.obj) {
            o.obj = nullptr;
        }
        Wrapper* obj;

        T* operator->() const { return &obj->x; }
        T& operator*() const { return obj->x; }
        T* get() const { return &obj->x; }

        ~CacheItem() {
            if (obj) {
                DbContextObjCacheFreeExcessMem<T, void>(&obj->x);
                obj->owner->pool.emplace_back(obj);
            }
        }
    };
    valvec<Wrapper*> pool;
public:
    ~DbContextObjCache() {
        for (auto item : pool) {
            delete item;
        }
    }
    CacheItem get() {
        if (pool.empty()) {
            return CacheItem(new Wrapper{this, {}});
        }
        else {
            return CacheItem(pool.pop_val());
        }
    }
};

class TERARK_DB_DLL DbContextLink : public RefCounter {
	friend class DbTable;
protected:
	DbContextLink();
	~DbContextLink();
//	DbContextLink *m_prev, *m_next;
};
class TERARK_DB_DLL DbContext : public DbContextLink {
	friend class DbTable;
public:
	explicit DbContext(const DbTable* tab);
	~DbContext();

	void doSyncSegCtxNoLock(const DbTable* tab);
	void trySyncSegCtxNoLock(const DbTable* tab);
	void trySyncSegCtxSpeculativeLock(const DbTable* tab);
	class StoreIterator* getWrtStoreIterNoLock(size_t segIdx);
	class IndexIterator* getIndexIterNoLock(size_t segIdx, size_t indexId);

	void getWrSegWrtStoreData(const class ReadableSegment* seg, llong subId, valvec<byte>* buf);

	void debugCheckUnique(fstring row, size_t uniqIndexId);

/// @{ delegate methods
	StoreIteratorPtr createTableIterForward();
	StoreIteratorPtr createTableIterBackward();

	void getValueAppend(llong id, valvec<byte>* val);
	void getValue(llong id, valvec<byte>* val);

	llong insertRow(fstring row);
	llong upsertRow(fstring row);
	llong updateRow(llong id, fstring row);
	void  removeRow(llong id);

	void indexInsert(size_t indexId, fstring indexKey, llong id);
	void indexRemove(size_t indexId, fstring indexKey, llong id);
	void indexUpdate(size_t indexId, fstring indexKey, llong oldId, llong newId);

	void indexSearchExact(size_t indexId, fstring key, valvec<llong>* recIdvec);
	bool indexKeyExists(size_t indexId, fstring key);

	void indexSearchExactNoLock(size_t indexId, fstring key, valvec<llong>* recIdvec);
	bool indexKeyExistsNoLock(size_t indexId, fstring key);

	bool indexMatchRegex(size_t indexId, class RegexForIndex*, valvec<llong>* recIdvec);

	void selectColumns(llong id, const valvec<size_t>& cols, valvec<byte>* colsData);
	void selectColumns(llong id, const size_t* colsId, size_t colsNum, valvec<byte>* colsData);
	void selectOneColumn(llong id, size_t columnId, valvec<byte>* colsData);

	void selectColgroups(llong id, const valvec<size_t>& cgIdvec, valvec<valvec<byte> >* cgDataVec);
	void selectColgroups(llong id, const size_t* cgIdvec, size_t cgIdvecSize, valvec<byte>* cgDataVec);

	void selectOneColgroup(llong id, size_t cgId, valvec<byte>* cgData);

	void selectColumnsNoLock(llong id, const valvec<size_t>& cols, valvec<byte>* colsData);
	void selectColumnsNoLock(llong id, const size_t* colsId, size_t colsNum, valvec<byte>* colsData);
	void selectOneColumnNoLock(llong id, size_t columnId, valvec<byte>* colsData);

	void selectColgroupsNoLock(llong id, const valvec<size_t>& cgIdvec, valvec<valvec<byte> >* cgDataVec);
	void selectColgroupsNoLock(llong id, const size_t* cgIdvec, size_t cgIdvecSize, valvec<byte>* cgDataVec);

	void selectOneColgroupNoLock(llong id, size_t cgId, valvec<byte>* cgData);
/// @}

	class ReadableSegment* getSegmentPtr(size_t segIdx) const;

	void ensureTransactionNoLock();
	void freeWritableSegmentResources();

public:
	struct SegCtx {
		class ReadableSegment* seg;
		class StoreIterator* wrtStoreIter;
		class IndexIterator* indexIter[1];
	private:
		friend class DbContext;
		~SegCtx() = delete;
		SegCtx() = delete;
		SegCtx(const SegCtx&) = delete;
		SegCtx& operator=(const SegCtx&) = delete;
		static SegCtx* create(ReadableSegment* seg, size_t indexNum);
		static void destory(SegCtx*& p, size_t indexNum);
		static void reset(SegCtx* p, size_t indexNum, ReadableSegment* seg);
	};
	DbTable* m_tab;
	class WritableSegment* m_wrSegPtr;
	std::unique_ptr<class DbTransaction> m_transaction;
	valvec<SegCtx*> m_segCtx;
	valvec<llong>   m_rowNumVec; // copy of DbTable::m_rowNumVec
	llong           m_mySnapshotVersion;
	std::string  errMsg;
    DbContextObjCache<valvec<byte>> bufs;
    DbContextObjCache<ColumnVec> cols;
	valvec<uint32_t> offsets;
	valvec<llong> exactMatchRecIdvec;
    boost::intrusive_ptr<RefCounter> trbLog;
	size_t regexMatchMemLimit;
	size_t segArrayUpdateSeq;
	int  upsertMaxRetry;
	bool syncIndex;
	bool m_isUserDefineSnapshot;
    bool syncOnCommit;
	byte isUpsertOverwritten;
};
typedef boost::intrusive_ptr<DbContext> DbContextPtr;

} } // namespace terark::db

#endif // __terark_db_db_context_hpp__
<commit_msg>Fix DbContext FreeExcessMem bug<commit_after>#ifndef __terark_db_db_context_hpp__
#define __terark_db_db_context_hpp__

#include "db_conf.hpp"

namespace terark {
	class BaseDFA;
}

namespace terark { namespace db {

typedef boost::intrusive_ptr<class DbTable> DbTablePtr;
typedef boost::intrusive_ptr<class StoreIterator> StoreIteratorPtr;

template<class T>
struct DbContextObjCacheFreeExcessMem {
    static void invoke(T*) {}
};
template<>
struct DbContextObjCacheFreeExcessMem<valvec<byte>> {
    static void invoke(valvec<byte>* obj) {
        static size_t constexpr limit_size = 1024 * 1204;
        if (obj->size() > limit_size) {
            obj->clear();
        }
    }
};

template<class T>
class DbContextObjCache {
private:
    struct Wrapper {
        DbContextObjCache* owner;
        T x;
    };
    struct CacheItem {
        CacheItem(Wrapper *o) : obj(o) {}
        CacheItem(CacheItem const &) = delete;
        CacheItem(CacheItem &&o) : obj(o.obj) {
            o.obj = nullptr;
        }
        Wrapper* obj;

        T* operator->() const { return &obj->x; }
        T& operator*() const { return obj->x; }
        T* get() const { return &obj->x; }

        ~CacheItem() {
            if (obj) {
                DbContextObjCacheFreeExcessMem<T>::invoke(&obj->x);
                obj->owner->pool.emplace_back(obj);
            }
        }
    };
    valvec<Wrapper*> pool;
public:
    ~DbContextObjCache() {
        for (auto item : pool) {
            delete item;
        }
    }
    CacheItem get() {
        if (pool.empty()) {
            return CacheItem(new Wrapper{this, {}});
        }
        else {
            return CacheItem(pool.pop_val());
        }
    }
};

class TERARK_DB_DLL DbContextLink : public RefCounter {
	friend class DbTable;
protected:
	DbContextLink();
	~DbContextLink();
//	DbContextLink *m_prev, *m_next;
};
class TERARK_DB_DLL DbContext : public DbContextLink {
	friend class DbTable;
public:
	explicit DbContext(const DbTable* tab);
	~DbContext();

	void doSyncSegCtxNoLock(const DbTable* tab);
	void trySyncSegCtxNoLock(const DbTable* tab);
	void trySyncSegCtxSpeculativeLock(const DbTable* tab);
	class StoreIterator* getWrtStoreIterNoLock(size_t segIdx);
	class IndexIterator* getIndexIterNoLock(size_t segIdx, size_t indexId);

	void getWrSegWrtStoreData(const class ReadableSegment* seg, llong subId, valvec<byte>* buf);

	void debugCheckUnique(fstring row, size_t uniqIndexId);

/// @{ delegate methods
	StoreIteratorPtr createTableIterForward();
	StoreIteratorPtr createTableIterBackward();

	void getValueAppend(llong id, valvec<byte>* val);
	void getValue(llong id, valvec<byte>* val);

	llong insertRow(fstring row);
	llong upsertRow(fstring row);
	llong updateRow(llong id, fstring row);
	void  removeRow(llong id);

	void indexInsert(size_t indexId, fstring indexKey, llong id);
	void indexRemove(size_t indexId, fstring indexKey, llong id);
	void indexUpdate(size_t indexId, fstring indexKey, llong oldId, llong newId);

	void indexSearchExact(size_t indexId, fstring key, valvec<llong>* recIdvec);
	bool indexKeyExists(size_t indexId, fstring key);

	void indexSearchExactNoLock(size_t indexId, fstring key, valvec<llong>* recIdvec);
	bool indexKeyExistsNoLock(size_t indexId, fstring key);

	bool indexMatchRegex(size_t indexId, class RegexForIndex*, valvec<llong>* recIdvec);

	void selectColumns(llong id, const valvec<size_t>& cols, valvec<byte>* colsData);
	void selectColumns(llong id, const size_t* colsId, size_t colsNum, valvec<byte>* colsData);
	void selectOneColumn(llong id, size_t columnId, valvec<byte>* colsData);

	void selectColgroups(llong id, const valvec<size_t>& cgIdvec, valvec<valvec<byte> >* cgDataVec);
	void selectColgroups(llong id, const size_t* cgIdvec, size_t cgIdvecSize, valvec<byte>* cgDataVec);

	void selectOneColgroup(llong id, size_t cgId, valvec<byte>* cgData);

	void selectColumnsNoLock(llong id, const valvec<size_t>& cols, valvec<byte>* colsData);
	void selectColumnsNoLock(llong id, const size_t* colsId, size_t colsNum, valvec<byte>* colsData);
	void selectOneColumnNoLock(llong id, size_t columnId, valvec<byte>* colsData);

	void selectColgroupsNoLock(llong id, const valvec<size_t>& cgIdvec, valvec<valvec<byte> >* cgDataVec);
	void selectColgroupsNoLock(llong id, const size_t* cgIdvec, size_t cgIdvecSize, valvec<byte>* cgDataVec);

	void selectOneColgroupNoLock(llong id, size_t cgId, valvec<byte>* cgData);
/// @}

	class ReadableSegment* getSegmentPtr(size_t segIdx) const;

	void ensureTransactionNoLock();
	void freeWritableSegmentResources();

public:
	struct SegCtx {
		class ReadableSegment* seg;
		class StoreIterator* wrtStoreIter;
		class IndexIterator* indexIter[1];
	private:
		friend class DbContext;
		~SegCtx() = delete;
		SegCtx() = delete;
		SegCtx(const SegCtx&) = delete;
		SegCtx& operator=(const SegCtx&) = delete;
		static SegCtx* create(ReadableSegment* seg, size_t indexNum);
		static void destory(SegCtx*& p, size_t indexNum);
		static void reset(SegCtx* p, size_t indexNum, ReadableSegment* seg);
	};
	DbTable* m_tab;
	class WritableSegment* m_wrSegPtr;
	std::unique_ptr<class DbTransaction> m_transaction;
	valvec<SegCtx*> m_segCtx;
	valvec<llong>   m_rowNumVec; // copy of DbTable::m_rowNumVec
	llong           m_mySnapshotVersion;
	std::string  errMsg;
    DbContextObjCache<valvec<byte>> bufs;
    DbContextObjCache<ColumnVec> cols;
	valvec<uint32_t> offsets;
	valvec<llong> exactMatchRecIdvec;
    boost::intrusive_ptr<RefCounter> trbLog;
	size_t regexMatchMemLimit;
	size_t segArrayUpdateSeq;
	int  upsertMaxRetry;
	bool syncIndex;
	bool m_isUserDefineSnapshot;
    bool syncOnCommit;
	byte isUpsertOverwritten;
};
typedef boost::intrusive_ptr<DbContext> DbContextPtr;

} } // namespace terark::db

#endif // __terark_db_db_context_hpp__
<|endoftext|>


<commit_before>//
// Created by Yinyin Qian on 8/18/17.
//

#include "gtest/gtest.h"
#include "filesystem.h"
#include <algorithm>

using namespace std;

TEST(filesystem, ListFiles) {
  vector<string> files;
  const string path(u8"C:/Users/yyqian/Downloads/软件");
  cout << path << endl;
  ListFiles(path, files, true);
  for_each(files.cbegin(), files.cend(), [](const string &str) {
    cout << str << endl;
  });
}
<commit_msg>treate utf-8 and bom<commit_after>//
// Created by Yinyin Qian on 8/18/17.
//

#include "gtest/gtest.h"
#include "filesystem.h"
#include <algorithm>

using namespace std;

TEST(filesystem, ListFiles) {
  vector<string> files;
  const string path(u8"C:/Users/yyqian/Downloads/\u8F6F\u4EF6");
  cout << path << endl;
  ListFiles(path, files, true);
  for_each(files.cbegin(), files.cend(), [](const string &str) {
    cout << str << endl;
  });
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <vector>
#include "prevector.h"

#include "serialize.h"
#include "streams.h"

#include "test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup)

template<unsigned int N, typename T>
class prevector_tester {
    typedef std::vector<T> realtype;
    realtype real_vector;
    realtype real_vector_alt;

    typedef prevector<N, T> pretype;
    pretype pre_vector;
    pretype pre_vector_alt;

    typedef typename pretype::size_type Size;
    bool passed = true;
    FastRandomContext rand_cache;
    uint256 rand_seed;

    template <typename A, typename B>
        void local_check_equal(A a, B b)
        {
            local_check(a == b);
        }
    void local_check(bool b)
    {
        passed &= b;
    }
    void test() {
        const pretype& const_pre_vector = pre_vector;
        local_check_equal(real_vector.size(), pre_vector.size());
        local_check_equal(real_vector.empty(), pre_vector.empty());
        for (Size s = 0; s < real_vector.size(); s++) {
             local_check(real_vector[s] == pre_vector[s]);
             local_check(&(pre_vector[s]) == &(pre_vector.begin()[s]));
             local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s));
             local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
        }
        // local_check(realtype(pre_vector) == real_vector);
        local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
        local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
        size_t pos = 0;
        for (const T& v : pre_vector) {
             local_check(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
             local_check(v == real_vector[--pos]);
        }
        for (const T& v : const_pre_vector) {
             local_check(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
             local_check(v == real_vector[--pos]);
        }
        CDataStream ss1(SER_DISK, 0);
        CDataStream ss2(SER_DISK, 0);
        ss1 << real_vector;
        ss2 << pre_vector;
        local_check_equal(ss1.size(), ss2.size());
        for (Size s = 0; s < ss1.size(); s++) {
            local_check_equal(ss1[s], ss2[s]);
        }
    }

public:
    void resize(Size s) {
        real_vector.resize(s);
        local_check_equal(real_vector.size(), s);
        pre_vector.resize(s);
        local_check_equal(pre_vector.size(), s);
        test();
    }

    void reserve(Size s) {
        real_vector.reserve(s);
        local_check(real_vector.capacity() >= s);
        pre_vector.reserve(s);
        local_check(pre_vector.capacity() >= s);
        test();
    }

    void insert(Size position, const T& value) {
        real_vector.insert(real_vector.begin() + position, value);
        pre_vector.insert(pre_vector.begin() + position, value);
        test();
    }

    void insert(Size position, Size count, const T& value) {
        real_vector.insert(real_vector.begin() + position, count, value);
        pre_vector.insert(pre_vector.begin() + position, count, value);
        test();
    }

    template<typename I>
    void insert_range(Size position, I first, I last) {
        real_vector.insert(real_vector.begin() + position, first, last);
        pre_vector.insert(pre_vector.begin() + position, first, last);
        test();
    }

    void erase(Size position) {
        real_vector.erase(real_vector.begin() + position);
        pre_vector.erase(pre_vector.begin() + position);
        test();
    }

    void erase(Size first, Size last) {
        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
        test();
    }

    void update(Size pos, const T& value) {
        real_vector[pos] = value;
        pre_vector[pos] = value;
        test();
    }

    void push_back(const T& value) {
        real_vector.push_back(value);
        pre_vector.push_back(value);
        test();
    }

    void pop_back() {
        real_vector.pop_back();
        pre_vector.pop_back();
        test();
    }

    void clear() {
        real_vector.clear();
        pre_vector.clear();
    }

    void assign(Size n, const T& value) {
        real_vector.assign(n, value);
        pre_vector.assign(n, value);
    }

    Size size() {
        return real_vector.size();
    }

    Size capacity() {
        return pre_vector.capacity();
    }

    void shrink_to_fit() {
        pre_vector.shrink_to_fit();
        test();
    }

    void swap() {
        real_vector.swap(real_vector_alt);
        pre_vector.swap(pre_vector_alt);
        test();
    }

    void move() {
        real_vector = std::move(real_vector_alt);
        real_vector_alt.clear();
        pre_vector = std::move(pre_vector_alt);
        pre_vector_alt.clear();
    }

    void copy() {
        real_vector = real_vector_alt;
        pre_vector = pre_vector_alt;
    }

    ~prevector_tester() {
        BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
    }

    prevector_tester() {
        seed_insecure_rand();
        rand_seed = insecure_rand_seed;
        rand_cache = insecure_rand_ctx;
    }
};

BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{
    for (int j = 0; j < 64; j++) {
        prevector_tester<8, int> test;
        for (int i = 0; i < 2048; i++) {
            int r = insecure_rand();
            if ((r % 4) == 0) {
                test.insert(insecure_randrange(test.size() + 1), insecure_rand());
            }
            if (test.size() > 0 && ((r >> 2) % 4) == 1) {
                test.erase(insecure_randrange(test.size()));
            }
            if (((r >> 4) % 8) == 2) {
                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (insecure_randrange(5)) - 2));
                test.resize(new_size);
            }
            if (((r >> 7) % 8) == 3) {
                test.insert(insecure_randrange(test.size() + 1), 1 + insecure_randrange(2), insecure_rand());
            }
            if (((r >> 10) % 8) == 4) {
                int del = std::min<int>(test.size(), 1 + (insecure_randrange(2)));
                int beg = insecure_randrange(test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (((r >> 13) % 16) == 5) {
                test.push_back(insecure_rand());
            }
            if (test.size() > 0 && ((r >> 17) % 16) == 6) {
                test.pop_back();
            }
            if (((r >> 21) % 32) == 7) {
                int values[4];
                int num = 1 + (insecure_randrange(4));
                for (int k = 0; k < num; k++) {
                    values[k] = insecure_rand();
                }
                test.insert_range(insecure_randrange(test.size() + 1), values, values + num);
            }
            if (((r >> 26) % 32) == 8) {
                int del = std::min<int>(test.size(), 1 + (insecure_randrange(4)));
                int beg = insecure_randrange(test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            r = insecure_rand();
            if (r % 32 == 9) {
                test.reserve(insecure_randrange(32));
            }
            if ((r >> 5) % 64 == 10) {
                test.shrink_to_fit();
            }
            if (test.size() > 0) {
                test.update(insecure_randrange(test.size()), insecure_rand());
            }
            if (((r >> 11) % 1024) == 11) {
                test.clear();
            }
            if (((r >> 21) % 512) == 12) {
                test.assign(insecure_randrange(32), insecure_rand());
            }
            if (((r >> 15) % 8) == 3) {
                test.swap();
            }
            if (((r >> 15) % 16) == 8) {
                test.copy();
            }
            if (((r >> 15) % 32) == 18) {
                test.move();
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Use randbits instead of ad-hoc emulation in prevector tests<commit_after>// Copyright (c) 2015-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <vector>
#include "prevector.h"

#include "serialize.h"
#include "streams.h"

#include "test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup)

template<unsigned int N, typename T>
class prevector_tester {
    typedef std::vector<T> realtype;
    realtype real_vector;
    realtype real_vector_alt;

    typedef prevector<N, T> pretype;
    pretype pre_vector;
    pretype pre_vector_alt;

    typedef typename pretype::size_type Size;
    bool passed = true;
    FastRandomContext rand_cache;
    uint256 rand_seed;

    template <typename A, typename B>
        void local_check_equal(A a, B b)
        {
            local_check(a == b);
        }
    void local_check(bool b)
    {
        passed &= b;
    }
    void test() {
        const pretype& const_pre_vector = pre_vector;
        local_check_equal(real_vector.size(), pre_vector.size());
        local_check_equal(real_vector.empty(), pre_vector.empty());
        for (Size s = 0; s < real_vector.size(); s++) {
             local_check(real_vector[s] == pre_vector[s]);
             local_check(&(pre_vector[s]) == &(pre_vector.begin()[s]));
             local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s));
             local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size()));
        }
        // local_check(realtype(pre_vector) == real_vector);
        local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector);
        local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector);
        size_t pos = 0;
        for (const T& v : pre_vector) {
             local_check(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, pre_vector) {
             local_check(v == real_vector[--pos]);
        }
        for (const T& v : const_pre_vector) {
             local_check(v == real_vector[pos++]);
        }
        BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) {
             local_check(v == real_vector[--pos]);
        }
        CDataStream ss1(SER_DISK, 0);
        CDataStream ss2(SER_DISK, 0);
        ss1 << real_vector;
        ss2 << pre_vector;
        local_check_equal(ss1.size(), ss2.size());
        for (Size s = 0; s < ss1.size(); s++) {
            local_check_equal(ss1[s], ss2[s]);
        }
    }

public:
    void resize(Size s) {
        real_vector.resize(s);
        local_check_equal(real_vector.size(), s);
        pre_vector.resize(s);
        local_check_equal(pre_vector.size(), s);
        test();
    }

    void reserve(Size s) {
        real_vector.reserve(s);
        local_check(real_vector.capacity() >= s);
        pre_vector.reserve(s);
        local_check(pre_vector.capacity() >= s);
        test();
    }

    void insert(Size position, const T& value) {
        real_vector.insert(real_vector.begin() + position, value);
        pre_vector.insert(pre_vector.begin() + position, value);
        test();
    }

    void insert(Size position, Size count, const T& value) {
        real_vector.insert(real_vector.begin() + position, count, value);
        pre_vector.insert(pre_vector.begin() + position, count, value);
        test();
    }

    template<typename I>
    void insert_range(Size position, I first, I last) {
        real_vector.insert(real_vector.begin() + position, first, last);
        pre_vector.insert(pre_vector.begin() + position, first, last);
        test();
    }

    void erase(Size position) {
        real_vector.erase(real_vector.begin() + position);
        pre_vector.erase(pre_vector.begin() + position);
        test();
    }

    void erase(Size first, Size last) {
        real_vector.erase(real_vector.begin() + first, real_vector.begin() + last);
        pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last);
        test();
    }

    void update(Size pos, const T& value) {
        real_vector[pos] = value;
        pre_vector[pos] = value;
        test();
    }

    void push_back(const T& value) {
        real_vector.push_back(value);
        pre_vector.push_back(value);
        test();
    }

    void pop_back() {
        real_vector.pop_back();
        pre_vector.pop_back();
        test();
    }

    void clear() {
        real_vector.clear();
        pre_vector.clear();
    }

    void assign(Size n, const T& value) {
        real_vector.assign(n, value);
        pre_vector.assign(n, value);
    }

    Size size() {
        return real_vector.size();
    }

    Size capacity() {
        return pre_vector.capacity();
    }

    void shrink_to_fit() {
        pre_vector.shrink_to_fit();
        test();
    }

    void swap() {
        real_vector.swap(real_vector_alt);
        pre_vector.swap(pre_vector_alt);
        test();
    }

    void move() {
        real_vector = std::move(real_vector_alt);
        real_vector_alt.clear();
        pre_vector = std::move(pre_vector_alt);
        pre_vector_alt.clear();
    }

    void copy() {
        real_vector = real_vector_alt;
        pre_vector = pre_vector_alt;
    }

    ~prevector_tester() {
        BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
    }

    prevector_tester() {
        seed_insecure_rand();
        rand_seed = insecure_rand_seed;
        rand_cache = insecure_rand_ctx;
    }
};

BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{
    for (int j = 0; j < 64; j++) {
        prevector_tester<8, int> test;
        for (int i = 0; i < 2048; i++) {
            if (insecure_randbits(2) == 0) {
                test.insert(insecure_randrange(test.size() + 1), insecure_rand());
            }
            if (test.size() > 0 && insecure_randbits(2) == 1) {
                test.erase(insecure_randrange(test.size()));
            }
            if (insecure_randbits(3) == 2) {
                int new_size = std::max<int>(0, std::min<int>(30, test.size() + (insecure_randrange(5)) - 2));
                test.resize(new_size);
            }
            if (insecure_randbits(3) == 3) {
                test.insert(insecure_randrange(test.size() + 1), 1 + insecure_randrange(2), insecure_rand());
            }
            if (insecure_randbits(3) == 4) {
                int del = std::min<int>(test.size(), 1 + (insecure_randrange(2)));
                int beg = insecure_randrange(test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (insecure_randbits(4) == 5) {
                test.push_back(insecure_rand());
            }
            if (test.size() > 0 && insecure_randbits(4) == 6) {
                test.pop_back();
            }
            if (insecure_randbits(5) == 7) {
                int values[4];
                int num = 1 + (insecure_randrange(4));
                for (int k = 0; k < num; k++) {
                    values[k] = insecure_rand();
                }
                test.insert_range(insecure_randrange(test.size() + 1), values, values + num);
            }
            if (insecure_randbits(5) == 8) {
                int del = std::min<int>(test.size(), 1 + (insecure_randrange(4)));
                int beg = insecure_randrange(test.size() + 1 - del);
                test.erase(beg, beg + del);
            }
            if (insecure_randbits(5) == 9) {
                test.reserve(insecure_randrange(32));
            }
            if (insecure_randbits(6) == 10) {
                test.shrink_to_fit();
            }
            if (test.size() > 0) {
                test.update(insecure_randrange(test.size()), insecure_rand());
            }
            if (insecure_randbits(10) == 11) {
                test.clear();
            }
            if (insecure_randbits(9) == 12) {
                test.assign(insecure_randrange(32), insecure_rand());
            }
            if (insecure_randbits(3) == 3) {
                test.swap();
            }
            if (insecure_randbits(4) == 8) {
                test.copy();
            }
            if (insecure_randbits(5) == 18) {
                test.move();
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <cstdlib>
#include <sstream>

#ifdef CLEVER_WIN32
# include <direct.h>
# include <windows.h>
# define PATH_MAX MAX_PATH
#else
# include <dirent.h>
# include <sys/resource.h>
# include <sys/time.h>
# include <unistd.h>
#endif
#include "core/clever.h"
#include "core/value.h"
#include "core/driver.h"
#include "core/native_types.h"
#include "core/modmanager.h"
#include "core/cexception.h"
#include "modules/std/sys/sys.h"

#ifndef PATH_MAX
# define PATH_MAX 1024
#endif

namespace clever { namespace modules { namespace std {

namespace sys {

// system(string command)
// Calls a command and returns the exit code
static CLEVER_FUNCTION(system)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	result->setInt(::system(args[0]->getStr()->c_str()));
}

// putenv(string env)
// Sets an environment variable
static CLEVER_FUNCTION(putenv)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	::putenv(const_cast<char*>(args[0]->getStr()->c_str()));
}

// getenv(string env)
// Gets an environment variable
static CLEVER_FUNCTION(getenv)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* ret = ::getenv(const_cast<char*>(args[0]->getStr()->c_str()));

	if (ret) {
		result->setStr(CSTRINGT(ret));
	} else {
		result->setStr(CSTRING(""));
	}
}

// getcwd()
// Gets the current working directory
static CLEVER_FUNCTION(getcwd)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	char temp[PATH_MAX];
	const char* path = ::getcwd(temp, PATH_MAX);

	result->setStr(CSTRING(path ? path : ""));
}

// argv(int n)
// Get n-th argv value
static CLEVER_FUNCTION(argv)
{
	if (!clever_static_check_args("i")) {
		return;
	}

	if (args[0]->getInt() >= *g_clever_argc) {
		result->setBool(false);
	} else {
		result->setStr(new StrObject((*g_clever_argv)[args[0]->getInt()]));
	}
}

// argc()
// Get argc value
static CLEVER_FUNCTION(argc)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(*g_clever_argc);
}

// sleep(int time)
// Sleep for 'time' milliseconds
static CLEVER_FUNCTION(sleep)
{
	if (!clever_static_check_args("i")) {
		return;
	}

	int time = static_cast<int>(args[0]->getInt());

#ifdef CLEVER_WIN32
	SleepEx(time, false);
#else
	usleep(time * 1000);
#endif
}

// clock()
// Returns the execution clock
static CLEVER_FUNCTION(clock)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(clock());
}

// time()
// Returns the execution time in sec
static CLEVER_FUNCTION(time)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	struct timeval tp = {0};
	if (gettimeofday(&tp, NULL)) {
		result->setBool(false);
		return;
	}
	result->setDouble(tp.tv_sec);
}

// microtime()
// Returns the unix timestamp with microseconds
static CLEVER_FUNCTION(microtime)
{
	struct timeval tp = {0};

	if (!clever_static_check_no_args()) {
		return;
	}
	if (gettimeofday(&tp, NULL)) {
		result->setBool(false);
		return;
	}

	result->setDouble(tp.tv_sec + tp.tv_usec / 1000000.00);
}

// getpid()
// Returns the current process id
static CLEVER_FUNCTION(getpid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::getpid());
}

// getppid()
// Returns the current process id
static CLEVER_FUNCTION(getppid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::getppid());
}

// getuid()
// Returns the process user id
static CLEVER_FUNCTION(getuid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::geteuid());
}

// getsid()
// Returns the process group id
static CLEVER_FUNCTION(getsid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::getsid(0));
}

// info()
// Returns information about the build and environment
static CLEVER_FUNCTION(info)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	::std::ostringstream oss;
	oss << "Version: " << CLEVER_VERSION_STRING << "\n";
	oss << "Debug Mode: " << (CLEVER_DEBUG ? "Yes" : "No") << "\n";
	oss << "OS: ";
#ifdef CLEVER_WIN32
	oss << "Windows";
# ifdef CLEVER_CYGWIN
	oss << " (Cygwin)";
# elif CLEVER_MSVC
	oss << " (MSVC)";
# endif
#elif CLEVER_APPLE
	oss << "Mac OSX";
#elif CLEVER_HAIKU
	oss << "Haiku";
#else
	oss << "Unknown";
#endif
	oss << "\n\n";

	oss << "Integer Size: " << sizeof(long) * 8 << " bits (" << sizeof(long)
		<< " bytes)";

	// TODO(muriloadriano): Add more and more detailed information about the
	// environment and the enabled modules.

	return result->setStr(new StrObject(oss.str()));
}

} // clever::modules::std::sys

// Initializes Standard module
CLEVER_MODULE_INIT(SYSModule)
{
	addFunction(new Function("system",    &CLEVER_NS_FNAME(sys, system)));
	addFunction(new Function("putenv",    &CLEVER_NS_FNAME(sys, putenv)));
	addFunction(new Function("getenv",    &CLEVER_NS_FNAME(sys, getenv)));
	addFunction(new Function("getcwd",    &CLEVER_NS_FNAME(sys, getcwd)));
	addFunction(new Function("getpid",    &CLEVER_NS_FNAME(sys, getpid)));
	addFunction(new Function("getppid",   &CLEVER_NS_FNAME(sys, getppid)));
	addFunction(new Function("getuid",    &CLEVER_NS_FNAME(sys, getuid)));
	addFunction(new Function("getsid",    &CLEVER_NS_FNAME(sys, getsid)));
	addFunction(new Function("argc",      &CLEVER_NS_FNAME(sys, argc)));
	addFunction(new Function("argv",      &CLEVER_NS_FNAME(sys, argv)));
	addFunction(new Function("sleep",     &CLEVER_NS_FNAME(sys, sleep)));
	addFunction(new Function("clock",     &CLEVER_NS_FNAME(sys, clock)));
	addFunction(new Function("time",      &CLEVER_NS_FNAME(sys, time)));
	addFunction(new Function("microtime", &CLEVER_NS_FNAME(sys, microtime)));
	addFunction(new Function("info",      &CLEVER_NS_FNAME(sys, info)));
}

}}} // clever::modules::std
<commit_msg>Testing preprocessor macro with #if<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <cstdlib>
#include <sstream>

#ifdef CLEVER_WIN32
# include <direct.h>
# include <windows.h>
# define PATH_MAX MAX_PATH
#else
# include <dirent.h>
# include <sys/resource.h>
# include <sys/time.h>
# include <unistd.h>
#endif
#include "core/clever.h"
#include "core/value.h"
#include "core/driver.h"
#include "core/native_types.h"
#include "core/modmanager.h"
#include "core/cexception.h"
#include "modules/std/sys/sys.h"

#ifndef PATH_MAX
# define PATH_MAX 1024
#endif

namespace clever { namespace modules { namespace std {

namespace sys {

// system(string command)
// Calls a command and returns the exit code
static CLEVER_FUNCTION(system)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	result->setInt(::system(args[0]->getStr()->c_str()));
}

// putenv(string env)
// Sets an environment variable
static CLEVER_FUNCTION(putenv)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	::putenv(const_cast<char*>(args[0]->getStr()->c_str()));
}

// getenv(string env)
// Gets an environment variable
static CLEVER_FUNCTION(getenv)
{
	if (!clever_static_check_args("s")) {
		return;
	}

	const char* ret = ::getenv(const_cast<char*>(args[0]->getStr()->c_str()));

	if (ret) {
		result->setStr(CSTRINGT(ret));
	} else {
		result->setStr(CSTRING(""));
	}
}

// getcwd()
// Gets the current working directory
static CLEVER_FUNCTION(getcwd)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	char temp[PATH_MAX];
	const char* path = ::getcwd(temp, PATH_MAX);

	result->setStr(CSTRING(path ? path : ""));
}

// argv(int n)
// Get n-th argv value
static CLEVER_FUNCTION(argv)
{
	if (!clever_static_check_args("i")) {
		return;
	}

	if (args[0]->getInt() >= *g_clever_argc) {
		result->setBool(false);
	} else {
		result->setStr(new StrObject((*g_clever_argv)[args[0]->getInt()]));
	}
}

// argc()
// Get argc value
static CLEVER_FUNCTION(argc)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(*g_clever_argc);
}

// sleep(int time)
// Sleep for 'time' milliseconds
static CLEVER_FUNCTION(sleep)
{
	if (!clever_static_check_args("i")) {
		return;
	}

	int time = static_cast<int>(args[0]->getInt());

#ifdef CLEVER_WIN32
	SleepEx(time, false);
#else
	usleep(time * 1000);
#endif
}

// clock()
// Returns the execution clock
static CLEVER_FUNCTION(clock)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(clock());
}

// time()
// Returns the execution time in sec
static CLEVER_FUNCTION(time)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	struct timeval tp = {0};
	if (gettimeofday(&tp, NULL)) {
		result->setBool(false);
		return;
	}
	result->setDouble(tp.tv_sec);
}

// microtime()
// Returns the unix timestamp with microseconds
static CLEVER_FUNCTION(microtime)
{
	struct timeval tp = {0};

	if (!clever_static_check_no_args()) {
		return;
	}
	if (gettimeofday(&tp, NULL)) {
		result->setBool(false);
		return;
	}

	result->setDouble(tp.tv_sec + tp.tv_usec / 1000000.00);
}

// getpid()
// Returns the current process id
static CLEVER_FUNCTION(getpid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::getpid());
}

// getppid()
// Returns the current process id
static CLEVER_FUNCTION(getppid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::getppid());
}

// getuid()
// Returns the process user id
static CLEVER_FUNCTION(getuid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::geteuid());
}

// getsid()
// Returns the process group id
static CLEVER_FUNCTION(getsid)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	result->setInt(::getsid(0));
}

// info()
// Returns information about the build and environment
static CLEVER_FUNCTION(info)
{
	if (!clever_static_check_no_args()) {
		return;
	}

	::std::ostringstream oss;
	oss << "Version: " << CLEVER_VERSION_STRING << "\n";
	oss << "Debug Mode: ";
#ifdef CLEVER_DEBUG
	oss << "Yes\n";
#else
	oss << "No";
#endif

	oss << "OS: ";
#ifdef CLEVER_WIN32
	oss << "Windows";
# ifdef CLEVER_CYGWIN
	oss << " (Cygwin)";
# elif CLEVER_MSVC
	oss << " (MSVC)";
# endif
#elif CLEVER_APPLE
	oss << "Mac OSX";
#elif CLEVER_HAIKU
	oss << "Haiku";
#else
	oss << "Unknown";
#endif
	oss << "\n\n";

	oss << "Integer Size: " << sizeof(long) * 8 << " bits (" << sizeof(long)
		<< " bytes)";

	// TODO(muriloadriano): Add more and more detailed information about the
	// environment and the enabled modules.

	return result->setStr(new StrObject(oss.str()));
}

} // clever::modules::std::sys

// Initializes Standard module
CLEVER_MODULE_INIT(SYSModule)
{
	addFunction(new Function("system",    &CLEVER_NS_FNAME(sys, system)));
	addFunction(new Function("putenv",    &CLEVER_NS_FNAME(sys, putenv)));
	addFunction(new Function("getenv",    &CLEVER_NS_FNAME(sys, getenv)));
	addFunction(new Function("getcwd",    &CLEVER_NS_FNAME(sys, getcwd)));
	addFunction(new Function("getpid",    &CLEVER_NS_FNAME(sys, getpid)));
	addFunction(new Function("getppid",   &CLEVER_NS_FNAME(sys, getppid)));
	addFunction(new Function("getuid",    &CLEVER_NS_FNAME(sys, getuid)));
	addFunction(new Function("getsid",    &CLEVER_NS_FNAME(sys, getsid)));
	addFunction(new Function("argc",      &CLEVER_NS_FNAME(sys, argc)));
	addFunction(new Function("argv",      &CLEVER_NS_FNAME(sys, argv)));
	addFunction(new Function("sleep",     &CLEVER_NS_FNAME(sys, sleep)));
	addFunction(new Function("clock",     &CLEVER_NS_FNAME(sys, clock)));
	addFunction(new Function("time",      &CLEVER_NS_FNAME(sys, time)));
	addFunction(new Function("microtime", &CLEVER_NS_FNAME(sys, microtime)));
	addFunction(new Function("info",      &CLEVER_NS_FNAME(sys, info)));
}

}}} // clever::modules::std
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "ScrollbarThemeWin.h"

#include "GraphicsContext.h"
#include "PlatformMouseEvent.h"
#include "Scrollbar.h"
#include "SoftLinking.h"

// Generic state constants
#define TS_NORMAL    1
#define TS_HOVER     2
#define TS_ACTIVE    3
#define TS_DISABLED  4

#define SP_BUTTON          1
#define SP_THUMBHOR        2
#define SP_THUMBVERT       3
#define SP_TRACKSTARTHOR   4
#define SP_TRACKENDHOR     5
#define SP_TRACKSTARTVERT  6
#define SP_TRACKENDVERT    7
#define SP_GRIPPERHOR      8
#define SP_GRIPPERVERT     9

#define TS_UP_BUTTON       0
#define TS_DOWN_BUTTON     4
#define TS_LEFT_BUTTON     8
#define TS_RIGHT_BUTTON    12
#define TS_UP_BUTTON_HOVER   17
#define TS_DOWN_BUTTON_HOVER  18
#define TS_LEFT_BUTTON_HOVER  19
#define TS_RIGHT_BUTTON_HOVER   20

using namespace std;

namespace WebCore {

static HANDLE scrollbarTheme;
static bool haveTheme;
static bool runningVista;

// FIXME:  Refactor the soft-linking code so that it can be shared with RenderThemeWin
SOFT_LINK_LIBRARY(uxtheme)
SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))

static bool isRunningOnVistaOrLater()
{
    static bool os = false;
    static bool initialized = false;
    if (!initialized) {
        OSVERSIONINFOEX vi = {sizeof(vi), 0};
        GetVersionEx((OSVERSIONINFO*)&vi);

        // NOTE: This does not work under a debugger - Vista shims Visual Studio,
        // making it believe it is xpsp2, which is inherited by debugged applications
        os = vi.dwMajorVersion >= 6;
        initialized = true;
    }
    return os;
}

static void checkAndInitScrollbarTheme()
{
    if (uxthemeLibrary() && !scrollbarTheme)
        scrollbarTheme = OpenThemeData(0, L"Scrollbar");
    haveTheme = scrollbarTheme && IsThemeActive();
}

#if !USE(SAFARI_THEME)
ScrollbarTheme* ScrollbarTheme::nativeTheme()
{
    static SafariThemeWin winTheme;
    return &winTheme;
}
#endif

ScrollbarThemeWin::ScrollbarThemeWin()
{
    static bool initialized;
    if (!initialized) {
        initialized = true;
        checkAndInitScrollbarTheme();
        runningVista = isRunningOnVistaOrLater();
    }
}

ScrollbarThemeWin::~ScrollbarThemeWin()
{
}

int ScrollbarThemeWin::scrollbarThickness(ScrollbarControlSize)
{
    static int thickness;
    if (!thickness)
        thickness = ::GetSystemMetrics(SM_CXVSCROLL);
    return thickness;
}

void ScrollbarThemeWin::themeChanged()
{
    if (haveTheme)
        CloseThemeData(scrollbarTheme);
}

bool ScrollbarThemeWin::invalidateOnMouseEnterExit()
{
    return runningVista;
}

bool ScrollbarThemeWin::hasThumb(Scrollbar* scrollbar)
{
    return thumbLength(scrollbar) > 0;
}

IntRect ScrollbarThemeWin::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
{
    // Windows just has single arrows.
    if (part == BackButtonEndPart)
        return IntRect();

    // Our desired rect is essentially 17x17.

    // Our actual rect will shrink to half the available space when
    // we have < 34 pixels left.  This allows the scrollbar
    // to scale down and function even at tiny sizes.
    int thickness = scrollbarThickness();
    if (scrollbar->orientation() == HorizontalScrollbar)
        return IntRect(scrollbar->x(), scrollbar->y(),
                       scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness, thickness);
    return IntRect(scrollbar->x(), scrollbar->y(),
                   thickness, scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness);
}

IntRect ScrollbarThemeWin::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
{
    // Windows just has single arrows.
    if (part == ForwardButtonStartPart)
        return IntRect();

    // Our desired rect is essentially 17x17.

    // Our actual rect will shrink to half the available space when
    // we have < 34 pixels left.  This allows the scrollbar
    // to scale down and function even at tiny sizes.
    int thickness = scrollbarThickness();
    if (scrollbar->orientation() == HorizontalScrollbar) {
        int w = scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness;
        return IntRect(scrollbar->x() + scrollbar->width() - w, scrollbar->y(), w, thickness);
    }

    int h = scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness;
    return IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - h, thickness, h);
}

IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool)
{
    int thickness = scrollbarThickness();
    if (scrollbar->orientation() == HorizontalScrollbar) {
        if (scrollbar->width() < 2 * thickness)
            return IntRect();
        return IntRect(scrollbar->x() + thickness, scrollbar->y(), scrollbar->width() - 2 * thickness, thickness);
    }
    if (scrollbar->height() < 2 * thickness)
        return IntRect();
    return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness);
}

void ScrollbarThemeWin::paintTrack(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarControlPartMask mask)
{
    checkAndInitScrollbarTheme();

    bool start = mask & BackTrackPart;
    int part;
    if (scrollbar->orientation() == HorizontalScrollbar)
        part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
    else
        part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;

    int state;
    if (!scrollbar->enabled())
        state = TS_DISABLED;
    else if ((scrollbar->hoveredPart() == BackTrackPart && start) ||
             (scrollbar->hoveredPart() == ForwardTrackPart && !start))
        state = (scrollbar->pressedPart() == scrollbar->hoveredPart() ? TS_ACTIVE : TS_HOVER);
    else
        state = TS_NORMAL;

    bool alphaBlend = false;
    if (scrollbarTheme)
        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, part, state);
    HDC hdc = context->getWindowsContext(rect, alphaBlend);
    RECT themeRect(rect);
    if (scrollbarTheme)
        DrawThemeBackground(scrollbarTheme, hdc, part, state, &themeRect, 0);
    else {
        DWORD color3DFace = ::GetSysColor(COLOR_3DFACE);
        DWORD colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);
        DWORD colorWindow = ::GetSysColor(COLOR_WINDOW);
        if ((color3DFace != colorScrollbar) && (colorWindow != colorScrollbar))
            ::FillRect(hdc, &themeRect, HBRUSH(COLOR_SCROLLBAR+1));
        else {
            static WORD patternBits[8] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
            HBITMAP patternBitmap = ::CreateBitmap(8, 8, 1, 1, patternBits);
            HBRUSH brush = ::CreatePatternBrush(patternBitmap);
            SaveDC(hdc);
            ::SetTextColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
            ::SetBkColor(hdc, ::GetSysColor(COLOR_3DFACE));
            ::SetBrushOrgEx(hdc, rect.x(), rect.y(), NULL);
            ::SelectObject(hdc, brush);
            ::FillRect(hdc, &themeRect, brush);
            ::RestoreDC(hdc, -1);
            ::DeleteObject(brush);
            ::DeleteObject(patternBitmap);
        }
    }
    context->releaseWindowsContext(hdc, rect, alphaBlend);
}

void ScrollbarThemeWin::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
{
    checkAndInitScrollbarTheme();

    bool start = (part == BackButtonStartPart);
    int xpState = 0;
    int classicState = 0;
    if (scrollbar->orientation() == HorizontalScrollbar)
        xpState = start ? TS_LEFT_BUTTON : TS_RIGHT_BUTTON;
    else
        xpState = start ? TS_UP_BUTTON : TS_DOWN_BUTTON;
    classicState = xpState / 4;

    if (!scrollbar->enabled()) {
        xpState += TS_DISABLED;
        classicState |= DFCS_INACTIVE;
    } else if ((scrollbar->hoveredPart() == BackButtonPart && start) ||
               (scrollbar->hoveredPart() == ForwardButtonPart && !start)) {
        if (scrollbar->pressedPart() == scrollbar->hoveredPart()) {
            xpState += TS_ACTIVE;
            classicState |= DFCS_PUSHED | DFCS_FLAT;
        } else
            xpState += TS_HOVER;
    } else {
        if (scrollbar->hoveredPart() == NoPart || !runningVista)
            xpState += TS_NORMAL;
        else {
            if (scrollbar->orientation() == HorizontalScrollbar)
                xpState = start ? TS_LEFT_BUTTON_HOVER : TS_RIGHT_BUTTON_HOVER;
            else
                xpState = start ? TS_UP_BUTTON_HOVER : TS_DOWN_BUTTON_HOVER;
        }
    }

    bool alphaBlend = false;
    if (scrollbarTheme)
        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, SP_BUTTON, xpState);
    HDC hdc = context->getWindowsContext(rect, alphaBlend);

    RECT themeRect(rect);
    if (scrollbarTheme)
        DrawThemeBackground(scrollbarTheme, hdc, SP_BUTTON, xpState, &themeRect, 0);
    else
        ::DrawFrameControl(hdc, &themeRect, DFC_SCROLL, classicState);
    context->releaseWindowsContext(hdc, rect, alphaBlend);
}

static IntRect gripperRect(int thickness, const IntRect& thumbRect)
{
    // Center in the thumb.
    int gripperThickness = thickness / 2;
    return IntRect(thumbRect.x() + (thumbRect.width() - gripperThickness) / 2,
                   thumbRect.y() + (thumbRect.height() - gripperThickness) / 2,
                   gripperThickness, gripperThickness);
}

static void paintGripper(Scrollbar* scrollbar, HDC hdc, const IntRect& rect)
{
    if (!scrollbarTheme)
        return;  // Classic look has no gripper.

    int state;
    if (!scrollbar->enabled())
        state = TS_DISABLED;
    else if (scrollbar->pressedPart() == ThumbPart)
        state = TS_ACTIVE; // Thumb always stays active once pressed.
    else if (scrollbar->hoveredPart() == ThumbPart)
        state = TS_HOVER;
    else
        state = TS_NORMAL;

    RECT themeRect(rect);
    DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_GRIPPERHOR : SP_GRIPPERVERT, state, &themeRect, 0);
}

void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
{
    checkAndInitScrollbarTheme();

    int state;
    if (!scrollbar->enabled())
        state = TS_DISABLED;
    else if (scrollbar->pressedPart() == ThumbPart)
        state = TS_ACTIVE; // Thumb always stays active once pressed.
    else if (scrollbar->hoveredPart() == ThumbPart)
        state = TS_HOVER;
    else
        state = TS_NORMAL;

    bool alphaBlend = false;
    if (scrollbarTheme)
        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state);
    HDC hdc = context->getWindowsContext(rect, alphaBlend);
    RECT themeRect(rect);
    if (scrollbarTheme) {
        DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state, &themeRect, 0);
        paintGripper(scrollbar, hdc, gripperRect(scrollbarThickness(), rect));
    } else
        ::DrawEdge(hdc, &themeRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
    context->releaseWindowsContext(hdc, rect, alphaBlend);
}

bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
{
    return evt.shiftKey() && evt.button() == LeftButton;
}

}

<commit_msg>Fix build bustage.<commit_after>/*
 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "ScrollbarThemeWin.h"

#include "GraphicsContext.h"
#include "PlatformMouseEvent.h"
#include "Scrollbar.h"
#include "SoftLinking.h"

// Generic state constants
#define TS_NORMAL    1
#define TS_HOVER     2
#define TS_ACTIVE    3
#define TS_DISABLED  4

#define SP_BUTTON          1
#define SP_THUMBHOR        2
#define SP_THUMBVERT       3
#define SP_TRACKSTARTHOR   4
#define SP_TRACKENDHOR     5
#define SP_TRACKSTARTVERT  6
#define SP_TRACKENDVERT    7
#define SP_GRIPPERHOR      8
#define SP_GRIPPERVERT     9

#define TS_UP_BUTTON       0
#define TS_DOWN_BUTTON     4
#define TS_LEFT_BUTTON     8
#define TS_RIGHT_BUTTON    12
#define TS_UP_BUTTON_HOVER   17
#define TS_DOWN_BUTTON_HOVER  18
#define TS_LEFT_BUTTON_HOVER  19
#define TS_RIGHT_BUTTON_HOVER   20

using namespace std;

namespace WebCore {

static HANDLE scrollbarTheme;
static bool haveTheme;
static bool runningVista;

// FIXME:  Refactor the soft-linking code so that it can be shared with RenderThemeWin
SOFT_LINK_LIBRARY(uxtheme)
SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))

static bool isRunningOnVistaOrLater()
{
    static bool os = false;
    static bool initialized = false;
    if (!initialized) {
        OSVERSIONINFOEX vi = {sizeof(vi), 0};
        GetVersionEx((OSVERSIONINFO*)&vi);

        // NOTE: This does not work under a debugger - Vista shims Visual Studio,
        // making it believe it is xpsp2, which is inherited by debugged applications
        os = vi.dwMajorVersion >= 6;
        initialized = true;
    }
    return os;
}

static void checkAndInitScrollbarTheme()
{
    if (uxthemeLibrary() && !scrollbarTheme)
        scrollbarTheme = OpenThemeData(0, L"Scrollbar");
    haveTheme = scrollbarTheme && IsThemeActive();
}

#if !USE(SAFARI_THEME)
ScrollbarTheme* ScrollbarTheme::nativeTheme()
{
    static SafariThemeWin winTheme;
    return &winTheme;
}
#endif

ScrollbarThemeWin::ScrollbarThemeWin()
{
    static bool initialized;
    if (!initialized) {
        initialized = true;
        checkAndInitScrollbarTheme();
        runningVista = isRunningOnVistaOrLater();
    }
}

ScrollbarThemeWin::~ScrollbarThemeWin()
{
}

int ScrollbarThemeWin::scrollbarThickness(ScrollbarControlSize)
{
    static int thickness;
    if (!thickness)
        thickness = ::GetSystemMetrics(SM_CXVSCROLL);
    return thickness;
}

void ScrollbarThemeWin::themeChanged()
{
    if (haveTheme)
        CloseThemeData(scrollbarTheme);
}

bool ScrollbarThemeWin::invalidateOnMouseEnterExit()
{
    return runningVista;
}

bool ScrollbarThemeWin::hasThumb(Scrollbar* scrollbar)
{
    return thumbLength(scrollbar) > 0;
}

IntRect ScrollbarThemeWin::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
{
    // Windows just has single arrows.
    if (part == BackButtonEndPart)
        return IntRect();

    // Our desired rect is essentially 17x17.

    // Our actual rect will shrink to half the available space when
    // we have < 34 pixels left.  This allows the scrollbar
    // to scale down and function even at tiny sizes.
    int thickness = scrollbarThickness();
    if (scrollbar->orientation() == HorizontalScrollbar)
        return IntRect(scrollbar->x(), scrollbar->y(),
                       scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness, thickness);
    return IntRect(scrollbar->x(), scrollbar->y(),
                   thickness, scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness);
}

IntRect ScrollbarThemeWin::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
{
    // Windows just has single arrows.
    if (part == ForwardButtonStartPart)
        return IntRect();

    // Our desired rect is essentially 17x17.

    // Our actual rect will shrink to half the available space when
    // we have < 34 pixels left.  This allows the scrollbar
    // to scale down and function even at tiny sizes.
    int thickness = scrollbarThickness();
    if (scrollbar->orientation() == HorizontalScrollbar) {
        int w = scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness;
        return IntRect(scrollbar->x() + scrollbar->width() - w, scrollbar->y(), w, thickness);
    }

    int h = scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness;
    return IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - h, thickness, h);
}

IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool)
{
    int thickness = scrollbarThickness();
    if (scrollbar->orientation() == HorizontalScrollbar) {
        if (scrollbar->width() < 2 * thickness)
            return IntRect();
        return IntRect(scrollbar->x() + thickness, scrollbar->y(), scrollbar->width() - 2 * thickness, thickness);
    }
    if (scrollbar->height() < 2 * thickness)
        return IntRect();
    return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness);
}

void ScrollbarThemeWin::paintTrack(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarControlPartMask mask)
{
    checkAndInitScrollbarTheme();

    bool start = mask & BackTrackPart;
    int part;
    if (scrollbar->orientation() == HorizontalScrollbar)
        part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
    else
        part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;

    int state;
    if (!scrollbar->enabled())
        state = TS_DISABLED;
    else if ((scrollbar->hoveredPart() == BackTrackPart && start) ||
             (scrollbar->hoveredPart() == ForwardTrackPart && !start))
        state = (scrollbar->pressedPart() == scrollbar->hoveredPart() ? TS_ACTIVE : TS_HOVER);
    else
        state = TS_NORMAL;

    bool alphaBlend = false;
    if (scrollbarTheme)
        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, part, state);
    HDC hdc = context->getWindowsContext(rect, alphaBlend);
    RECT themeRect(rect);
    if (scrollbarTheme)
        DrawThemeBackground(scrollbarTheme, hdc, part, state, &themeRect, 0);
    else {
        DWORD color3DFace = ::GetSysColor(COLOR_3DFACE);
        DWORD colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);
        DWORD colorWindow = ::GetSysColor(COLOR_WINDOW);
        if ((color3DFace != colorScrollbar) && (colorWindow != colorScrollbar))
            ::FillRect(hdc, &themeRect, HBRUSH(COLOR_SCROLLBAR+1));
        else {
            static WORD patternBits[8] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
            HBITMAP patternBitmap = ::CreateBitmap(8, 8, 1, 1, patternBits);
            HBRUSH brush = ::CreatePatternBrush(patternBitmap);
            SaveDC(hdc);
            ::SetTextColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
            ::SetBkColor(hdc, ::GetSysColor(COLOR_3DFACE));
            ::SetBrushOrgEx(hdc, rect.x(), rect.y(), NULL);
            ::SelectObject(hdc, brush);
            ::FillRect(hdc, &themeRect, brush);
            ::RestoreDC(hdc, -1);
            ::DeleteObject(brush);
            ::DeleteObject(patternBitmap);
        }
    }
    context->releaseWindowsContext(hdc, rect, alphaBlend);
}

void ScrollbarThemeWin::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
{
    checkAndInitScrollbarTheme();

    bool start = (part == BackButtonStartPart);
    int xpState = 0;
    int classicState = 0;
    if (scrollbar->orientation() == HorizontalScrollbar)
        xpState = start ? TS_LEFT_BUTTON : TS_RIGHT_BUTTON;
    else
        xpState = start ? TS_UP_BUTTON : TS_DOWN_BUTTON;
    classicState = xpState / 4;

    if (!scrollbar->enabled()) {
        xpState += TS_DISABLED;
        classicState |= DFCS_INACTIVE;
    } else if ((scrollbar->hoveredPart() == BackButtonStartPart && start) ||
               (scrollbar->hoveredPart() == ForwardButtonEndPart && !start)) {
        if (scrollbar->pressedPart() == scrollbar->hoveredPart()) {
            xpState += TS_ACTIVE;
            classicState |= DFCS_PUSHED | DFCS_FLAT;
        } else
            xpState += TS_HOVER;
    } else {
        if (scrollbar->hoveredPart() == NoPart || !runningVista)
            xpState += TS_NORMAL;
        else {
            if (scrollbar->orientation() == HorizontalScrollbar)
                xpState = start ? TS_LEFT_BUTTON_HOVER : TS_RIGHT_BUTTON_HOVER;
            else
                xpState = start ? TS_UP_BUTTON_HOVER : TS_DOWN_BUTTON_HOVER;
        }
    }

    bool alphaBlend = false;
    if (scrollbarTheme)
        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, SP_BUTTON, xpState);
    HDC hdc = context->getWindowsContext(rect, alphaBlend);

    RECT themeRect(rect);
    if (scrollbarTheme)
        DrawThemeBackground(scrollbarTheme, hdc, SP_BUTTON, xpState, &themeRect, 0);
    else
        ::DrawFrameControl(hdc, &themeRect, DFC_SCROLL, classicState);
    context->releaseWindowsContext(hdc, rect, alphaBlend);
}

static IntRect gripperRect(int thickness, const IntRect& thumbRect)
{
    // Center in the thumb.
    int gripperThickness = thickness / 2;
    return IntRect(thumbRect.x() + (thumbRect.width() - gripperThickness) / 2,
                   thumbRect.y() + (thumbRect.height() - gripperThickness) / 2,
                   gripperThickness, gripperThickness);
}

static void paintGripper(Scrollbar* scrollbar, HDC hdc, const IntRect& rect)
{
    if (!scrollbarTheme)
        return;  // Classic look has no gripper.

    int state;
    if (!scrollbar->enabled())
        state = TS_DISABLED;
    else if (scrollbar->pressedPart() == ThumbPart)
        state = TS_ACTIVE; // Thumb always stays active once pressed.
    else if (scrollbar->hoveredPart() == ThumbPart)
        state = TS_HOVER;
    else
        state = TS_NORMAL;

    RECT themeRect(rect);
    DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_GRIPPERHOR : SP_GRIPPERVERT, state, &themeRect, 0);
}

void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
{
    checkAndInitScrollbarTheme();

    int state;
    if (!scrollbar->enabled())
        state = TS_DISABLED;
    else if (scrollbar->pressedPart() == ThumbPart)
        state = TS_ACTIVE; // Thumb always stays active once pressed.
    else if (scrollbar->hoveredPart() == ThumbPart)
        state = TS_HOVER;
    else
        state = TS_NORMAL;

    bool alphaBlend = false;
    if (scrollbarTheme)
        alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state);
    HDC hdc = context->getWindowsContext(rect, alphaBlend);
    RECT themeRect(rect);
    if (scrollbarTheme) {
        DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state, &themeRect, 0);
        paintGripper(scrollbar, hdc, gripperRect(scrollbarThickness(), rect));
    } else
        ::DrawEdge(hdc, &themeRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
    context->releaseWindowsContext(hdc, rect, alphaBlend);
}

bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
{
    return evt.shiftKey() && evt.button() == LeftButton;
}

}

<|endoftext|>


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

#ifndef TOOLKIT_INC_TOOLKIT_HELPER_SOLARRELEASE_HXX
#define TOOLKIT_INC_TOOLKIT_HELPER_SOLARRELEASE_HXX

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

//........................................................................
namespace toolkit
{
//........................................................................

    //====================================================================
    //= ReleaseSolarMutex
    //====================================================================
    class ReleaseSolarMutex
    {
        sal_uInt32  mnLockCount;
    public:
        ReleaseSolarMutex()
        {
            mnLockCount = Application::ReleaseSolarMutex();
        }

        ~ReleaseSolarMutex()
        {
            Application::AcquireSolarMutex( mnLockCount );
        }
    };

//........................................................................
} // namespace toolkit
//........................................................................

#endif // TOOLKIT_INC_TOOLKIT_HELPER_SOLARRELEASE_HXX

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.30); FILE MERGED 2005/09/05 16:57:50 rt 1.2.30.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: solarrelease.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 12:58:09 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef TOOLKIT_INC_TOOLKIT_HELPER_SOLARRELEASE_HXX
#define TOOLKIT_INC_TOOLKIT_HELPER_SOLARRELEASE_HXX

#ifndef _SV_SVAPP_HXX
#include <vcl/svapp.hxx>
#endif

//........................................................................
namespace toolkit
{
//........................................................................

    //====================================================================
    //= ReleaseSolarMutex
    //====================================================================
    class ReleaseSolarMutex
    {
        sal_uInt32  mnLockCount;
    public:
        ReleaseSolarMutex()
        {
            mnLockCount = Application::ReleaseSolarMutex();
        }

        ~ReleaseSolarMutex()
        {
            Application::AcquireSolarMutex( mnLockCount );
        }
    };

//........................................................................
} // namespace toolkit
//........................................................................

#endif // TOOLKIT_INC_TOOLKIT_HELPER_SOLARRELEASE_HXX

<|endoftext|>


<commit_before>#include <QScopedPointer>

#include <QtTest/QtTest>
#include "amqp_testcase.h"

#include "amqp_client.h"
#include "amqp_queue.h"
#include "amqp_exchange.h"

using namespace QAMQP;
class tst_QAMQPQueue : public TestCase
{
    Q_OBJECT
private Q_SLOTS:
    void init();
    void cleanup();

    void defaultExchange();
    void standardExchanges_data();
    void standardExchanges();
    void invalidDeclaration_data();
    void invalidDeclaration();
    void invalidBind();
    void unnamed();
    void exclusiveAccess();
    void exclusiveRemoval();
    void notFound();
    void remove();
    void removeIfUnused();
    void removeIfEmpty();
    void unbind();
    void purge();
    void canOnlyStartConsumingOnce();
    void cancel();
    void invalidCancelBecauseNotConsuming();
    void invalidCancelBecauseInvalidConsumerTag();
    void getEmpty();

private:
    void declareQueueAndVerifyConsuming(Queue *queue);
    QScopedPointer<Client> client;

};

void tst_QAMQPQueue::declareQueueAndVerifyConsuming(Queue *queue)
{
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    QVERIFY(queue->consume());
    QSignalSpy spy(queue, SIGNAL(consuming(QString)));
    QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString))));
    QVERIFY(queue->isConsuming());
    QVERIFY(!spy.isEmpty());
    QList<QVariant> arguments = spy.takeFirst();
    QCOMPARE(arguments.at(0).toString(), queue->consumerTag());
}

void tst_QAMQPQueue::init()
{
    client.reset(new Client);
    client->connectToHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}

void tst_QAMQPQueue::cleanup()
{
    if (client->isConnected()) {
        client->disconnectFromHost();
        QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
    }
}

void tst_QAMQPQueue::defaultExchange()
{
    Queue *queue = client->createQueue("test-default-exchange");
    declareQueueAndVerifyConsuming(queue);

    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("first message", "test-default-exchange");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    Message message = queue->dequeue();
    QCOMPARE(message.payload(), QByteArray("first message"));
}

void tst_QAMQPQueue::standardExchanges_data()
{
    QTest::addColumn<QString>("exchange");
    QTest::newRow("amq.direct") << "amq.direct";
    QTest::newRow("amq.fanout") << "amq.fanout";
    QTest::newRow("amq.headers") << "amq.headers";
    QTest::newRow("amq.match") << "amq.match";
    QTest::newRow("amq.topic") << "amq.topic";
}

void tst_QAMQPQueue::standardExchanges()
{
    QFETCH(QString, exchange);

    QString queueName = QString("test-%1").arg(exchange);
    QString routingKey = QString("testRoutingKey-%1").arg(exchange);

    Queue *queue = client->createQueue(queueName);
    declareQueueAndVerifyConsuming(queue);

    queue->bind(exchange, routingKey);
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));

    Exchange *defaultExchange = client->createExchange(exchange);
    defaultExchange->publish("test message", routingKey);
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    QCOMPARE(queue->dequeue().payload(), QByteArray("test message"));
}

void tst_QAMQPQueue::invalidDeclaration_data()
{
    QTest::addColumn<QString>("queueName");
    QTest::addColumn<QAMQP::Error>("error");

    QTest::newRow("amq.direct") << "amq.direct" <<  QAMQP::AccessRefusedError;
    QTest::newRow("amq.fanout") << "amq.fanout" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.headers") << "amq.headers" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.match") << "amq.match" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.topic") << "amq.topic" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.reserved") << "amq.reserved" << QAMQP::AccessRefusedError;
}

void tst_QAMQPQueue::invalidDeclaration()
{
    QFETCH(QString, queueName);
    QFETCH(QAMQP::Error, error);

    Queue *queue = client->createQueue(queueName);
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), error);
}

void tst_QAMQPQueue::invalidBind()
{
    Queue *queue = client->createQueue("test-invalid-bind");
    declareQueueAndVerifyConsuming(queue);

    queue->bind("non-existant-exchange", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), QAMQP::NotFoundError);
}

void tst_QAMQPQueue::unnamed()
{
    Queue *queue = client->createQueue();
    declareQueueAndVerifyConsuming(queue);
    QVERIFY(!queue->name().isEmpty());
}

void tst_QAMQPQueue::exclusiveAccess()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));

    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(passiveQueue->error(), QAMQP::ResourceLockedError);

    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::exclusiveRemoval()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    client.data()->disconnectFromHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));

    // create a new client and try to access the queue that should
    // no longer exist
    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(passiveQueue->error(), QAMQP::NotFoundError);
    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::notFound()
{
    Queue *queue = client->createQueue("test-not-found");
    queue->declare(Queue::Passive);
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), QAMQP::NotFoundError);
}

void tst_QAMQPQueue::remove()
{
    Queue *queue = client->createQueue("test-remove");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->remove(Queue::roIfEmpty|Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::removeIfUnused()
{
    Queue *queue = client->createQueue("test-remove-if-unused");
    declareQueueAndVerifyConsuming(queue);

    queue->remove(Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), QAMQP::PreconditionFailedError);
    QVERIFY(!queue->errorString().isEmpty());
}

void tst_QAMQPQueue::removeIfEmpty()
{
    // declare the queue and send messages to it
    Queue *queue = client->createQueue("test-remove-if-empty");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("first message", "test-remove-if-empty");

    // create a second client and try to delete the queue
    {
        Client secondClient;
        secondClient.connectToHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
        Queue *testDeleteQueue = secondClient.createQueue("test-remove-if-empty");
        testDeleteQueue->declare(Queue::Passive);
        QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(declared())));

        testDeleteQueue->remove(Queue::roIfEmpty);
        QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(error(QAMQP::Error))));
        QCOMPARE(testDeleteQueue->error(), QAMQP::PreconditionFailedError);
        QVERIFY(!testDeleteQueue->errorString().isEmpty());

        secondClient.disconnectFromHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
    }

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::unbind()
{
    Queue *queue = client->createQueue("test-unbind");
    declareQueueAndVerifyConsuming(queue);

    queue->bind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));
    queue->unbind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
}

void tst_QAMQPQueue::purge()
{
    Queue *queue = client->createQueue("test-purge");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("first message", "test-purge");
    defaultExchange->publish("second message", "test-purge");
    defaultExchange->publish("third message", "test-purge");

    // create second client to listen to messages and attempt purge
    {
        Client secondClient;
        secondClient.connectToHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
        Queue *testPurgeQueue = secondClient.createQueue("test-purge");
        testPurgeQueue->declare(Queue::Passive);
        QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(declared())));

        QSignalSpy spy(testPurgeQueue, SIGNAL(purged(int)));
        testPurgeQueue->purge();
        QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(purged(int))));
        QCOMPARE(spy.count(), 1);
        QCOMPARE(testPurgeQueue->size(), 0);
        QList<QVariant> arguments = spy.takeFirst();
        QCOMPARE(arguments.at(0).toInt(), 3);

        secondClient.disconnectFromHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
    }

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::canOnlyStartConsumingOnce()
{
    Queue *queue = client->createQueue("test-single-consumer");
    declareQueueAndVerifyConsuming(queue);
    QCOMPARE(queue->consume(), false);
}

void tst_QAMQPQueue::cancel()
{
    Queue *queue = client->createQueue("test-cancel");
    declareQueueAndVerifyConsuming(queue);

    QString consumerTag = queue->consumerTag();
    QSignalSpy cancelSpy(queue, SIGNAL(cancelled(QString)));
    QVERIFY(queue->cancel());
    QVERIFY(waitForSignal(queue, SIGNAL(cancelled(QString))));
    QVERIFY(!cancelSpy.isEmpty());
    QList<QVariant> arguments = cancelSpy.takeFirst();
    QCOMPARE(arguments.at(0).toString(), consumerTag);
}

void tst_QAMQPQueue::invalidCancelBecauseNotConsuming()
{
    Queue *queue = client->createQueue("test-invalid-cancel-because-not-consuming");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    QCOMPARE(queue->cancel(), false);

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::invalidCancelBecauseInvalidConsumerTag()
{
    Queue *queue = client->createQueue("test-invalid-cancel-because-invalid-consumer-tag");
    declareQueueAndVerifyConsuming(queue);
    queue->setConsumerTag(QString());
    QCOMPARE(queue->cancel(), false);
}

void tst_QAMQPQueue::getEmpty()
{
    Queue *queue = client->createQueue("test-get-empty");
    declareQueueAndVerifyConsuming(queue);

    queue->get();
    QVERIFY(waitForSignal(queue, SIGNAL(empty())));
}

QTEST_MAIN(tst_QAMQPQueue)
#include "tst_qamqpqueue.moc"
<commit_msg>add an auto test for synchronous get<commit_after>#include <QScopedPointer>

#include <QtTest/QtTest>
#include "amqp_testcase.h"

#include "amqp_client.h"
#include "amqp_queue.h"
#include "amqp_exchange.h"

using namespace QAMQP;
class tst_QAMQPQueue : public TestCase
{
    Q_OBJECT
private Q_SLOTS:
    void init();
    void cleanup();

    void defaultExchange();
    void standardExchanges_data();
    void standardExchanges();
    void invalidDeclaration_data();
    void invalidDeclaration();
    void invalidBind();
    void unnamed();
    void exclusiveAccess();
    void exclusiveRemoval();
    void notFound();
    void remove();
    void removeIfUnused();
    void removeIfEmpty();
    void unbind();
    void purge();
    void canOnlyStartConsumingOnce();
    void cancel();
    void invalidCancelBecauseNotConsuming();
    void invalidCancelBecauseInvalidConsumerTag();
    void getEmpty();
    void get();

private:
    void declareQueueAndVerifyConsuming(Queue *queue);
    QScopedPointer<Client> client;

};

void tst_QAMQPQueue::declareQueueAndVerifyConsuming(Queue *queue)
{
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    QVERIFY(queue->consume());
    QSignalSpy spy(queue, SIGNAL(consuming(QString)));
    QVERIFY(waitForSignal(queue, SIGNAL(consuming(QString))));
    QVERIFY(queue->isConsuming());
    QVERIFY(!spy.isEmpty());
    QList<QVariant> arguments = spy.takeFirst();
    QCOMPARE(arguments.at(0).toString(), queue->consumerTag());
}

void tst_QAMQPQueue::init()
{
    client.reset(new Client);
    client->connectToHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(connected())));
}

void tst_QAMQPQueue::cleanup()
{
    if (client->isConnected()) {
        client->disconnectFromHost();
        QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));
    }
}

void tst_QAMQPQueue::defaultExchange()
{
    Queue *queue = client->createQueue("test-default-exchange");
    declareQueueAndVerifyConsuming(queue);

    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("first message", "test-default-exchange");
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    Message message = queue->dequeue();
    QCOMPARE(message.payload(), QByteArray("first message"));
}

void tst_QAMQPQueue::standardExchanges_data()
{
    QTest::addColumn<QString>("exchange");
    QTest::newRow("amq.direct") << "amq.direct";
    QTest::newRow("amq.fanout") << "amq.fanout";
    QTest::newRow("amq.headers") << "amq.headers";
    QTest::newRow("amq.match") << "amq.match";
    QTest::newRow("amq.topic") << "amq.topic";
}

void tst_QAMQPQueue::standardExchanges()
{
    QFETCH(QString, exchange);

    QString queueName = QString("test-%1").arg(exchange);
    QString routingKey = QString("testRoutingKey-%1").arg(exchange);

    Queue *queue = client->createQueue(queueName);
    declareQueueAndVerifyConsuming(queue);

    queue->bind(exchange, routingKey);
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));

    Exchange *defaultExchange = client->createExchange(exchange);
    defaultExchange->publish("test message", routingKey);
    QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
    QCOMPARE(queue->dequeue().payload(), QByteArray("test message"));
}

void tst_QAMQPQueue::invalidDeclaration_data()
{
    QTest::addColumn<QString>("queueName");
    QTest::addColumn<QAMQP::Error>("error");

    QTest::newRow("amq.direct") << "amq.direct" <<  QAMQP::AccessRefusedError;
    QTest::newRow("amq.fanout") << "amq.fanout" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.headers") << "amq.headers" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.match") << "amq.match" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.topic") << "amq.topic" << QAMQP::AccessRefusedError;
    QTest::newRow("amq.reserved") << "amq.reserved" << QAMQP::AccessRefusedError;
}

void tst_QAMQPQueue::invalidDeclaration()
{
    QFETCH(QString, queueName);
    QFETCH(QAMQP::Error, error);

    Queue *queue = client->createQueue(queueName);
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), error);
}

void tst_QAMQPQueue::invalidBind()
{
    Queue *queue = client->createQueue("test-invalid-bind");
    declareQueueAndVerifyConsuming(queue);

    queue->bind("non-existant-exchange", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), QAMQP::NotFoundError);
}

void tst_QAMQPQueue::unnamed()
{
    Queue *queue = client->createQueue();
    declareQueueAndVerifyConsuming(queue);
    QVERIFY(!queue->name().isEmpty());
}

void tst_QAMQPQueue::exclusiveAccess()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));

    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(passiveQueue->error(), QAMQP::ResourceLockedError);

    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::exclusiveRemoval()
{
    Queue *queue = client->createQueue("test-exclusive-queue");
    queue->declare(Queue::Exclusive);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    client.data()->disconnectFromHost();
    QVERIFY(waitForSignal(client.data(), SIGNAL(disconnected())));

    // create a new client and try to access the queue that should
    // no longer exist
    Client secondClient;
    secondClient.connectToHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
    Queue *passiveQueue = secondClient.createQueue("test-exclusive-queue");
    passiveQueue->declare(Queue::Passive);
    QVERIFY(waitForSignal(passiveQueue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(passiveQueue->error(), QAMQP::NotFoundError);
    secondClient.disconnectFromHost();
    QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
}

void tst_QAMQPQueue::notFound()
{
    Queue *queue = client->createQueue("test-not-found");
    queue->declare(Queue::Passive);
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), QAMQP::NotFoundError);
}

void tst_QAMQPQueue::remove()
{
    Queue *queue = client->createQueue("test-remove");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    queue->remove(Queue::roIfEmpty|Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::removeIfUnused()
{
    Queue *queue = client->createQueue("test-remove-if-unused");
    declareQueueAndVerifyConsuming(queue);

    queue->remove(Queue::roIfUnused);
    QVERIFY(waitForSignal(queue, SIGNAL(error(QAMQP::Error))));
    QCOMPARE(queue->error(), QAMQP::PreconditionFailedError);
    QVERIFY(!queue->errorString().isEmpty());
}

void tst_QAMQPQueue::removeIfEmpty()
{
    // declare the queue and send messages to it
    Queue *queue = client->createQueue("test-remove-if-empty");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("first message", "test-remove-if-empty");

    // create a second client and try to delete the queue
    {
        Client secondClient;
        secondClient.connectToHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
        Queue *testDeleteQueue = secondClient.createQueue("test-remove-if-empty");
        testDeleteQueue->declare(Queue::Passive);
        QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(declared())));

        testDeleteQueue->remove(Queue::roIfEmpty);
        QVERIFY(waitForSignal(testDeleteQueue, SIGNAL(error(QAMQP::Error))));
        QCOMPARE(testDeleteQueue->error(), QAMQP::PreconditionFailedError);
        QVERIFY(!testDeleteQueue->errorString().isEmpty());

        secondClient.disconnectFromHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
    }

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::unbind()
{
    Queue *queue = client->createQueue("test-unbind");
    declareQueueAndVerifyConsuming(queue);

    queue->bind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(bound())));
    queue->unbind("amq.topic", "routingKey");
    QVERIFY(waitForSignal(queue, SIGNAL(unbound())));
}

void tst_QAMQPQueue::purge()
{
    Queue *queue = client->createQueue("test-purge");
    queue->declare(Queue::Durable);
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    Exchange *defaultExchange = client->createExchange();
    defaultExchange->publish("first message", "test-purge");
    defaultExchange->publish("second message", "test-purge");
    defaultExchange->publish("third message", "test-purge");

    // create second client to listen to messages and attempt purge
    {
        Client secondClient;
        secondClient.connectToHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(connected())));
        Queue *testPurgeQueue = secondClient.createQueue("test-purge");
        testPurgeQueue->declare(Queue::Passive);
        QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(declared())));

        QSignalSpy spy(testPurgeQueue, SIGNAL(purged(int)));
        testPurgeQueue->purge();
        QVERIFY(waitForSignal(testPurgeQueue, SIGNAL(purged(int))));
        QCOMPARE(spy.count(), 1);
        QCOMPARE(testPurgeQueue->size(), 0);
        QList<QVariant> arguments = spy.takeFirst();
        QCOMPARE(arguments.at(0).toInt(), 3);

        secondClient.disconnectFromHost();
        QVERIFY(waitForSignal(&secondClient, SIGNAL(disconnected())));
    }

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::canOnlyStartConsumingOnce()
{
    Queue *queue = client->createQueue("test-single-consumer");
    declareQueueAndVerifyConsuming(queue);
    QCOMPARE(queue->consume(), false);
}

void tst_QAMQPQueue::cancel()
{
    Queue *queue = client->createQueue("test-cancel");
    declareQueueAndVerifyConsuming(queue);

    QString consumerTag = queue->consumerTag();
    QSignalSpy cancelSpy(queue, SIGNAL(cancelled(QString)));
    QVERIFY(queue->cancel());
    QVERIFY(waitForSignal(queue, SIGNAL(cancelled(QString))));
    QVERIFY(!cancelSpy.isEmpty());
    QList<QVariant> arguments = cancelSpy.takeFirst();
    QCOMPARE(arguments.at(0).toString(), consumerTag);
}

void tst_QAMQPQueue::invalidCancelBecauseNotConsuming()
{
    Queue *queue = client->createQueue("test-invalid-cancel-because-not-consuming");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));
    QCOMPARE(queue->cancel(), false);

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

void tst_QAMQPQueue::invalidCancelBecauseInvalidConsumerTag()
{
    Queue *queue = client->createQueue("test-invalid-cancel-because-invalid-consumer-tag");
    declareQueueAndVerifyConsuming(queue);
    queue->setConsumerTag(QString());
    QCOMPARE(queue->cancel(), false);
}

void tst_QAMQPQueue::getEmpty()
{
    Queue *queue = client->createQueue("test-get-empty");
    declareQueueAndVerifyConsuming(queue);

    queue->get();
    QVERIFY(waitForSignal(queue, SIGNAL(empty())));
}

void tst_QAMQPQueue::get()
{
    Queue *queue = client->createQueue("test-get");
    queue->declare();
    QVERIFY(waitForSignal(queue, SIGNAL(declared())));

    const int messageCount = 50;
    Exchange *defaultExchange = client->createExchange();
    for (int i = 0; i < messageCount; ++i) {
        QString expected = QString("message %1").arg(i);
        defaultExchange->publish(expected, "test-get");
    }

    // wait for messages to be delivered
    QTest::qWait(25);

    for (int i = 0; i < messageCount; ++i) {
        QString expected = QString("message %1").arg(i);
        queue->get(false);
        QVERIFY(waitForSignal(queue, SIGNAL(messageReceived())));
        Message message = queue->dequeue();
        QCOMPARE(message.payload(), expected.toUtf8());
        queue->ack(message);
    }

    queue->get(false);
    QVERIFY(waitForSignal(queue, SIGNAL(empty())));

    // clean up queue
    queue->remove(Queue::roForce);
    QVERIFY(waitForSignal(queue, SIGNAL(removed())));
}

QTEST_MAIN(tst_QAMQPQueue)
#include "tst_qamqpqueue.moc"
<|endoftext|>