cellular/telephonysettings/xqbindings/psetwrapper/tsrc/common/testutilities.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 15:45:17 +0300
branchRCL_3
changeset 19 7d48bed6ce0c
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/

#include <QByteArray>
#include "testutilities.h"

/*!
  Replaces global new operator for utilizing binary. Enables OOM 
  simulation and memory leak detection.
  
  Note that creation of CBase derived Symbian classes 
  are not tracked, because CBase overloads new operator. 
 */
void* operator new(std::size_t sz) throw(std::bad_alloc)
{
    return MemoryAllocator::alloc(sz);
}

/*!
  Replaces global delete operator for utilizing binary. Enables OOM 
  simulation and memory leak detection. 
 */
void operator delete(void* memoryAddr) throw()
{
    return MemoryAllocator::free(memoryAddr);
}

void* operator new(std::size_t sz, const std::nothrow_t&) throw()
{
    return qMalloc(sz);
}

void  operator delete(void* memoryAddress, const std::nothrow_t&) throw()
{
    if (NULL != memoryAddress) {
        qFree(memoryAddress);
    }
}

bool MemoryAllocator::m_isOomSimulationEnabled = false;
int MemoryAllocator::m_numOfAllocsSinceLastFail = 0;
int MemoryAllocator::m_allocFailIndex = 1;
QList<void*> MemoryAllocator::m_allocList;

/*!
  MemoryAllocator::enableOomSimulation
 */
void MemoryAllocator::enableOomSimulation()
{
    m_isOomSimulationEnabled = true;
    m_allocFailIndex = 1;
    m_numOfAllocsSinceLastFail = 0;
}

/*!
  MemoryAllocator::disableOomSimulation
 */
void MemoryAllocator::disableOomSimulation()
{
    m_isOomSimulationEnabled = false;
}

/*!
  MemoryAllocator::isOomSimulationEnabled
 */
bool MemoryAllocator::isOomSimulationEnabled()
{
    return m_isOomSimulationEnabled;
}

/*!
  MemoryAllocator::currentAllocFailIndex
 */
int MemoryAllocator::currentAllocFailIndex()
{
    return m_allocFailIndex;
}

/*!
  MemoryAllocator::alloc
 */
void* MemoryAllocator::alloc(std::size_t sz)
{
    if (isOomSimulationEnabled()) {
        m_numOfAllocsSinceLastFail++;
        if (m_allocFailIndex == m_numOfAllocsSinceLastFail) {
            m_allocFailIndex++;
            m_numOfAllocsSinceLastFail = 0;
#ifdef QT_NO_EXCEPTIONS
            return NULL;
#else
            throw std::bad_alloc();
#endif
        }
    }
    
    void *allocatedMemoryAddr = qMalloc(sz);
    m_allocList.append(allocatedMemoryAddr);
    return allocatedMemoryAddr;
}

/*!
  MemoryAllocator::free
 */
void MemoryAllocator::free(void *memoryAddress)
{
    if (memoryAddress) {
        int index = m_allocList.indexOf(memoryAddress);
        if (-1 != index) {
            m_allocList.removeAt(index);
        }
        qFree(memoryAddress);
    }
}

/*!
  MemoryAllocator::verifyMemoryAllocations
 */
void MemoryAllocator::verifyMemoryAllocations()
{
    int numOfUnfreedCells = m_allocList.count();
    if (0 != numOfUnfreedCells) {
        for ( int i = 0; i < numOfUnfreedCells; i++) {
            qDebug("UNFREED CELL: %x", reinterpret_cast<int>(m_allocList.at(i)));
        }
    
    m_allocList.clear();
    throw std::bad_alloc();
    }
    
    m_allocList.clear();
}


/*!
  OomTestExecuter::runTest
 */
void OomTestExecuter::runTest(
    QObject &testObject, const char *testMethod)
{
    qDebug() << "OomTestExecuter::runTest : IN :" << testMethod;
    
    MemoryAllocator::enableOomSimulation();

    bool exceptionCaught = false;
    do {
        exceptionCaught = false;
        int currentAllocFailIndex = MemoryAllocator::currentAllocFailIndex();
        
        try {
            try {
                QMetaObject::invokeMethod(
                    &testObject, "init", Qt::DirectConnection);
                QMetaObject::invokeMethod(
                    &testObject, testMethod, Qt::DirectConnection);
            } catch (const std::bad_alloc &ex) {
                exceptionCaught = true;
                QMetaObject::invokeMethod(
                    &testObject, "cleanup", Qt::DirectConnection);
            }
        // TODO: for some reason bad_alloc exception is corrupted to 
        // unknown exception and nested catch block is needed to be able to
        // handle situation. One level catch does not work for some reason.
        } catch (...) {
            exceptionCaught = true;
            QMetaObject::invokeMethod(
                &testObject, "cleanup", Qt::DirectConnection);
            if (currentAllocFailIndex == MemoryAllocator::currentAllocFailIndex()) {
                qDebug() << "OomTestExecuter::runTest, ERROR: unexpected exception!";
                throw;
            }
        }
    } while(exceptionCaught);
    
    QMetaObject::invokeMethod(&testObject, "cleanup", Qt::DirectConnection);
    MemoryAllocator::disableOomSimulation();
    qDebug() << "OomTestExecuter::runTest : OUT :" << testMethod;
}

/*!
  OomTestExecuter::runAllTests
 */
void OomTestExecuter::runAllTests(
    QObject &testObject, const char *callingTestMethod)
{
    const QMetaObject *metaObject = testObject.metaObject();
    
    int methodCount = metaObject->methodCount();
    for (int i = 0; i < methodCount; ++i) {
        QMetaMethod slotMethodCandidate = metaObject->method(i);
        if (!isValidSlot(slotMethodCandidate)) {
            continue;
        }
        
        QByteArray slotMethodName(slotMethodCandidate.signature());
        // remove parentheses
        slotMethodName = slotMethodName.left(slotMethodName.length() - 2);
        
        // Prevent from infinite loop and do not execute test method, which
        // has called runAllTests.
        if (slotMethodName != callingTestMethod) {
            runTest(testObject, slotMethodName);
        }
    }
}

/*!
  OomTestExecuter::isValidSlot
 */
bool OomTestExecuter::isValidSlot(const QMetaMethod &sl)
{
    if ((sl.access() != QMetaMethod::Private) || !sl.parameterTypes().isEmpty()
        || qstrlen(sl.typeName()) || (sl.methodType() != QMetaMethod::Slot)) {
        return false;
    }
    
    const char *sig = sl.signature();
    int len = qstrlen(sig);
    if (len < 2) {
        return false;
    }
    
    if (sig[len - 2] != '(' || sig[len - 1] != ')') {
        return false;
    }
    
    if (len > 7 && strcmp(sig + (len - 7), "_data()") == 0) {
        return false;
    }
    
    if ((strcmp(sig, "initTestCase()") == 0) || (strcmp(sig, "cleanupTestCase()") == 0)
        || (strcmp(sig, "cleanup()") == 0) || (strcmp(sig, "init()") == 0)) {
        return false;
    }
    
    return true;
}